@@ -381,7 +381,10 @@ def scrub(txt): | |||||
def get_module_path(module, *joins): | def get_module_path(module, *joins): | ||||
module = scrub(module) | module = scrub(module) | ||||
return get_pymodule_path(local.module_app[module] + "." + module, *joins) | return get_pymodule_path(local.module_app[module] + "." + module, *joins) | ||||
def get_app_path(app_name, *joins): | |||||
return get_pymodule_path(app_name, *joins) | |||||
def get_pymodule_path(modulename, *joins): | def get_pymodule_path(modulename, *joins): | ||||
joins = [scrub(part) for part in joins] | joins = [scrub(part) for part in joins] | ||||
return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins) | return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins) | ||||
@@ -39,8 +39,10 @@ def get_bootinfo(): | |||||
# home page | # home page | ||||
bootinfo.modules = {} | bootinfo.modules = {} | ||||
for app in webnotes.get_installed_apps(): | for app in webnotes.get_installed_apps(): | ||||
desktop_icons_path = webnotes.get_pymodule_path(app, "desktop.json") | |||||
bootinfo.modules.update(json.loads(webnotes.read_file(desktop_icons_path) or "{}")) | |||||
try: | |||||
bootinfo.modules.update(webnotes.get_attr(app + ".config.desktop.data") or {}) | |||||
except ImportError, e: | |||||
pass | |||||
bootinfo.hidden_modules = webnotes.conn.get_global("hidden_modules") | bootinfo.hidden_modules = webnotes.conn.get_global("hidden_modules") | ||||
bootinfo.doctype_icons = dict(webnotes.conn.sql("""select name, icon from | bootinfo.doctype_icons = dict(webnotes.conn.sql("""select name, icon from | ||||
@@ -1,22 +1,24 @@ | |||||
{ | |||||
from webnotes import _ | |||||
data = { | |||||
"Calendar": { | "Calendar": { | ||||
"color": "#2980b9", | "color": "#2980b9", | ||||
"icon": "icon-calendar", | "icon": "icon-calendar", | ||||
"label": "Calendar", | |||||
"label": _("Calendar"), | |||||
"link": "Calendar/Event", | "link": "Calendar/Event", | ||||
"type": "view" | "type": "view" | ||||
}, | }, | ||||
"Messages": { | "Messages": { | ||||
"color": "#9b59b6", | "color": "#9b59b6", | ||||
"icon": "icon-comments", | "icon": "icon-comments", | ||||
"label": "Messages", | |||||
"label": _("Messages"), | |||||
"link": "messages", | "link": "messages", | ||||
"type": "page" | "type": "page" | ||||
}, | }, | ||||
"To Do": { | "To Do": { | ||||
"color": "#f1c40f", | "color": "#f1c40f", | ||||
"icon": "icon-check", | "icon": "icon-check", | ||||
"label": "To Do", | |||||
"label": _("To Do"), | |||||
"link": "List/ToDo", | "link": "List/ToDo", | ||||
"doctype": "ToDo", | "doctype": "ToDo", | ||||
"type": "list" | "type": "list" | ||||
@@ -31,6 +33,7 @@ | |||||
"color": "#888", | "color": "#888", | ||||
"icon": "icon-download", | "icon": "icon-download", | ||||
"link": "applications", | "link": "applications", | ||||
"type": "page" | |||||
"type": "page", | |||||
"label": _("Installer") | |||||
} | } | ||||
} | } |
@@ -0,0 +1,111 @@ | |||||
from webnotes import _ | |||||
data = [ | |||||
{ | |||||
"label": _("Users and Permissions"), | |||||
"icon": "icon-group", | |||||
"items": [ | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Profile", | |||||
"description": _("System and Website Users") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Role", | |||||
"description": _("User Roles") | |||||
}, | |||||
{ | |||||
"type": "page", | |||||
"name": "permission-manager", | |||||
"label": "Permission Manager", | |||||
"icon": "icon-lock", | |||||
"description": _("Set Permissions on Document Types and Roles") | |||||
}, | |||||
{ | |||||
"type": "page", | |||||
"name": "user-properties", | |||||
"label": "User Properties", | |||||
"icon": "icon-user", | |||||
"description": _("Set Defaults and Restrictions for Users") | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
"label": _("Workflow"), | |||||
"icon": "icon-random", | |||||
"items": [ | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Workflow", | |||||
"description": _("Define workflows for forms.") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Workflow State", | |||||
"description": _("States for workflow (e.g. Draft, Approved, Cancelled).") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Workflow Action", | |||||
"description": _("Actions for workflow (e.g. Approve, Cancel).") | |||||
}, | |||||
] | |||||
}, | |||||
{ | |||||
"label": _("Tools"), | |||||
"icon": "icon-wrench", | |||||
"items": [ | |||||
{ | |||||
"type": "page", | |||||
"name": "data-import-tool", | |||||
"label": _("Import / Export Data"), | |||||
"icon": "icon-upload", | |||||
"description": _("Import / Export Data from .csv files.") | |||||
}, | |||||
{ | |||||
"type": "page", | |||||
"name": "modules_setup", | |||||
"label": _("Show / Hide Modules"), | |||||
"icon": "icon-upload", | |||||
"description": _("Show or hide modules globally.") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Naming Series", | |||||
"description": _("Set numbering series for transactions.") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Rename Tool", | |||||
"description": _("Rename many items by uploading a .csv file.") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "File Data", | |||||
"description": _("Manage uploaded files.") | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
"label": _("Customize"), | |||||
"icon": "icon-glass", | |||||
"items": [ | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Customize Form", | |||||
"description": _("Change field properties (hide, readonly, permission etc.)") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Custom Field", | |||||
"description": _("Add fields to forms.") | |||||
}, | |||||
{ | |||||
"type": "doctype", | |||||
"name": "Custom Script", | |||||
"description": _("Add custom javascript to forms.") | |||||
} | |||||
] | |||||
} | |||||
] |
@@ -2,6 +2,7 @@ wn.pages['applications'].onload = function(wrapper) { | |||||
wn.ui.make_app_page({ | wn.ui.make_app_page({ | ||||
parent: wrapper, | parent: wrapper, | ||||
title: wn._('Application Installer'), | title: wn._('Application Installer'), | ||||
icon: "icon-download", | |||||
single_column: true | single_column: true | ||||
}); | }); | ||||
@@ -0,0 +1,106 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
// MIT License. See license.txt | |||||
wn.pages['Setup'].onload = function(wrapper) { | |||||
if(msg_dialog && msg_dialog.display) msg_dialog.hide(); | |||||
wn.ui.make_app_page({ | |||||
parent: wrapper, | |||||
title: wn._('Setup'), | |||||
single_column: true | |||||
}); | |||||
wrapper.appframe.add_module_icon("Setup"); | |||||
wrapper.appframe.set_title_right(wn._("Refresh"), function() { | |||||
wn.setup.make(wrapper); | |||||
}); | |||||
wn.setup.make(wrapper); | |||||
} | |||||
wn.setup = { | |||||
make: function(wrapper) { | |||||
wn.call({ | |||||
method: "webnotes.core.page.setup.setup.get", | |||||
callback: function(r) { | |||||
wn.setup.render(r.message, $(wrapper).find(".layout-main").empty()) | |||||
} | |||||
}) | |||||
}, | |||||
render: function(data, wrapper) { | |||||
$('<div class="row">\ | |||||
<div class="col-sm-3">\ | |||||
<ul class="nav nav-pills nav-stacked"></ul>\ | |||||
</div>\ | |||||
<div class="col-sm-9 contents">\ | |||||
</div>\ | |||||
</div>').appendTo(wrapper); | |||||
var $sections = wrapper.find(".nav-pills"); | |||||
$.each(data, function(i, d) { | |||||
d._label = d.label.toLowerCase().replace(/ /g, "_"); | |||||
$nav = $sections.find('[data-label="'+d._label+'"]'); | |||||
if(!$sections.find('[data-label="'+d._label+'"]').length) { | |||||
$nav = $('<li><a><i class="'+d.icon+'"></i> ' | |||||
+ wn._(d.label)+'</a></li>') | |||||
.attr("data-label", d._label) | |||||
.appendTo($sections); | |||||
$content = $('<div class="panel panel-default"></div>') | |||||
.toggle(false) | |||||
.attr("id", d._label) | |||||
.appendTo(wrapper.find(".contents")) | |||||
$('<div class="panel-heading">').appendTo($content).html('<i class="'+d.icon+'"></i> ' | |||||
+ d.label); | |||||
$list = $('<ul class="list-group">').appendTo($content); | |||||
} | |||||
// add items | |||||
$.each(d.items, function(i, item) { | |||||
if((item.type==="doctype" && wn.model.can_read(item.name)) | |||||
|| (item.type==="page" && wn.boot.page_info[item.name])) { | |||||
if(!item.label) { | |||||
item.label = item.name; | |||||
} | |||||
if(item.type==="doctype") { | |||||
item.icon = wn.boot.doctype_icons[item.name]; | |||||
} | |||||
$list_item = $($r('<li class="list-group-item">\ | |||||
<div class="row">\ | |||||
<div class="col-xs-4"><a><i class="%(icon)s"></i> %(label)s</a></div>\ | |||||
<div class="col-xs-8 text-muted">%(description)s</div>\ | |||||
</div>\ | |||||
</li>', item)).appendTo($list); | |||||
$list_item.find("a") | |||||
.attr("data-type", item.type) | |||||
.attr("data-name", item.name) | |||||
.on("click", function() { | |||||
if($(this).attr("data-type")==="doctype") { | |||||
wn.set_route("List", $(this).attr("data-name")) | |||||
} | |||||
else if($(this).attr("data-type")==="page") { | |||||
wn.set_route($(this).attr("data-name")) | |||||
} | |||||
}); | |||||
} | |||||
}) | |||||
}) | |||||
// section selection (can't use tab api - routing) | |||||
$sections.find('a').click(function (e) { | |||||
e.preventDefault(); | |||||
if($(this).parent().hasClass("active")) { | |||||
return; | |||||
} | |||||
$(this).parents("ul:first").find("li.active").removeClass("active"); | |||||
$(this).parent().addClass("active"); | |||||
wrapper.find(".panel").toggle(false); | |||||
$("#" + $(this).parent().attr("data-label")).toggle(true); | |||||
}); | |||||
$sections.find('a:first').trigger("click"); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes, json, os | |||||
from webnotes import _ | |||||
@webnotes.whitelist() | |||||
def get(): | |||||
setup = [] | |||||
for app in webnotes.get_installed_apps(): | |||||
try: | |||||
setup += webnotes.get_attr(app + ".config.setup.data") | |||||
except ImportError, e: | |||||
pass | |||||
return setup |
@@ -0,0 +1,32 @@ | |||||
[ | |||||
{ | |||||
"creation": "2012-06-14 15:07:28", | |||||
"docstatus": 0, | |||||
"modified": "2014-02-07 14:48:08", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"doctype": "Page", | |||||
"icon": "icon-cog", | |||||
"module": "Core", | |||||
"name": "__common__", | |||||
"page_name": "Setup", | |||||
"standard": "Yes" | |||||
}, | |||||
{ | |||||
"doctype": "Page Role", | |||||
"name": "__common__", | |||||
"parent": "Setup", | |||||
"parentfield": "roles", | |||||
"parenttype": "Page", | |||||
"role": "System Manager" | |||||
}, | |||||
{ | |||||
"doctype": "Page", | |||||
"name": "Setup" | |||||
}, | |||||
{ | |||||
"doctype": "Page Role" | |||||
} | |||||
] |
@@ -83,6 +83,13 @@ wn.set_route = function() { | |||||
wn.app.set_favicon(); | wn.app.set_favicon(); | ||||
} | } | ||||
wn.set_re_route = function() { | |||||
var tmp = window.location.hash; | |||||
wn.set_route.apply(null, arguments); | |||||
wn.re_route[tmp] = window.location.hash; | |||||
}; | |||||
wn._cur_route = null; | wn._cur_route = null; | ||||
$(window).on('hashchange', function() { | $(window).on('hashchange', function() { | ||||
@@ -195,8 +195,7 @@ wn.ui.AppFrame = Class.extend({ | |||||
} | } | ||||
var icon = wn.boot.doctype_icons[doctype] || module_info.icon; | var icon = wn.boot.doctype_icons[doctype] || module_info.icon; | ||||
this.$title_area.find(".title-icon").html('<i class="'+icon+'"></i> ') | |||||
.toggle(true) | |||||
this.get_main_icon(icon) | |||||
.attr("doctype-name", doctype) | .attr("doctype-name", doctype) | ||||
.attr("module-link", module_info.link) | .attr("module-link", module_info.link) | ||||
.click(onclick || function() { | .click(onclick || function() { | ||||
@@ -218,6 +217,10 @@ wn.ui.AppFrame = Class.extend({ | |||||
} | } | ||||
}, | }, | ||||
get_main_icon: function(icon) { | |||||
return this.$title_area.find(".title-icon").html('<i class="'+icon+'"></i> ').toggle(true); | |||||
}, | |||||
add_help_button: function(txt) { | add_help_button: function(txt) { | ||||
this.add_icon_btn("2", "icon-question-sign", wn._("Help"), | this.add_icon_btn("2", "icon-question-sign", wn._("Help"), | ||||
function() { msgprint($(this).data('help-text'), 'Help'); }) | function() { msgprint($(this).data('help-text'), 'Help'); }) | ||||
@@ -346,5 +349,5 @@ wn.ui.make_app_page = function(opts) { | |||||
if(opts.set_document_title!==undefined) | if(opts.set_document_title!==undefined) | ||||
opts.parent.appframe.set_document_title = opts.set_document_title; | opts.parent.appframe.set_document_title = opts.set_document_title; | ||||
if(opts.title) opts.parent.appframe.set_title(opts.title); | if(opts.title) opts.parent.appframe.set_title(opts.title); | ||||
if(opts.icon) opts.parent.appframe.add_module_icon(null, opts.icon); | |||||
if(opts.icon) opts.parent.appframe.get_main_icon(opts.icon); | |||||
} | } |
@@ -8,10 +8,14 @@ wn.views.ListFactory = wn.views.Factory.extend({ | |||||
make: function(route) { | make: function(route) { | ||||
var me = this; | var me = this; | ||||
wn.model.with_doctype(route[1], function() { | wn.model.with_doctype(route[1], function() { | ||||
new wn.views.DocListView({ | |||||
doctype: route[1], | |||||
page: me.make_page(true) | |||||
}); | |||||
if(locals["DocType"][route[1]].issingle) { | |||||
wn.set_re_route("Form", route[1]); | |||||
} else { | |||||
new wn.views.DocListView({ | |||||
doctype: route[1], | |||||
page: me.make_page(true) | |||||
}); | |||||
} | |||||
}); | }); | ||||
} | } | ||||
}); | }); | ||||
@@ -252,15 +252,17 @@ wn.views.GridReport = Class.extend({ | |||||
input.autocomplete({ | input.autocomplete({ | ||||
source: v.list || [], | source: v.list || [], | ||||
}); | }); | ||||
} else if(v.fieldtype=='Button') { | |||||
} else if(v.fieldtype==='Button' && v.label==="Refresh") { | |||||
input = me.appframe.set_title_right(v.label, null, v.icon); | |||||
} else if(v.fieldtype==='Button') { | |||||
input = me.appframe.add_primary_action(v.label, null, v.icon); | input = me.appframe.add_primary_action(v.label, null, v.icon); | ||||
} else if(v.fieldtype=='Date') { | |||||
} else if(v.fieldtype==='Date') { | |||||
input = me.appframe.add_date(v.label); | input = me.appframe.add_date(v.label); | ||||
} else if(v.fieldtype=='Label') { | |||||
} else if(v.fieldtype==='Label') { | |||||
input = me.appframe.add_label(v.label); | input = me.appframe.add_label(v.label); | ||||
} else if(v.fieldtype=='Data') { | |||||
} else if(v.fieldtype==='Data') { | |||||
input = me.appframe.add_data(v.label); | input = me.appframe.add_data(v.label); | ||||
} else if(v.fieldtype=='Check') { | |||||
} else if(v.fieldtype==='Check') { | |||||
input = me.appframe.add_check(v.label); | input = me.appframe.add_check(v.label); | ||||
} | } | ||||
@@ -26,9 +26,11 @@ def make_boilerplate(): | |||||
webnotes.create_folder(os.path.join(hooks.app_name, hooks.app_name, hooks.app_name)) | webnotes.create_folder(os.path.join(hooks.app_name, hooks.app_name, hooks.app_name)) | ||||
webnotes.create_folder(os.path.join(hooks.app_name, hooks.app_name, "templates")) | webnotes.create_folder(os.path.join(hooks.app_name, hooks.app_name, "templates")) | ||||
webnotes.create_folder(os.path.join(hooks.app_name, hooks.app_name, "config")) | |||||
touch_file(os.path.join(hooks.app_name, hooks.app_name, "__init__.py")) | touch_file(os.path.join(hooks.app_name, hooks.app_name, "__init__.py")) | ||||
touch_file(os.path.join(hooks.app_name, hooks.app_name, hooks.app_name, "__init__.py")) | touch_file(os.path.join(hooks.app_name, hooks.app_name, hooks.app_name, "__init__.py")) | ||||
touch_file(os.path.join(hooks.app_name, hooks.app_name, "templates", "__init__.py")) | touch_file(os.path.join(hooks.app_name, hooks.app_name, "templates", "__init__.py")) | ||||
touch_file(os.path.join(hooks.app_name, hooks.app_name, "config", "__init__.py")) | |||||
with open(os.path.join(hooks.app_name, "MANIFEST.in"), "w") as f: | with open(os.path.join(hooks.app_name, "MANIFEST.in"), "w") as f: | ||||
f.write(manifest_template.format(**hooks)) | f.write(manifest_template.format(**hooks)) | ||||
@@ -55,7 +57,7 @@ def make_boilerplate(): | |||||
touch_file(os.path.join(hooks.app_name, hooks.app_name, "patches.txt")) | touch_file(os.path.join(hooks.app_name, hooks.app_name, "patches.txt")) | ||||
with open(os.path.join(hooks.app_name, hooks.app_name, "desktop.json"), "w") as f: | |||||
with open(os.path.join(hooks.app_name, hooks.app_name, "config", "desktop.py"), "w") as f: | |||||
f.write(desktop_template.format(**hooks)) | f.write(desktop_template.format(**hooks)) | ||||
@@ -91,12 +93,14 @@ app_url = {app_url} | |||||
app_version = 0.0.1 | app_version = 0.0.1 | ||||
""" | """ | ||||
desktop_template = """{{ | |||||
desktop_template = """from webnotes import _ | |||||
data = {{ | |||||
"{app_title}": {{ | "{app_title}": {{ | ||||
"color": "{app_color}", | "color": "{app_color}", | ||||
"icon": "{app_icon}", | "icon": "{app_icon}", | ||||
"label": "{app_title}" | |||||
}} | |||||
"label": _("{app_title}") | |||||
}} | |||||
}} | }} | ||||
""" | """ | ||||