From d9bbd103822bc45d4a3b257e955cd39a4c9fe0bd Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 4 Dec 2019 15:59:38 +0530 Subject: [PATCH] fix: added a 'Continue' type slide --- .../onboarding_slide/onboarding_slide.json | 34 +++++----- .../onboarding_slide/onboarding_slide.py | 68 ++++++++++++++----- .../company_letter_head.json | 5 +- frappe/public/js/frappe/desk.js | 5 -- .../public/js/frappe/ui/onboarding_dialog.js | 27 +++++++- 5 files changed, 95 insertions(+), 44 deletions(-) diff --git a/frappe/desk/doctype/onboarding_slide/onboarding_slide.json b/frappe/desk/doctype/onboarding_slide/onboarding_slide.json index c5497070ed..3f6f0d719f 100644 --- a/frappe/desk/doctype/onboarding_slide/onboarding_slide.json +++ b/frappe/desk/doctype/onboarding_slide/onboarding_slide.json @@ -15,7 +15,6 @@ "slide_desc", "action_section_break", "slide_type", - "submit_method", "column_break_6", "max_count", "add_more_button", @@ -25,7 +24,8 @@ "section_break_10", "domains", "column_break_12", - "help_links" + "help_links", + "is_completed" ], "fields": [ { @@ -36,13 +36,6 @@ "reqd": 1, "unique": 1 }, - { - "depends_on": "eval:doc.slide_type!='Information'", - "description": "By default the code inside `create_onboarding_docs` method of the `Reference Document Type` is executed. If your method is not on the doctype level, place this method in {app_name}.utilities.onboarding_utils.{method_name} and specify the method name here", - "fieldname": "submit_method", - "fieldtype": "Data", - "label": "Submit Method" - }, { "fieldname": "slide_desc", "fieldtype": "HTML Editor", @@ -58,13 +51,13 @@ }, { "default": "0", - "depends_on": "eval:doc.slide_type!='Information'", + "depends_on": "eval:doc.slide_type=='Create' || doc.slide_type=='Settings'", "fieldname": "add_more_button", "fieldtype": "Check", "label": "Add More Button" }, { - "depends_on": "eval:doc.slide_type!='Information'", + "depends_on": "eval:doc.slide_type=='Create' || doc.slide_type=='Settings'", "fieldname": "slide_fields", "fieldtype": "Table", "label": "Slide Fields", @@ -98,11 +91,11 @@ "label": "Action Settings" }, { - "description": "If slide type is Action there should be a submit method bound to be executed after the slide is completed.", + "description": "If Slide Type is Create or Settings there should be a 'create_onboarding_docs' method in the {ref_doctype}.py file bound to be executed after the slide is completed.", "fieldname": "slide_type", "fieldtype": "Select", "label": "Slide Type", - "options": "Information\nCreate\nSettings", + "options": "Information\nCreate\nSettings\nContinue", "reqd": 1 }, { @@ -131,7 +124,7 @@ "label": "Description" }, { - "depends_on": "eval:doc.slide_type!='Information'", + "depends_on": "eval:doc.slide_type=='Create' || doc.slide_type=='Settings'", "fieldname": "ref_doctype", "fieldtype": "Link", "label": "Reference Document Type", @@ -145,19 +138,28 @@ "label": "Slide Order" }, { - "depends_on": "eval:doc.slide_type=='Information'", + "depends_on": "eval:doc.slide_type=='Information' || doc.slide_type=='Continue'", "fieldname": "slide_module", "fieldtype": "Link", "label": "Module", "options": "Module Def" }, { + "collapsible_depends_on": "eval:doc.slide_type=='Create' || doc.slide_type=='Settings'", "fieldname": "section_break_18", "fieldtype": "Section Break", "label": "Fields" + }, + { + "default": "0", + "fieldname": "is_completed", + "fieldtype": "Check", + "hidden": 1, + "label": "Is Completed", + "print_hide": 1 } ], - "modified": "2019-12-02 16:17:17.368741", + "modified": "2019-12-04 10:50:43.528901", "modified_by": "Administrator", "module": "Desk", "name": "Onboarding Slide", diff --git a/frappe/desk/doctype/onboarding_slide/onboarding_slide.py b/frappe/desk/doctype/onboarding_slide/onboarding_slide.py index 1aacab2391..7f1f3e9e7b 100644 --- a/frappe/desk/doctype/onboarding_slide/onboarding_slide.py +++ b/frappe/desk/doctype/onboarding_slide/onboarding_slide.py @@ -5,10 +5,15 @@ from __future__ import unicode_literals import frappe import json +from frappe import _ from frappe.model.document import Document from frappe.modules.export_file import export_to_files class OnboardingSlide(Document): + def validate(self): + if frappe.db.exists('Onboarding Slide', {'slide_type': 'Continue', 'name': ('!=', self.name)}): + frappe.throw(_("An Onboarding Slide of Slide Type Continue already exists.")) + def on_update(self): if self.ref_doctype: module = frappe.db.get_value('DocType', self.ref_doctype, 'module') @@ -18,14 +23,19 @@ class OnboardingSlide(Document): def get_onboarding_slides_as_list(): slides = [] - slide_docs = frappe.get_all('Onboarding Slide', - filters={'slide_order': ('!=', 0)}, + slide_docs = frappe.db.get_all('Onboarding Slide', + filters={'is_completed': 0}, + or_filters={'slide_order': ('!=', 0), 'slide_type': 'Continue'}, order_by='slide_order') + + # to check if continue slide is required + first_slide = get_first_slide() + for entry in slide_docs: # using get_doc because child table fields are not fetched in get_all slide_doc = frappe.get_doc('Onboarding Slide', entry.name) if frappe.scrub(slide_doc.app) in frappe.get_installed_apps(): - slides.append(frappe._dict( + slide = frappe._dict( slide_type=slide_doc.slide_type, title=slide_doc.slide_title, help=slide_doc.slide_desc, @@ -33,11 +43,16 @@ def get_onboarding_slides_as_list(): help_links=get_help_links(slide_doc), add_more=slide_doc.add_more_button, max_count=slide_doc.max_count, - submit_method=slide_doc.submit_method, image_src=get_slide_image(slide_doc), ref_doctype=slide_doc.ref_doctype, app=slide_doc.app - )) + ) + if slide.slide_type == 'Continue': + if is_continue_slide_required(first_slide): + slides.insert(0, slide) + else: + slides.append(slide) + return slides @frappe.whitelist() @@ -65,21 +80,26 @@ def get_slide_image(slide_doc): return slide_doc.image_src return None +def is_continue_slide_required(first_slide): + # check if first slide itself is not completed + if not first_slide.is_completed: + return False + + # check if there is any active slide which is not completed + return frappe.db.exists('Onboarding Slide', { + 'is_completed': 0, + 'slide_order': ('!=', 0), + 'slide_type': ('!=', 'Continue') + }) + @frappe.whitelist() -def create_onboarding_docs(values, doctype=None, submit_method=None, app=None, slide_type=None): +def create_onboarding_docs(values, doctype=None, app=None, slide_type=None): data = json.loads(values) - if submit_method: - try: - method = frappe.scrub(app) + '.utilities.onboarding_utils.' + submit_method - frappe.call(method, data) - except AttributeError: - create_generic_onboarding_doc(data, doctype, slide_type) + doc = frappe.new_doc(doctype) + if hasattr(doc, 'create_onboarding_docs'): + doc.create_onboarding_docs(data) else: - doc = frappe.new_doc(doctype) - if hasattr(doc, 'create_onboarding_docs'): - doc.create_onboarding_docs(data) - else: - create_generic_onboarding_doc(data, doctype, slide_type) + create_generic_onboarding_doc(data, doctype, slide_type) def create_generic_onboarding_doc(data, doctype, slide_type): if slide_type == 'Settings': @@ -94,4 +114,16 @@ def create_generic_onboarding_doc(data, doctype, slide_type): doc.set(entry, data.get(entry)) doc.flags.ignore_mandatory = True doc.flags.ignore_links = True - doc.insert() \ No newline at end of file + doc.insert() + +@frappe.whitelist() +def mark_slide_as_completed(slide_title): + frappe.db.set_value('Onboarding Slide', slide_title, 'is_completed', 1) + +def get_first_slide(): + slides = frappe.db.get_all('Onboarding Slide', + filters={'slide_order': ('!=', 0), 'slide_type': ('!=', 'Continue')}, + order_by='slide_order', + fields=['name', 'is_completed'] + ) + return slides[0] \ No newline at end of file diff --git a/frappe/printing/onboarding_slide/company_letter_head/company_letter_head.json b/frappe/printing/onboarding_slide/company_letter_head/company_letter_head.json index 6b4ad815e4..2f51d2e18a 100644 --- a/frappe/printing/onboarding_slide/company_letter_head/company_letter_head.json +++ b/frappe/printing/onboarding_slide/company_letter_head/company_letter_head.json @@ -14,7 +14,7 @@ "idx": 0, "image_src": "/assets/erpnext/images/illustrations/letterhead-onboard.png", "max_count": 0, - "modified": "2019-12-02 12:57:41.353913", + "modified": "2019-12-03 22:54:57.618989", "modified_by": "Administrator", "name": "Company Letter Head", "owner": "Administrator", @@ -32,6 +32,5 @@ ], "slide_order": 20, "slide_title": "Company Letter Head", - "slide_type": "Create", - "submit_method": "" + "slide_type": "Create" } \ No newline at end of file diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index ebc5973c73..dbdb698ebb 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -496,11 +496,6 @@ frappe.Application = Class.extend({ slides: slides }); me.progress_dialog.show(); - frappe.call({ - method: "frappe.desk.page.setup_wizard.setup_wizard.reset_is_first_startup", - args: {}, - callback: () => {} - }); }); } } diff --git a/frappe/public/js/frappe/ui/onboarding_dialog.js b/frappe/public/js/frappe/ui/onboarding_dialog.js index c5299e745a..be6f0fc91b 100644 --- a/frappe/public/js/frappe/ui/onboarding_dialog.js +++ b/frappe/public/js/frappe/ui/onboarding_dialog.js @@ -44,12 +44,12 @@ frappe.setup.OnboardingSlide = class OnboardingSlide extends frappe.ui.Slide { args: { values: me.values, doctype: me.ref_doctype, - submit_method: me.submit_method, app: me.app, slide_type: me.slide_type }, callback: function() { if (me.id === me.parent[0].children.length-1) { + me.reset_is_first_startup(); $('.onboarding-dialog').modal('toggle'); frappe.msgprint({ message: __('You are all set up!'), @@ -86,11 +86,34 @@ frappe.setup.OnboardingSlide = class OnboardingSlide extends frappe.ui.Slide { } setup_action_button() { - if (this.slide_type !== 'Information') { + if (this.slide_type === 'Create' || this.slide_type == 'Settings' || this.id === this.parent[0].children.length-1) { this.$action_button.addClass('primary'); } else { this.$action_button.removeClass('primary'); } + + this.$action_button.on('click', () => { + if (this.slide_type != 'Continue') { + this.mark_as_completed(); + } + }); + } + + mark_as_completed() { + frappe.call({ + method: 'frappe.desk.doctype.onboarding_slide.onboarding_slide.mark_slide_as_completed', + args: {slide_title: this.title}, + callback: () => {}, + freeze: true + }); + } + + reset_is_first_startup() { + frappe.call({ + method: "frappe.desk.page.setup_wizard.setup_wizard.reset_is_first_startup", + args: {}, + callback: () => {} + }); } };