Merge branch 'master' into develop
This commit is contained in:
commit
78447337d7
16 changed files with 358 additions and 15 deletions
|
|
@ -13,7 +13,7 @@ import os, sys, importlib, inspect, json
|
|||
from .exceptions import *
|
||||
from .utils.jinja import get_jenv, get_template, render_template
|
||||
|
||||
__version__ = '7.2.19'
|
||||
__version__ = '7.2.20'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ $.extend(frappe.desktop, {
|
|||
desktop_items: all_icons,
|
||||
}));
|
||||
|
||||
frappe.desktop.setup_help_messages();
|
||||
frappe.desktop.setup_module_click();
|
||||
|
||||
// notifications
|
||||
|
|
@ -60,6 +61,80 @@ $.extend(frappe.desktop, {
|
|||
});
|
||||
|
||||
$(document).trigger("desktop-render");
|
||||
|
||||
},
|
||||
|
||||
setup_help_messages: function() {
|
||||
// {
|
||||
// title: 'Sign up for a Premium Plan',
|
||||
// description: 'Sign up for a premium plan and add users, get more disk space and priority support',
|
||||
// action: 'Select Plan',
|
||||
// route: 'usage-info'
|
||||
// }
|
||||
|
||||
if(!frappe.user.has_role('System Manager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: 'frappe.core.page.desktop.desktop.get_help_messages',
|
||||
callback: function(r) {
|
||||
frappe.desktop.render_help_messages(r.message);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
render_help_messages: function(help_messages) {
|
||||
var wrapper = frappe.desktop.wrapper.find('.help-message-wrapper');
|
||||
var $help_messages = wrapper.find('.help-messages');
|
||||
|
||||
set_current_message = function(idx) {
|
||||
idx = cint(idx);
|
||||
wrapper.current_message_idx = idx;
|
||||
wrapper.find('.left-arrow, .right-arrow').addClass('disabled');
|
||||
wrapper.find('.help-message-item').addClass('hidden');
|
||||
wrapper.find('[data-message-idx="'+idx+'"]').removeClass('hidden');
|
||||
if(idx > 0) {
|
||||
wrapper.find('.left-arrow').removeClass('disabled');
|
||||
}
|
||||
if(idx < help_messages.length - 1) {
|
||||
wrapper.find('.right-arrow').removeClass('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
if(help_messages) {
|
||||
wrapper.removeClass('hidden');
|
||||
help_messages.forEach(function(message, i) {
|
||||
var $message = $('<div class="help-message-item hidden"></div>')
|
||||
.attr('data-message-idx', i)
|
||||
.html($.format('<div><span class="indicator blue">{0}</span></div>\
|
||||
<p>{1}</p>\
|
||||
<div><a class="btn btn-sm btn-default" href="#{2}">{3}</a></div>',
|
||||
[message.title, message.description, message.route, message.action]))
|
||||
.appendTo($help_messages);
|
||||
|
||||
});
|
||||
|
||||
set_current_message(0);
|
||||
|
||||
wrapper.find('.close').on('click', function() {
|
||||
wrapper.addClass('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
wrapper.find('.left-arrow').on('click', function() {
|
||||
if(wrapper.current_message_idx) {
|
||||
set_current_message(wrapper.current_message_idx - 1);
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.find('.right-arrow').on('click', function() {
|
||||
if(help_messages.length > wrapper.current_message_idx + 1) {
|
||||
set_current_message(wrapper.current_message_idx + 1);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
setup_module_click: function() {
|
||||
|
|
|
|||
23
frappe/core/page/desktop/desktop.py
Normal file
23
frappe/core/page/desktop/desktop.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_help_messages():
|
||||
'''Return help messages for the desktop (called via `get_help_messages` hook)
|
||||
|
||||
Format for message:
|
||||
|
||||
{
|
||||
title: _('Add Employees to Manage Them'),
|
||||
description: _('Add your Employees so you can manage leaves, expenses and payroll'),
|
||||
action: 'Add Employee',
|
||||
route: 'List/Employee'
|
||||
}
|
||||
|
||||
'''
|
||||
messages = []
|
||||
for fn in frappe.get_hooks('get_help_messages'):
|
||||
messages += frappe.get_attr(fn)()
|
||||
|
||||
return sorted(messages, lambda a, b: cmp(a.get('count'), b.get('count')))
|
||||
|
|
@ -4,5 +4,18 @@
|
|||
{{ frappe.render_template("desktop_module_icon", desktop_items[i]) }}
|
||||
{% } %}
|
||||
</div>
|
||||
<div class="help-message-wrapper hidden">
|
||||
<div class="help-message-container">
|
||||
<a class="close pull-right" style="margin-right: -7px;">
|
||||
<i class="octicon octicon-x"></i></a>
|
||||
<div class="help-messages">
|
||||
|
||||
</div>
|
||||
<a class="left-arrow octicon octicon-chevron-left">
|
||||
</a>
|
||||
<a class="right-arrow octicon octicon-chevron-right">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
|
|
|
|||
|
|
@ -153,7 +153,9 @@ class EmailAccount(Document):
|
|||
try:
|
||||
email_server.connect()
|
||||
except (error_proto, imaplib.IMAP4.error), e:
|
||||
if in_receive and ("authentication failed" in e.message.lower() or "log in via your web browser" in e.message.lower()):
|
||||
message = e.message.lower().replace(" ","")
|
||||
if in_receive and any(map(lambda t: t in message, ['authenticationfail', 'loginviayourwebbrowser', #abbreviated to work with both failure and failed
|
||||
'loginfailed', 'err[auth]', 'errtemporaryerror'])): #temporary error to deal with godaddy
|
||||
# if called via self.receive and it leads to authentication error, disable incoming
|
||||
# and send email to system manager
|
||||
self.handle_incoming_connect_error(
|
||||
|
|
|
|||
|
|
@ -186,3 +186,51 @@ body[data-route=""] .navbar-set-desktop-icons,
|
|||
body[data-route="desktop"] .navbar-set-desktop-icons {
|
||||
display: block;
|
||||
}
|
||||
.help-message-wrapper {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
.help-message-wrapper .help-message-container {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
margin: auto;
|
||||
width: 500px;
|
||||
background-color: #fff;
|
||||
padding: 10px 15px 15px 15px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.help-message-wrapper h5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.help-message-wrapper .help-message-item {
|
||||
font-size: 12px;
|
||||
}
|
||||
.help-message-wrapper .octicon {
|
||||
color: #8D99A6;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
}
|
||||
.help-message-wrapper .octicon.disabled {
|
||||
color: #d1d8dd;
|
||||
}
|
||||
.help-message-wrapper .octicon:hover {
|
||||
color: #36414C;
|
||||
text-decoration: none;
|
||||
}
|
||||
.help-message-wrapper .left-arrow {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
bottom: 15px;
|
||||
text-align: left;
|
||||
}
|
||||
.help-message-wrapper .right-arrow {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
.help-message-wrapper .indicator {
|
||||
color: #36414C;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,9 +144,15 @@
|
|||
padding-bottom: 15px;
|
||||
}
|
||||
.form-links .document-link {
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
}
|
||||
.form-links .document-link:hover .badge-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.form-links .document-link:hover .badge-link[disabled='disabled'] {
|
||||
text-decoration: none;
|
||||
}
|
||||
.form-links .count {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
|
|
|
|||
|
|
@ -298,7 +298,6 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
|
|||
if(me.only_input) {
|
||||
make_input();
|
||||
update_input();
|
||||
me.$input && me.$input.prop("disabled", true);
|
||||
} else {
|
||||
$(me.input_area).toggle(false);
|
||||
if (me.disp_area) {
|
||||
|
|
@ -306,6 +305,7 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
|
|||
$(me.disp_area).toggle(true);
|
||||
}
|
||||
}
|
||||
me.$input && me.$input.prop("disabled", true);
|
||||
}
|
||||
|
||||
me.set_description();
|
||||
|
|
@ -782,11 +782,20 @@ frappe.ui.form.ControlText = frappe.ui.form.ControlData.extend({
|
|||
make_wrapper: function() {
|
||||
this._super();
|
||||
this.$wrapper.find(".like-disabled-input").addClass("for-description");
|
||||
},
|
||||
make_input: function() {
|
||||
this._super();
|
||||
this.$input.css({'height': '300px'})
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.ControlLongText = frappe.ui.form.ControlText;
|
||||
frappe.ui.form.ControlSmallText = frappe.ui.form.ControlText;
|
||||
frappe.ui.form.ControlSmallText = frappe.ui.form.ControlText.extend({
|
||||
make_input: function() {
|
||||
this._super();
|
||||
this.$input.css({'height': '150px'})
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
|
||||
input_type: "checkbox",
|
||||
|
|
|
|||
|
|
@ -146,6 +146,16 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
}
|
||||
},
|
||||
|
||||
after_refresh: function() {
|
||||
var me = this;
|
||||
// show / hide new buttons (if allowed)
|
||||
this.links_area.find('.btn-new').each(function() {
|
||||
if(me.frm.can_create($(this).attr('data-doctype'))) {
|
||||
$(this).removeClass('hidden');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
init_data: function() {
|
||||
this.data = this.frm.meta.__dashboard || {};
|
||||
if(!this.data.transactions) this.data.transactions = [];
|
||||
|
|
@ -177,12 +187,16 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
render_links: function() {
|
||||
var me = this;
|
||||
this.links_area.removeClass('hidden');
|
||||
this.links_area.find('.btn-new').addClass('hidden');
|
||||
if(this.data_rendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(frappe.render_template('form_links',
|
||||
{transactions: this.data.transactions}))
|
||||
//this.transactions_area.empty();
|
||||
|
||||
this.data.frm = this.frm;
|
||||
|
||||
$(frappe.render_template('form_links', this.data))
|
||||
.appendTo(this.transactions_area)
|
||||
|
||||
// bind links
|
||||
|
|
@ -195,6 +209,11 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
me.open_document_list($(this).parent(), true);
|
||||
});
|
||||
|
||||
// bind new
|
||||
this.transactions_area.find('.btn-new').on('click', function() {
|
||||
me.frm.make_new($(this).attr('data-doctype'));
|
||||
});
|
||||
|
||||
this.data_rendered = true;
|
||||
},
|
||||
open_document_list: function($link, show_open) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@
|
|||
data-doctype="{{ doctype }}">
|
||||
<a class="badge-link small">{{ __(doctype) }}</a>
|
||||
<span class="text-muted small count"></span>
|
||||
<span class="open-notification hidden" title="{{ __("Open {0}", [__(doctype)])}}"></span>
|
||||
<span class="open-notification hidden"
|
||||
title="{{ __("Open {0}", [__(doctype)])}}"></span>
|
||||
{% if !internal_links[doctype] %}
|
||||
<button class="btn btn-new btn-default btn-xs pull-right hidden"
|
||||
data-doctype="{{ doctype }}">{{ __("New") }}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ frappe.ui.Page = Class.extend({
|
|||
add_inner_button: function(label, action, group) {
|
||||
if(group) {
|
||||
var $group = this.get_inner_group_button(group);
|
||||
$('<li><a>'+label+'</a></li>').on('click', action).appendTo($group.find(".dropdown-menu"));
|
||||
return $('<li><a>'+label+'</a></li>').on('click', action).appendTo($group.find(".dropdown-menu"));
|
||||
} else {
|
||||
return $('<button class="btn btn-default btn-xs" style="margin-left: 10px;">'+__(label)+'</btn>')
|
||||
.on("click", action).appendTo(this.inner_toolbar.removeClass("hide"))
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
docfield = columnDef.report_docfield;
|
||||
|
||||
docfield.link_onclick =
|
||||
repl('frappe.container.page.reportview.set_filter("%(fieldname)s", "%(value)s")',
|
||||
repl('frappe.container.page.reportview.filter_or_open("%(fieldname)s", "%(value)s")',
|
||||
{fieldname:docfield.fieldname, value:value});
|
||||
}
|
||||
return frappe.format(value, docfield, {for_print: for_print, always_show_decimals: true}, dataContext);
|
||||
|
|
@ -358,6 +358,25 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
});
|
||||
},
|
||||
|
||||
filter_or_open: function(fieldname, value) {
|
||||
// set filter on click, if filter is set, open the document
|
||||
var filter_set = false;
|
||||
this.filter_list.get_filters().forEach(function(f) {
|
||||
if(f[1]===fieldname) {
|
||||
filter_set = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(!filter_set) {
|
||||
this.set_filter(fieldname, value);
|
||||
} else {
|
||||
var df = frappe.meta.get_docfield(this.doctype, fieldname);
|
||||
if(df.fieldtype==='Link') {
|
||||
frappe.set_route('Form', df.options, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// render data
|
||||
render_list: function() {
|
||||
var me = this;
|
||||
|
|
|
|||
|
|
@ -450,5 +450,53 @@ _f.Frm.prototype.set_indicator_formatter = function(fieldname, get_color, get_te
|
|||
return '';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
_f.Frm.prototype.can_create = function(doctype) {
|
||||
// return true or false if the user can make a particlar doctype
|
||||
// will check permission, `can_make_methods` if exists, or will decided on
|
||||
// basis of whether the document is submittable
|
||||
if(!frappe.model.can_create(doctype)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.custom_make_buttons && this.custom_make_buttons[doctype]) {
|
||||
// if the button is present, then show make
|
||||
return !!this.custom_buttons[this.custom_make_buttons[doctype]];
|
||||
}
|
||||
|
||||
if(this.can_make_methods && this.can_make_methods[doctype]) {
|
||||
return this.can_make_methods[doctype](this);
|
||||
} else {
|
||||
if(this.meta.is_submittable && !this.doc.docstatus==1) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_f.Frm.prototype.make_new = function(doctype) {
|
||||
// make new doctype from the current form
|
||||
// will handover to `make_methods` if defined
|
||||
// or will create and match link fields
|
||||
var me = this;
|
||||
if(this.make_methods && this.make_methods[doctype]) {
|
||||
return this.make_methods[doctype](this);
|
||||
} else if(this.custom_make_buttons && this.custom_make_buttons[doctype]) {
|
||||
this.custom_buttons[this.custom_make_buttons[doctype]].trigger('click');
|
||||
} else {
|
||||
frappe.model.with_doctype(doctype, function() {
|
||||
new_doc = frappe.model.get_new_doc(doctype);
|
||||
|
||||
// set link fields (if found)
|
||||
frappe.get_meta(doctype).fields.forEach(function(df) {
|
||||
if(df.fieldtype==='Link' && df.options===me.doctype) {
|
||||
new_doc[df.fieldname] = me.doc.name;
|
||||
}
|
||||
});
|
||||
|
||||
frappe.set_route('Form', doctype, new_doc.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ _f.Frm = function(doctype, parent, in_form) {
|
|||
|
||||
var me = this;
|
||||
this.opendocs = {};
|
||||
this.custom_buttons = {};
|
||||
this.sections = [];
|
||||
this.grids = [];
|
||||
this.cscript = new frappe.ui.form.Controller({frm:this});
|
||||
|
|
@ -521,10 +522,13 @@ _f.Frm.prototype.render_form = function(is_a_different_doc) {
|
|||
this.script_manager.trigger("onload_post_render");
|
||||
}
|
||||
|
||||
// update dashboard after refresh
|
||||
this.dashboard.after_refresh();
|
||||
|
||||
// focus on first input
|
||||
|
||||
if(this.doc.docstatus==0) {
|
||||
var first = this.form_wrapper.find('.form-layout :input:first');
|
||||
if(this.is_new()) {
|
||||
var first = this.form_wrapper.find('.form-layout input:first');
|
||||
if(!in_list(["Date", "Datetime"], first.attr("data-fieldtype"))) {
|
||||
first.focus();
|
||||
}
|
||||
|
|
@ -891,12 +895,15 @@ _f.Frm.prototype.set_footnote = function(txt) {
|
|||
_f.Frm.prototype.add_custom_button = function(label, fn, group) {
|
||||
// temp! old parameter used to be icon
|
||||
if(group && group.indexOf("fa fa-")!==-1) group = null;
|
||||
return this.page.add_inner_button(label, fn, group);
|
||||
var btn = this.page.add_inner_button(label, fn, group);
|
||||
this.custom_buttons[label] = btn;
|
||||
return btn;
|
||||
}
|
||||
|
||||
_f.Frm.prototype.clear_custom_buttons = function() {
|
||||
this.page.clear_inner_toolbar();
|
||||
this.page.clear_user_actions();
|
||||
this.custom_buttons = {};
|
||||
}
|
||||
|
||||
_f.Frm.prototype.add_fetch = function(link_field, src_field, tar_field) {
|
||||
|
|
|
|||
|
|
@ -234,3 +234,64 @@ body[data-route=""] .navbar-set-desktop-icons,
|
|||
body[data-route="desktop"] .navbar-set-desktop-icons {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.help-message-wrapper {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
width: 100%;
|
||||
|
||||
.help-message-container {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
margin: auto;
|
||||
width: 500px;
|
||||
background-color: #fff;
|
||||
padding: 10px 15px 15px 15px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.help-message-item {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
color: @text-muted;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.octicon.disabled {
|
||||
color: @text-extra-muted;
|
||||
}
|
||||
|
||||
.octicon:hover {
|
||||
color: @text-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.left-arrow {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
bottom: 15px;
|
||||
text-align: left;
|
||||
// margin-top: 2px;
|
||||
}
|
||||
.right-arrow {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
text-align: right;
|
||||
// margin-top: -18px;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,10 +187,18 @@
|
|||
|
||||
.form-links {
|
||||
.document-link {
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.document-link:hover .badge-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.document-link:hover .badge-link[disabled='disabled'] {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.count {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue