@@ -62,6 +62,11 @@ def get_modules_from_app(app): | |||
to_add = False | |||
if to_add: | |||
<<<<<<< HEAD | |||
======= | |||
m["shortcuts"] = get_onboard_items(app, frappe.scrub(m["module_name"]))[:5] | |||
m["app"] = app | |||
>>>>>>> feat(desk): DeskModuleBox, get some links if not set | |||
active_modules_list.append(m) | |||
return active_modules_list | |||
@@ -252,6 +252,46 @@ def get_setup_section(app, module, label, icon): | |||
"items": section["items"] | |||
} | |||
def get_onboard_items(app, module): | |||
try: | |||
sections = get_config(app, module) | |||
except ImportError: | |||
return [] | |||
onboard_items = [] | |||
fallback_items = [] | |||
for section in sections: | |||
for item in section["items"]: | |||
if item.get("onboard", 0) == 1: | |||
onboard_items.append(item) | |||
# in case onboard is not set | |||
fallback_items.append(item) | |||
if len(onboard_items) > 5: | |||
return onboard_items | |||
return onboard_items or fallback_items | |||
@frappe.whitelist() | |||
def get_links(app, module): | |||
try: | |||
sections = get_config(app, frappe.scrub(module)) | |||
except ImportError: | |||
return [] | |||
link_names = [] | |||
for section in sections: | |||
for item in section["items"]: | |||
link_names.append(item.get("label")) | |||
print(link_names) | |||
return link_names | |||
def set_last_modified(data): | |||
for section in data: | |||
for item in section["items"]: | |||
@@ -11,7 +11,6 @@ from frappe.utils.fixtures import sync_fixtures | |||
from frappe.cache_manager import clear_global_cache | |||
from frappe.desk.notifications import clear_notifications | |||
from frappe.website import render, router | |||
from frappe.desk.doctype.desktop_icon.desktop_icon import sync_desktop_icons | |||
from frappe.core.doctype.language.language import sync_languages | |||
from frappe.modules.utils import sync_customizations | |||
@@ -41,7 +40,6 @@ def migrate(verbose=True, rebuild_website=False): | |||
frappe.translate.clear_cache() | |||
sync_fixtures() | |||
sync_customizations() | |||
sync_desktop_icons() | |||
sync_languages() | |||
frappe.get_doc('Portal Settings', 'Portal Settings').sync_menu() | |||
@@ -0,0 +1,96 @@ | |||
<template> | |||
<div :href="type === 'module' ? '#modules/' + module_name : link" | |||
class="border module-box" | |||
:draggable="true" | |||
> | |||
<div class="flush-top"> | |||
<div class="module-box-content"> | |||
<div class="level"> | |||
<h4 class="h4"> | |||
<span class="indicator" :class="count ? 'red' : (onboard_present ? 'orange' : 'grey')"></span> | |||
{{ label }} | |||
</h4> | |||
<span class="octicon octicon-three-bars text-extra-muted" style=" | |||
font-size: 12px; | |||
"></span> | |||
</div> | |||
<p | |||
v-if="shortcuts.length" | |||
class="small text-muted"> | |||
<a | |||
v-for="shortcut in shortcuts" | |||
:key="shortcut.name" | |||
:href="shortcut.link" | |||
class="btn btn-default btn-xs shortcut-tag" title="toggle Tag"> {{ shortcut.label }} | |||
</a> | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
props: ['name', 'label', 'type', 'module_name', 'link', 'count', 'onboard_present', 'shortcuts', 'description'], | |||
methods: { | |||
on_dragstart() { | |||
return 0; | |||
}, | |||
on_dragend() { | |||
return 0; | |||
}, | |||
on_hover() { | |||
return 1; | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
.module-box { | |||
border-radius: 4px; | |||
padding: 5px 15px; | |||
padding-top: 3px; | |||
display: block; | |||
background-color: #ffffff; | |||
} | |||
.octicon-three-bars:hover { | |||
cursor: pointer; | |||
} | |||
.module-box-content { | |||
width: 100%; | |||
h4 { | |||
margin-bottom: 5px | |||
} | |||
p { | |||
margin-top: 5px; | |||
font-size: 80%; | |||
display: flex; | |||
overflow: hidden; | |||
} | |||
} | |||
.icon-box { | |||
padding: 15px; | |||
width: 54px; | |||
display: flex; | |||
justify-content: center; | |||
} | |||
.icon { | |||
font-size: 24px; | |||
} | |||
.open-notification { | |||
top: -2px; | |||
} | |||
.shortcut-tag { | |||
margin-right: 5px; | |||
} | |||
</style> | |||
@@ -0,0 +1,148 @@ | |||
<template> | |||
<div> | |||
<div class="section-header level text-muted"> | |||
<div class="module-category h6 uppercase"> | |||
{{ category }} | |||
</div> | |||
<div> | |||
<a class="small text-muted" @click="show_customize_dialog">{{ __("Customize") }}</a> | |||
</div> | |||
</div> | |||
<div class="modules-container"> | |||
<desk-module-box | |||
v-for="module in modules" | |||
:key="module.name" | |||
v-bind="module" | |||
> | |||
</desk-module-box> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import DeskModuleBox from "./DeskModuleBox.vue"; | |||
export default { | |||
props: ['category', 'initial_modules'], | |||
components: { | |||
DeskModuleBox | |||
}, | |||
data() { | |||
return { | |||
modules: this.initial_modules, | |||
dragged_index: -1, | |||
hovered_index: -1, | |||
} | |||
}, | |||
methods: { | |||
show_customize_dialog() { | |||
if(!this.dialog) { | |||
let all_modules = this.modules; | |||
let fields = []; | |||
all_modules.forEach(module => { | |||
fields.push({ | |||
label: __(module.module_name), | |||
fieldname: module.module_name, | |||
fieldtype: "Check", | |||
default: 1 | |||
}); | |||
if(module.shortcuts) { | |||
fields.push({ | |||
label: __(""), | |||
fieldname: module.module_name + "_shortcuts", | |||
fieldtype: "MultiSelect", | |||
get_data: function() { | |||
let data = []; | |||
frappe.call({ | |||
type: "GET", | |||
method:'frappe.desk.moduleview.get_links', | |||
async: false, | |||
no_spinner: true, | |||
args: { | |||
app: module.app, | |||
module: module.module_name, | |||
}, | |||
callback: function(r) { | |||
data = r.message; | |||
} | |||
}); | |||
return data; | |||
}, | |||
default: module.shortcuts.map(m => (m.name || m.label)), | |||
depends_on: module.module_name | |||
}); | |||
} | |||
}); | |||
this.dialog = new frappe.ui.Dialog({ | |||
title: __("Customize " + this.category), | |||
fields: fields, | |||
primary_action_label: __("Update"), | |||
primary_action: (values) => { | |||
let settings = {}; | |||
Object.keys(values).forEach(key => { | |||
if(!key.includes('shortcuts') && values[key]) { | |||
settings[key] = { | |||
links: values[key + '_shortcuts'] || [] | |||
} | |||
} | |||
if(!values[key]) { | |||
let index = -1; | |||
this.modules.map((m, i) => { | |||
if(m.module_name === key) { | |||
index = i; | |||
} | |||
}) | |||
this.modules.splice(index, 1); | |||
} | |||
}); | |||
const user = frappe.session.user; | |||
const fieldname = 'home_settings'; | |||
frappe.db.get_value('User', user,fieldname) | |||
.then((resp) => { | |||
let home_settings = JSON.parse(resp.message[fieldname]); | |||
home_settings[this.category] = settings; | |||
frappe.db.set_value('User', user, fieldname, home_settings) | |||
.then((resp) => { | |||
this.dialog.hide(); | |||
}) | |||
.fail((err) => { | |||
frappe.msgprint(err); | |||
}); | |||
}) | |||
} | |||
}); | |||
this.dialog.modal_body.find('.clearfix').css({'display': 'none'}); | |||
this.dialog.modal_body.find('.frappe-control*[data-fieldtype="MultiSelect"]').css({'margin-bottom': '30px'}); | |||
} | |||
this.dialog.show(); | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
.section-header { | |||
margin-top: 30px; | |||
margin-bottom: 15px; | |||
border-bottom: 1px solid #d0d8dd; | |||
} | |||
.modules-container { | |||
display: grid; | |||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |||
grid-auto-rows: minmax(72px, 1fr); | |||
column-gap: 15px; | |||
row-gap: 15px; | |||
} | |||
</style> | |||
@@ -36,7 +36,7 @@ | |||
"socket.io": "^2.0.4", | |||
"superagent": "^3.8.2", | |||
"touch": "^3.1.0", | |||
"vue": "^2.5.17", | |||
"vue": "2.5.17", | |||
"vue-router": "^2.0.0" | |||
}, | |||
"devDependencies": { | |||