@@ -381,7 +381,10 @@ def scrub(txt): | |||
def get_module_path(module, *joins): | |||
module = scrub(module) | |||
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): | |||
joins = [scrub(part) for part in joins] | |||
return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins) | |||
@@ -39,8 +39,10 @@ def get_bootinfo(): | |||
# home page | |||
bootinfo.modules = {} | |||
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.doctype_icons = dict(webnotes.conn.sql("""select name, icon from | |||
@@ -1,22 +1,24 @@ | |||
{ | |||
from webnotes import _ | |||
data = { | |||
"Calendar": { | |||
"color": "#2980b9", | |||
"icon": "icon-calendar", | |||
"label": "Calendar", | |||
"label": _("Calendar"), | |||
"link": "Calendar/Event", | |||
"type": "view" | |||
}, | |||
"Messages": { | |||
"color": "#9b59b6", | |||
"icon": "icon-comments", | |||
"label": "Messages", | |||
"label": _("Messages"), | |||
"link": "messages", | |||
"type": "page" | |||
}, | |||
"To Do": { | |||
"color": "#f1c40f", | |||
"icon": "icon-check", | |||
"label": "To Do", | |||
"label": _("To Do"), | |||
"link": "List/ToDo", | |||
"doctype": "ToDo", | |||
"type": "list" | |||
@@ -31,6 +33,7 @@ | |||
"color": "#888", | |||
"icon": "icon-download", | |||
"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({ | |||
parent: wrapper, | |||
title: wn._('Application Installer'), | |||
icon: "icon-download", | |||
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.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; | |||
$(window).on('hashchange', function() { | |||
@@ -195,8 +195,7 @@ wn.ui.AppFrame = Class.extend({ | |||
} | |||
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("module-link", module_info.link) | |||
.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) { | |||
this.add_icon_btn("2", "icon-question-sign", wn._("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) | |||
opts.parent.appframe.set_document_title = opts.set_document_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) { | |||
var me = this; | |||
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({ | |||
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); | |||
} else if(v.fieldtype=='Date') { | |||
} else if(v.fieldtype==='Date') { | |||
input = me.appframe.add_date(v.label); | |||
} else if(v.fieldtype=='Label') { | |||
} else if(v.fieldtype==='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); | |||
} else if(v.fieldtype=='Check') { | |||
} else if(v.fieldtype==='Check') { | |||
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, "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, 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, "config", "__init__.py")) | |||
with open(os.path.join(hooks.app_name, "MANIFEST.in"), "w") as f: | |||
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")) | |||
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)) | |||
@@ -91,12 +93,14 @@ app_url = {app_url} | |||
app_version = 0.0.1 | |||
""" | |||
desktop_template = """{{ | |||
desktop_template = """from webnotes import _ | |||
data = {{ | |||
"{app_title}": {{ | |||
"color": "{app_color}", | |||
"icon": "{app_icon}", | |||
"label": "{app_title}" | |||
}} | |||
"label": _("{app_title}") | |||
}} | |||
}} | |||
""" | |||