awsss 2 years ago
parent
commit
65a6ce3dc4
  1. 17
      smart_service/public/build.json
  2. 158
      smart_service/public/js/capture.js
  3. 55
      smart_service/public/js/control.js
  4. 2
      smart_service/public/js/datepicker.min.js
  5. 62
      smart_service/public/js/datepicker_i18n.js
  6. 1796
      smart_service/public/js/form.js
  7. 110
      smart_service/public/js/formview.js
  8. 20
      smart_service/public/js/meta_tag.js
  9. 625
      smart_service/public/js/request.js
  10. 22
      smart_service/public/js/templates/address_list.html
  11. 54
      smart_service/public/js/templates/contact_list.html
  12. 20
      smart_service/public/js/templates/form_dashboard.html
  13. 9
      smart_service/public/js/templates/form_footer.html
  14. 33
      smart_service/public/js/templates/form_links.html
  15. 160
      smart_service/public/js/templates/form_sidebar.html
  16. 56
      smart_service/public/js/templates/print_layout.html
  17. 23
      smart_service/public/js/templates/report_links.html
  18. 71
      smart_service/public/js/templates/set_sharing.html
  19. 92
      smart_service/public/js/templates/timeline_message_box.html
  20. 13
      smart_service/public/js/templates/users_in_sidebar.html

17
smart_service/public/build.json

@ -1,6 +1,21 @@
{ {
"css/smart_service.min.css": [ "css/smart_service.min.css": [
"public/css/smart_service.css" "public/css/smart_service.css"
],
"js/control.min.js": [
"public/js/datepicker.min.js",
"public/js/datepicker_i18n.js",
"public/js/capture.js",
"public/js/control.js"
],
"js/form.min.js": [
"public/js/templates/**.html",
"public/js/control.js",
"public/js/formview.js",
"public/js/form.js",
"public/js/meta_tag.js"
],
"js/request.min.js": [
"public/js/request.js"
] ]
} }

158
smart_service/public/js/capture.js

@ -0,0 +1,158 @@
// frappe.ui.Capture
// Author - Achilles Rasquinha <achilles@frappe.io>
/**
* @description Converts a canvas, image or a video to a data URL string.
*
* @param {HTMLElement} element - canvas, img or video.
* @returns {string} - The data URL string.
*
* @example
* frappe._.get_data_uri(video)
* // returns "data:image/pngbase64,..."
*/
frappe._.get_data_uri = element => {
const width = element.videoWidth;
const height = element.videoHeight;
const $canvas = $('<canvas/>');
$canvas[0].width = width;
$canvas[0].height = height;
const context = $canvas[0].getContext('2d');
context.drawImage(element, 0, 0, width, height);
const data_uri = $canvas[0].toDataURL('image/png');
return data_uri;
};
/**
* @description Frappe's Capture object.
*
* @example
* const capture = frappe.ui.Capture()
* capture.show()
*
* capture.click((data_uri) => {
* // do stuff
* })
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Taking_still_photos
*/
frappe.ui.Capture = class {
constructor(options = {}) {
this.options = frappe.ui.Capture.OPTIONS;
this.set_options(options);
}
set_options(options) {
this.options = { ...frappe.ui.Capture.OPTIONS, ...options };
return this;
}
render() {
return navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
this.stream = stream;
this.dialog = new frappe.ui.Dialog({
title: this.options.title,
animate: this.options.animate,
on_hide: () => this.stop_media_stream()
});
this.dialog.get_close_btn().on('click', () => {
this.hide();
});
const set_take_photo_action = () => {
this.dialog.set_primary_action(__('Take Photo'), () => {
const data_url = frappe._.get_data_uri(video);
$e.find('.fc-p').attr('src', data_url);
$e.find('.fc-s').hide();
$e.find('.fc-p').show();
this.dialog.set_secondary_action_label(__('Retake'));
this.dialog.get_secondary_btn().show();
this.dialog.set_primary_action(__('Submit'), () => {
this.hide();
if (this.callback) this.callback(data_url);
});
});
};
set_take_photo_action();
this.dialog.set_secondary_action(() => {
$e.find('.fc-p').hide();
$e.find('.fc-s').show();
this.dialog.get_secondary_btn().hide();
this.dialog.get_primary_btn().off('click');
set_take_photo_action();
});
this.dialog.get_secondary_btn().hide();
const $e = $(frappe.ui.Capture.TEMPLATE);
const video = $e.find('video')[0];
video.srcObject = this.stream;
video.play();
const $container = $(this.dialog.body);
$container.html($e);
});
}
show() {
this.render()
.then(() => {
this.dialog.show();
})
.catch(err => {
if (this.options.error) {
frappe.show_alert(frappe.ui.Capture.ERR_MESSAGE, 3);
}
throw err;
});
}
hide() {
if (this.dialog) this.dialog.hide();
this.stop_media_stream();
}
stop_media_stream() {
if (this.stream) {
this.stream.getTracks().forEach((track) => {
track.stop();
});
}
}
submit(fn) {
this.callback = fn;
}
};
frappe.ui.Capture.OPTIONS = {
title: __("Camera"),
animate: false,
error: false
};
frappe.ui.Capture.ERR_MESSAGE = __('Unable to load camera.');
frappe.ui.Capture.TEMPLATE = `
<div class="frappe-capture">
<div class="panel panel-default">
<div class="embed-responsive embed-responsive-16by9">
<img class="fc-p embed-responsive-item" style="object-fit: contain; display: none;"/>
<video class="fc-s embed-responsive-item">${frappe.ui.Capture.ERR_MESSAGE}</video>
</div>
</div>
</div>
`;

55
smart_service/public/js/control.js

@ -0,0 +1,55 @@
import 'frappe/public/js/frappe/form/controls/base_control';
import 'frappe/public/js/frappe/form/controls/base_input';
import 'frappe/public/js/frappe/form/controls/data';
import 'frappe/public/js/frappe/form/controls/int';
import 'frappe/public/js/frappe/form/controls/float';
import 'frappe/public/js/frappe/form/controls/currency';
import 'frappe/public/js/frappe/form/controls/date';
import 'frappe/public/js/frappe/form/controls/time';
import 'frappe/public/js/frappe/form/controls/datetime';
import 'frappe/public/js/frappe/form/controls/date_range';
import 'frappe/public/js/frappe/form/controls/select';
import 'frappe/public/js/frappe/form/controls/link';
import 'frappe/public/js/frappe/form/controls/dynamic_link';
import 'frappe/public/js/frappe/form/controls/text';
import 'frappe/public/js/frappe/form/controls/code';
import 'frappe/public/js/frappe/form/controls/text_editor';
import 'frappe/public/js/frappe/form/controls/comment';
import 'frappe/public/js/frappe/form/controls/check';
import 'frappe/public/js/frappe/form/controls/image';
import 'frappe/public/js/frappe/form/controls/attach';
import 'frappe/public/js/frappe/form/controls/attach_image';
import 'frappe/public/js/frappe/form/controls/table';
import 'frappe/public/js/frappe/form/controls/color';
import 'frappe/public/js/frappe/form/controls/signature';
import 'frappe/public/js/frappe/form/controls/password';
import 'frappe/public/js/frappe/form/controls/read_only';
import 'frappe/public/js/frappe/form/controls/button';
import 'frappe/public/js/frappe/form/controls/html';
import 'frappe/public/js/frappe/form/controls/markdown_editor';
import 'frappe/public/js/frappe/form/controls/html_editor';
import 'frappe/public/js/frappe/form/controls/heading';
import 'frappe/public/js/frappe/form/controls/autocomplete';
import 'frappe/public/js/frappe/form/controls/barcode';
import 'frappe/public/js/frappe/form/controls/geolocation';
import 'frappe/public/js/frappe/form/controls/multiselect';
import 'frappe/public/js/frappe/form/controls/multicheck';
import 'frappe/public/js/frappe/form/controls/table_multiselect';
import 'frappe/public/js/frappe/form/controls/multiselect_pills';
import 'frappe/public/js/frappe/form/controls/multiselect_list';
import 'frappe/public/js/frappe/form/controls/rating';
import 'frappe/public/js/frappe/form/controls/duration';
import 'frappe/public/js/frappe/form/controls/icon';
frappe.ui.form.make_control = function (opts) {
debugger;
var control_class_name = "Control" + opts.df.fieldtype.replace(/ /g, "");
if(frappe.ui.form[control_class_name]) {
return new frappe.ui.form[control_class_name](opts);
} else {
// eslint-disable-next-line
console.log("Invalid Control Name: " + opts.df.fieldtype);
}
};

2
smart_service/public/js/datepicker.min.js

File diff suppressed because one or more lines are too long

62
smart_service/public/js/datepicker_i18n.js

@ -0,0 +1,62 @@
import "air-datepicker/dist/js/i18n/datepicker.cs.js";
import "air-datepicker/dist/js/i18n/datepicker.da.js";
import "air-datepicker/dist/js/i18n/datepicker.de.js";
import "air-datepicker/dist/js/i18n/datepicker.en.js";
import "air-datepicker/dist/js/i18n/datepicker.es.js";
import "air-datepicker/dist/js/i18n/datepicker.fi.js";
import "air-datepicker/dist/js/i18n/datepicker.fr.js";
import "air-datepicker/dist/js/i18n/datepicker.hu.js";
import "air-datepicker/dist/js/i18n/datepicker.nl.js";
import "air-datepicker/dist/js/i18n/datepicker.pl.js";
import "air-datepicker/dist/js/i18n/datepicker.pt-BR.js";
import "air-datepicker/dist/js/i18n/datepicker.pt.js";
import "air-datepicker/dist/js/i18n/datepicker.ro.js";
import "air-datepicker/dist/js/i18n/datepicker.sk.js";
import "air-datepicker/dist/js/i18n/datepicker.zh.js";
(function ($) {
$.fn.datepicker.language['ar'] = {
days: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'],
daysShort: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'],
daysMin: ['الأحد', 'الأثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت'],
months: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'],
monthsShort: ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو', 'يوليو', 'أغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر'],
today: 'اليوم',
clear: 'Clear',
dateFormat: 'dd/mm/yyyy',
timeFormat: 'hh:ii aa',
firstDay: 0
};
})(jQuery);
(function ($) {
$.fn.datepicker.language['gr'] = {
days: ['Κυριακή', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο'],
daysShort: ['Κυρ', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ'],
daysMin: ['Κυ', 'Δε', 'Τρ', 'Τε', 'Πε', 'Πα', 'Σα'],
months: ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος'],
monthsShort: ['Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μάι', 'Ι/ν', 'Ι/λ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'],
today: 'Σήμερα',
clear: 'Καθαρισμός',
dateFormat: 'dd/mm/yyyy',
timeFormat: 'hh:ii aa',
firstDay: 0
};
})(jQuery);
(function ($) {
$.fn.datepicker.language['it'] = {
days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
daysShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'],
daysMin: ['Do', 'Lu', 'Ma', 'Me', 'Gi', 'Ve', 'Sa'],
months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto',
'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
monthsShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'],
today: 'Oggi',
clear: 'Reset',
dateFormat: 'dd/mm/yyyy',
timeFormat: 'hh:ii',
firstDay: 1
};
})(jQuery);

1796
smart_service/public/js/form.js

File diff suppressed because it is too large

110
smart_service/public/js/formview.js

@ -0,0 +1,110 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
frappe.provide('frappe.views.formview');
frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
make(route) {
var doctype = route[1],
doctype_layout = frappe.router.doctype_layout || doctype;
if (!frappe.views.formview[doctype_layout]) {
frappe.model.with_doctype(doctype, () => {
this.page = frappe.container.add_page(doctype_layout);
frappe.views.formview[doctype_layout] = this.page;
this.make_and_show(doctype, route);
});
} else {
this.show_doc(route);
}
this.setup_events();
}
make_and_show(doctype, route) {
if (frappe.router.doctype_layout) {
frappe.model.with_doc('DocType Layout', frappe.router.doctype_layout, () => {
this.make_form(doctype);
this.show_doc(route);
});
} else {
this.make_form(doctype);
this.show_doc(route);
}
}
make_form(doctype) {
this.page.frm = new frappe.ui.form.Form(doctype, this.page, true, frappe.router.doctype_layout);
}
setup_events() {
if (!this.initialized) {
$(document).on("page-change", function() {
frappe.ui.form.close_grid_form();
});
frappe.realtime.on("doc_viewers", function(data) {
// set users that currently viewing the form
frappe.ui.form.FormViewers.set_users(data, 'viewers');
});
frappe.realtime.on("doc_typers", function(data) {
// set users that currently typing on the form
frappe.ui.form.FormViewers.set_users(data, 'typers');
});
}
this.initialized = true;
}
show_doc(route) {
var doctype = route[1],
doctype_layout = frappe.router.doctype_layout || doctype,
name = route.slice(2).join("/");
if (frappe.model.new_names[name]) {
// document has been renamed, reroute
name = frappe.model.new_names[name];
frappe.set_route("Form", doctype_layout, name);
return;
}
const doc = frappe.get_doc(doctype, name);
if (doc && frappe.model.get_docinfo(doctype, name) && (doc.__islocal || frappe.model.is_fresh(doc))) {
// is document available and recent?
this.render(doctype_layout, name);
} else {
this.fetch_and_render(doctype, name, doctype_layout);
}
}
fetch_and_render(doctype, name, doctype_layout) {
frappe.model.with_doc(doctype, name, (name, r) => {
if (r && r['403']) return; // not permitted
if (!(locals[doctype] && locals[doctype][name])) {
if (name && name.substr(0, 3) === 'new') {
this.render_new_doc(doctype, name, doctype_layout);
} else {
frappe.show_not_found();
}
return;
}
this.render(doctype_layout, name);
});
}
render_new_doc(doctype, name, doctype_layout) {
const new_name = frappe.model.make_new_doc_and_get_name(doctype, true);
if (new_name===name) {
this.render(doctype_layout, name);
} else {
frappe.route_flags.replace_route = true;
frappe.set_route("Form", doctype_layout, new_name);
}
}
render(doctype_layout, name) {
frappe.container.change_to(doctype_layout);
frappe.views.formview[doctype_layout].frm.refresh(name);
}
}

20
smart_service/public/js/meta_tag.js

@ -0,0 +1,20 @@
frappe.provide('frappe.model');
frappe.provide('frappe.utils');
/**
* Opens the Website Meta Tag form if it exists for {route}
* or creates a new doc and opens the form
*/
frappe.utils.set_meta_tag = function(route) {
frappe.db.exists('Website Route Meta', route)
.then(exists => {
if (exists) {
frappe.set_route('Form', 'Website Route Meta', route);
} else {
// new doc
const doc = frappe.model.get_new_doc('Website Route Meta');
doc.__newname = route;
frappe.set_route('Form', doc.doctype, doc.name);
}
});
};

625
smart_service/public/js/request.js

@ -0,0 +1,625 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
// My HTTP Request
// console.log = function(){};
console.error = function () { };
// console.clear();
frappe.provide('frappe.request');
frappe.provide('frappe.request.error_handlers');
frappe.request.url = '/';
frappe.request.ajax_count = 0;
frappe.request.waiting_for_ajax = [];
frappe.request.logs = {};
frappe.xcall = function(method, params) {
console.log('api',method)
return new Promise((resolve, reject) => {
frappe.call({
method: method,
args: params,
callback: (r) => {
resolve(r.message);
},
error: (r) => {
reject(r.message);
}
});
});
};
// generic server call (call page, object)
frappe.call = function(opts) {
if (!frappe.is_online()) {
frappe.show_alert({
indicator: 'orange',
message: __('Connection Lost'),
subtitle: __('You are not connected to Internet. Retry after sometime.')
}, 3);
opts.always && opts.always();
return $.ajax();
}
if (typeof arguments[0]==='string') {
opts = {
method: arguments[0],
args: arguments[1],
callback: arguments[2],
headers: arguments[3]
}
}
if(opts.quiet) {
opts.no_spinner = true;
}
var args = $.extend({}, opts.args);
if (args.freeze) {
opts.freeze = opts.freeze || args.freeze;
opts.freeze_message = opts.freeze_message || args.freeze_message;
}
// cmd
if(opts.module && opts.page) {
args.cmd = opts.module+'.page.'+opts.page+'.'+opts.page+'.'+opts.method;
} else if(opts.doc) {
$.extend(args, {
cmd: "run_doc_method",
docs: frappe.get_doc(opts.doc.doctype, opts.doc.name),
method: opts.method,
args: opts.args,
});
} else if(opts.method) {
args.cmd = opts.method;
}
var callback = function(data, response_text) {
if(data.task_id) {
// async call, subscribe
frappe.socketio.subscribe(data.task_id, opts);
if(opts.queued) {
opts.queued(data);
}
}
else if (opts.callback) {
// ajax
return opts.callback(data, response_text);
}
}
let url = opts.url;
if (!url) {
url = '/api/method/' + args.cmd;
if (window.cordova) {
let host = frappe.request.url;
host = host.slice(0, host.length - 1);
url = host + url;
}
delete args.cmd;
}
// debouce if required
if (opts.debounce && frappe.request.is_fresh(args, opts.debounce)) {
return Promise.resolve();
}
return frappe.request.call({
type: opts.type || "POST",
args: args,
success: callback,
error: opts.error,
always: opts.always,
btn: opts.btn,
freeze: opts.freeze,
freeze_message: opts.freeze_message,
headers: opts.headers || {},
error_handlers: opts.error_handlers || {},
// show_spinner: !opts.no_spinner,
async: opts.async,
silent: opts.silent,
url,
});
}
frappe.request.call = function(opts) {
frappe.request.prepare(opts);
var statusCode = {
200: function(data, xhr) {
opts.success_callback && opts.success_callback(data, xhr.responseText);
},
401: function(xhr) {
if(frappe.app.session_expired_dialog && frappe.app.session_expired_dialog.display) {
frappe.app.redirect_to_login();
} else {
frappe.app.handle_session_expired();
}
},
404: function(xhr) {
if (frappe.flags.setting_original_route) {
// original route is wrong, redirect to login
frappe.app.redirect_to_login();
} else {
frappe.msgprint({title: __("Not found"), indicator: 'red',
message: __('The resource you are looking for is not available')});
}
},
403: function(xhr) {
if (frappe.session.user === "Guest" && frappe.session.logged_in_user !== "Guest") {
// session expired
frappe.app.handle_session_expired();
} else if (xhr.responseJSON && xhr.responseJSON._error_message) {
frappe.msgprint({
title: __("Not permitted"), indicator: 'red',
message: xhr.responseJSON._error_message
});
xhr.responseJSON._server_messages = null;
} else if (xhr.responseJSON && xhr.responseJSON._server_messages) {
var _server_messages = JSON.parse(xhr.responseJSON._server_messages);
// avoid double messages
if (_server_messages.indexOf(__("Not permitted")) !== -1) {
return;
}
} else {
frappe.msgprint({
title: __("Not permitted"), indicator: 'red',
message: __('You do not have enough permissions to access this resource. Please contact your manager to get access.')});
}
},
508: function(xhr) {
frappe.utils.play_sound("error");
frappe.msgprint({title:__('Please try again'), indicator:'red',
message:__("Another transaction is blocking this one. Please try again in a few seconds.")});
},
413: function(data, xhr) {
frappe.msgprint({indicator:'red', title:__('File too big'), message:__("File size exceeded the maximum allowed size of {0} MB",
[(frappe.boot.max_file_size || 5242880) / 1048576])});
},
417: function(xhr) {
var r = xhr.responseJSON;
if (!r) {
try {
r = JSON.parse(xhr.responseText);
} catch (e) {
r = xhr.responseText;
}
}
opts.error_callback && opts.error_callback(r);
},
501: function(data, xhr) {
if(typeof data === "string") data = JSON.parse(data);
opts.error_callback && opts.error_callback(data, xhr.responseText);
},
500: function(xhr) {
frappe.utils.play_sound("error");
try {
opts.error_callback && opts.error_callback();
frappe.request.report_error(xhr, opts);
} catch (e) {
frappe.request.report_error(xhr, opts);
}
},
504: function(xhr) {
frappe.msgprint(__("Request Timed Out"))
opts.error_callback && opts.error_callback();
},
502: function(xhr) {
frappe.msgprint(__("Internal Server Error"));
}
};
var exception_handlers = {
'QueryTimeoutError': function() {
frappe.utils.play_sound("error");
frappe.msgprint({
title: __('Request Timeout'),
indicator: 'red',
message: __("Server was too busy to process this request. Please try again.")
});
},
'QueryDeadlockError': function() {
frappe.utils.play_sound("error");
frappe.msgprint({
title: __('Deadlock Occurred'),
indicator: 'red',
message: __("Server was too busy to process this request. Please try again.")
});
}
};
var ajax_args = {
url: opts.url || frappe.request.url,
data: opts.args,
type: opts.type,
dataType: opts.dataType || 'json',
async: opts.async,
headers: Object.assign({
"X-Frappe-CSRF-Token": frappe.csrf_token,
"Accept": "application/json",
"X-Frappe-CMD": (opts.args && opts.args.cmd || '') || ''
}, opts.headers),
cache: false
};
if (opts.args && opts.args.doctype) {
ajax_args.headers["X-Frappe-Doctype"] = encodeURIComponent(opts.args.doctype);
}
frappe.last_request = ajax_args.data;
return $.ajax(ajax_args)
.done(function(data, textStatus, xhr) {
try {
if(typeof data === "string") data = JSON.parse(data);
// sync attached docs
if(data.docs || data.docinfo) {
frappe.model.sync(data);
}
// sync translated messages
if(data.__messages) {
$.extend(frappe._messages, data.__messages);
}
// callbacks
var status_code_handler = statusCode[xhr.statusCode().status];
if (status_code_handler) {
status_code_handler(data, xhr);
}
} catch(e) {
console.log("Unable to handle success response", data); // eslint-disable-line
console.trace(e); // eslint-disable-line
}
})
.always(function(data, textStatus, xhr) {
try {
if(typeof data==="string") {
data = JSON.parse(data);
}
if(data.responseText) {
var xhr = data;
data = JSON.parse(data.responseText);
}
} catch(e) {
data = null;
// pass
}
frappe.request.cleanup(opts, data);
if(opts.always) {
opts.always(data);
}
})
.fail(function(xhr, textStatus) {
try {
if (xhr.getResponseHeader('content-type') == 'application/json' && xhr.responseText) {
var data;
try {
data = JSON.parse(xhr.responseText);
} catch (e) {
// console.log("Unable to parse reponse text");
// console.log(xhr.responseText);
// console.log(e);
}
if (data && data.exception) {
// frappe.exceptions.CustomError: (1024, ...) -> CustomError
var exception = data.exception.split('.').at(-1).split(':').at(0);
var exception_handler = exception_handlers[exception];
if (exception_handler) {
exception_handler(data);
return;
}
}
}
var status_code_handler = statusCode[xhr.statusCode().status];
if (status_code_handler) {
status_code_handler(xhr);
return;
}
// if not handled by error handler!
opts.error_callback && opts.error_callback(xhr);
} catch(e) {
// console.log("Unable to handle failed response"); // eslint-disable-line
// console.trace(e); // eslint-disable-line
}
});
}
frappe.request.is_fresh = function(args, threshold) {
// return true if a request with similar args has been sent recently
if (!frappe.request.logs[args.cmd]) {
frappe.request.logs[args.cmd] = [];
}
for (let past_request of frappe.request.logs[args.cmd]) {
// check if request has same args and was made recently
if ((new Date() - past_request.timestamp) < threshold
&& frappe.utils.deep_equal(args, past_request.args)) {
// eslint-disable-next-line no-console
console.log('throttled');
return true;
}
}
// log the request
frappe.request.logs[args.cmd].push({args: args, timestamp: new Date()});
return false;
};
// call execute serverside request
frappe.request.prepare = function(opts) {
$("body").attr("data-ajax-state", "triggered");
// btn indicator
if(opts.btn) $(opts.btn).prop("disabled", true);
// freeze page
if(opts.freeze) frappe.dom.freeze(opts.freeze_message);
// stringify args if required
for(var key in opts.args) {
if(opts.args[key] && ($.isPlainObject(opts.args[key]) || $.isArray(opts.args[key]))) {
opts.args[key] = JSON.stringify(opts.args[key]);
}
}
// no cmd?
if(!opts.args.cmd && !opts.url) {
// console.log(opts)
throw "Incomplete Request";
}
opts.success_callback = opts.success;
opts.error_callback = opts.error;
delete opts.success;
delete opts.error;
}
frappe.request.cleanup = function(opts, r) {
// stop button indicator
if(opts.btn) {
$(opts.btn).prop("disabled", false);
}
$("body").attr("data-ajax-state", "complete");
// un-freeze page
if(opts.freeze) frappe.dom.unfreeze();
if(r) {
// session expired? - Guest has no business here!
if (r.session_expired ||
(frappe.session.user === 'Guest' && frappe.session.logged_in_user !== "Guest")) {
frappe.app.handle_session_expired();
return;
}
// error handlers
let global_handlers = frappe.request.error_handlers[r.exc_type] || [];
let request_handler = opts.error_handlers ? opts.error_handlers[r.exc_type] : null;
let handlers = [].concat(global_handlers, request_handler).filter(Boolean);
if (r.exc_type) {
handlers.forEach(handler => {
handler(r);
});
}
// show messages
if(r._server_messages && !opts.silent) {
// show server messages if no handlers exist
if (handlers.length === 0) {
r._server_messages = JSON.parse(r._server_messages);
frappe.hide_msgprint();
frappe.msgprint(r._server_messages);
}
}
// show errors
if(r.exc) {
r.exc = JSON.parse(r.exc);
if(r.exc instanceof Array) {
$.each(r.exc, function(i, v) {
if(v) {
// console.log(v);
}
})
} else {
// console.log(r.exc);
}
}
// debug messages
if(r._debug_messages) {
// if(opts.args) {
// console.log("======== arguments ========");
// console.log(opts.args);
// console.log("========")
// }
// $.each(JSON.parse(r._debug_messages), function(i, v) { console.log(v); });
// console.log("======== response ========");
// delete r._debug_messages;
// console.log(r);
// console.log("========");
}
}
frappe.last_response = r;
}
frappe.after_server_call = () => {
if(frappe.request.ajax_count) {
return new Promise(resolve => {
frappe.request.waiting_for_ajax.push(() => {
resolve();
});
});
} else {
return null;
}
};
frappe.after_ajax = function(fn) {
return new Promise(resolve => {
if(frappe.request.ajax_count) {
frappe.request.waiting_for_ajax.push(() => {
if(fn) return resolve(fn());
resolve();
});
} else {
if(fn) return resolve(fn());
resolve();
}
});
};
frappe.request.report_error = function(xhr, request_opts) {
var data = JSON.parse(xhr.responseText);
var exc;
if (data.exc) {
try {
exc = (JSON.parse(data.exc) || []).join("\n");
} catch (e) {
exc = data.exc;
}
delete data.exc;
} else {
exc = "";
}
const copy_markdown_to_clipboard = () => {
const code_block = snippet => '```\n' + snippet + '\n```';
const traceback_info = [
'### App Versions',
code_block(JSON.stringify(frappe.boot.versions, null, "\t")),
'### Route',
code_block(frappe.get_route_str()),
'### Trackeback',
code_block(exc),
'### Request Data',
code_block(JSON.stringify(request_opts, null, "\t")),
'### Response Data',
code_block(JSON.stringify(data, null, '\t')),
].join("\n");
frappe.utils.copy_to_clipboard(traceback_info);
};
var show_communication = function() {
var error_report_message = [
'<h5>Please type some additional information that could help us reproduce this issue:</h5>',
'<div style="min-height: 100px; border: 1px solid #bbb; \
border-radius: 5px; padding: 15px; margin-bottom: 15px;"></div>',
'<hr>',
'<h5>App Versions</h5>',
'<pre>' + JSON.stringify(frappe.boot.versions, null, "\t") + '</pre>',
'<h5>Route</h5>',
'<pre>' + frappe.get_route_str() + '</pre>',
'<hr>',
'<h5>Error Report</h5>',
'<pre>' + exc + '</pre>',
'<hr>',
'<h5>Request Data</h5>',
'<pre>' + JSON.stringify(request_opts, null, "\t") + '</pre>',
'<hr>',
'<h5>Response JSON</h5>',
'<pre>' + JSON.stringify(data, null, '\t')+ '</pre>'
].join("\n");
var communication_composer = new frappe.views.CommunicationComposer({
subject: 'Error Report [' + frappe.datetime.nowdate() + ']',
recipients: error_report_email,
message: error_report_message,
doc: {
doctype: "User",
name: frappe.session.user
}
});
communication_composer.dialog.$wrapper.css("z-index", cint(frappe.msg_dialog.$wrapper.css("z-index")) + 1);
}
if (exc) {
var error_report_email = frappe.boot.error_report_email;
request_opts = frappe.request.cleanup_request_opts(request_opts);
// window.msg_dialog = frappe.msgprint({message:error_message, indicator:'red', big: true});
if (!frappe.error_dialog) {
frappe.error_dialog = new frappe.ui.Dialog({
title: __('Server Error'),
primary_action_label: __('Report'),
primary_action: () => {
if (error_report_email) {
show_communication();
} else {
frappe.msgprint(__('Support Email Address Not Specified'));
}
frappe.error_dialog.hide();
},
secondary_action_label: __('Copy error to clipboard'),
secondary_action: () => {
copy_markdown_to_clipboard();
frappe.error_dialog.hide();
}
});
frappe.error_dialog.wrapper.classList.add('msgprint-dialog');
}
let parts = strip(exc).split('\n');
frappe.error_dialog.$body.html(parts[parts.length - 1]);
frappe.error_dialog.show();
}
};
frappe.request.cleanup_request_opts = function(request_opts) {
var doc = (request_opts.args || {}).doc;
if (doc) {
doc = JSON.parse(doc);
$.each(Object.keys(doc), function(i, key) {
if (key.indexOf("password")!==-1 && doc[key]) {
// mask the password
doc[key] = "*****";
}
});
request_opts.args.doc = JSON.stringify(doc);
}
return request_opts;
};
frappe.request.on_error = function(error_type, handler) {
frappe.request.error_handlers[error_type] = frappe.request.error_handlers[error_type] || [];
frappe.request.error_handlers[error_type].push(handler);
}
$(document).ajaxSend(function() {
frappe.request.ajax_count++;
});
$(document).ajaxComplete(function() {
frappe.request.ajax_count--;
if(!frappe.request.ajax_count) {
$.each(frappe.request.waiting_for_ajax || [], function(i, fn) {
fn();
});
frappe.request.waiting_for_ajax = [];
}
});

22
smart_service/public/js/templates/address_list.html

@ -0,0 +1,22 @@
<div class="clearfix"></div>
{% for(var i=0, l=addr_list.length; i<l; i++) { %}
<div class="address-box">
<p class="h6">
{%= i+1 %}. {%= addr_list[i].address_title %}{% if(addr_list[i].address_type!="Other") { %}
<span class="text-muted">({%= __(addr_list[i].address_type) %})</span>{% } %}
{% if(addr_list[i].is_primary_address) { %}
<span class="text-muted">({%= __("Primary") %})</span>{% } %}
{% if(addr_list[i].is_shipping_address) { %}
<span class="text-muted">({%= __("Shipping") %})</span>{% } %}
<a href="/app/Form/Address/{%= encodeURIComponent(addr_list[i].name) %}" class="btn btn-default btn-xs pull-right"
style="margin-top:-3px; margin-right: -5px;">
{%= __("Edit") %}</a>
</p>
<p>{%= addr_list[i].display %}</p>
</div>
{% } %}
{% if(!addr_list.length) { %}
<p class="text-muted small">{%= __("No address added yet.") %}</p>
{% } %}
<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>

54
smart_service/public/js/templates/contact_list.html

@ -0,0 +1,54 @@
<div class="clearfix"></div>
{% for(var i=0, l=contact_list.length; i<l; i++) { %}
<div class="address-box">
<p class="h6 flex align-center">
{%= contact_list[i].first_name %} {%= contact_list[i].last_name %}
{% if(contact_list[i].is_primary_contact) { %}
<span class="text-muted">&nbsp;({%= __("Primary") %})</span>
{% } %}
{% if(contact_list[i].designation){ %}
<span class="text-muted">&ndash; {%= contact_list[i].designation %}</span>
{% } %}
<a href="/app/Form/Contact/{%= encodeURIComponent(contact_list[i].name) %}"
class="btn btn-xs btn-default ml-auto">
{%= __("Edit") %}
</a>
</p>
{% if (contact_list[i].phones || contact_list[i].email_ids) { %}
<p>
{% if(contact_list[i].phone) { %}
{%= __("Phone") %}: {%= contact_list[i].phone %}<span class="text-muted"> ({%= __("Primary") %})</span><br>
{% endif %}
{% if(contact_list[i].mobile_no) { %}
{%= __("Mobile No") %}: {%= contact_list[i].mobile_no %}<span class="text-muted"> ({%= __("Primary") %})</span><br>
{% endif %}
{% if(contact_list[i].phone_nos) { %}
{% for(var j=0, k=contact_list[i].phone_nos.length; j<k; j++) { %}
{%= __("Phone") %}: {%= contact_list[i].phone_nos[j].phone %}<br>
{% } %}
{% endif %}
</p>
<p>
{% if(contact_list[i].email_id) { %}
{%= __("Email") %}: {%= contact_list[i].email_id %}<span class="text-muted"> ({%= __("Primary") %})</span><br>
{% endif %}
{% if(contact_list[i].email_ids) { %}
{% for(var j=0, k=contact_list[i].email_ids.length; j<k; j++) { %}
{%= __("Email") %}: {%= contact_list[i].email_ids[j].email_id %}<br>
{% } %}
{% endif %}
</p>
{% endif %}
<p>
{% if (contact_list[i].address) { %}
{%= __("Address") %}: {%= contact_list[i].address %}<br>
{% endif %}
</p>
</div>
{% } %}
{% if(!contact_list.length) { %}
<p class="text-muted small">{%= __("No contacts added yet.") %}</p>
{% } %}
<p><button class="btn btn-xs btn-default btn-contact">
{{ __("New Contact") }}</button>
</p>

20
smart_service/public/js/templates/form_dashboard.html

@ -0,0 +1,20 @@
<div class="form-dashboard-wrapper">
<div class="progress-area hidden form-dashboard-section">
</div>
<div class="form-heatmap hidden form-dashboard-section">
<div class="section-head">{{ __("Overview") }}</div>
<div id="heatmap-{{ frappe.model.scrub(frm.doctype) }}" class="heatmap"></div>
<div class="text-muted small heatmap-message hidden"></div>
</div>
<div class="form-graph form-dashboard-section hidden">
<div class="section-head">{{ __("Graph") }}</div>
</div>
<div class="form-stats form-dashboard-section hidden">
<div class="section-head">{{ __("Stats") }}</div>
<div class="row"></div>
</div>
<div class="form-links form-dashboard-section hidden">
<div class="section-head">{{ __("Documents") }}</div>
<div class="transactions"></div>
</div>
</div>

9
smart_service/public/js/templates/form_footer.html

@ -0,0 +1,9 @@
<div class="form-footer">
<div class="after-save">
<div class="comment-box"></div>
<div class="timeline"></div>
</div>
<button class="scroll-to-top btn btn-default icon-btn" onclick="frappe.utils.scroll_to(0)">
<svg class="icon icon-xs"><use href="#icon-up-line"></use></svg>
</button>
</div>

33
smart_service/public/js/templates/form_links.html

@ -0,0 +1,33 @@
<div class="form-documents">
{% for (let i=0; i < transactions.length; i++) { %}
{% if (i % 3 === 0) { %}
<div class="row">
{% } %}
<div class="col-md-4">
<div class="form-link-title">
<span>{{ __(transactions[i].label) }}<span>
</div>
{% for (let j=0; j < transactions[i].items.length; j++) { %}
{% let doctype = transactions[i].items[j]; %}
<div class="document-link" data-doctype="{{ doctype }}">
<div class="document-link-badge" data-doctype="{{ doctype }}">
<span class="count hidden"></span>
<a class="badge-link">{{ __(doctype) }}</a>
</div>
<span class="open-notification hidden"
title="{{ __("Open {0}", [__(doctype)])}}">
</span>
{% if !internal_links[doctype] %}
<button class="btn btn-new btn-secondary btn-xs icon-btn hidden"
data-doctype="{{ doctype }}">
<svg class="icon icon-sm"><use href="#icon-add"></use></svg>
</button>
{% endif %}
</div>
{% } %}
</div>
{% if (i % 3 === 2 || i === (transactions.length - 1)) { %}
</div>
{% } %}
{% } %}
</div>

160
smart_service/public/js/templates/form_sidebar.html

@ -0,0 +1,160 @@
<ul class="list-unstyled sidebar-menu user-actions hidden"></ul>
<ul class="list-unstyled sidebar-menu sidebar-image-section hide">
<li class="sidebar-image-wrapper">
<img class="sidebar-image">
<div class="sidebar-standard-image">
<div class="standard-image"></div>
</div>
<div class="sidebar-image-actions">
<div class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ __("Change") }}</a>
<div class="dropdown-menu" role="menu">
<a class="dropdown-item sidebar-image-change">{{ __("Upload") }}</a>
<a class="dropdown-item sidebar-image-remove">{{ __("Remove") }}</a>
</div>
</div>
</div>
</li>
</ul>
{% if frm.meta.beta %}
<div class="sidebar-menu">
<p><label class="indicator-pill yellow" title="{{ __("This feature is brand new and still experimental") }}">{{ __("Experimental") }}</label></p>
<p><a class="small text-muted" href="https://github.com/frappe/{{ frappe.boot.module_app[frappe.scrub(frm.meta.module)] }}/issues/new"
target="_blank">
{{ __("Click here to post bugs and suggestions") }}</a></p>
</div>
{% endif %}
<ul class="list-unstyled sidebar-menu sidebar-rating hide">
<li style="position: relative;">
<a class="strong badge-hover">
<span>{%= __("Feedback") %}</span>
</a>
</li>
<li class="rating-icons"></li>
</ul>
<ul class="list-unstyled sidebar-menu hidden">
{% if (frappe.help.has_help(doctype)) { %}
<li><a class="help-link list-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li>
{% } %}
</ul>
<ul class="list-unstyled sidebar-menu form-assignments">
<li class="sidebar-label">
<svg class="icon icon-sm"><use href="#icon-assign"></use></svg>
{%= __("Assigned To") %}
</li>
<li class="flex flex-wrap">
<span class="assignments"></span>
<button class="text-muted btn btn-default icon-btn add-assignment-btn">
<svg class="icon icon-sm"><use href="#icon-add"></use></svg>
</button>
</li>
</ul>
<ul class="list-unstyled sidebar-menu form-attachments">
<li class="sidebar-label attachments-label">
<svg class="icon icon-sm"><use href="#icon-attachment"></use></svg>
{%= __("Attachments") %}
</li>
<li class="add-attachment-btn">
<button class="data-pill btn">
<span class="pill-label ellipsis">
{%= __("Attach File") %}
</span>
<svg class="icon icon-sm">
<use href="#icon-add"></use>
</svg>
</button>
</li>
</ul>
<ul class="list-unstyled sidebar-menu form-reviews">
<li class="sidebar-label reviews-label">
<svg class="icon icon-sm"><use href="#icon-review"></use></svg>
{%= __("Reviews") %}
</li>
<li class="reviews">
<button class="add-review-btn text-muted btn btn-default icon-btn">
<svg class="icon icon-sm"><use href="#icon-add"></use></svg>
</button>
</li>
</ul>
<ul class="list-unstyled sidebar-menu form-shared">
<li class="sidebar-label">
<svg class="icon icon-sm"><use href="#icon-share"></use></svg>
{%= __("Shared With") %}
</li>
<li class="flex flex-wrap">
<span class="shares"></span>
<button class="share-doc-btn text-muted btn btn-default icon-btn">
<svg class="icon icon-sm"><use href="#icon-add"></use></svg>
</button>
</li>
</ul>
<ul class="list-unstyled sidebar-menu followed-by-section">
<li class="sidebar-label followed-by-label hidden">
<svg class="icon icon-sm">
<use href="#icon-link-url" class="like-icon"></use>
</svg>
{%= __("Followed by") %}
</li>
<li class="followed-by"></li>
<li class="document-follow">
<a class="badge-hover follow-document-link hidden">
{%= __("Follow") %}
</a>
<a class="badge-hover unfollow-document-link hidden">
{%= __("Unfollow") %}
</a>
</li>
</ul>
<ul class="list-unstyled sidebar-menu form-tags">
<li class="sidebar-label tags-label">
<svg class="icon icon-sm"><use href="#icon-tag"></use></svg>
{%= __("Tags") %}
</li>
</ul>
<ul class="list-unstyled sidebar-menu">
<a><li class="auto-repeat-status"><li></a>
</ul>
<ul class="list-unstyled sidebar-menu form-sidebar-stats">
<li class="flex">
<div class="form-stats">
<span class="form-stats-likes">
<span class="liked-by like-action">
<svg class="icon icon-sm">
<use href="#icon-heart" class="like-icon"></use>
</svg>
<span class="like-count"></span>
</span>
</span>
<span class="mx-1">·</span>
<a class="comments">
<svg class="icon icon-sm">
<use href="#icon-comment" class="comment-icon"></use>
</svg>
<span class="comments-count"></span>
</a>
</div>
<a class="form-follow text-sm">
Follow
</a>
</li>
</ul>
<hr>
<!-- <ul class="list-unstyled sidebar-menu">
<li class="liked-by-parent">
<span class="liked-by like-action">
<svg class="icon icon-sm">
<use href="#icon-heart" class="like-icon"></use>
</svg>
<span class="likes-count"></span>
</span>
</li>
</ul> -->
<ul class="list-unstyled sidebar-menu text-muted">
<li class="pageview-count"></li>
<li class="modified-by"></li>
<li class="created-by"></li>
</ul>
{% if(frappe.get_form_sidebar_extension) { %}
{{ frappe.get_form_sidebar_extension() }}
{% } %}

56
smart_service/public/js/templates/print_layout.html

@ -0,0 +1,56 @@
<!-- <div class="form-print-wrapper frappe-card">
<div class="print-toolbar row">
<div class="col-xs-3">
<div class="flex">
<select class="print-preview-select input-sm form-control"></select>
<button class="btn btn-default btn-sm border print-preview-refresh" type="button">{%= __("Refresh") %}</button>
</div>
</div>
<div class="col-xs-2">
<select class="languages input-sm form-control"
placeholder="{{ __("Language") }}"></select></div>
<div class="col-xs-2">
<div class="checkbox small" style="margin-top: 7px; margin-bottom: 0px;">
<label>
<input type="checkbox" class="print-letterhead text-muted"/>
{%= __("Letter Head") %}</label>
</div>
</div>
<div class="col-xs-5 text-right">
<a class="close btn-print-close" style="margin-top: 2px; margin-left: 10px;">&times;</a>
<div class="btn-group">
<a class="btn btn-default btn-sm"
style="border-top-right-radius:0px; border-bottom-right-radius: 0px;"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span>{%= __("Settings") %}</span>
<span>
<svg class="icon icon-xs">
<use xlink:href="#icon-select"></use>
</svg>
</span>
</a>
<ul class="dropdown-menu print-format-dropdown" style="max-height: 300px;
overflow-y: auto; left: auto;">
<li><a class="dropdown-item" href="/app/Form/Print Settings">
{%= __("Print Settings") %}</a></li>
<li><a class="btn-printer-setting dropdown-item" style="display: none;">
{%= __("Raw Printing Settings") %}</a></li>
<li><a class="btn-print-edit dropdown-item">
{%= __("Customize") %}</a></li>
</ul>
<a class="btn-print-preview btn-sm btn btn-default">
{%= __("Full Page") %}</a>
<a class="btn-download-pdf btn-sm btn btn-default">
{%= __("PDF") %}</a>
<a class="btn-print-print btn-sm btn btn-default">
<strong>{%= __("Print") %}</strong></a>
</div>
</div>
</div>
<div class="print-preview-wrapper">
<div class="print-preview">
<div class="print-format"></div>
</div>
<div class="page-break-message text-muted text-center text-medium margin-top"></div>
</div>
</div> -->

23
smart_service/public/js/templates/report_links.html

@ -0,0 +1,23 @@
<div class="form-documents">
{% for (var i=0; i < reports.length; i++) { %}
{% if (i % 3 === 0) { %}
<div class="row">
{% } %}
<div class="col-md-4">
<div class="form-link-title">
<span>{{ __(reports[i].label) }}</span>
</div>
{% for (let j=0; j < reports[i].items.length; j++) { %}
{% let report = reports[i].items[j]; %}
<div class="document-link" data-report="{{ report }}">
<div class="report-link-badge" data-report="{{ report }}">
<a class="report-link">{{ __(report) }}</a>
</div>
</div>
{% } %}
</div>
{% if (i % 3 === 2 || i === (reports.length - 1)) { %}
</div>
{% } %}
{% } %}
</div>

71
smart_service/public/js/templates/set_sharing.html

@ -0,0 +1,71 @@
<div>
<div class="row">
<div class="col-xs-4"><h6>{%= __("User") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Read") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Write") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Submit") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Share") %}</h6></div>
</div>
<div class="row shared-user" data-everyone=1>
<div class="col-xs-4 share-all"><b>{{ __("Everyone") }}</b></div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="read"
{% if(cint(everyone.read)) { %}checked{% } %} class="edit-share"></div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="write"
class="edit-share"
{% if(cint(everyone.write)) { %}checked{% } %}
{% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}>
</div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="submit"
class="edit-share"
{% if(cint(everyone.submit)) { %}checked{% } %}
{% if (!frm.perm[0].submit){ %} disabled="disabled"{% } %}>
</div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="share"
{% if(cint(everyone.share)) { %}checked{% } %} class="edit-share"></div>
</div>
{% for (var i=0, l=shared.length; i < l; i++) {
var s = shared[i]; %}
{% if(s && !s.everyone) { %}
<div class="row shared-user" data-user="{%= s.user %}" data-name="{%= s.name %}">
<div class="col-xs-4">{%= s.user %}</div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="read"
{% if(cint(s.read)) { %}checked{% } %} class="edit-share"></div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="write"
{% if(cint(s.write)) { %}checked{% } %} class="edit-share"{% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}></div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="submit"
{% if(cint(s.submit)) { %}checked{% } %} class="edit-share"{% if (!frm.perm[0].submit){ %} disabled="disabled"{% } %}></div>
<div class="col-xs-2 flex justify-center align-center"><input type="checkbox" name="share"
{% if(cint(s.share)) { %}checked{% } %} class="edit-share"></div>
</div>
{% } %}
{% } %}
{% if(frappe.model.can_share(null, frm)) { %}
<hr>
<div class="row">
<div class="col-xs-4"><h6>{%= __("Share this document with") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Read") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Write") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Submit") %}</h6></div>
<div class="col-xs-2 flex justify-center align-center"><h6>{%= __("Can Share") %}</h6></div>
</div>
<div class="row">
<div class="col-xs-4 input-wrapper-add-share"></div>
<div class="col-xs-2 flex justify-center align-flex-start mt-2"><input type="checkbox" class="add-share-read" name="read"></div>
<div class="col-xs-2 flex justify-center align-flex-start mt-2"><input type="checkbox" class="add-share-write" name="write"
{% if (!frm.perm[0].write){ %} disabled="disabled"{% } %}>
</div>
<div class="col-xs-2 flex justify-center align-flex-start mt-2"><input type="checkbox" class="add-share-submit" name="submit"
{% if (!frm.perm[0].submit){ %} disabled="disabled"{% } %}>
</div>
<div class="col-xs-2 flex justify-center align-flex-start mt-2"><input type="checkbox" class="add-share-share" name="share"></div>
</div>
<div>
<button class="btn btn-primary btn-sm btn-add-share mt-3">{{ __("Add") }}</button>
</div>
{% endif %}
</div>

92
smart_service/public/js/templates/timeline_message_box.html

@ -0,0 +1,92 @@
<div class="timeline-message-box" data-communication-type="{{ doc.communication_type }}">
<span class="flex justify-between">
<span class="text-color flex">
{% if (doc.communication_type && doc.communication_type == "Automated Message") { %}
<span>
<!-- Display maximum of 3 users-->
{{ __("Notification sent to") }}
{% var recipients = (doc.recipients && doc.recipients.split(",")) || [] %}
{% var cc = (doc.cc && doc.cc.split(",")) || [] %}
{% var bcc = (doc.bcc && doc.bcc.split(",")) || [] %}
{% var emails = recipients.concat(cc, bcc) %}
{% var display_emails_len = Math.min(emails.length, 3) %}
{% for (var i=0, len=display_emails_len; i<len; i++) { var email = emails[i]; %}
{{ frappe.user_info(email).fullname || email }}
{% if (len > i+1) { %}
{{ "," }}
{% } %}
{% } %}
{% if (emails.length > display_emails_len) { %}
{{ "..." }}
{% } %}
<div class="text-muted">
{{ comment_when(doc.creation) }}
</div>
</span>
{% } else if (doc.comment_type && doc.comment_type == "Comment") { %}
<span>
{{ doc.user_full_name || frappe.user.full_name(doc.owner) }} {{ __("commented") }}
<span class="text-muted margin-left">
{{ comment_when(doc.creation) }}
</span>
</span>
{% } else { %}
<span class="margin-right">
{{ frappe.avatar(doc.owner, "avatar-medium") }}
</span>
<span>
{{ doc.user_full_name || frappe.user.full_name(doc.owner) }}
<div class="text-muted">
{{ comment_when(doc.creation) }}
</div>
</span>
{% } %}
</span>
<span class="actions">
{% if (doc._doc_status && doc._doc_status_indicator) { %}
<span class="indicator-pill {%= doc._doc_status_indicator %}"
title="{%= __(doc._doc_status) %}"
style="order: -1">
<span class="hidden-xs small">
{%= __(doc._doc_status) %}
</span>
</span>
{% } %}
{% if (doc._url) { %}
<a class="action-btn" href="{{ doc._url }}" title="{{ __("Open Communication") }}">
<svg class="icon icon-sm">
<use href="#icon-link-url" class="like-icon"></use>
</svg>
</a>
{% } %}
</span>
</span>
<div class="content">
{{ doc.content }}
</div>
{% if (doc.attachments && doc.attachments.length) { %}
<div style="margin-top: 10px">
{% $.each(doc.attachments, function(i, a) { %}
<div class="ellipsis flex">
<a href="{%= encodeURI(a.file_url).replace(/#/g, \'%23\') %}"
class="text-muted small" target="_blank" rel="noopener noreferrer">
<svg viewBox="0 0 16 16" class="icon icon-xs" xmlns="http://www.w3.org/2000/svg">
<path d="M14 7.66625L8.68679 12.8875C7.17736 14.3708 4.64151 14.3708 3.13208 12.8875C1.62264 11.4042 1.62264 8.91224 3.13208 7.42892L7.84151 2.80099C8.9283 1.733 10.6189 1.733 11.7057 2.80099C12.7925 3.86897 12.7925 5.53028 11.7057 6.59827L7.35849 10.8109C6.75472 11.4042 5.78868 11.4042 5.24528 10.8109C4.64151 10.2176 4.64151 9.26823 5.24528 8.73424L8.86792 5.17429" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round"/>
</svg>
{%= a.file_url.split("/").slice(-1)[0] %}
{% if (a.is_private) { %}
<svg class="icon icon-xs" style="color: var(--yellow-300)"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.077 1.45h-.055a3.356 3.356 0 00-3.387 3.322v.35H3.75a2 2 0 00-2 2v5.391a2 2 0 002 2h8.539a2 2 0 002-2V7.122a2 2 0 00-2-2h-.885v-.285A3.356 3.356 0 008.082 1.45h-.005zm2.327 3.672V4.83a2.356 2.356 0 00-2.33-2.38h-.06a2.356 2.356 0 00-2.38 2.33v.342h4.77zm-6.654 1a1 1 0 00-1 1v5.391a1 1 0 001 1h8.539a1 1 0 001-1V7.122a1 1 0 00-1-1H3.75zm4.27 4.269a.573.573 0 100-1.147.573.573 0 000 1.147zm1.573-.574a1.573 1.573 0 11-3.147 0 1.573 1.573 0 013.147 0z" fill="currentColor" stroke="currentColor"></path>
</svg>
{% } %}
</a>
</div>
{% }); %}
</div>
{% } %}
</div>

13
smart_service/public/js/templates/users_in_sidebar.html

@ -0,0 +1,13 @@
{% for (var i=0, l=users.length; i < l; i++) {
var u = users[i];
%}
<span class="avatar avatar-small {{ u.avatar_class || "" }}" title="{{ u.title }}">
{% if (u.icon) { %}
<i class="{{ u.icon }}"></i>
{% } else if(u.image) { %}
<img class="media-object" src="{{ u.image }}" alt="{{ u.fullname }}">
{% } else { %}
<div class="standard-image" style="background-color: {{ u.color }};">{{ u.abbr.substr(0,1) }}</div>
{% } %}
</span>
{% } %}
Loading…
Cancel
Save