[enhancement] added heatmaps and item count in dashboard
This commit is contained in:
parent
8783bd16f6
commit
4bb2fce345
18 changed files with 3844 additions and 97 deletions
|
|
@ -446,13 +446,16 @@ def clear_cache(user=None, doctype=None):
|
|||
|
||||
frappe.local.role_permissions = {}
|
||||
|
||||
def has_permission(doctype, ptype="read", doc=None, user=None, verbose=False, throw=False):
|
||||
def has_permission(doctype=None, ptype="read", doc=None, user=None, verbose=False, throw=False):
|
||||
"""Raises `frappe.PermissionError` if not permitted.
|
||||
|
||||
:param doctype: DocType for which permission is to be check.
|
||||
:param ptype: Permission type (`read`, `write`, `create`, `submit`, `cancel`, `amend`). Default: `read`.
|
||||
:param doc: [optional] Checks User permissions for given doc.
|
||||
:param user: [optional] Check for given user. Default: current user."""
|
||||
if not doctype and doc:
|
||||
doctype = doc.doctype
|
||||
|
||||
import frappe.permissions
|
||||
out = frappe.permissions.has_permission(doctype, ptype, doc=doc, verbose=verbose, user=user)
|
||||
if throw and not out:
|
||||
|
|
|
|||
|
|
@ -118,28 +118,7 @@ def get_communications(doctype, name, start=0, limit=20):
|
|||
|
||||
|
||||
def _get_communications(doctype, name, start=0, limit=20):
|
||||
communications = frappe.db.sql("""select name, communication_type,
|
||||
communication_medium, comment_type,
|
||||
content, sender, sender_full_name, creation, subject, delivery_status, _liked_by,
|
||||
timeline_doctype, timeline_name,
|
||||
reference_doctype, reference_name,
|
||||
link_doctype, link_name,
|
||||
"Communication" as doctype
|
||||
from tabCommunication
|
||||
where
|
||||
communication_type in ("Communication", "Comment")
|
||||
and (
|
||||
(reference_doctype=%(doctype)s and reference_name=%(name)s)
|
||||
or (timeline_doctype=%(doctype)s
|
||||
and timeline_name=%(name)s
|
||||
and communication_type="Comment"
|
||||
and comment_type in ("Created", "Updated", "Submitted", "Cancelled", "Deleted"))
|
||||
)
|
||||
and (comment_type is null or comment_type != 'Update')
|
||||
order by creation desc limit %(start)s, %(limit)s""",
|
||||
{ "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
|
||||
as_dict=True)
|
||||
|
||||
communications = get_communication_data(doctype, name, start, limit)
|
||||
for c in communications:
|
||||
if c.communication_type=="Communication":
|
||||
c.attachments = json.dumps(frappe.get_all("File",
|
||||
|
|
@ -153,6 +132,43 @@ def _get_communications(doctype, name, start=0, limit=20):
|
|||
|
||||
return communications
|
||||
|
||||
def get_communication_data(doctype, name, start=0, limit=20, after=None, fields=None,
|
||||
group_by=None, as_dict=True):
|
||||
'''Returns list of communicataions for a given document'''
|
||||
if not fields:
|
||||
fields = '''name, communication_type,
|
||||
communication_medium, comment_type,
|
||||
content, sender, sender_full_name, creation, subject, delivery_status, _liked_by,
|
||||
timeline_doctype, timeline_name,
|
||||
reference_doctype, reference_name,
|
||||
link_doctype, link_name,
|
||||
"Communication" as doctype'''
|
||||
|
||||
conditions = '''communication_type in ("Communication", "Comment")
|
||||
and (
|
||||
(reference_doctype=%(doctype)s and reference_name=%(name)s)
|
||||
or (timeline_doctype=%(doctype)s
|
||||
and timeline_name=%(name)s
|
||||
and communication_type="Comment"
|
||||
and comment_type in ("Created", "Updated", "Submitted", "Cancelled", "Deleted"))
|
||||
)
|
||||
and (comment_type is null or comment_type != 'Update')'''
|
||||
|
||||
if after:
|
||||
# find after a particular date
|
||||
conditions+= ' and creation > {after}'
|
||||
limit = 1000
|
||||
|
||||
communications = frappe.db.sql("""select {fields}
|
||||
from tabCommunication
|
||||
where {conditions} {group_by}
|
||||
order by creation desc limit %(start)s, %(limit)s""".format(
|
||||
fields = fields, conditions=conditions, group_by=group_by or ""),
|
||||
{ "doctype": doctype, "name": name, "start": frappe.utils.cint(start), "limit": limit },
|
||||
as_dict=as_dict)
|
||||
|
||||
return communications
|
||||
|
||||
def get_assignments(dt, dn):
|
||||
cl = frappe.db.sql("""select owner, description from `tabToDo`
|
||||
where reference_type=%(doctype)s and reference_name=%(name)s and status="Open"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from __future__ import unicode_literals
|
|||
import frappe
|
||||
from frappe.utils import time_diff_in_seconds, now, now_datetime, DATETIME_FORMAT
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from frappe import _
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_notifications():
|
||||
|
|
@ -178,9 +177,6 @@ def get_open_count(doctype, name):
|
|||
:param transactions: List of transactions (json/dict)
|
||||
:param filters: optional filters (json/list)'''
|
||||
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
if not doc.has_permission('read'):
|
||||
frappe.msgprint(_("Not permitted"), raise_exception=True)
|
||||
|
||||
links = frappe.get_meta(doctype).get_links_setup()
|
||||
|
||||
|
|
@ -192,15 +188,20 @@ def get_open_count(doctype, name):
|
|||
out = []
|
||||
for doctype in items:
|
||||
filters = get_filters_for(doctype)
|
||||
fieldname = links.get('non_standard_fieldnames', {}).get(doctype, links.fieldname)
|
||||
data = {'name': doctype}
|
||||
if filters:
|
||||
# get the fieldname for the current document
|
||||
# we only need open documents related to the current document
|
||||
fieldname = links.get('non_standard_fieldnames', {}).get(doctype, links.fieldname)
|
||||
filters[fieldname] = name
|
||||
total = len(frappe.get_all(doctype, fields='name',
|
||||
filters=filters, limit_page_length=6, distinct=True))
|
||||
data['open_count'] = total
|
||||
|
||||
if filters:
|
||||
open_count = len(frappe.get_all(doctype, fields='name',
|
||||
filters=filters, limit_page_length=6, distinct=True))
|
||||
out.append({'name': doctype, 'count': open_count})
|
||||
total = len(frappe.get_all(doctype, fields='name',
|
||||
filters={fieldname: name}, limit_page_length=10, distinct=True))
|
||||
data['count'] = total
|
||||
out.append(data)
|
||||
|
||||
return out
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
"public/css/bootstrap.css",
|
||||
"public/css/font-awesome.css",
|
||||
"public/css/octicons/octicons.css",
|
||||
"public/css/font/open-sans/open-sans.css",
|
||||
"public/css/cal-heatmap.css",
|
||||
"public/css/desk.css",
|
||||
"public/css/indicator.css",
|
||||
"public/css/avatar.css",
|
||||
|
|
@ -63,6 +63,8 @@
|
|||
"public/js/lib/moment/moment-with-locales.min.js",
|
||||
"public/js/lib/moment/moment-timezone-with-data.min.js",
|
||||
"public/js/lib/socket.io.min.js",
|
||||
"public/js/lib/d3.min.js",
|
||||
"public/js/lib/cal-heatmap.js",
|
||||
|
||||
"public/js/frappe/provide.js",
|
||||
"public/js/frappe/class.js",
|
||||
|
|
@ -150,6 +152,7 @@
|
|||
"public/js/frappe/form/templates/users_in_sidebar.html",
|
||||
"public/js/frappe/form/templates/set_sharing.html",
|
||||
"public/js/frappe/form/templates/form_sidebar.html",
|
||||
"public/js/frappe/form/templates/form_dashboard.html",
|
||||
"public/js/frappe/form/templates/form_links.html",
|
||||
"public/js/frappe/views/formview.js",
|
||||
"public/js/legacy/form.js",
|
||||
|
|
|
|||
140
frappe/public/css/cal-heatmap.css
Executable file
140
frappe/public/css/cal-heatmap.css
Executable file
|
|
@ -0,0 +1,140 @@
|
|||
/* Cal-HeatMap CSS */
|
||||
|
||||
.cal-heatmap-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-label
|
||||
{
|
||||
fill: #999;
|
||||
font-size: 10px
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph, .cal-heatmap-container .graph-legend rect {
|
||||
shape-rendering: crispedges
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-rect
|
||||
{
|
||||
fill: #ededed
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-subdomain-group rect:hover
|
||||
{
|
||||
stroke: #000;
|
||||
stroke-width: 1px
|
||||
}
|
||||
|
||||
.cal-heatmap-container .subdomain-text {
|
||||
font-size: 8px;
|
||||
fill: #999;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.cal-heatmap-container .hover_cursor:hover {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.cal-heatmap-container .qi {
|
||||
background-color: #999;
|
||||
fill: #999
|
||||
}
|
||||
|
||||
/*
|
||||
Remove comment to apply this style to date with value equal to 0
|
||||
.q0
|
||||
{
|
||||
background-color: #fff;
|
||||
fill: #fff;
|
||||
stroke: #ededed
|
||||
}
|
||||
*/
|
||||
|
||||
.cal-heatmap-container .q1
|
||||
{
|
||||
background-color: #dae289;
|
||||
fill: #dae289
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q2
|
||||
{
|
||||
background-color: #cedb9c;
|
||||
fill: #9cc069
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q3
|
||||
{
|
||||
background-color: #b5cf6b;
|
||||
fill: #669d45
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q4
|
||||
{
|
||||
background-color: #637939;
|
||||
fill: #637939
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q5
|
||||
{
|
||||
background-color: #3b6427;
|
||||
fill: #3b6427
|
||||
}
|
||||
|
||||
.cal-heatmap-container rect.highlight
|
||||
{
|
||||
stroke:#444;
|
||||
stroke-width:1
|
||||
}
|
||||
|
||||
.cal-heatmap-container text.highlight
|
||||
{
|
||||
fill: #444
|
||||
}
|
||||
|
||||
.cal-heatmap-container rect.now
|
||||
{
|
||||
stroke: red
|
||||
}
|
||||
|
||||
.cal-heatmap-container text.now
|
||||
{
|
||||
fill: red;
|
||||
font-weight: 800
|
||||
}
|
||||
|
||||
.cal-heatmap-container .domain-background {
|
||||
fill: none;
|
||||
shape-rendering: crispedges
|
||||
}
|
||||
|
||||
.ch-tooltip {
|
||||
padding: 10px;
|
||||
background: #222;
|
||||
color: #bbb;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
width: 140px;
|
||||
position: absolute;
|
||||
z-index: 99999;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ch-tooltip::after{
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
content: "";
|
||||
padding: 0;
|
||||
display: block;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: #222;
|
||||
}
|
||||
|
|
@ -28,9 +28,30 @@
|
|||
border-top: 1px solid #d1d8dd;
|
||||
}
|
||||
.form-dashboard {
|
||||
display: none;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.form-dashboard-section {
|
||||
padding: 15px 30px;
|
||||
margin: 0px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
.form-dashboard-section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.form-heatmap {
|
||||
padding-top: 30px;
|
||||
}
|
||||
.form-links .document-link {
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
position: relative;
|
||||
}
|
||||
.form-links .count {
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
top: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
.form-section {
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
|
|
|
|||
|
|
@ -412,7 +412,6 @@ frappe.get_desktop_icons = function(show_hidden, show_global) {
|
|||
if(m.blocked && !show_global) {
|
||||
out = false;
|
||||
}
|
||||
console.log(module, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,12 @@ frappe.ui.form.Control = Class.extend({
|
|||
this.set_input(value);
|
||||
}
|
||||
},
|
||||
set_focus: function() {
|
||||
if(this.$input) {
|
||||
this.$input.get(0).focus();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
|
||||
|
|
@ -1464,6 +1470,13 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
|
|||
this.editor.set_input(value);
|
||||
this.md_editor.val(value);
|
||||
this.last_value = value;
|
||||
},
|
||||
set_focus: function() {
|
||||
var editor = this.$wrapper.find('.text-editor');
|
||||
if(editor) {
|
||||
editor.focus();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,27 +4,30 @@
|
|||
frappe.ui.form.Dashboard = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
this.wrapper = $('<div class="form-dashboard shaded-section"></div>')
|
||||
.prependTo(this.frm.layout.wrapper);
|
||||
this.body = $('<div class="row"></div>').appendTo(this.wrapper)
|
||||
.css("padding", "15px 30px");
|
||||
this.wrapper = $(frappe.render_template('form_dashboard',
|
||||
{frm: this.frm})).prependTo(this.frm.layout.wrapper);
|
||||
|
||||
this.headline = this.wrapper.find('.form-headline');
|
||||
this.heatmap_area = this.wrapper.find('.form-heatmap');
|
||||
this.stats_area = this.wrapper.find('.form-stats');
|
||||
this.links_area = this.wrapper.find('.form-links');
|
||||
this.transactions_area = this.links_area.find('.transactions');
|
||||
|
||||
},
|
||||
reset: function() {
|
||||
this.wrapper.toggle(false);
|
||||
this.body.empty();
|
||||
this.badge_area = $('<div class="hidden" \
|
||||
style="padding-left: 15px; padding-right: 15px;">\
|
||||
<p class="text-muted small" style="margin-bottom: 0px;">'
|
||||
+ __("Documents related to {0}", [this.frm.doc.name]) +'</p></div>').appendTo(this.body);
|
||||
this.wrapper.addClass('hidden');
|
||||
this.clear_headline();
|
||||
|
||||
// clear links
|
||||
this.links_area.addClass('hidden');
|
||||
this.transactions_area.empty();
|
||||
|
||||
// clear stats
|
||||
this.stats_area.empty().addClass('hidden');
|
||||
},
|
||||
set_headline: function(html) {
|
||||
if(!this.headline)
|
||||
this.headline =
|
||||
$('<h4 class="form-headline col-md-12 hidden"></h4>').prependTo(this.body);
|
||||
this.headline.html(html).removeClass('hidden');
|
||||
this.wrapper.toggle(true);
|
||||
this.show();
|
||||
},
|
||||
clear_headline: function() {
|
||||
if(this.headline) {
|
||||
|
|
@ -67,7 +70,7 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
title="%(title)s"></div>', opts)).appendTo(progress);
|
||||
});
|
||||
|
||||
this.wrapper.toggle(true);
|
||||
this.show();
|
||||
},
|
||||
make_progress_chart: function(title) {
|
||||
var progress_area = this.body.find(".progress-area");
|
||||
|
|
@ -85,6 +88,8 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
return progress_chart;
|
||||
},
|
||||
|
||||
//
|
||||
show_links: function() {
|
||||
this.reset();
|
||||
if(this.frm.doc.__islocal)
|
||||
|
|
@ -96,7 +101,7 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
}
|
||||
this.render_links();
|
||||
this.set_open_count();
|
||||
|
||||
this.show_heatmap();
|
||||
},
|
||||
filter_permissions: function() {
|
||||
// filter out transactions for which the user
|
||||
|
|
@ -123,24 +128,24 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
var me = this;
|
||||
$(frappe.render_template('form_links',
|
||||
{transactions: this.links.transactions}))
|
||||
.appendTo(this.badge_area)
|
||||
.appendTo(this.transactions_area)
|
||||
|
||||
// bind links
|
||||
this.badge_area.find(".badge-link").on('click', function() {
|
||||
me.open_document_list($(this).attr('data-doctype'));
|
||||
this.transactions_area.find(".badge-link").on('click', function() {
|
||||
me.open_document_list($(this).parent().attr('data-doctype'));
|
||||
});
|
||||
|
||||
// bind open notifications
|
||||
this.badge_area.find('.open-notification').on('click', function() {
|
||||
me.open_document_list($(this).attr('data-doctype'), true);
|
||||
this.transactions_area.find('.open-notification').on('click', function() {
|
||||
me.open_document_list($(this).parent().attr('data-doctype'), true);
|
||||
});
|
||||
|
||||
this.wrapper.toggle(true);
|
||||
this.badge_area.removeClass('hidden');
|
||||
this.show();
|
||||
this.links_area.removeClass('hidden');
|
||||
},
|
||||
open_document_list: function(doctype, show_open) {
|
||||
// show document list with filters
|
||||
frappe.route_options = this.get_document_filter();
|
||||
frappe.route_options = this.get_document_filter(doctype);
|
||||
if(show_open) {
|
||||
$.extend(frappe.route_options, frappe.ui.notifications.get_filters(doctype));
|
||||
}
|
||||
|
|
@ -168,25 +173,70 @@ frappe.ui.form.Dashboard = Class.extend({
|
|||
|
||||
frappe.call({
|
||||
type: "GET",
|
||||
method: "frappe.desk.notifications.get_open_count",
|
||||
method: frappe.model.get_server_module_name(this.frm.doctype) + ".get_dashboard_data",
|
||||
args: {
|
||||
doctype: this.frm.doc.doctype,
|
||||
name: this.frm.doc.name,
|
||||
},
|
||||
callback: function(r) {
|
||||
$.each(r.message, function(i, d) {
|
||||
if(d.count) {
|
||||
me.frm.dashboard.set_badge_count(d.name, (d.count > 5) ? '5+' : d.count)
|
||||
}
|
||||
})
|
||||
me.heatmap.update(r.message.timeline_data);
|
||||
$.each(r.message.count, function(i, d) {
|
||||
me.frm.dashboard.set_badge_count(d.name, cint(d.open_count), cint(d.count));
|
||||
});
|
||||
me.frm.dashboard_data = r.message;
|
||||
me.frm.trigger('dashboard_update');
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
set_badge_count: function(doctype, count) {
|
||||
$(this.wrapper)
|
||||
.find('.open-notification[data-doctype="'+doctype+'"]')
|
||||
.removeClass('hidden')
|
||||
.html(count);
|
||||
set_badge_count: function(doctype, open_count, count) {
|
||||
var $link = $(this.transactions_area)
|
||||
.find('.document-link[data-doctype="'+doctype+'"]');
|
||||
|
||||
if(open_count) {
|
||||
$link.find('.open-notification')
|
||||
.removeClass('hidden')
|
||||
.html((open_count > 5) ? '5+' : open_count);
|
||||
}
|
||||
|
||||
if(count) {
|
||||
$link.find('.count')
|
||||
.html((count > 9) ? '9+' : count);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// heatmap
|
||||
show_heatmap: function() {
|
||||
if(!this.heatmap) {
|
||||
this.heatmap = new CalHeatMap();
|
||||
this.heatmap.init({
|
||||
itemSelector: "#heatmap-" + this.frm.doctype,
|
||||
domain: "month",
|
||||
subDomain: "day",
|
||||
start: moment().subtract(1, 'year').add(1, 'month').toDate(),
|
||||
cellSize: 9,
|
||||
cellPadding: 2,
|
||||
domainGutter: 2,
|
||||
range: 12,
|
||||
domainLabelFormat: function(date) {
|
||||
return moment(date).format("MMM").toUpperCase();
|
||||
},
|
||||
displayLegend: false,
|
||||
legend: [5, 10, 15, 20]
|
||||
// subDomainTextFormat: "%d",
|
||||
});
|
||||
|
||||
// center the heatmap
|
||||
this.heatmap_area.removeClass('hidden').find('svg').css({'margin': 'auto'});
|
||||
}
|
||||
},
|
||||
|
||||
// stats
|
||||
add_stats: function(html) {
|
||||
this.stats_area.html(html).removeClass('hidden');
|
||||
this.show();
|
||||
},
|
||||
show: function() {
|
||||
this.wrapper.removeClass('hidden');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
10
frappe/public/js/frappe/form/templates/form_dashboard.html
Normal file
10
frappe/public/js/frappe/form/templates/form_dashboard.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<div class="form-dashboard shaded-section hidden">
|
||||
<h4 class="form-headline hidden form-dashboard-section">
|
||||
</h4>
|
||||
<div class="form-heatmap hidden form-dashboard-section"
|
||||
id="heatmap-{{ frm.doctype }}"></div>
|
||||
<div class="form-stats form-dashboard-section hidden"></div>
|
||||
<div class="form-links form-dashboard-section hidden">
|
||||
<div class="transactions"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
<div class="form-documents">
|
||||
{% for (var i=0; i < transactions.length; i++) { %}
|
||||
{% if((i % 2)===0) { %}<div class="row">{% } %}
|
||||
<div class="col-xs-6">
|
||||
<div class="col-xs-6" style="padding-left: 30px;">
|
||||
<h5 style="margin-top: 15px;">{{ transactions[i].label }}</h5>
|
||||
{% for (var j=0; j < transactions[i].items.length; j++) {
|
||||
var doctype = transactions[i].items[j]; %}
|
||||
<div style="margin-bottom: 10px; height: 22px;">
|
||||
<a data-doctype="{{ doctype }}" class="badge-link small">
|
||||
{{ __(doctype) }}</a>
|
||||
<span class="open-notification hidden" data-doctype="{{ doctype }}"></span>
|
||||
<div class="document-link"
|
||||
data-doctype="{{ doctype }}">
|
||||
<span class="text-muted small count"></span>
|
||||
<a class="badge-link small">{{ __(doctype) }}</a>
|
||||
<span class="open-notification hidden"></span>
|
||||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -65,14 +65,11 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({
|
|||
|
||||
},
|
||||
focus_on_first_input: function() {
|
||||
var first = $(this.body).find(':input:first');
|
||||
if(first.length && first.attr("data-fieldtype")!="Date") {
|
||||
try {
|
||||
first.get(0).focus();
|
||||
} catch(e) {
|
||||
console.log("Dialog: unable to focus on first input: " + e);
|
||||
this.fields_list.every(function(f) {
|
||||
if(!in_list(['Date', 'Datetime', 'Time'], f.df.fieldtype) && f.set_focus()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
get_primary_btn: function() {
|
||||
return this.$wrapper.find(".modal-header .btn-primary");
|
||||
|
|
|
|||
|
|
@ -937,5 +937,7 @@ _f.Frm.prototype.scroll_to_element = function() {
|
|||
if (selector.length) {
|
||||
frappe.ui.scroll(selector, true, 30);
|
||||
}
|
||||
} else {
|
||||
window.scroll(0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3471
frappe/public/js/lib/cal-heatmap.js
Executable file
3471
frappe/public/js/lib/cal-heatmap.js
Executable file
File diff suppressed because it is too large
Load diff
5
frappe/public/js/lib/d3.min.js
vendored
Normal file
5
frappe/public/js/lib/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,11 +0,0 @@
|
|||
/**
|
||||
* Prism: Lightweight, robust, elegant syntax highlighting
|
||||
* MIT license http://www.opensource.org/licenses/mit-license.php/
|
||||
* @author Lea Verou http://lea.verou.me
|
||||
*/(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data),o);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar,l.language);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r,i){return n.stringify(t.tokenize(e,r),i)},tokenize:function(e,n,r){var i=t.Token,s=[e],o=n.rest;if(o){for(var u in o)n[u]=o[u];delete n.rest}e:for(var u in n){if(!n.hasOwnProperty(u)||!n[u])continue;var a=n[u],f=a.inside,l=!!a.lookbehind||0;a=a.pattern||a;for(var c=0;c<s.length;c++){var h=s[c];if(s.length>e.length)break e;if(h instanceof i)continue;a.lastIndex=0;var p=a.exec(h);if(p){l&&(l=p[1].length);var d=p.index-1+l,p=p[0].slice(l),v=p.length,m=d+v,g=h.slice(0,d+1),y=h.slice(m+1),b=[c,1];g&&b.push(g);var w=new i(u,f?t.tokenize(p,f):p);b.push(w);y&&b.push(y);Array.prototype.splice.apply(s,b)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+"</"+s.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();;
|
||||
Prism.languages.markup={comment:/<!--[\w\W]*?--(>|>)/g,prolog:/<\?.+?\?>/,doctype:/<!DOCTYPE.+?>/,cdata:/<!\[CDATA\[[\w\W]+?]]>/i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});;
|
||||
Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:/@[\w-]+?(\s+[^;{]+)?(?=\s*{|\s*;)/gi,url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,property:/(\b|\B)[a-z-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[\{\};:]/g};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig,inside:{tag:{pattern:/(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});;
|
||||
Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:class|interface|extends|implements|trait|instanceof|new)\s+)[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
|
||||
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig,inside:{tag:{pattern:/(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});;
|
||||
Prism.languages.python={comment:{pattern:/(^|[^\\])#.*?(\r?\n|$)/g,lookbehind:!0},string: /("|')(\\?.)*?\1/g,keyword:/\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/g,boolean:/\b(True|False)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|=?<|=?>|!|={1,2}|(&){1,2}|(&){1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
|
||||
Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)).*?(\r?\n|$))/g,lookbehind:!0},string: /("|')(\\?.)*?\1/g,keyword:/\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,boolean:/\b(TRUE|FALSE|NULL)\b/gi,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?<|=?>|={1}|(&){1,2}|\|?\||\?|\*|\//gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[;[\]()`,.]/g};;
|
||||
2
frappe/public/js/lib/shepherd.min.js
vendored
2
frappe/public/js/lib/shepherd.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -37,10 +37,38 @@
|
|||
}
|
||||
|
||||
.form-dashboard {
|
||||
display: none;
|
||||
border-bottom: 1px solid @light-border-color;
|
||||
}
|
||||
|
||||
.form-dashboard-section {
|
||||
padding: 15px 30px;
|
||||
margin: 0px;
|
||||
border-bottom: 1px solid @light-border-color;
|
||||
}
|
||||
|
||||
.form-dashboard-section:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.form-heatmap {
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.form-links {
|
||||
.document-link {
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.count {
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
top: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue