diff --git a/webnotes/__init__.py b/webnotes/__init__.py
index 50419c9192..35ee5b44f1 100644
--- a/webnotes/__init__.py
+++ b/webnotes/__init__.py
@@ -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)
diff --git a/webnotes/boot.py b/webnotes/boot.py
index a4c4c4d7f2..f52cc810ca 100644
--- a/webnotes/boot.py
+++ b/webnotes/boot.py
@@ -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
diff --git a/webnotes/config/__init__.py b/webnotes/config/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/webnotes/desktop.json b/webnotes/config/desktop.py
similarity index 78%
rename from webnotes/desktop.json
rename to webnotes/config/desktop.py
index 28d06d2b59..c4529dd7eb 100644
--- a/webnotes/desktop.json
+++ b/webnotes/config/desktop.py
@@ -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")
}
}
\ No newline at end of file
diff --git a/webnotes/config/setup.py b/webnotes/config/setup.py
new file mode 100644
index 0000000000..83a88b0f8a
--- /dev/null
+++ b/webnotes/config/setup.py
@@ -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.")
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/webnotes/core/page/applications/applications.js b/webnotes/core/page/applications/applications.js
index 2a60fcb992..1389d4cb61 100644
--- a/webnotes/core/page/applications/applications.js
+++ b/webnotes/core/page/applications/applications.js
@@ -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
});
diff --git a/webnotes/core/page/setup/__init__.py b/webnotes/core/page/setup/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/webnotes/core/page/setup/setup.js b/webnotes/core/page/setup/setup.js
new file mode 100644
index 0000000000..c929be3b5d
--- /dev/null
+++ b/webnotes/core/page/setup/setup.js
@@ -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) {
+ $('
').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 = $(' '
+ + wn._(d.label)+'')
+ .attr("data-label", d._label)
+ .appendTo($sections);
+ $content = $('')
+ .toggle(false)
+ .attr("id", d._label)
+ .appendTo(wrapper.find(".contents"))
+ $('').appendTo($content).html('
'
+ + d.label);
+ $list = $('
').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('- \
+
\
+
\
+
%(description)s
\
+
\
+ ', 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");
+ }
+}
diff --git a/webnotes/core/page/setup/setup.py b/webnotes/core/page/setup/setup.py
new file mode 100644
index 0000000000..b7c30d2cf1
--- /dev/null
+++ b/webnotes/core/page/setup/setup.py
@@ -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
diff --git a/webnotes/core/page/setup/setup.txt b/webnotes/core/page/setup/setup.txt
new file mode 100644
index 0000000000..faf64a661d
--- /dev/null
+++ b/webnotes/core/page/setup/setup.txt
@@ -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"
+ }
+]
\ No newline at end of file
diff --git a/webnotes/public/js/wn/router.js b/webnotes/public/js/wn/router.js
index 16f8a127ea..7040c7170a 100644
--- a/webnotes/public/js/wn/router.js
+++ b/webnotes/public/js/wn/router.js
@@ -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() {
diff --git a/webnotes/public/js/wn/ui/appframe.js b/webnotes/public/js/wn/ui/appframe.js
index 4814dd1af7..aca64cf495 100644
--- a/webnotes/public/js/wn/ui/appframe.js
+++ b/webnotes/public/js/wn/ui/appframe.js
@@ -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(' ')
- .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(' ').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);
}
\ No newline at end of file
diff --git a/webnotes/public/js/wn/views/doclistview.js b/webnotes/public/js/wn/views/doclistview.js
index 815f36b89c..6f006464ef 100644
--- a/webnotes/public/js/wn/views/doclistview.js
+++ b/webnotes/public/js/wn/views/doclistview.js
@@ -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)
+ });
+ }
});
}
});
diff --git a/webnotes/public/js/wn/views/grid_report.js b/webnotes/public/js/wn/views/grid_report.js
index 44286108e1..cf93955d72 100644
--- a/webnotes/public/js/wn/views/grid_report.js
+++ b/webnotes/public/js/wn/views/grid_report.js
@@ -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);
}
diff --git a/webnotes/utils/boilerplate.py b/webnotes/utils/boilerplate.py
index e891b4d2c2..fa0bb79095 100644
--- a/webnotes/utils/boilerplate.py
+++ b/webnotes/utils/boilerplate.py
@@ -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}")
+ }}
}}
"""