diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py index ccde3aad40..0f78bce3e1 100644 --- a/frappe/desk/moduleview.py +++ b/frappe/desk/moduleview.py @@ -287,44 +287,141 @@ 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): +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 = get_home_settings() + + 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 if l in module_links_by_label] + + 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] + + # 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_hidden_modules(category_map): + category_map = frappe.parse_json(category_map) + home_settings = get_home_settings() + + saved_hidden_modules = home_settings.hidden_modules or [] + + 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.hidden_modules = saved_hidden_modules + set_home_settings(home_settings) + + return get_desktop_settings() + + +@frappe.whitelist() +def update_modules_order(module_category, modules): modules = frappe.parse_json(modules) - 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 - frappe.db.set_value('User', frappe.session.user, 'home_settings', json.dumps(home_settings)) - - return home_settings + home_settings = get_home_settings() + home_settings.modules_by_category = home_settings.modules_by_category or {} + home_settings.modules_by_category[module_category] = modules + set_home_settings(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 + + set_home_settings(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() + + hidden_modules = home_settings.hidden_modules or [] + + options = [] + for module in all_modules: + module = frappe._dict(module) + options.append({ + 'category': module.category, + 'label': module.label, + 'value': module.module_name, + '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(): + 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 diff --git a/frappe/patches.txt b/frappe/patches.txt index 74a8656379..0a43328a12 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -237,7 +237,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 31c6cf9207..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" >
@@ -10,7 +11,7 @@

- + {{ label }}

@@ -54,7 +55,7 @@ export default { }; }, computed: { - iconClass() { + icon_class() { if (this.icon) { return this.icon; } else { @@ -82,7 +83,12 @@ export default { background-color: #ffffff; } -.module-box:hover { +.module-box.sortable-chosen { + background-color: @disabled-background; + border-color: @disabled-background; +} + +.modules-container:not(.dragging) .module-box:hover { border-color: @text-muted; } diff --git a/frappe/public/js/frappe/views/components/DeskSection.vue b/frappe/public/js/frappe/views/components/DeskSection.vue index d7504c7d76..5c006920af 100644 --- a/frappe/public/js/frappe/views/components/DeskSection.vue +++ b/frappe/public/js/frappe/views/components/DeskSection.vue @@ -4,10 +4,10 @@
{{ category }}
-
+
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..c1cca4d58b 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,96 @@ 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 + } + }).filter(f => f.options.length > 0); - 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 old_values = null; - d.show(); + const d = new frappe.ui.Dialog({ + title: __('Show / Hide Cards'), + fields: fields, + primary_action_label: __('Save'), + primary_action: (values) => { + + let category_map = {}; + for (let category of this.module_categories) { + let old_modules = old_values[category] || []; + let new_modules = values[category] || []; + + 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())); + }); } } }