From d575878369ec9aaf6dffaba9ff543f2c3664f793 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 16 May 2019 16:28:51 +0530 Subject: [PATCH 1/2] feat: Ability to reorder cards --- frappe/desk/moduleview.py | 121 +++++++++++++--- frappe/patches.txt | 2 +- frappe/patches/v12_0/init_desk_settings.py | 2 +- .../frappe/views/components/DeskModuleBox.vue | 12 +- .../frappe/views/components/DeskSection.vue | 31 +++- .../js/frappe/views/components/Desktop.vue | 135 ++++++++---------- 6 files changed, 203 insertions(+), 100 deletions(-) diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py index a9a460b124..24542e8abb 100644 --- a/frappe/desk/moduleview.py +++ b/frappe/desk/moduleview.py @@ -287,45 +287,132 @@ def get_onboard_items(app, module): return onboard_items or fallback_items - @frappe.whitelist() +def get_links_for_module(app, module): + return [l.get('label') for l in get_links(app, module)] + def get_links(app, module): try: sections = get_config(app, frappe.scrub(module)) except ImportError: return [] - link_names = [] - + links = [] for section in sections: - for item in section["items"]: - link_names.append(item.get("label")) - return link_names + for item in section['items']: + links.append(item) + return links @frappe.whitelist() -def hide_modules_from_desktop(modules): - modules = frappe.parse_json(modules) - home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings') +def get_desktop_settings(): + from frappe.config import get_modules_from_all_apps_for_user + all_modules = get_modules_from_all_apps_for_user() + home_settings = frappe.db.get_value('User', frappe.session.user, 'home_settings') home_settings = frappe.parse_json(home_settings or '{}') - home_settings['hidden_modules'] = modules + modules_by_name = {} + for m in all_modules: + modules_by_name[m['module_name']] = m + + module_categories = ['Modules', 'Domains', 'Places', 'Administration'] + user_modules_by_category = {} + + user_saved_modules_by_category = home_settings.modules_by_category or {} + user_saved_links_by_module = home_settings.links_by_module or {} + + def apply_user_saved_links(module): + module = frappe._dict(module) + all_links = get_links(module.app, module.module_name) + module_links_by_label = {} + for link in all_links: + module_links_by_label[link['label']] = link + + if module.module_name in user_saved_links_by_module: + user_links = frappe.parse_json(user_saved_links_by_module[module.module_name]) + module.links = [module_links_by_label[l] for l in user_links] + + return module + + for category in module_categories: + if category in user_saved_modules_by_category: + user_modules = user_saved_modules_by_category[category] + user_modules_by_category[category] = [apply_user_saved_links(modules_by_name[m]) \ + for m in user_modules] + else: + user_modules_by_category[category] = [apply_user_saved_links(m) \ + for m in all_modules if m['category'] == category] + + return user_modules_by_category + +@frappe.whitelist() +def update_modules_for_desktop(modules_by_category): + modules_by_category = frappe.parse_json(modules_by_category) + home_settings = get_home_settings() + + user_modules_by_category = home_settings.modules_by_category or {} + + for category in modules_by_category: + new_user_modules = modules_by_category[category] + user_modules = user_modules_by_category.get(category, [{'name': m, 'hidden': False} for m in new_user_modules]) + for module in user_modules: + module['hidden'] = module['name'] not in new_user_modules + user_modules_by_category[category] = user_modules + + home_settings.modules_by_category = user_modules_by_category + frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) + return get_desktop_settings() - return home_settings +@frappe.whitelist() +def update_modules_order(module_category, modules): + modules = frappe.parse_json(modules) + home_settings = get_home_settings() + home_settings.modules_by_category = home_settings.modules_by_category or {} + home_settings.modules_by_category[module_category] = modules + frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) @frappe.whitelist() def update_links_for_module(module_name, links): - home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings') - home_settings = frappe.parse_json(home_settings or '{}') + links = frappe.parse_json(links) + home_settings = get_home_settings() - home_settings.setdefault('links', {}) - home_settings['links'].setdefault(module_name, None) - home_settings['links'][module_name] = links + home_settings.setdefault('links_by_module', {}) + home_settings['links_by_module'].setdefault(module_name, None) + home_settings['links_by_module'][module_name] = links frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) - return home_settings + return get_desktop_settings() + +@frappe.whitelist() +def get_options_for_show_hide_cards(): + from frappe.config import get_modules_from_all_apps_for_user + all_modules = get_modules_from_all_apps_for_user() + home_settings = get_home_settings() + + + visible_modules_by_category = home_settings.modules_by_category or {} + visible_modules = [] + for category in visible_modules_by_category: + visible_modules += visible_modules_by_category[category] + + options = [] + for module in all_modules: + module = frappe._dict(module) + checked = module.category not in visible_modules_by_category or module.module_name in visible_modules + options.append({ + 'category': module.category, + 'label': module.label, + 'value': module.module_name, + 'checked': checked + }) + + return options + +def get_home_settings(): + home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings') + return frappe.parse_json(home_settings or '{}') def get_module_link_items_from_list(app, module, list_of_link_names): diff --git a/frappe/patches.txt b/frappe/patches.txt index c0b2a8238f..d28e7eb318 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -235,7 +235,7 @@ frappe.patches.v12_0.set_primary_key_in_series execute:frappe.delete_doc("Page", "modules", ignore_missing=True) frappe.patches.v11_0.set_default_letter_head_source frappe.patches.v12_0.setup_comments_from_communications -frappe.patches.v12_0.init_desk_settings #11-03-2019 +frappe.patches.v12_0.init_desk_settings #16-05-2019 frappe.patches.v12_0.replace_null_values_in_tables frappe.patches.v12_0.reset_home_settings frappe.patches.v12_0.update_print_format_type diff --git a/frappe/patches/v12_0/init_desk_settings.py b/frappe/patches/v12_0/init_desk_settings.py index 782ced8a26..ecd9c94d5b 100644 --- a/frappe/patches/v12_0/init_desk_settings.py +++ b/frappe/patches/v12_0/init_desk_settings.py @@ -8,4 +8,4 @@ from frappe.desk.moduleview import get_onboard_items def execute(): """Reset the initial customizations for desk, with modules, indices and links.""" frappe.reload_doc("core", "doctype", "user") - frappe.db.sql("""update tabUser set home_settings = %s""", (''), debug=True) + frappe.db.sql("""update tabUser set home_settings = ''""") diff --git a/frappe/public/js/frappe/views/components/DeskModuleBox.vue b/frappe/public/js/frappe/views/components/DeskModuleBox.vue index e57b128033..355a447475 100644 --- a/frappe/public/js/frappe/views/components/DeskModuleBox.vue +++ b/frappe/public/js/frappe/views/components/DeskModuleBox.vue @@ -3,6 +3,7 @@ v-if="!hidden" class="border module-box" :class="{ 'hovered-box': hovered }" + :data-module-name="module_name" >
-
+
this.dragging = true, + onEnd: () => { + this.dragging = false; + let modules = Array.from(modules_container.querySelectorAll('.module-box')) + .map(node => node.dataset.moduleName); + + this.$emit('module-order-change', { + module_category: this.category, + modules + }); + } + }) + }, show_module_card_customize_dialog(module) { const d = new frappe.ui.Dialog({ title: __('Customize Shortcuts'), @@ -34,7 +59,7 @@ export default { fieldname: 'links', fieldtype: 'MultiSelectPills', get_data() { - return frappe.call('frappe.desk.moduleview.get_links', { + return frappe.call('frappe.desk.moduleview.get_links_for_module', { app: module.app, module: module.module_name, }).then(r => r.message); @@ -48,7 +73,7 @@ export default { module_name: module.module_name, links }).then(r => { - this.$emit('update_home_settings', r.message); + this.$emit('update-desktop-settings', r.message); }); d.hide(); } diff --git a/frappe/public/js/frappe/views/components/Desktop.vue b/frappe/public/js/frappe/views/components/Desktop.vue index dd2f68911a..2560b8a794 100644 --- a/frappe/public/js/frappe/views/components/Desktop.vue +++ b/frappe/public/js/frappe/views/components/Desktop.vue @@ -14,7 +14,8 @@ v-if="get_modules_for_category(category).length" :category="category" :modules="get_modules_for_category(category)" - @update_home_settings="hs => update_modules_with_home_settings(hs)" + @update-desktop-settings="update_desktop_settings" + @module-order-change="update_module_order" >
@@ -30,99 +31,83 @@ export default { DeskSection }, data() { - let modules_list = frappe.boot.allowed_modules - .filter(d => (d.type==='module' || d.category==='Places') && !d.blocked) - .map(d => { - d.links = (d.links || []).map(link => { - link.route = generate_route(link); - return link; - }); - return d; - }); - return { module_categories: ['Modules', 'Domains', 'Places', 'Administration'], - modules: modules_list, + modules: [], home_settings_fetched: false }; }, created() { - this.fetch_home_settings(); + this.fetch_desktop_settings(); }, methods: { - fetch_home_settings() { - return frappe.db.get_value('User', user, 'home_settings') + fetch_desktop_settings() { + frappe.call('frappe.desk.moduleview.get_desktop_settings') .then(r => { - let home_settings = JSON.parse(r.message.home_settings || '{}'); - this.update_modules_with_home_settings(home_settings); - this.home_settings_fetched = true; + if (r.message) { + this.update_desktop_settings(r.message); + this.home_settings_fetched = true; + } }); }, - update_modules_with_home_settings(home_settings) { - this.modules = this.modules.map(m => { - let hidden_modules = home_settings.hidden_modules || []; - m.hidden = hidden_modules.includes(m.module_name); - - let links = home_settings.links && home_settings.links[m.module_name]; - - if (links) { - links = JSON.parse(links); - - let default_links = m.links.map(link => link.name); - m.links = m.links.map(link => { - link.hidden = !links.includes(link.name); + update_desktop_settings(desktop_settings) { + this.modules = this.add_routes_for_module_links(desktop_settings); + }, + add_routes_for_module_links(user_settings) { + for (let category in user_settings) { + user_settings[category] = user_settings[category].map(m => { + m.links = (m.links || []).map(link => { + link.route = generate_route(link); return link; }); - let new_links = links - .filter(link => !default_links.includes(link)) - .filter(Boolean) - .map(link => { - let new_link = { name: link, label: link, type: 'doctype' }; - new_link.route = generate_route(new_link); - return new_link; - }); - m.links = m.links.concat(new_links); - } - - return m; - }); + return m; + }); + } + return user_settings; + }, + update_module_order({ module_category, modules }) { + frappe.call('frappe.desk.moduleview.update_modules_order', { module_category, modules }); }, get_modules_for_category(category) { - return this.modules.filter(m => m.category === category && !m.hidden); + return this.modules[category] || []; }, show_hide_cards_dialog() { - let fields = this.module_categories.map(category => { - let modules = this.modules.filter(m => m.category === category); - let options = modules.map( - m => ({ label: m.label, value: m.module_name, checked: !m.hidden }) - ); - return { - label: category, - fieldname: category, - fieldtype: 'MultiCheck', - options, - columns: 2 - } - }); - const d = new frappe.ui.Dialog({ - title: __('Show / Hide Cards'), - fields: fields.filter(f => f.options.length > 0), - primary_action_label: __('Save'), - primary_action: (values) => { - let all_modules = this.modules.map(m => m.module_name); - let modules_to_show = Object.keys(values).map(k => values[k]).flatMap(m => m); - let modules_to_hide = all_modules.filter(m => !modules_to_show.includes(m)); - d.hide(); + frappe.call('frappe.desk.moduleview.get_options_for_show_hide_cards') + .then(r => { + let module_options = r.message; + let fields = this.module_categories.map(category => { + let options = module_options.filter(m => m.category === category); + return { + label: category, + fieldname: category, + fieldtype: 'MultiCheck', + options, + columns: 2 + } + }); + const d = new frappe.ui.Dialog({ + title: __('Show / Hide Cards'), + fields: fields.filter(f => f.options.length > 0), + primary_action_label: __('Save'), + primary_action: (values) => { + d.hide(); - frappe.call('frappe.desk.moduleview.hide_modules_from_desktop', { - modules: modules_to_hide - }) - .then(r => r.message) - .then(hs => this.update_modules_with_home_settings(hs)); - } - }); + let modules_by_category = {}; + for (let category of this.module_categories) { + let modules = values[category] || []; + modules_by_category[category] = this.get_modules_for_category(category) + .map(m => m.module_name) + .filter(m => modules.includes(m)); + } - d.show(); + frappe.call('frappe.desk.moduleview.update_modules_for_desktop', { + modules_by_category + }).then(r => this.update_desktop_settings(r.message)); + } + }); + + d.show(); + }); } } } From 54c6720b28731f2b4825f07abe98c7f522717327 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 18 Jul 2019 15:51:35 +0530 Subject: [PATCH 2/2] fix: Store hidden modules separately - Get/Set values from cache --- frappe/desk/moduleview.py | 60 +++++++++++-------- .../frappe/views/components/DeskSection.vue | 2 +- .../js/frappe/views/components/Desktop.vue | 37 ++++++++---- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py index 0db55bad8a..0f78bce3e1 100644 --- a/frappe/desk/moduleview.py +++ b/frappe/desk/moduleview.py @@ -307,8 +307,7 @@ def get_links(app, module): def get_desktop_settings(): from frappe.config import get_modules_from_all_apps_for_user all_modules = get_modules_from_all_apps_for_user() - home_settings = frappe.db.get_value('User', frappe.session.user, 'home_settings') - home_settings = frappe.parse_json(home_settings or '{}') + home_settings = get_home_settings() modules_by_name = {} for m in all_modules: @@ -329,7 +328,7 @@ def get_desktop_settings(): if module.module_name in user_saved_links_by_module: user_links = frappe.parse_json(user_saved_links_by_module[module.module_name]) - module.links = [module_links_by_label[l] for l in user_links] + module.links = [module_links_by_label[l] for l in user_links if l in module_links_by_label] return module @@ -342,27 +341,33 @@ def get_desktop_settings(): user_modules_by_category[category] = [apply_user_saved_links(m) \ for m in all_modules if m['category'] == category] + # filter out hidden modules + if home_settings.hidden_modules: + for category in user_modules_by_category: + hidden_modules = home_settings.hidden_modules or [] + modules = user_modules_by_category[category] + user_modules_by_category[category] = [module for module in modules if module.module_name not in hidden_modules] + return user_modules_by_category @frappe.whitelist() -def update_modules_for_desktop(modules_by_category): - modules_by_category = frappe.parse_json(modules_by_category) +def update_hidden_modules(category_map): + category_map = frappe.parse_json(category_map) home_settings = get_home_settings() - user_modules_by_category = home_settings.modules_by_category or {} + saved_hidden_modules = home_settings.hidden_modules or [] - for category in modules_by_category: - new_user_modules = modules_by_category[category] - user_modules = user_modules_by_category.get(category, [{'name': m, 'hidden': False} for m in new_user_modules]) - for module in user_modules: - module['hidden'] = module['name'] not in new_user_modules - user_modules_by_category[category] = user_modules + for category in category_map: + config = frappe._dict(category_map[category]) + saved_hidden_modules += config.removed or [] + saved_hidden_modules = [d for d in saved_hidden_modules if d not in (config.added or [])] - home_settings.modules_by_category = user_modules_by_category + home_settings.hidden_modules = saved_hidden_modules + set_home_settings(home_settings) - frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) return get_desktop_settings() + @frappe.whitelist() def update_modules_order(module_category, modules): modules = frappe.parse_json(modules) @@ -370,8 +375,8 @@ def update_modules_order(module_category, modules): home_settings.modules_by_category = home_settings.modules_by_category or {} home_settings.modules_by_category[module_category] = modules - frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) + set_home_settings(home_settings) @frappe.whitelist() def update_links_for_module(module_name, links): @@ -381,7 +386,8 @@ def update_links_for_module(module_name, links): home_settings.setdefault('links_by_module', {}) home_settings['links_by_module'].setdefault(module_name, None) home_settings['links_by_module'][module_name] = links - frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) + + set_home_settings(home_settings) return get_desktop_settings() @@ -391,28 +397,32 @@ def get_options_for_show_hide_cards(): all_modules = get_modules_from_all_apps_for_user() home_settings = get_home_settings() - - visible_modules_by_category = home_settings.modules_by_category or {} - visible_modules = [] - for category in visible_modules_by_category: - visible_modules += visible_modules_by_category[category] + hidden_modules = home_settings.hidden_modules or [] options = [] for module in all_modules: module = frappe._dict(module) - checked = module.category not in visible_modules_by_category or module.module_name in visible_modules options.append({ 'category': module.category, 'label': module.label, 'value': module.module_name, - 'checked': checked + 'checked': module.module_name not in hidden_modules }) return options +def set_home_settings(home_settings): + frappe.cache().hset('home_settings', frappe.session.user, home_settings) + frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) + +@frappe.whitelist() def get_home_settings(): - home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings') - return frappe.parse_json(home_settings or '{}') + def get_from_db(): + settings = frappe.db.get_value("User", frappe.session.user, 'home_settings') + return frappe.parse_json(settings or '{}') + + home_settings = frappe.cache().hget('home_settings', frappe.session.user, get_from_db) + return home_settings def get_module_link_items_from_list(app, module, list_of_link_names): diff --git a/frappe/public/js/frappe/views/components/DeskSection.vue b/frappe/public/js/frappe/views/components/DeskSection.vue index a981e13d34..5c006920af 100644 --- a/frappe/public/js/frappe/views/components/DeskSection.vue +++ b/frappe/public/js/frappe/views/components/DeskSection.vue @@ -7,7 +7,7 @@
f.options.length > 0); + + let old_values = null; + const d = new frappe.ui.Dialog({ title: __('Show / Hide Cards'), - fields: fields.filter(f => f.options.length > 0), + fields: fields, primary_action_label: __('Save'), primary_action: (values) => { - d.hide(); - let modules_by_category = {}; + let category_map = {}; for (let category of this.module_categories) { - let modules = values[category] || []; - modules_by_category[category] = this.get_modules_for_category(category) - .map(m => m.module_name) - .filter(m => modules.includes(m)); - } + let old_modules = old_values[category] || []; + let new_modules = values[category] || []; - frappe.call('frappe.desk.moduleview.update_modules_for_desktop', { - modules_by_category - }).then(r => this.update_desktop_settings(r.message)); + let removed = old_modules.filter(module => !new_modules.includes(module)); + let added = new_modules.filter(module => !old_modules.includes(module)); + + category_map[category] = { added, removed }; + } + + frappe.call({ + method: 'frappe.desk.moduleview.update_hidden_modules', + args: { category_map }, + btn: d.get_primary_btn() + }).then(r => { + this.update_desktop_settings(r.message) + d.hide(); + }); } }); d.show(); + + // deepcopy + old_values = JSON.parse(JSON.stringify(d.get_values())); }); } }