diff --git a/.eslintrc b/.eslintrc
index a2538feab5..d123023a68 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -147,6 +147,7 @@
"context": true,
"before": true,
"beforeEach": true,
- "qz": true
+ "qz": true,
+ "localforage": true
}
}
diff --git a/cypress/integration/control_rating.js b/cypress/integration/control_rating.js
index 31c036d240..592ed87004 100644
--- a/cypress/integration/control_rating.js
+++ b/cypress/integration/control_rating.js
@@ -18,7 +18,7 @@ context('Control Rating', () => {
get_dialog_with_rating().as('dialog');
cy.get('div.rating')
- .children('i.fa')
+ .children('svg')
.first()
.click()
.should('have.class', 'star-click');
@@ -33,11 +33,11 @@ context('Control Rating', () => {
get_dialog_with_rating();
cy.get('div.rating')
- .children('i.fa')
+ .children('svg')
.first()
.invoke('trigger', 'mouseenter')
.should('have.class', 'star-hover')
.invoke('trigger', 'mouseleave')
.should('not.have.class', 'star-hover');
});
-});
\ No newline at end of file
+});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 416d782ffe..1964b96d70 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -312,7 +312,6 @@ Cypress.Commands.add('add_filter', () => {
cy.get('.filter-section .filter-button').click();
cy.wait(300);
cy.get('.filter-popover').should('exist');
- cy.get('.filter-popover').find('.add-filter').click();
});
Cypress.Commands.add('clear_filters', () => {
diff --git a/frappe/app.py b/frappe/app.py
index adf2bfa8c9..784db3d976 100644
--- a/frappe/app.py
+++ b/frappe/app.py
@@ -152,10 +152,10 @@ def process_response(response):
def set_cors_headers(response):
origin = frappe.request.headers.get('Origin')
- if not origin:
+ allow_cors = frappe.conf.allow_cors
+ if not (origin and allow_cors):
return
- allow_cors = frappe.conf.allow_cors
if allow_cors != "*":
if not isinstance(allow_cors, list):
allow_cors = [allow_cors]
@@ -181,6 +181,9 @@ def make_form_dict(request):
else:
args = request.form or request.args
+ if not isinstance(args, dict):
+ frappe.throw("Invalid request arguments")
+
try:
frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
for k, v in iteritems(args) })
diff --git a/frappe/boot.py b/frappe/boot.py
index 8cf75e02bb..0dfcb8d1b4 100644
--- a/frappe/boot.py
+++ b/frappe/boot.py
@@ -21,7 +21,7 @@ from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabl
from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
from frappe.model.base_document import get_controller
from frappe.social.doctype.post.post import frequently_visited_links
-from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings
+from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings, get_app_logo
def get_bootinfo():
"""build and return boot info"""
@@ -62,6 +62,7 @@ def get_bootinfo():
doclist.extend(get_meta_bundle("Page"))
bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1})
bootinfo.navbar_settings = get_navbar_settings()
+ bootinfo.notification_settings = get_notification_settings()
# ipinfo
if frappe.session.data.get('ipinfo'):
@@ -90,6 +91,7 @@ def get_bootinfo():
bootinfo.link_preview_doctypes = get_link_preview_doctypes()
bootinfo.additional_filters_config = get_additional_filters_from_hooks()
bootinfo.desk_settings = get_desk_settings()
+ bootinfo.app_logo_url = get_app_logo()
return bootinfo
@@ -323,4 +325,7 @@ def get_desk_settings():
for key in desk_properties:
desk_settings[key] = desk_settings.get(key) or role.get(key)
- return desk_settings
\ No newline at end of file
+ return desk_settings
+
+def get_notification_settings():
+ return frappe.get_cached_doc('Notification Settings', frappe.session.user)
diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json
index 569414e98b..1533829b3c 100644
--- a/frappe/core/doctype/doctype/doctype.json
+++ b/frappe/core/doctype/doctype/doctype.json
@@ -555,7 +555,7 @@
},
{
"group": "Customization",
- "link_doctype": "Custom Script",
+ "link_doctype": "Client Script",
"link_fieldname": "dt"
},
{
@@ -609,7 +609,7 @@
"link_fieldname": "reference_doctype"
}
],
- "modified": "2020-12-10 15:10:09.227205",
+ "modified": "2021-02-04 15:10:09.227205",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",
diff --git a/frappe/core/doctype/navbar_settings/navbar_settings.py b/frappe/core/doctype/navbar_settings/navbar_settings.py
index db510981a4..2244bc9e4e 100644
--- a/frappe/core/doctype/navbar_settings/navbar_settings.py
+++ b/frappe/core/doctype/navbar_settings/navbar_settings.py
@@ -25,7 +25,7 @@ class NavbarSettings(Document):
@frappe.whitelist(allow_guest=True)
def get_app_logo():
- app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo')
+ app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo', cache=True)
if not app_logo:
app_logo = frappe.get_hooks('app_logo_url')[-1]
diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
index 0d6aa3d7d1..e02d9e5db0 100644
--- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
+++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
@@ -3,6 +3,7 @@
# For license information, please see license.txt
from __future__ import unicode_literals
+from typing import Dict, List
import frappe, json
from frappe.model.document import Document
@@ -11,12 +12,13 @@ from datetime import datetime
from croniter import croniter
from frappe.utils.background_jobs import enqueue, get_jobs
+
class ScheduledJobType(Document):
def autoname(self):
- self.name = '.'.join(self.method.split('.')[-2:])
+ self.name = ".".join(self.method.split(".")[-2:])
def validate(self):
- if self.frequency != 'All':
+ if self.frequency != "All":
# force logging for all events other than continuous ones (ALL)
self.create_log = 1
@@ -84,7 +86,7 @@ class ScheduledJobType(Document):
def log_status(self, status):
# log file
- frappe.logger("scheduler").info('Scheduled Job {0}: {1} for {2}'.format(status, self.method, frappe.local.site))
+ frappe.logger("scheduler").info(f"Scheduled Job {status}: {self.method} for {frappe.local.site}")
self.update_scheduler_log(status)
def update_scheduler_log(self, status):
@@ -111,28 +113,28 @@ class ScheduledJobType(Document):
@frappe.whitelist()
-def execute_event(doc):
- frappe.only_for('System Manager')
+def execute_event(doc: str):
+ frappe.only_for("System Manager")
doc = json.loads(doc)
- frappe.get_doc('Scheduled Job Type', doc.get('name')).enqueue(force=True)
+ frappe.get_doc("Scheduled Job Type", doc.get("name")).enqueue(force=True)
-def run_scheduled_job(job_type):
- '''This is a wrapper function that runs a hooks.scheduler_events method'''
+def run_scheduled_job(job_type: str):
+ """This is a wrapper function that runs a hooks.scheduler_events method"""
try:
- frappe.get_doc('Scheduled Job Type', dict(method=job_type)).execute()
+ frappe.get_doc("Scheduled Job Type", dict(method=job_type)).execute()
except Exception:
print(frappe.get_traceback())
-def sync_jobs(hooks=None):
+def sync_jobs(hooks: Dict = None):
frappe.reload_doc("core", "doctype", "scheduled_job_type")
scheduler_events = hooks or frappe.get_hooks("scheduler_events")
all_events = insert_events(scheduler_events)
clear_events(all_events)
-def insert_events(scheduler_events):
+def insert_events(scheduler_events: Dict) -> List:
cron_jobs, event_jobs = [], []
for event_type in scheduler_events:
events = scheduler_events.get(event_type)
@@ -144,7 +146,7 @@ def insert_events(scheduler_events):
return cron_jobs + event_jobs
-def insert_cron_jobs(events):
+def insert_cron_jobs(events: Dict) -> List:
cron_jobs = []
for cron_format in events:
for event in events.get(cron_format):
@@ -153,25 +155,29 @@ def insert_cron_jobs(events):
return cron_jobs
-def insert_event_jobs(events, event_type):
+def insert_event_jobs(events: List, event_type: str) -> List:
event_jobs = []
for event in events:
event_jobs.append(event)
- frequency = event_type.replace('_', ' ').title()
+ frequency = event_type.replace("_", " ").title()
insert_single_event(frequency, event)
return event_jobs
-def insert_single_event(frequency, event, cron_format=None):
+def insert_single_event(frequency: str, event: str, cron_format: str = None):
cron_expr = {"cron_format": cron_format} if cron_format else {}
- doc = frappe.get_doc({
- "doctype": "Scheduled Job Type",
- "method": event,
- "cron_format": cron_format,
- "frequency": frequency
- })
+ doc = frappe.get_doc(
+ {
+ "doctype": "Scheduled Job Type",
+ "method": event,
+ "cron_format": cron_format,
+ "frequency": frequency,
+ }
+ )
- if not frappe.db.exists("Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr }):
+ if not frappe.db.exists(
+ "Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr}
+ ):
try:
doc.insert()
except frappe.DuplicateEntryError:
@@ -179,7 +185,12 @@ def insert_single_event(frequency, event, cron_format=None):
doc.insert()
-def clear_events(all_events):
- for event in frappe.get_all("Scheduled Job Type", ("name", "method")):
- if event.method not in all_events:
+def clear_events(all_events: List):
+ for event in frappe.get_all(
+ "Scheduled Job Type", fields=["name", "method", "server_script"]
+ ):
+ is_server_script = event.server_script
+ is_defined_in_hooks = event.method in all_events
+
+ if not (is_defined_in_hooks or is_server_script):
frappe.delete_doc("Scheduled Job Type", event.name)
diff --git a/frappe/core/doctype/server_script/server_script.js b/frappe/core/doctype/server_script/server_script.js
index a317d69166..95a63780f8 100644
--- a/frappe/core/doctype/server_script/server_script.js
+++ b/frappe/core/doctype/server_script/server_script.js
@@ -6,46 +6,11 @@ frappe.ui.form.on('Server Script', {
frm.trigger('setup_help');
},
refresh: function(frm) {
- if (frm.doc.script_type === 'Scheduler Event' && !frm.doc.disabled) {
- frm.add_custom_button('Schedule Script', function() {
- var d = new frappe.ui.Dialog({
- title: "Schedule Script Execution",
- fields: [
- {
- fieldname: "event_type",
- label: __('Select Event Type'),
- fieldtype: "Select",
- options: "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
- },
- ],
- primary_action_label: __('Schedule Script'),
- primary_action: () => {
- d.get_primary_btn().attr('disabled', true);
- var data = d.get_values();
- d.hide();
- if(data) {
- frm.events.schedule_script(frm, data);
- }
-
- }
- });
-
- d.show();
-
- });
+ if (frm.doc.script_type != 'Scheduler Event') {
+ frm.dashboard.hide();
}
},
- schedule_script(frm, data) {
- frm.call({
- method: "frappe.core.doctype.server_script.server_script.setup_scheduler_events",
- args: {
- 'script_name': frm.doc.name,
- 'frequency': data.event_type
- }
- });
- },
-
setup_help(frm) {
frm.get_field('help_html').html(`
DocType Event
diff --git a/frappe/core/doctype/server_script/server_script.json b/frappe/core/doctype/server_script/server_script.json
index 9aa7b5afe5..b7e49673f8 100644
--- a/frappe/core/doctype/server_script/server_script.json
+++ b/frappe/core/doctype/server_script/server_script.json
@@ -8,6 +8,7 @@
"field_order": [
"script_type",
"reference_doctype",
+ "event_frequency",
"doctype_event",
"api_method",
"allow_guest",
@@ -84,11 +85,24 @@
{
"fieldname": "help_html",
"fieldtype": "HTML"
+ },
+ {
+ "depends_on": "eval:doc.script_type == \"Scheduler Event\"",
+ "fieldname": "event_frequency",
+ "fieldtype": "Select",
+ "label": "Event Frequency",
+ "mandatory_depends_on": "eval:doc.script_type == \"Scheduler Event\"",
+ "options": "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
}
],
"index_web_pages_for_search": 1,
- "links": [],
- "modified": "2021-01-03 18:50:14.767595",
+ "links": [
+ {
+ "link_doctype": "Scheduled Job Type",
+ "link_fieldname": "server_script"
+ }
+ ],
+ "modified": "2021-02-18 12:36:19.803425",
"modified_by": "Administrator",
"module": "Core",
"name": "Server Script",
diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py
index 88d68dba14..8838d9e954 100644
--- a/frappe/core/doctype/server_script/server_script.py
+++ b/frappe/core/doctype/server_script/server_script.py
@@ -5,6 +5,7 @@
from __future__ import unicode_literals
import ast
+from typing import Dict, List
import frappe
from frappe.model.document import Document
@@ -14,67 +15,146 @@ from frappe import _
class ServerScript(Document):
def validate(self):
- frappe.only_for('Script Manager', True)
+ frappe.only_for("Script Manager", True)
+ self.validate_script()
+ self.sync_scheduled_jobs()
+ self.clear_scheduled_events()
+
+ def on_update(self):
+ frappe.cache().delete_value("server_script_map")
+ self.sync_scheduler_events()
+
+ def on_trash(self):
+ if self.script_type == "Scheduler Event":
+ for job in self.scheduled_jobs:
+ frappe.delete_doc("Scheduled Job Type", job.name)
+
+ @property
+ def scheduled_jobs(self) -> List[Dict[str, str]]:
+ return frappe.get_all(
+ "Scheduled Job Type",
+ filters={"server_script": self.name},
+ fields=["name", "stopped"],
+ )
+
+ def validate_script(self):
+ """Utilizes the ast module to check for syntax errors
+ """
ast.parse(self.script)
- @staticmethod
- def on_update():
- frappe.cache().delete_value('server_script_map')
+ def sync_scheduled_jobs(self):
+ """Sync Scheduled Job Type statuses if Server Script's disabled status is changed
+ """
+ if self.script_type != "Scheduler Event" or not self.has_value_changed("disabled"):
+ return
- def execute_method(self):
- if self.script_type == 'API':
- # validate if guest is allowed
- if frappe.session.user == 'Guest' and not self.allow_guest:
- raise frappe.PermissionError
- _globals, _locals = safe_exec(self.script)
- return _globals.frappe.flags # output can be stored in flags
- else:
- # wrong report type!
+ for scheduled_job in self.scheduled_jobs:
+ if bool(scheduled_job.stopped) != bool(self.disabled):
+ job = frappe.get_doc("Scheduled Job Type", scheduled_job.name)
+ job.stopped = self.disabled
+ job.save()
+
+ def sync_scheduler_events(self):
+ """Create or update Scheduled Job Type documents for Scheduler Event Server Scripts
+ """
+ if not self.disabled and self.event_frequency and self.script_type == "Scheduler Event":
+ setup_scheduler_events(script_name=self.name, frequency=self.event_frequency)
+
+ def clear_scheduled_events(self):
+ """Deletes existing scheduled jobs by Server Script if self.event_frequency has changed
+ """
+ if self.script_type == "Scheduler Event" and self.has_value_changed("event_frequency"):
+ for scheduled_job in self.scheduled_jobs:
+ frappe.delete_doc("Scheduled Job Type", scheduled_job.name)
+
+ def execute_method(self) -> Dict:
+ """Specific to API endpoint Server Scripts
+
+ Raises:
+ frappe.DoesNotExistError: If self.script_type is not API
+ frappe.PermissionError: If self.allow_guest is unset for API accessed by Guest user
+
+ Returns:
+ dict: Evaluates self.script with frappe.utils.safe_exec.safe_exec and returns the flags set in it's safe globals
+ """
+ # wrong report type!
+ if self.script_type != "API":
raise frappe.DoesNotExistError
- def execute_doc(self, doc):
- # execute event
- safe_exec(self.script, None, dict(doc = doc))
+ # validate if guest is allowed
+ if frappe.session.user == "Guest" and not self.allow_guest:
+ raise frappe.PermissionError
+
+ # output can be stored in flags
+ _globals, _locals = safe_exec(self.script)
+ return _globals.frappe.flags
+
+ def execute_doc(self, doc: Document):
+ """Specific to Document Event triggered Server Scripts
+
+ Args:
+ doc (Document): Executes script with for a certain document's events
+ """
+ safe_exec(self.script, _locals={"doc": doc})
def execute_scheduled_method(self):
- if self.script_type == 'Scheduler Event':
- safe_exec(self.script)
- else:
- # wrong report type!
+ """Specific to Scheduled Jobs via Server Scripts
+
+ Raises:
+ frappe.DoesNotExistError: If script type is not a scheduler event
+ """
+ if self.script_type != "Scheduler Event":
raise frappe.DoesNotExistError
- def get_permission_query_conditions(self, user):
+ safe_exec(self.script)
+
+ def get_permission_query_conditions(self, user: str) -> List[str]:
+ """Specific to Permission Query Server Scripts
+
+ Args:
+ user (str): Takes user email to execute script and return list of conditions
+
+ Returns:
+ list: Returns list of conditions defined by rules in self.script
+ """
locals = {"user": user, "conditions": ""}
safe_exec(self.script, None, locals)
if locals["conditions"]:
return locals["conditions"]
+
@frappe.whitelist()
def setup_scheduler_events(script_name, frequency):
- method = frappe.scrub('{0}-{1}'.format(script_name, frequency))
- scheduled_script = frappe.db.get_value('Scheduled Job Type',
- dict(method=method))
+ """Creates or Updates Scheduled Job Type documents based on the specified script name and frequency
+
+ Args:
+ script_name (str): Name of the Server Script document
+ frequency (str): Event label compatible with the Frappe scheduler
+ """
+ method = frappe.scrub(f"{script_name}-{frequency}")
+ scheduled_script = frappe.db.get_value("Scheduled Job Type", {"method": method})
if not scheduled_script:
- doc = frappe.get_doc(dict(
- doctype = 'Scheduled Job Type',
- method = method,
- frequency = frequency,
- server_script = script_name
- ))
+ frappe.get_doc(
+ {
+ "doctype": "Scheduled Job Type",
+ "method": method,
+ "frequency": frequency,
+ "server_script": script_name,
+ }
+ ).insert()
- doc.insert()
-
- frappe.msgprint(_('Enabled scheduled execution for script {0}').format(script_name))
+ frappe.msgprint(_("Enabled scheduled execution for script {0}").format(script_name))
else:
- doc = frappe.get_doc('Scheduled Job Type', scheduled_script)
- doc.update(dict(
- doctype = 'Scheduled Job Type',
- method = method,
- frequency = frequency,
- server_script = script_name
- ))
+ doc = frappe.get_doc("Scheduled Job Type", scheduled_script)
+
+ if doc.frequency == frequency:
+ return
+
+ doc.frequency = frequency
doc.save()
- frappe.msgprint(_('Scheduled execution for script {0} has updated').format(script_name))
+ frappe.msgprint(
+ _("Scheduled execution for script {0} has updated").format(script_name)
+ )
diff --git a/frappe/core/workspace/build/build.json b/frappe/core/workspace/build/build.json
index c4bde55d7f..aefda698b1 100644
--- a/frappe/core/workspace/build/build.json
+++ b/frappe/core/workspace/build/build.json
@@ -11,6 +11,7 @@
"hide_custom": 0,
"icon": "tool",
"idx": 0,
+ "is_default": 0,
"is_standard": 1,
"label": "Build",
"links": [
@@ -163,8 +164,8 @@
{
"hidden": 0,
"is_query_report": 0,
- "label": "Custom Script",
- "link_to": "Custom Script",
+ "label": "Client Script",
+ "link_to": "Client Script",
"link_type": "DocType",
"onboard": 0,
"only_for": "",
@@ -181,7 +182,7 @@
"type": "Link"
}
],
- "modified": "2021-01-02 14:03:15.029699",
+ "modified": "2021-02-04 13:48:48.493146",
"modified_by": "Administrator",
"module": "Core",
"name": "Build",
diff --git a/frappe/custom/doctype/custom_script/README.md b/frappe/custom/doctype/client_script/README.md
similarity index 100%
rename from frappe/custom/doctype/custom_script/README.md
rename to frappe/custom/doctype/client_script/README.md
diff --git a/frappe/custom/doctype/custom_script/__init__.py b/frappe/custom/doctype/client_script/__init__.py
similarity index 100%
rename from frappe/custom/doctype/custom_script/__init__.py
rename to frappe/custom/doctype/client_script/__init__.py
diff --git a/frappe/custom/doctype/custom_script/custom_script.js b/frappe/custom/doctype/client_script/client_script.js
similarity index 97%
rename from frappe/custom/doctype/custom_script/custom_script.js
rename to frappe/custom/doctype/client_script/client_script.js
index 711e7d1796..21e7334b82 100644
--- a/frappe/custom/doctype/custom_script/custom_script.js
+++ b/frappe/custom/doctype/client_script/client_script.js
@@ -1,7 +1,7 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Custom Script', {
+frappe.ui.form.on('Client Script', {
refresh(frm) {
if (frm.doc.dt && frm.doc.script) {
frm.add_custom_button(__('Go to {0}', [frm.doc.dt]),
diff --git a/frappe/custom/doctype/custom_script/custom_script.json b/frappe/custom/doctype/client_script/client_script.json
similarity index 86%
rename from frappe/custom/doctype/custom_script/custom_script.json
rename to frappe/custom/doctype/client_script/client_script.json
index 328b247c49..57e6c68094 100644
--- a/frappe/custom/doctype/custom_script/custom_script.json
+++ b/frappe/custom/doctype/client_script/client_script.json
@@ -2,7 +2,7 @@
"actions": [],
"allow_import": 1,
"creation": "2013-01-10 16:34:01",
- "description": "Adds a client custom script to a DocType",
+ "description": "Adds a custom client script to a DocType",
"doctype": "DocType",
"document_type": "Document",
"engine": "InnoDB",
@@ -22,9 +22,7 @@
"oldfieldname": "dt",
"oldfieldtype": "Link",
"options": "DocType",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
+ "reqd": 1
},
{
"fieldname": "script",
@@ -32,35 +30,29 @@
"label": "Script",
"oldfieldname": "script",
"oldfieldtype": "Code",
- "options": "JS",
- "show_days": 1,
- "show_seconds": 1
+ "options": "JS"
},
{
"fieldname": "sample",
"fieldtype": "HTML",
"label": "Sample",
- "options": "Custom Script Help \nCustom Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started
\n\n\n// fetch local_tax_no on selection of customer \n// cur_frm.add_fetch(link_field, source_fieldname, target_fieldname); \ncur_frm.add_fetch('customer', 'local_tax_no', 'local_tax_no');\n\n// additional validation on dates \nfrappe.ui.form.on('Task', 'validate', function(frm) {\n if (frm.doc.from_date < get_today()) {\n msgprint('You can not select past date in From Date');\n validated = false;\n } \n});\n\n// make a field read-only after saving \nfrappe.ui.form.on('Task', {\n refresh: function(frm) {\n // use the __islocal value of doc, to check if the doc is saved or not\n frm.set_df_property('myfield', 'read_only', frm.doc.__islocal ? 0 : 1);\n } \n});\n\n// additional permission check\nfrappe.ui.form.on('Task', {\n validate: function(frm) {\n if(user=='user1@example.com' && frm.doc.purpose!='Material Receipt') {\n msgprint('You are only allowed Material Receipt');\n validated = false;\n }\n } \n});\n\n// calculate sales incentive\nfrappe.ui.form.on('Sales Invoice', {\n validate: function(frm) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(frm.doc.sales_team, function(i, d) {\n // calculate incentive\n var incentive_percent = 2;\n if(frm.doc.base_grand_total > 400) incentive_percent = 4;\n // actual incentive\n d.incentives = flt(frm.doc.base_grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n frm.doc.total_incentive = total_incentive;\n } \n})\n\n ",
- "show_days": 1,
- "show_seconds": 1
+ "options": "Client Script Help \nClient Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started
\n\n\n// fetch local_tax_no on selection of customer \n// cur_frm.add_fetch(link_field, source_fieldname, target_fieldname); \ncur_frm.add_fetch('customer', 'local_tax_no', 'local_tax_no');\n\n// additional validation on dates \nfrappe.ui.form.on('Task', 'validate', function(frm) {\n if (frm.doc.from_date < get_today()) {\n msgprint('You can not select past date in From Date');\n validated = false;\n } \n});\n\n// make a field read-only after saving \nfrappe.ui.form.on('Task', {\n refresh: function(frm) {\n // use the __islocal value of doc, to check if the doc is saved or not\n frm.set_df_property('myfield', 'read_only', frm.doc.__islocal ? 0 : 1);\n } \n});\n\n// additional permission check\nfrappe.ui.form.on('Task', {\n validate: function(frm) {\n if(user=='user1@example.com' && frm.doc.purpose!='Material Receipt') {\n msgprint('You are only allowed Material Receipt');\n validated = false;\n }\n } \n});\n\n// calculate sales incentive\nfrappe.ui.form.on('Sales Invoice', {\n validate: function(frm) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(frm.doc.sales_team, function(i, d) {\n // calculate incentive\n var incentive_percent = 2;\n if(frm.doc.base_grand_total > 400) incentive_percent = 4;\n // actual incentive\n d.incentives = flt(frm.doc.base_grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n frm.doc.total_incentive = total_incentive;\n } \n})\n\n "
},
{
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
- "label": "Enabled",
- "show_days": 1,
- "show_seconds": 1
+ "label": "Enabled"
}
],
"icon": "fa fa-glass",
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2020-08-24 21:56:07.719579",
+ "modified": "2021-02-04 13:57:56.509437",
"modified_by": "Administrator",
"module": "Custom",
- "name": "Custom Script",
+ "name": "Client Script",
"owner": "Administrator",
"permissions": [
{
@@ -86,6 +78,7 @@
"write": 1
}
],
+ "sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/custom/doctype/custom_script/custom_script.py b/frappe/custom/doctype/client_script/client_script.py
similarity index 84%
rename from frappe/custom/doctype/custom_script/custom_script.py
rename to frappe/custom/doctype/client_script/client_script.py
index e15819de65..e252e2a750 100644
--- a/frappe/custom/doctype/custom_script/custom_script.py
+++ b/frappe/custom/doctype/client_script/client_script.py
@@ -5,9 +5,9 @@ import frappe
from frappe.model.document import Document
-class CustomScript(Document):
+class ClientScript(Document):
def autoname(self):
- self.name = self.dt + "-Client"
+ self.name = self.dt
def on_update(self):
frappe.clear_cache(doctype=self.dt)
diff --git a/frappe/custom/doctype/custom_script/test_custom_script.py b/frappe/custom/doctype/client_script/test_client_script.py
similarity index 65%
rename from frappe/custom/doctype/custom_script/test_custom_script.py
rename to frappe/custom/doctype/client_script/test_client_script.py
index 6947e6060d..de113c1ce7 100644
--- a/frappe/custom/doctype/custom_script/test_custom_script.py
+++ b/frappe/custom/doctype/client_script/test_client_script.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
import unittest
-# test_records = frappe.get_test_records('Custom Script')
+# test_records = frappe.get_test_records('Client Script')
-class TestCustomScript(unittest.TestCase):
+class TestClientScript(unittest.TestCase):
pass
diff --git a/frappe/custom/workspace/customization/customization.json b/frappe/custom/workspace/customization/customization.json
index 3631914249..cdc3b73366 100644
--- a/frappe/custom/workspace/customization/customization.json
+++ b/frappe/custom/workspace/customization/customization.json
@@ -10,6 +10,7 @@
"hide_custom": 0,
"icon": "customization",
"idx": 0,
+ "is_default": 0,
"is_standard": 1,
"label": "Customization",
"links": [
@@ -81,8 +82,8 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
- "label": "Custom Script",
- "link_to": "Custom Script",
+ "label": "Client Script",
+ "link_to": "Client Script",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -115,7 +116,7 @@
"type": "Link"
}
],
- "modified": "2020-12-01 13:38:39.843773",
+ "modified": "2021-02-04 13:50:35.750463",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customization",
@@ -134,8 +135,14 @@
"type": "DocType"
},
{
- "label": "Custom Script",
- "link_to": "Custom Script",
+ "label": "Client Script",
+ "link_to": "Client Script",
+ "type": "DocType"
+ },
+ {
+ "doc_view": "",
+ "label": "Server Script",
+ "link_to": "Server Script",
"type": "DocType"
}
]
diff --git a/frappe/desk/doctype/kanban_board/kanban_board.py b/frappe/desk/doctype/kanban_board/kanban_board.py
index f1ad41db6c..a655e9e1da 100644
--- a/frappe/desk/doctype/kanban_board/kanban_board.py
+++ b/frappe/desk/doctype/kanban_board/kanban_board.py
@@ -17,6 +17,10 @@ class KanbanBoard(Document):
def on_update(self):
frappe.clear_cache(doctype=self.reference_doctype)
+ def before_insert(self):
+ for column in self.columns:
+ column.order = get_order_for_column(self, column.column_name)
+
def validate_column_name(self):
for column in self.columns:
if not column.column_name:
@@ -125,6 +129,53 @@ def update_order(board_name, order):
board.save()
return board, updated_cards
+@frappe.whitelist()
+def update_order_for_single_card(board_name, docname, from_colname, to_colname, old_index, new_index):
+ '''Save the order of cards in columns'''
+ board = frappe.get_doc('Kanban Board', board_name)
+ doctype = board.reference_doctype
+ fieldname = board.field_name
+ old_index = frappe.parse_json(old_index)
+ new_index = frappe.parse_json(new_index)
+
+ # save current order and index of columns to be updated
+ from_col_order, from_col_idx = get_kanban_column_order_and_index(board, from_colname)
+ to_col_order, to_col_idx = get_kanban_column_order_and_index(board, to_colname)
+
+ if from_colname == to_colname:
+ from_col_order = to_col_order
+
+ to_col_order.insert(new_index, from_col_order.pop((old_index)))
+
+ # save updated order
+ board.columns[from_col_idx].order = frappe.as_json(from_col_order)
+ board.columns[to_col_idx].order = frappe.as_json(to_col_order)
+ board.save()
+
+ # update changed value in doc
+ frappe.set_value(doctype, docname, fieldname, to_colname)
+
+ return board
+
+def get_kanban_column_order_and_index(board, colname):
+ for i, col in enumerate(board.columns):
+ if col.column_name == colname:
+ col_order = frappe.parse_json(col.order)
+ col_idx = i
+
+ return col_order, col_idx
+
+@frappe.whitelist()
+def add_card(board_name, docname, colname):
+ board = frappe.get_doc('Kanban Board', board_name)
+
+ col_order, col_idx = get_kanban_column_order_and_index(board, colname)
+ col_order.insert(0, docname)
+
+ board.columns[col_idx].order = frappe.as_json(col_order)
+
+ board.save()
+ return board
@frappe.whitelist()
def quick_kanban_board(doctype, board_name, field_name, project=None):
@@ -133,6 +184,13 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
doc = frappe.new_doc('Kanban Board')
meta = frappe.get_meta(doctype)
+ doc.kanban_board_name = board_name
+ doc.reference_doctype = doctype
+ doc.field_name = field_name
+
+ if project:
+ doc.filters = '[["Task","project","=","{0}"]]'.format(project)
+
options = ''
for field in meta.fields:
if field.fieldname == field_name:
@@ -149,12 +207,6 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
column_name=column
))
- doc.kanban_board_name = board_name
- doc.reference_doctype = doctype
- doc.field_name = field_name
-
- if project:
- doc.filters = '[["Task","project","=","{0}"]]'.format(project)
if doctype in ['Note', 'ToDo']:
doc.private = 1
@@ -162,6 +214,12 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
doc.save()
return doc
+def get_order_for_column(board, colname):
+ filters = [[board.reference_doctype, board.field_name, '=', colname]]
+ if board.filters:
+ filters.append(frappe.parse_json(board.filters)[0])
+
+ return frappe.as_json(frappe.get_list(board.reference_doctype, filters=filters, pluck='name'))
@frappe.whitelist()
def update_column_order(board_name, order):
diff --git a/frappe/desk/form/meta.py b/frappe/desk/form/meta.py
index d5428b1da2..c63da93a33 100644
--- a/frappe/desk/form/meta.py
+++ b/frappe/desk/form/meta.py
@@ -130,7 +130,7 @@ class FormMeta(Meta):
def add_custom_script(self):
"""embed all require files"""
# custom script
- custom = frappe.db.get_value("Custom Script", {"dt": self.name, "enabled": 1}, "script") or ""
+ custom = frappe.db.get_value("Client Script", {"dt": self.name, "enabled": 1}, "script") or ""
self.set("__custom_js", custom)
diff --git a/frappe/desk/form/utils.py b/frappe/desk/form/utils.py
index 4c3bab2e23..395d2b9571 100644
--- a/frappe/desk/form/utils.py
+++ b/frappe/desk/form/utils.py
@@ -47,7 +47,7 @@ def validate_link():
except Exception as e:
error_message = str(e).split("Unknown column '")
fieldname = None if len(error_message)<=1 else error_message[1].split("'")[0]
- frappe.msgprint(_("Wrong fieldname {0} in add_fetch configuration of custom script").format(fieldname))
+ frappe.msgprint(_("Wrong fieldname {0} in add_fetch configuration of custom client script").format(fieldname))
frappe.errprint(frappe.get_traceback())
if fetch_value:
diff --git a/frappe/desk/page/leaderboard/leaderboard.js b/frappe/desk/page/leaderboard/leaderboard.js
index 825e1d959b..b3fccf84f9 100644
--- a/frappe/desk/page/leaderboard/leaderboard.js
+++ b/frappe/desk/page/leaderboard/leaderboard.js
@@ -141,7 +141,7 @@ class Leaderboard {
}
create_date_range_field() {
- let timespan_field = $(this.parent).find(`.frappe-control[data-original-title='Timespan']`);
+ let timespan_field = $(this.parent).find(`.frappe-control[data-original-title=${__('Timespan')}]`);
this.date_range_field = $(`
`).insertAfter(timespan_field).hide();
let date_field = frappe.ui.form.make_control({
diff --git a/frappe/desk/search.py b/frappe/desk/search.py
index f4e6543844..6faa827dde 100644
--- a/frappe/desk/search.py
+++ b/frappe/desk/search.py
@@ -80,13 +80,15 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
is_whitelisted(frappe.get_attr(query))
frappe.response["values"] = frappe.call(query, doctype, txt,
searchfield, start, page_length, filters, as_dict=as_dict)
- except Exception as e:
+ except frappe.exceptions.PermissionError as e:
if frappe.local.conf.developer_mode:
raise e
else:
frappe.respond_as_web_page(title='Invalid Method', html='Method not found',
indicator_color='red', http_status_code=404)
return
+ except Exception as e:
+ raise e
elif not query and doctype in standard_queries:
# from standard queries
search_widget(doctype, txt, standard_queries[doctype][0],
diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py
index 9b0b5e41d7..3fcabb9495 100644
--- a/frappe/email/test_email_body.py
+++ b/frappe/email/test_email_body.py
@@ -17,7 +17,7 @@ class TestEmailBody(unittest.TestCase):
Hey John Doe!
This is embedded image you asked for
-
+
'''
email_text = '''
@@ -25,7 +25,7 @@ Hey John Doe!
This is the text version of this email
'''
- img_path = os.path.abspath('assets/frappe/images/favicon.png')
+ img_path = os.path.abspath('assets/frappe/images/frappe-favicon.svg')
with open(img_path, 'rb') as f:
img_content = f.read()
img_base64 = base64.b64encode(img_content).decode()
@@ -77,12 +77,11 @@ This is the text version of this email
def test_image(self):
img_signature = '''
-Content-Type: image/png
+Content-Type: image/svg+xml
MIME-Version: 1.0
Content-Transfer-Encoding: base64
-Content-Disposition: inline; filename="favicon.png"
+Content-Disposition: inline; filename="frappe-favicon.svg"
'''
-
self.assertTrue(img_signature in self.email_string)
self.assertTrue(self.img_base64 in self.email_string)
@@ -117,7 +116,7 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
def test_replace_filename_with_cid(self):
original_message = '''
'''
diff --git a/frappe/integrations/doctype/social_login_key/social_login_key.py b/frappe/integrations/doctype/social_login_key/social_login_key.py
index 1092c3240e..d84e6ef11d 100644
--- a/frappe/integrations/doctype/social_login_key/social_login_key.py
+++ b/frappe/integrations/doctype/social_login_key/social_login_key.py
@@ -124,7 +124,7 @@ class SocialLoginKey(Document):
"provider_name": "Frappe",
"enable_social_login": 1,
"custom_base_url": 1,
- "icon":"/assets/frappe/images/favicon.png",
+ "icon":"/assets/frappe/images/frappe-favicon.svg",
"redirect_url": "/api/method/frappe.www.login.login_via_frappe",
"api_endpoint": "/api/method/frappe.integrations.oauth2.openid_profile",
"api_endpoint_args":None,
diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
index c39a73ccd7..af06696621 100644
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -118,7 +118,7 @@ core_doctypes_list = (
'Customize Form Field',
'Property Setter',
'Custom Field',
- 'Custom Script'
+ 'Client Script'
)
log_types = (
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 7a90ecaca5..295585665f 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -69,13 +69,13 @@ def get_controller(doctype):
if frappe.local.dev_server:
return _get_controller()
-
+
site_controllers = frappe.controllers.setdefault(frappe.local.site, {})
if doctype not in site_controllers:
site_controllers[doctype] = _get_controller()
-
+
return site_controllers[doctype]
-
+
class BaseDocument(object):
ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")
@@ -94,6 +94,14 @@ class BaseDocument(object):
return self._meta
def update(self, d):
+ """ Update multiple fields of a doctype using a dictionary of key-value pairs.
+
+ Example:
+ doc.update({
+ "user": "admin",
+ "balance": 42000
+ })
+ """
if "doctype" in d:
self.set("doctype", d.get("doctype"))
@@ -159,6 +167,15 @@ class BaseDocument(object):
del self.__dict__[key]
def append(self, key, value=None):
+ """ Append an item to a child table.
+
+ Example:
+ doc.append("childtable", {
+ "child_table_field": "value",
+ "child_table_int_field": 0,
+ ...
+ })
+ """
if value==None:
value={}
if isinstance(value, (dict, BaseDocument)):
diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py
index 7b29692ad1..d0e0a6fb1a 100644
--- a/frappe/model/delete_doc.py
+++ b/frappe/model/delete_doc.py
@@ -68,7 +68,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
check_permission_and_not_submitted(doc)
frappe.db.sql("delete from `tabCustom Field` where dt = %s", name)
- frappe.db.sql("delete from `tabCustom Script` where dt = %s", name)
+ frappe.db.sql("delete from `tabClient Script` where dt = %s", name)
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", name)
frappe.db.sql("delete from `tabReport` where ref_doctype=%s", name)
frappe.db.sql("delete from `tabCustom DocPerm` where parent=%s", name)
diff --git a/frappe/model/document.py b/frappe/model/document.py
index 1cd981ead8..3ecc335cdd 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -1015,6 +1015,8 @@ class Document(BaseDocument):
def notify_update(self):
"""Publish realtime that the current document is modified"""
+ if frappe.flags.in_patch: return
+
frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name},
doctype=self.doctype, docname=self.name, after_commit=True)
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 0f37946398..d43690eac2 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -35,6 +35,7 @@ frappe.patches.v11_0.change_email_signature_fieldtype
execute:frappe.reload_doc('core', 'doctype', 'activity_log')
execute:frappe.reload_doc('core', 'doctype', 'deleted_document')
execute:frappe.reload_doc('core', 'doctype', 'domain_settings')
+frappe.patches.v13_0.rename_custom_client_script
frappe.patches.v8_0.rename_page_role_to_has_role #2017-03-16
frappe.patches.v7_2.setup_custom_perms #2017-01-19
frappe.patches.v8_0.set_user_permission_for_page_and_report #2017-03-20
@@ -329,3 +330,4 @@ frappe.core.doctype.page.patches.drop_unused_pages
execute:frappe.get_doc('Role', 'Guest').save() # remove desk access
frappe.patches.v13_0.rename_desk_page_to_workspace # 02.02.2021
frappe.patches.v13_0.delete_package_publish_tool
+frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings
diff --git a/frappe/patches/v12_0/reset_home_settings.py b/frappe/patches/v12_0/reset_home_settings.py
index db16c31f15..e4b9de6cb2 100644
--- a/frappe/patches/v12_0/reset_home_settings.py
+++ b/frappe/patches/v12_0/reset_home_settings.py
@@ -1,6 +1,7 @@
import frappe
def execute():
+ frappe.reload_doc('core', 'doctype', 'user')
frappe.db.sql('''
UPDATE `tabUser`
SET `home_settings` = ''
diff --git a/frappe/patches/v13_0/enable_custom_script.py b/frappe/patches/v13_0/enable_custom_script.py
index 92284e6dcc..edc242e700 100644
--- a/frappe/patches/v13_0/enable_custom_script.py
+++ b/frappe/patches/v13_0/enable_custom_script.py
@@ -5,9 +5,8 @@ from __future__ import unicode_literals
import frappe
def execute():
- """Enable all the existing custom script"""
- frappe.reload_doc("Custom", "doctype", "Custom Script")
+ """Enable all the existing Client script"""
frappe.db.sql("""
- UPDATE `tabCustom Script` SET enabled=1
+ UPDATE `tabClient Script` SET enabled=1
""")
\ No newline at end of file
diff --git a/frappe/patches/v13_0/rename_custom_client_script.py b/frappe/patches/v13_0/rename_custom_client_script.py
new file mode 100644
index 0000000000..718f1f6a46
--- /dev/null
+++ b/frappe/patches/v13_0/rename_custom_client_script.py
@@ -0,0 +1,9 @@
+import frappe
+
+
+def execute():
+ if frappe.db.exists("DocType", "Client Script"):
+ return
+
+ frappe.rename_doc("DocType", "Custom Script", "Client Script")
+ frappe.reload_doctype("Client Script", force=True)
diff --git a/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py
new file mode 100644
index 0000000000..fcf8afc826
--- /dev/null
+++ b/frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+
+def execute():
+ if frappe.db.table_exists('List View Setting'):
+ existing_list_view_settings = frappe.get_all('List View Settings', as_list=True)
+ for list_view_setting in frappe.get_all('List View Setting', fields = ['disable_count', 'disable_sidebar_stats', 'disable_auto_refresh', 'name']):
+ name = list_view_setting.pop('name')
+ if name not in [x[0] for x in existing_list_view_settings]:
+ list_view_setting['doctype'] = 'List View Settings'
+ list_view_settings = frappe.get_doc(list_view_setting)
+ # setting name here is necessary because autoname is set as prompt
+ list_view_settings.name = name
+ list_view_settings.insert()
+ frappe.delete_doc("DocType", "List View Setting", force=True)
+ frappe.db.commit()
diff --git a/frappe/public/build.json b/frappe/public/build.json
index f2a4d65582..51a2f55a37 100755
--- a/frappe/public/build.json
+++ b/frappe/public/build.json
@@ -27,8 +27,6 @@
"public/js/frappe/microtemplate.js",
"public/js/frappe/query_string.js",
- "public/js/frappe/ui/dropzone.js",
- "public/js/frappe/ui/upload.html",
"public/js/frappe/upload.js",
"public/js/frappe/model/meta.js",
@@ -36,7 +34,6 @@
"public/js/frappe/model/perm.js",
"website/js/website.js",
- "public/js/frappe/utils/rating_icons.html",
"public/js/frappe/socketio_client.js"
],
"js/bootstrap-4-web.min.js": "website/js/bootstrap-4.js",
@@ -62,7 +59,6 @@
],
"js/dialog.min.js": [
"public/js/frappe/dom.js",
-
"public/js/frappe/form/formatters.js",
"public/js/frappe/form/layout.js",
"public/js/frappe/ui/field_group.js",
@@ -79,8 +75,6 @@
"public/css/octicons/octicons.css",
"public/less/desk.less",
"public/less/module.less",
- "public/less/link_preview.less",
- "public/less/form.less",
"public/less/mobile.less",
"public/less/controls.less",
"public/less/chat.less",
@@ -99,22 +93,22 @@
"public/scss/print.scss"
],
"concat:js/libs.min.js": [
- "public/js/lib/awesomplete/awesomplete.min.js",
"public/js/lib/Sortable.min.js",
"public/js/lib/jquery/jquery.hotkeys.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/vue/dist/vue.min.js",
"node_modules/moment/min/moment-with-locales.min.js",
"node_modules/moment-timezone/builds/moment-timezone-with-data.min.js",
- "public/js/lib/socket.io.min.js",
+ "node_modules/socket.io-client/dist/socket.io.slim.js",
+ "node_modules/localforage/dist/localforage.min.js",
"public/js/lib/jSignature.min.js",
- "public/js/frappe/translate.js",
"public/js/lib/leaflet/leaflet.js",
"public/js/lib/leaflet/leaflet.draw.js",
"public/js/lib/leaflet/L.Control.Locate.js",
"public/js/lib/leaflet/easy-button.js"
],
"js/desk.min.js": [
+ "public/js/frappe/translate.js",
"public/js/frappe/class.js",
"public/js/frappe/polyfill.js",
"public/js/frappe/provide.js",
@@ -152,7 +146,6 @@
"public/js/frappe/ui/dialog.js",
"public/js/frappe/ui/capture.js",
"public/js/frappe/ui/app_icon.js",
- "public/js/frappe/ui/dropzone.js",
"public/js/frappe/ui/theme_switcher.js",
"public/js/frappe/model/model.js",
@@ -179,7 +172,6 @@
"public/js/frappe/utils/preview_email.js",
"public/js/frappe/utils/file_manager.js",
- "public/js/frappe/ui/upload.html",
"public/js/frappe/upload.js",
"public/js/frappe/ui/tree.js",
@@ -209,11 +201,11 @@
"public/js/frappe/ui/sort_selector.js",
"public/js/frappe/change_log.html",
+ "public/js/frappe/ui/workspace_loading_skeleton.html",
"public/js/frappe/desk.js",
"public/js/frappe/query_string.js",
"public/js/frappe/ui/comment.js",
- "public/js/frappe/utils/rating_icons.html",
"public/js/frappe/chat.js",
"public/js/frappe/utils/energy_point_utils.js",
@@ -231,7 +223,6 @@
"public/js/frappe/form/form.js",
"public/js/frappe/meta_tag.js"
],
- "css/list.min.css": "public/less/gantt.less",
"js/list.min.js": [
"public/js/frappe/ui/listing.html",
@@ -298,11 +289,12 @@
"css/web_form.css": [
"website/css/web_form.css",
"public/css/octicons/octicons.css",
- "public/less/controls.less",
+ "public/scss/controls.scss",
"node_modules/frappe-datatable/dist/frappe-datatable.css"
],
"css/email.css": "public/scss/email.scss",
"js/barcode_scanner.min.js": "public/js/frappe/barcode_scanner/quagga.js",
"js/user_profile_controller.min.js": "desk/page/user_profile/user_profile_controller.js",
- "css/login.css": "public/scss/login.scss"
+ "css/login.css": "public/scss/login.scss",
+ "js/data_import_tools.min.js": "public/js/frappe/data_import/index.js"
}
diff --git a/frappe/public/css/common.css b/frappe/public/css/common.css
deleted file mode 100644
index b08be904a6..0000000000
--- a/frappe/public/css/common.css
+++ /dev/null
@@ -1,253 +0,0 @@
-/* the element that this class is applied to, should have a max width for this to work*/
-body {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-}
-a {
- cursor: pointer;
-}
-a,
-a:hover,
-a:active,
-a:focus,
-.btn,
-.btn:hover,
-.btn:active,
-.btn:focus {
- outline: 0;
-}
-img {
- max-width: 100%;
-}
-p {
- margin: 10px 0px;
-}
-.text-color {
- color: #36414C !important;
-}
-.text-muted {
- color: #8D99A6 !important;
-}
-.text-extra-muted {
- color: #d1d8dd !important;
-}
-a,
-.badge {
- -webkit-transition: 0.2s;
- -o-transition: 0.2s;
- transition: 0.2s;
-}
-.btn {
- -webkit-transition: background-color 0.2s;
- -o-transition: background-color 0.2s;
- transition: background-color 0.2s;
-}
-a.disabled,
-a.disabled:hover {
- color: #888;
- cursor: default;
- text-decoration: none;
-}
-a.grey,
-.sidebar-section a,
-.control-value a,
-.data-row a {
- text-decoration: none;
-}
-a.grey:hover,
-.sidebar-section a:hover,
-.control-value a:hover,
-.data-row a:hover,
-a.grey:focus,
-.sidebar-section a:focus,
-.control-value a:focus,
-.data-row a:focus {
- text-decoration: underline;
-}
-a.text-muted,
-a.text-extra-muted {
- text-decoration: none;
-}
-.underline {
- text-decoration: underline;
-}
-.inline-block {
- display: inline-block;
-}
-.bold,
-.strong {
- font-weight: bold;
-}
-kbd {
- color: inherit;
- background-color: #F0F4F7;
-}
-.btn [class^="fa fa-"],
-.nav [class^="fa fa-"],
-.btn [class*="fa fa-"],
-.nav [class*="fa fa-"] {
- display: inline-block;
-}
-.dropdown-menu > li > a {
- padding: 14px;
- white-space: normal;
-}
-.dropdown-menu {
- min-width: 200px;
- padding: 0px;
- font-size: 12px;
- max-height: 400px;
- overflow: auto;
- border-radius: 0px 0px 4px 4px;
-}
-.dropdown-menu .dropdown-header {
- padding: 3px 14px;
- font-size: 11px;
- font-weight: 200;
- padding-top: 12px;
-}
-.dropdown-menu .divider {
- margin: 0px;
-}
-a.badge-hover:hover .badge,
-a.badge-hover:focus .badge,
-a.badge-hover:active .badge {
- background-color: #D8DFE5;
-}
-.msgprint {
- word-wrap: break-word;
-}
-.msgprint pre {
- text-align: left;
-}
-.centered {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- -webkit-transform: translate(-50%, -50%);
-}
-.border-top {
- border-top: 1px solid #d1d8dd;
-}
-.border-bottom {
- border-bottom: 1px solid #d1d8dd;
-}
-.border-left {
- border-left: 1px solid #d1d8dd;
-}
-.border-right {
- border-right: 1px solid #d1d8dd;
-}
-.border {
- border: 1px solid #d1d8dd;
-}
-.close-inline {
- font-size: 120%;
- font-weight: bold;
- line-height: 1;
- cursor: pointer;
- color: inherit;
- display: inline-block;
-}
-.close-inline:hover,
-.close-inline:focus {
- text-decoration: none;
-}
-.middle {
- vertical-align: middle;
-}
-.full-center-container {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-}
-.full-center {
- position: absolute;
- top: 50%;
- left: 50%;
- width: 100%;
- transform: translate(-50%, -50%);
- -webkit-transform: translate(-50%, -50%);
-}
-#freeze {
- z-index: 1020;
- bottom: 0px;
- opacity: 0;
- background-color: #fafbfc;
-}
-#freeze .freeze-message-container {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-}
-#freeze .freeze-message {
- position: absolute;
- top: 50%;
- left: 50%;
- width: 100%;
- transform: translate(-50%, -50%);
- -webkit-transform: translate(-50%, -50%);
- text-align: center;
- color: #36414C !important;
-}
-#freeze.dark {
- background-color: #334143;
-}
-#freeze.in {
- opacity: 0.5;
-}
-a.no-decoration {
- text-decoration: none;
- color: inherit;
-}
-a.no-decoration:hover,
-a.no-decoration:focus,
-a.no-decoration:active {
- text-decoration: none;
- color: inherit;
-}
-.padding {
- padding: 15px;
-}
-.margin {
- margin: 15px;
-}
-.margin-top {
- margin-top: 15px;
-}
-.margin-bottom {
- margin-bottom: 15px;
-}
-.margin-left {
- margin-left: 15px;
-}
-.margin-right {
- margin-right: 15px;
-}
-@media (max-width: 767px) {
- .text-center-xs {
- text-align: center;
- }
-}
-.grayscale {
- -webkit-filter: grayscale(100%);
- filter: grayscale(100%);
-}
-.uppercase {
- padding-bottom: 4px;
- text-transform: uppercase;
- font-size: 12px;
- letter-spacing: 0.4px;
- color: #8D99A6;
-}
-.ellipsis {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 100%;
- vertical-align: middle;
-}
diff --git a/frappe/public/css/docs.css b/frappe/public/css/docs.css
deleted file mode 100644
index 3c57d0bf45..0000000000
--- a/frappe/public/css/docs.css
+++ /dev/null
@@ -1,604 +0,0 @@
-/* the element that this class is applied to, should have a max width for this to work*/
-.navbar .dropdown-toggle {
- padding-top: 8px;
- padding-bottom: 8px;
-}
-.navbar-fixed-top {
- left: 0px;
- right: 0px;
-}
-.navbar a {
- font-size: 12px;
- font-weight: bold;
-}
-.navbar-icon-home {
- vertical-align: middle;
-}
-.navbar-icon-home:hover,
-.navbar-icon-home:focus,
-.navbar-icon-home:active,
-.navbar-icon-home-hover {
- opacity: 1;
- Filter: alpha(opacity=100);
- /* For IE8 and earlier */
-}
-.navbar-user-image {
- width: 24px;
- height: 24px;
- margin-right: 3px;
- border-radius: 4px;
-}
-@media (max-width: 991px) {
- .navbar-desk {
- width: 35% !important;
- }
- .navbar-desk ~ ul > li {
- float: left;
- }
- .navbar-desk ~ ul > li a {
- padding-left: 10px !important;
- padding-right: 10px !important;
- }
- .navbar-desk ~ ul > li a .avatar {
- margin-right: 0;
- }
- .dropdown-navbar-new-comments > a {
- padding: 8px 0 !important;
- margin-left: 0 !important;
- }
-}
-@media (max-width: 767px) {
- .navbar-desk {
- width: 50% !important;
- }
-}
-#search-modal .modal-dialog,
-#search-modal .modal-content {
- background: transparent;
-}
-#search-modal .modal-header {
- background: #fff;
- width: 100%;
-}
-#search-modal .modal-header form {
- vertical-align: middle;
-}
-#search-modal .modal-header button {
- line-height: 0;
- position: absolute;
- right: 0;
- top: 0;
- z-index: 9;
- padding: 9px;
-}
-.dropdown-navbar-new-comments > a {
- border: 0;
-}
-.dropdown-navbar-new-comments .dropdown-menu {
- margin-top: 0;
-}
-.dropdown-help .dropdown-menu {
- width: 350px !important;
- max-height: 440px;
- overflow: auto;
-}
-.dropdown-help .dropdown-menu .input-group {
- width: 100%;
- background-color: #f5f7fa;
- padding: 8px 12px;
-}
-.dropdown-help .dropdown-menu input {
- width: 100%;
- padding: 5px 10px;
- outline: none;
- border-radius: 3px 0 0 3px;
- border: 1px solid #d1d8dd;
- opacity: 0.9;
- line-height: 1.5;
-}
-.dropdown-help .dropdown-menu button {
- border: 1px solid #d1d8dd;
-}
-@media (max-width: 767px) {
- .dropdown-help .dropdown-menu {
- position: fixed !important;
- top: 40px;
- width: 100% !important;
- }
-}
-@media (max-width: 767px) {
- .dropdown-mobile.open .dropdown-menu {
- position: absolute;
- border-top: 1px solid rgba(0, 0, 0, 0.14902);
- box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
- background-color: #fff;
- right: 0;
- left: auto;
- }
- .dropdown-mobile.open .dropdown-menu > li > a {
- padding: 12px;
- }
- .dropdown-help {
- display: none !important;
- }
-}
-.navbar-new-comments {
- display: inline-block;
- min-width: 24px;
- height: 24px;
- border-radius: 4px;
- color: #fff;
- text-align: center;
- padding: 2px 5px;
- background-color: #b8c2cc;
-}
-.navbar-new-comments-true {
- background-color: #ff5858;
-}
-.navbar-form .awesomplete {
- margin-left: -15px;
- width: 300px;
-}
-@media (max-width: 1199px) {
- .navbar-form .awesomplete {
- width: 280px;
- }
-}
-@media (max-width: 991px) {
- .navbar-form .awesomplete {
- width: 250px;
- }
-}
-#navbar-search {
- width: 100%;
- background-color: rgba(255, 255, 255, 0.9);
-}
-.navbar .navbar-search-icon {
- color: #6C7680;
- font-size: inherit;
- position: relative;
- right: 24px;
- top: 1px;
-}
-.navbar .badge {
- font-weight: normal;
-}
-#navbar-search-results {
- left: auto;
- right: inherit;
- margin-top: -1px;
- max-height: 300px;
- overflow-y: auto;
- overflow-x: hidden;
-}
-.navbar-center {
- float: left;
- color: #6C7680;
-}
-#navbar-breadcrumbs > li > a:before {
- font-family: FontAwesome;
- font-weight: normal;
- font-style: normal;
- text-decoration: inherit;
- -webkit-font-smoothing: antialiased;
- *margin-right: 0.3em;
- display: inline-block;
- speak: none;
- font-size: 24px;
- transition: 0.2s;
- position: relative;
- top: 3px;
- content: "\f105";
- margin-right: 10px;
- color: #C0C9D2;
-}
-#navbar-breadcrumbs > li > a:hover:before,
-#navbar-breadcrumbs > li > a:focus:before,
-#navbar-breadcrumbs > li > a:active:before {
- color: #36414C;
-}
-#navbar-breadcrumbs > li > a {
- padding: 6px 15px 10px 0px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- max-width: 170px;
-}
-@media (min-width: 991px) and (max-width: 1199px) {
- #navbar-breadcrumbs > li > a {
- max-width: 120px;
- }
-}
-.toolbar-user-fullname {
- max-width: 150px;
- display: inline-block;
-}
-.navbar-brand > img {
- display: inline-block;
-}
-.toggle-sidebar {
- margin-right: 10px;
-}
-.navbar-default .navbar-nav > li > a,
-.navbar-default .navbar-brand {
- color: #8D99A6;
-}
-body {
- font-size: 16px;
- line-height: 1.65em;
- color: #454e57;
- -webkit-font-smoothing: antialiased;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
-}
-.container {
- max-width: 870px;
-}
-img {
- max-width: 100%;
-}
-.splash {
- border-bottom: 1px solid #d1d8dd;
-}
-.splash .jumbotron {
- background-color: transparent;
- padding: 40px 0 60px 0;
- text-align: center;
-}
-.splash .jumbotron h1 {
- font-size: 48px;
- font-weight: 400;
- opacity: 0.9;
- color: #2E3338;
-}
-.splash .jumbotron p {
- font-size: 24px;
- font-color: #8D99A6 !important;
- letter-spacing: 0px;
- opacity: 0.7;
- margin-bottom: 90px;
- font-weight: 300;
- line-height: 1.4em;
-}
-.splash .section {
- padding: 30px 0 0 0;
-}
-.page-container {
- padding-top: 38px;
- margin: 0 auto;
- max-width: 870px;
-}
-.page-container .webpage-content ol > li,
-.page-container .webpage-content ul > li {
- margin: 13px auto;
-}
-.page-container .webpage-content ol > li li,
-.page-container .webpage-content ul > li li {
- margin: 4px auto;
-}
-.page-container .webpage-content ol li ol {
- list-style-type: disc;
-}
-.page-container .webpage-content ul,
-.page-container .webpage-content ol {
- margin-bottom: 32px;
-}
-@media (min-width: 768px) {
- .page-container .page-content {
- width: 83%;
- margin: 0 auto;
- }
-}
-#page-index {
- padding-top: 0;
- width: 100%;
- margin: 0;
-}
-#page-index .page-content {
- width: 100%;
- margin: 0;
-}
-body[data-path="index"] .navbar .toggle-sidebar i {
- color: #fff;
-}
-code {
- color: #e66a12;
- background: #fff6df;
-}
-pre {
- background: #fafbfc;
- border: 1px solid #e1e9f0;
- border-radius: 2px;
-}
-.hljs {
- background: transparent;
- border: none;
- padding: 1.2em 1.5em 1.5em;
- color: #454e57;
-}
-.hljs-keyword,
-.hljs-tag,
-.css .hljs-class,
-.css .hljs-id,
-.lisp .hljs-title,
-.nginx .hljs-title,
-.hljs-request,
-.hljs-status,
-.clojure .hljs-attribute {
- color: #e66a12;
-}
-.diff .hljs-deletion,
-.hljs-string,
-.hljs-tag .hljs-value,
-.hljs-preprocessor,
-.hljs-pragma,
-.hljs-built_in,
-.hljs-javadoc,
-.smalltalk .hljs-class,
-.smalltalk .hljs-localvars,
-.smalltalk .hljs-array,
-.css .hljs-rules .hljs-value,
-.hljs-attr_selector,
-.hljs-pseudo,
-.apache .hljs-cbracket,
-.tex .hljs-formula,
-.coffeescript .hljs-attribute {
- color: #dd4a68;
-}
-.hljs-number,
-.hljs-date,
-.hljs-regexp,
-.hljs-literal,
-.hljs-hexcolor,
-.smalltalk .hljs-symbol,
-.smalltalk .hljs-char,
-.go .hljs-constant,
-.hljs-change,
-.lasso .hljs-variable,
-.makefile .hljs-variable,
-.asciidoc .hljs-bullet,
-.markdown .hljs-bullet,
-.asciidoc .hljs-link_url,
-.markdown .hljs-link_url {
- color: #7575ff;
-}
-.hljs-shebang,
-.diff .hljs-addition,
-.hljs-comment,
-.hljs-annotation,
-.hljs-template_comment,
-.hljs-pi,
-.hljs-doctype {
- color: #6a906a;
-}
-.dos .hljs-keyword,
-.hljs-decorator,
-.hljs-title,
-.hljs-type,
-.diff .hljs-header,
-.ruby .hljs-class .hljs-parent,
-.apache .hljs-tag,
-.nginx .hljs-built_in,
-.tex .hljs-command,
-.hljs-prompt {
- color: #4f4fa4;
-}
-.navbar {
- background-color: #36414C !important;
- margin-left: auto;
- margin-right: auto;
-}
-.navbar .container {
- max-width: 870px;
-}
-.navbar .brand-logo {
- width: 30px;
- margin-top: -4px;
- margin-right: 7px;
-}
-.navbar a {
- font-size: 16px;
- font-weight: normal;
- color: #fff !important;
-}
-.navbar a.navbar-brand {
- font-weight: bold;
-}
-.navbar a.toggle-sidebar {
- margin-top: 8px;
-}
-.sidebar a {
- font-size: 14px;
- padding-top: 14px !important;
- padding-bottom: 14px !important;
-}
-.breadcrumb {
- line-height: 1em;
- color: #8D99A6;
- background-color: transparent;
- margin-bottom: 32px;
- padding: 0px;
- padding-left: 20px;
- background: url('/assets/img/up.png') 0% 30% no-repeat;
-}
-.breadcrumb .icon {
- display: none;
-}
-.breadcrumb a,
-.breadcrumb a:hover,
-.breadcrumb a:focus,
-.breadcrumb a:visited {
- color: #7575ff;
- font-size: 16px;
-}
-.hero-and-content a,
-.hero-and-content a:hover,
-.hero-and-content a:focus,
-.hero-and-content a:visited {
- color: #5E64FF;
-}
-.hero-and-content a.btn {
- color: inherit;
-}
-a.btn-primary {
- color: #7575ff;
-}
-a.btn-primary:hover,
-a.btn-primary:focus,
-a.btn-primary:visited {
- color: #7575ff;
-}
-.btn-next-wrapper {
- margin-top: 32px;
- text-align: right;
-}
-h2 {
- margin-top: 48px;
- font-size: 24px;
-}
-h3,
-h4 {
- margin-top: 48px;
-}
-p {
- margin-bottom: 16px;
-}
-.hero-and-content > p {
- max-width: 723px;
- margin: 0 auto;
-}
-.navbar {
- background-color: transparent;
- border: none;
- padding: 15px 0px;
- border-radius: 0px;
- border-bottom: 1px solid #d1d8dd;
-}
-.section {
- padding: 64px 0 0 0;
-}
-.dev-header {
- margin-bottom: 30px;
-}
-.docs-footer {
- padding: 30px 0px 60px 0px;
- border-top: 1px solid #d1d8dd;
- max-width: 870px;
- margin: 0 auto;
- margin-top: 80px;
- font-size: 14px;
-}
-.docs-footer h3 {
- margin-top: 24px;
- font-size: 16px;
-}
-.docs-footer img.frappe-bird {
- width: 40px;
- height: 40px;
- background: #fff;
- margin-bottom: 10px;
- padding: 5px;
-}
-.docs-footer a {
- color: #8D99A6;
-}
-.docs-footer li {
- display: inline-block;
- margin: 0 10px;
-}
-.docs-footer .built-with-frappe {
- margin-top: -50px;
-}
-.browser-image {
- min-height: 200px;
- border: 1px solid #d1d8dd;
- border-bottom: 0px;
-}
-.fake-browser-frame {
- position: relative;
- margin: 24px auto 0px;
- box-shadow: 0px -6px 100px 1px rgba(0, 0, 0, 0.1), 0px -6px 50px 1px rgba(0, 0, 0, 0.4);
-}
-.fake-browser-frame::before {
- content: "";
- height: 24px;
- position: absolute;
- top: -24px;
- left: 0px;
- right: 0px;
- border: 1px solid #d1d8dd;
- background: #f5f7fa;
- border-bottom: none;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
-}
-.fake-browser-frame::after {
- content: '\f111 \00a0\00a0 \f111 \00a0\00a0 \f111';
- position: absolute;
- color: #d1d8dd;
- top: -15px;
- left: 8px;
- /* octicon */
- font: normal normal;
- font-size: 8px;
- font-family: 'FontAwesome';
- line-height: 1;
- display: inline-block;
- text-decoration: none;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.fake-iphone-frame {
- position: relative;
- padding: 40px 8px;
- border: 1px solid #d1d8dd;
- border-radius: 15px;
-}
-.fake-ipad-frame {
- position: relative;
- padding: 8px 40px;
- border: 1px solid #d1d8dd;
- border-radius: 15px;
-}
-hr {
- margin: 48px 0px 30px;
-}
-.edit {
- color: #8d99a6;
-}
-a.edit,
-a.edit:hover,
-a.edit:focus,
-a.edit:visited,
-.edit-container .icon {
- color: #8d99a6;
-}
-.btn-next {
- margin-top: 30px;
- margin-bottom: 0px;
-}
-.btn-next:after {
- content: " \2192";
-}
-#current td {
- font-weight: bold;
-}
-#current td code {
- font-weight: normal;
- background: transparent;
- font-family: "Helvetica Neue", Helvetica, Arial, "Open Sans", sans-serif;
- color: #454e57;
- font-size: 16px;
-}
-.hero-and-content [data-html-block="hero"] {
- overflow-y: hidden;
-}
-.page-content-wrapper > .row .col-sm-8 {
- width: 100%;
-}
-.page-content-wrapper > .row .col-sm-4 {
- display: none;
-}
diff --git a/frappe/public/css/fonts/inter/inter.css b/frappe/public/css/fonts/inter/inter.css
index 8fba7cf2cf..e7c92eed4e 100644
--- a/frappe/public/css/fonts/inter/inter.css
+++ b/frappe/public/css/fonts/inter/inter.css
@@ -1,5 +1,6 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 100;
src: url("/assets/frappe/css/fonts/inter/inter_thin.woff2") format("woff2"),
@@ -7,6 +8,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 100;
src: url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff2") format("woff2"),
@@ -15,6 +17,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralight.woff2") format("woff2"),
@@ -22,6 +25,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff2") format("woff2"),
@@ -30,6 +34,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_light.woff2") format("woff2"),
@@ -37,6 +42,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff2") format("woff2"),
@@ -45,6 +51,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_regular.woff2") format("woff2"),
@@ -52,6 +59,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_italic.woff2") format("woff2"),
@@ -60,6 +68,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_medium.woff2") format("woff2"),
@@ -67,6 +76,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff2") format("woff2"),
@@ -75,6 +85,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibold.woff2") format("woff2"),
@@ -82,6 +93,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff2") format("woff2"),
@@ -90,6 +102,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bold.woff2") format("woff2"),
@@ -97,6 +110,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff2") format("woff2"),
@@ -105,6 +119,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabold.woff2") format("woff2"),
@@ -112,6 +127,7 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff2") format("woff2"),
@@ -120,6 +136,7 @@
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: normal;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_black.woff2") format("woff2"),
@@ -127,8 +144,9 @@
}
@font-face {
font-family: 'Inter';
+ font-display: swap;
font-style: italic;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff");
-}
\ No newline at end of file
+}
diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css
deleted file mode 100644
index baad12b495..0000000000
--- a/frappe/public/css/form.css
+++ /dev/null
@@ -1,729 +0,0 @@
-.form-print-wrapper {
- border: 1px solid #d1d8dd;
- border-top: none;
-}
-.print-preview-wrapper {
- padding: 30px 0px;
- background-color: #f5f7fa;
-}
-.print-toolbar {
- margin: 0px;
- padding: 10px 0px;
- border-bottom: 1px solid #d1d8dd;
-}
-.print-toolbar > div {
- padding-right: 0px;
-}
-.print-toolbar > div:last-child {
- padding-right: 15px;
-}
-.form-inner-toolbar {
- padding: 10px 15px 0px;
- background-color: #fafbfc;
- text-align: right;
-}
-.form-inner-toolbar .btn {
- margin-bottom: 10px;
-}
-.form-clickable-section {
- border-top: 1px solid #d1d8dd;
- padding: 10px 15px;
- background-color: #F7FAFC;
-}
-.form-page.second-page {
- border-top: 1px solid #d1d8dd;
-}
-.form-message {
- padding: 15px 30px;
- border-bottom: 1px solid #d1d8dd;
-}
-.document-flow-wrapper {
- padding: 40px 15px 30px;
- font-size: 12px;
- border-bottom: 1px solid #EBEFF2;
-}
-.document-flow-wrapper .document-flow {
- display: inline-block;
- position: relative;
- left: 50%;
- transform: translateX(-50%);
-}
-.document-flow-wrapper .document-flow .document-flow-link-wrapper {
- width: 140px;
- display: inline-block;
-}
-.document-flow-wrapper .document-flow .document-flow-link-wrapper:not(:last-child) {
- border-top: 1px solid #b8c2cc;
- margin-right: -4px;
-}
-.document-flow-wrapper .document-flow .document-flow-link-wrapper:last-child {
- margin-right: -140px;
-}
-.document-flow-wrapper .document-flow .document-flow-link {
- margin-top: -10px;
- display: inline-block;
-}
-.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):hover .document-flow-link-label,
-.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):focus .document-flow-link-label,
-.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):active .document-flow-link-label {
- text-decoration: underline;
-}
-.document-flow-wrapper .document-flow .document-flow-link-label {
- display: inline-block;
- margin-left: -50%;
- margin-top: 5px;
-}
-@media (max-width: 767px) {
- .document-flow-wrapper {
- display: none;
- }
-}
-.form-dashboard {
- background-color: #fafbfc;
-}
-.form-dashboard-wrapper {
- margin: -15px 0px;
-}
-.form-documents h6 {
- margin-top: 15px;
-}
-.form-dashboard-section {
- margin: 0px -15px;
- padding: 15px 30px;
- border-bottom: 1px solid #EBEFF2;
-}
-.form-dashboard-section:first-child {
- padding-top: 0px;
-}
-.form-dashboard-section:last-child {
- border-bottom: none;
-}
-.form-heatmap .heatmap {
- display: flex;
- justify-content: center;
-}
-.form-heatmap .heatmap-message {
- margin-top: 10px;
-}
-@media (max-width: 991px) {
- .form-heatmap {
- overflow: hidden;
- overflow-x: scroll;
- }
-}
-.inline-graph .inline-graph-half {
- width: 48%;
- display: inline-block;
- position: relative;
- height: 30px;
-}
-.inline-graph .inline-graph-half .inline-graph-count {
- font-size: 10px;
- position: absolute;
- left: 0;
- right: 0;
- top: 3px;
- padding: 0px 5px;
- text-align: left;
-}
-.inline-graph .inline-graph-half .inline-graph-bar {
- position: absolute;
- left: 0;
- right: 0;
- top: 20px;
-}
-.inline-graph .inline-graph-half .inline-graph-bar-inner {
- display: block;
- float: left;
- background-color: #d1d8dd;
- height: 6px;
- border-radius: 0px 3px 3px 0px;
-}
-.inline-graph .inline-graph-half .inline-graph-bar-inner.dark {
- background-color: #36414C;
-}
-.inline-graph .inline-graph-half:first-child {
- border-right: 1px solid #d1d8dd;
- margin-right: -3px;
-}
-.inline-graph .inline-graph-half:first-child .inline-graph-count {
- text-align: right;
-}
-.inline-graph .inline-graph-half:first-child .inline-graph-bar-inner {
- float: right;
- border-radius: 3px 0px 0px 3px;
-}
-.progress-area {
- padding-top: 15px;
- padding-bottom: 15px;
-}
-.form-links .document-link {
- 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;
- margin-right: 5px;
-}
-h6.uppercase,
-.h6.uppercase {
- font-size: 11px;
- font-weight: normal;
- letter-spacing: 0.4px;
- text-transform: uppercase;
- color: #8D99A6;
-}
-.form-section {
- margin: 0px;
- padding: 15px;
-}
-.form-section .form-section-description {
- margin-bottom: 10px;
-}
-.form-section .form-section-heading {
- margin: 10px 0px;
-}
-.form-section .section-head {
- margin: 0px 0px 15px 15px;
- cursor: pointer;
-}
-.form-section .section-head .collapse-indicator {
- color: #d1d8dd;
- margin-left: 10px;
- position: relative;
- bottom: -1px;
-}
-.form-section .section-head .collapse-indicator.octicon-chevron-up {
- bottom: -2px;
-}
-.form-section .section-head.collapsed {
- margin-bottom: 0px;
-}
-.form-section:not(:last-child),
-.form-inner-toolbar {
- border-bottom: 1px solid #d1d8dd;
-}
-.empty-section {
- display: none !important;
-}
-.modal .form-layout {
- margin: -15px;
-}
-.modal .form-grid .form-layout {
- margin: 0px;
-}
-.modal .form-section {
- padding: 15px 7px;
-}
-.help ol {
- padding-left: 19px;
-}
-.field_description_top {
- margin-bottom: 3px;
-}
-.user-actions {
- margin-bottom: 15px;
-}
-.user-actions a {
- font-weight: bold;
-}
-.badge-important {
- background-color: #e74c3c;
-}
-.address-box {
- background-color: #fafbfc;
- padding: 0px 15px;
- margin: 15px 0px;
- border: 1px solid #d1d8dd;
- border-radius: 3px;
- font-size: 12px;
-}
-.timeline {
- margin: 30px 0px;
-}
-.timeline .timeline-head .comment-input {
- height: auto;
-}
-.timeline-item {
- margin-top: 0px;
-}
-.timeline-item b {
- color: #36414C !important;
-}
-.timeline-item blockquote {
- font-size: inherit;
-}
-.timeline-item .btn-more {
- margin-left: 65px;
-}
-.timeline-item .gmail_extra {
- display: none;
-}
-.timeline-items {
- position: relative;
-}
-.timeline {
- position: relative;
-}
-.timeline::before {
- content: " ";
- border-left: 1px solid #d1d8dd;
- position: absolute;
- top: 0px;
- bottom: -124px;
- left: 43px;
- z-index: 0;
-}
-.timeline.in-dialog::before {
- bottom: 0px;
-}
-@media (max-width: 991px) {
- .timeline::before {
- bottom: -64px;
- }
-}
-.timeline-item.user-content {
- margin: 30px 0px 30px 27px;
-}
-.timeline-item.user-content .media-body {
- border: 1px solid #d1d8dd;
- border-radius: 3px;
- margin-left: -7px;
- position: relative;
- max-width: calc(100% - 50px);
- padding-right: 0px;
- overflow: visible;
-}
-.timeline-item.user-content .avatar-medium {
- margin-right: 10px;
- height: 45px;
- width: 45px;
-}
-.timeline-item.user-content .action-btns {
- position: absolute;
- right: 0;
- padding: 8px 15px 0 5px;
-}
-.timeline-item.user-content .action-btns .edit-btn-container {
- margin-right: 13px;
-}
-.timeline-item.user-content .comment-header {
- background-color: #fafbfc;
- padding: 10px 15px 8px 13px;
- margin: 0px;
- color: #8D99A6;
- border-bottom: 1px solid #EBEFF2;
-}
-.timeline-item.user-content .comment-header.links-active {
- padding-right: 77px;
-}
-.timeline-item.user-content .comment-header .asset-details {
- display: inline-block;
- width: 100%;
-}
-.timeline-item.user-content .comment-header .asset-details .btn-link {
- border: 0;
- border-radius: 0;
- padding: 0;
-}
-.timeline-item.user-content .comment-header .asset-details .btn-link:hover {
- text-decoration: none;
-}
-.timeline-item.user-content .comment-header .commented-on-small {
- display: none;
-}
-.timeline-item.user-content .comment-header .octicon-heart {
- color: #ff5858;
- cursor: pointer;
-}
-.timeline-item.user-content .reply {
- padding: 15px;
- overflow: auto;
-}
-.timeline-item.user-content .reply > div > p:first-child {
- margin-top: 0px;
-}
-.timeline-item.user-content .reply > div > p:last-child {
- margin-bottom: 0px;
-}
-.timeline-item.user-content .reply hr {
- margin: 10px 0px;
-}
-.timeline-item.user-content .close-btn-container .close {
- color: inherit;
- opacity: 1;
- padding: 0;
- font-size: 18px;
-}
-.timeline-item.user-content .edit-btn-container {
- padding: 0;
-}
-.timeline-item.user-content .edit-btn-container .edit {
- color: inherit;
- font-size: 21px;
- line-height: 1;
-}
-.timeline-item.user-content .edit-btn-container .edit .octicon-check {
- font-size: 1em;
-}
-.timeline-item.user-content .edit-btn-container .edit:hover,
-.timeline-item.user-content .edit-btn-container .edit:focus {
- color: #000;
-}
-.timeline-item.user-content .comment-likes {
- margin-left: 5px;
-}
-.timeline-item.user-content .media-body:after,
-.timeline-item.user-content .media-body:before {
- right: 100%;
- top: 15px;
- border: solid transparent;
- content: " ";
- height: 0;
- width: 0;
- position: absolute;
- pointer-events: none;
-}
-.timeline-item.user-content .media-body:after {
- border-color: rgba(136, 183, 213, 0);
- border-right-color: #fafbfc;
- border-width: 6px;
- margin-top: -6px;
-}
-.timeline-item.user-content .media-body:before {
- border-color: rgba(194, 225, 245, 0);
- border-right-color: #d1d8dd;
- border-width: 7px;
- margin-top: -7px;
-}
-.timeline-item.notification-content {
- padding-left: 30px;
- margin: 30px 0px;
- position: relative;
- color: #8D99A6;
-}
-.timeline-item.notification-content * {
- color: #8D99A6;
-}
-.timeline-item.notification-content .fa-fw {
- margin-left: 36px;
-}
-.timeline-item.notification-content div.small {
- padding-left: 40px;
-}
-.timeline-item.notification-content div.small .fa-fw {
- margin-left: 0px;
-}
-.timeline-item.notification-content .octicon-heart {
- color: #ff5858 !important;
-}
-.timeline-item.notification-content::before {
- content: " ";
- width: 7px;
- height: 7px;
- background-color: #d1d8dd;
- position: absolute;
- left: 40px;
- border-radius: 50%;
- top: 5px;
-}
-.timeline-item .reply-link {
- margin-left: 15px;
- font-size: 12px;
-}
-.timeline-head {
- background-color: white;
- border: 1px solid #d1d8dd;
- border-radius: 3px;
- position: relative;
- z-index: 1;
-}
-.timeline-head .comment-input-header {
- background-color: #fafbfc;
- padding: 7px 15px;
- border-bottom: 1px solid #EBEFF2;
-}
-.timeline-head .comment-input-container {
- padding: 15px;
-}
-.timeline-head .comment-input-container .awesomplete > ul {
- min-width: 200px;
-}
-.timeline-head .comment-input {
- border-color: #EBEFF2;
- max-width: 100%;
-}
-.timeline-head .comment-input:focus {
- box-shadow: none;
-}
-@media (max-width: 767px) {
- .timeline-head {
- border-left: none;
- border-right: none;
- border-radius: 0px;
- }
-}
-.signature-field {
- min-height: 300px;
- background: #fff;
- border: 1px solid #d1d8dd;
- border-radius: 3px;
- position: relative;
- margin-top: -10px;
-}
-.signature-display {
- margin: 7px 0px;
- background: #fff;
-}
-.signature-btn-row {
- position: absolute;
- bottom: 12px;
- right: 12px;
-}
-.signature-reset {
- z-index: 10;
- height: 30px;
- width: 30px;
- padding: 4px 0px;
-}
-.signature-img {
- background: #fff;
- border-radius: 3px;
- margin-top: 5px;
- max-height: 150px;
-}
-.timeline-new-email {
- margin: 30px 0px;
- padding-left: 70px;
- position: relative;
-}
-.timeline-new-email::before {
- content: " ";
- width: 7px;
- height: 7px;
- background-color: #d1d8dd;
- position: absolute;
- left: 40px;
- border-radius: 50%;
- top: 5px;
-}
-.form-footer h5 {
- margin: 15px 0px;
- font-weight: bold;
-}
-.control-label,
-.grid-heading-row {
- color: #8D99A6;
- font-size: 12px;
-}
-.control-label {
- margin-bottom: 5px;
- font-weight: normal;
-}
-.like-disabled-input {
- margin-bottom: 7px;
- min-height: 30px;
- font-weight: bold;
- background-color: #f5f7fa;
- padding: 5px 10px;
- border-radius: 3px;
-}
-.disabled-check {
- color: #f5f7fa;
- margin-right: 5px;
- margin-bottom: -2px;
-}
-.like-disabled-input.for-description {
- font-weight: normal;
- font-size: 12px;
-}
-.frappe-control {
- margin-bottom: 10px;
-}
-.frappe-control .help-box {
- margin-top: 3px;
-}
-.frappe-control pre {
- white-space: pre-wrap;
- background-color: inherit;
- border: none;
- padding: 0px;
- margin: 0px;
-}
-.flex-justify-center {
- display: flex;
- justify-content: center;
-}
-.flex-justify-end {
- display: flex;
- justify-content: flex-end;
-}
-.hide-control {
- display: none !important;
-}
-.shared-user {
- margin-bottom: 10px;
-}
-.attach-missing-image,
-.attach-image-display {
- cursor: pointer;
-}
-select.form-control {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
-}
-.form-control.bold {
- color: #000;
- font-weight: bold;
- background-color: #fffdf4;
-}
-.form-control[data-fieldtype="Password"] {
- position: inherit;
-}
-.password-strength-indicator {
- float: right;
- padding: 15px;
- margin-top: -41px;
- margin-right: -7px;
-}
-.password-strength-message {
- margin-top: -10px;
-}
-.control-code,
-.control-code.bold {
- height: 400px;
- font-family: Monaco, "Courier New", monospace;
- color: #36414C;
- font-size: 12px;
- line-height: 1.7em;
-}
-.delivery-status-indicator {
- display: inline-block;
- margin-top: -3px;
- margin-left: 1px;
- font-weight: 500;
- color: #8D99A6;
-}
-.attach-btn {
- margin-top: 10px;
-}
-@media (min-width: 768px) {
- .layout-main .form-column.col-sm-12 > form > .input-max-width {
- max-width: 50%;
- padding-right: 15px;
- }
- .col-sm-6 .form-grid .form-column.col-sm-12 > form > .input-max-width {
- max-width: none;
- padding-right: 0px;
- }
- .form-column.col-sm-6 textarea[data-fieldtype="Code"] {
- height: 120px !important;
- }
-}
-@media (max-width: 991px) {
- .form-section .form-section-heading {
- margin-top: 10px;
- }
-}
-@media (max-width: 767px) {
- .form-section .section-head {
- padding: 15px 15px 15px 0px;
- }
- .form-section .section-body .form-column:first-child .radio,
- .form-section .section-body .form-column:first-child .checkbox {
- margin-top: 0;
- }
- .form-column {
- border-bottom: 1px solid #EBEFF2;
- padding-top: 15px;
- padding-bottom: 15px;
- }
- .form-column:last-child {
- border-bottom: 0px;
- }
- .form-section {
- padding-left: 0px !important;
- padding-right: 0px !important;
- }
- .form-grid {
- margin-left: -17px;
- margin-right: -17px;
- border-left: none !important;
- border-right: none !important;
- border-radius: none;
- }
- .form-page .form-section {
- padding: 0px 15px;
- }
- .frappe-control.form-page {
- padding: 7px 15px;
- border-bottom: 1px solid #EBEFF2;
- margin: 0px -15px;
- }
- .frappe-control.form-page .link-btn {
- top: -2px;
- }
- .frappe-control.form-page .like-disabled-input {
- min-height: 0px !important;
- }
- .frappe-control.form-page:last-child {
- margin-bottom: 0px;
- }
- .form-page .frappe-control:last-child {
- border-bottom: 0px;
- }
- .form-page .frappe-control[data-fieldtype="Table"] {
- padding: 0px 15px;
- margin-top: -1px;
- border-bottom: none;
- }
- .form-page .frappe-control[data-fieldtype="Table"] label {
- margin-top: 7px;
- }
- .form-page .form-control {
- border: none;
- border-bottom: 1px solid #d1d8dd;
- box-shadow: none;
- background-color: inherit;
- height: auto;
- padding: 0px;
- margin-bottom: 7px;
- border-radius: 0px;
- text-align: left !important;
- }
- .form-page .form-control:focus {
- box-shadow: none;
- }
-}
-/* goals */
-.goals-page-container {
- background-color: #fafbfc;
- padding-top: 1px;
-}
-.goals-page-container .goal-container {
- background-color: #fff;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
- border-radius: 2px;
- padding: 10px;
- margin: 10px;
-}
-body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] {
- height: 80px !important;
-}
-.frappe-control[data-fieldtype="Attach"] .attached-file {
- position: relative;
- margin-top: 5px;
-}
-.frappe-control[data-fieldtype="Attach"] .attached-file .close {
- position: absolute;
- top: 0;
- right: 0;
-}
diff --git a/frappe/public/css/mobile.css b/frappe/public/css/mobile.css
deleted file mode 100644
index 1cf8bb011a..0000000000
--- a/frappe/public/css/mobile.css
+++ /dev/null
@@ -1,411 +0,0 @@
-/* the element that this class is applied to, should have a max width for this to work*/
-html {
- min-height: 100%;
-}
-body {
- height: 100%;
- margin: 0px;
- padding: 0px !important;
-}
-html,
-body {
- overflow-x: hidden;
- overflow-y: overlay;
-}
-@media (max-width: 991px) {
- .intro-area,
- .footnote-area {
- padding: 15px;
- }
- .grid-row-open {
- top: 0;
- }
- .layout-main {
- position: relative;
- }
- body[data-route^="Form"] .page-title h1 {
- margin-top: 12px;
- }
- body[data-route^="Form"] .page-title h1.editable-title {
- padding-right: 80px;
- }
- body[data-route^="Form"] .page-title .indicator {
- display: inline-block;
- margin-top: 12px;
- }
- body[data-route^="Form"] .page-actions {
- padding-top: 20px !important;
- padding-bottom: 0px !important;
- padding-left: 0px !important;
- }
- body[data-route^="Form"] .page-head .sub-heading {
- font-weight: normal;
- font-size: 10px;
- display: block;
- position: absolute;
- right: 140px;
- min-width: 200px;
- }
- body[data-route^="Form"] .title-text {
- margin-top: 10px;
- }
- .toggle-navbar-new-comments {
- padding: 8px 0px !important;
- }
- .navbar > .container > .navbar-header {
- float: left;
- width: 80%;
- }
- .navbar > .container > .navbar-right {
- float: right;
- }
- .module-item {
- padding: 7px 0px !important;
- }
- .module-item h4 {
- font-weight: normal;
- }
- #navbar-breadcrumbs {
- margin: 0px;
- display: inline-block;
- max-width: 150px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
- #navbar-breadcrumbs > li,
- #navbar-breadcrumbs > li > a {
- display: inline-block;
- vertical-align: middle;
- }
- #navbar-breadcrumbs > li > a:before {
- content: "\f104";
- margin-right: 10px;
- color: #6C7680;
- }
- #navbar-breadcrumbs li:not(:nth-last-child(-n+1)) {
- display: none;
- }
- .navbar-nav {
- margin: 0px;
- margin-right: -15px;
- }
- .sidebar .form-group {
- margin-bottom: 0px;
- }
- #sidebar-search {
- height: 27px;
- }
- .sidebar .navbar-search-icon {
- float: right;
- color: #6C7680;
- font-size: inherit;
- position: relative;
- right: 7px;
- top: -20px;
- height: 0;
- }
- .sidebar form {
- padding: 7px;
- }
- .sidebar .main-menu {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 41px;
- overflow-y: auto;
- }
- .sidebar .user-menu {
- padding: 9px 14px;
- background-color: #f5f7fa;
- position: absolute;
- left: 0;
- bottom: 0;
- right: 0;
- }
- .sidebar .user-menu,
- .sidebar .user-menu .octicon {
- color: #6C7680;
- }
- .sidebar .user-menu img {
- margin-top: -1px;
- }
- body[data-route^="Module"] .navbar-center {
- display: block !important;
- position: absolute;
- top: 10px;
- left: 25%;
- right: 25%;
- text-align: center;
- }
- body.no-breadcrumbs .navbar .navbar-home {
- display: inline-block !important;
- padding-left: 0px;
- margin-left: 0px;
- padding-top: 6px;
- }
- body.no-breadcrumbs .navbar .navbar-home:before {
- font-family: FontAwesome;
- font-weight: normal;
- font-style: normal;
- text-decoration: inherit;
- -webkit-font-smoothing: antialiased;
- *margin-right: 0.3em;
- display: inline-block;
- speak: none;
- font-size: 24px;
- transition: 0.2s;
- position: relative;
- top: 3px;
- content: "\f104";
- margin-right: 10px;
- color: #6C7680;
- }
- body.no-breadcrumbs .navbar .navbar-home:hover:before,
- body.no-breadcrumbs .navbar .navbar-home:focus:before,
- body.no-breadcrumbs .navbar .navbar-home:active:before {
- color: #36414C !important;
- }
- body[data-route=""] .navbar .navbar-home,
- body[data-route="desktop"] .navbar .navbar-home {
- padding: 8px 10px;
- }
- body[data-route=""] .navbar .navbar-home:before,
- body[data-route="desktop"] .navbar .navbar-home:before {
- display: none;
- }
- body[data-route=""] .navbar .navbar-home img,
- body[data-route="desktop"] .navbar .navbar-home img {
- margin-top: 0;
- }
- body[data-route=""] .toggle-sidebar,
- body[data-route="desktop"] .toggle-sidebar {
- display: none !important;
- }
- body[data-sidebar="0"] .toggle-sidebar {
- display: none !important;
- }
- body[data-sidebar="0"] #navbar-breadcrumbs,
- body[data-sidebar="0"] .navbar-home {
- margin-left: 15px !important;
- }
-}
-@media (max-width: 991px) and (max-width: 480px) {
- #navbar-breadcrumbs li > a {
- width: 100px;
- }
-}
-@media (max-width: 767px) {
- .toggle-sidebar {
- margin-right: 0;
- }
- body[data-route^="Form"] .page-title .title-text {
- font-size: 16px;
- width: calc(100% - 90px);
- }
- body[data-route^="Form"] .page-title .indicator {
- float: left;
- margin-top: 10px;
- margin-right: 5px;
- }
- .modal .modal-dialog {
- margin: 0px;
- padding: 0px;
- width: 100%;
- background-color: #fff;
- }
- .modal .modal-content {
- border-radius: 0px;
- border: none;
- height: 100%;
- }
- .modal .modal-body .form-layout {
- margin: -15px;
- }
- .modal .file-upload .input-upload {
- width: 100%;
- text-align: center;
- }
- .modal .file-upload .input-upload .btn-browse {
- width: 100%;
- }
- .modal .file-upload .web-link-wrapper {
- display: block;
- width: 100% !important;
- text-align: center;
- }
- .modal .file-upload .web-link-wrapper .file-upload-or {
- display: block;
- margin: 15px 24px;
- }
- .modal .file-upload .web-link-wrapper .input-link {
- width: 100% !important;
- }
- .layout-main-section-wrapper {
- padding: 0px;
- }
- .layout-main-section {
- border-left-color: transparent !important;
- border-right-color: transparent !important;
- }
- .list-row {
- padding: 13px 15px !important;
- }
- .doclist-row {
- position: relative;
- padding-right: 10px;
- }
- .doclist-row .list-id {
- font-weight: normal;
- }
- .doclist-row .list-row-id {
- left: 18px;
- text-align: left;
- margin-top: 3px;
- }
- .doclist-row.has-checkbox .list-row-id {
- left: 40px;
- }
- .doclist-row .list-row-indicator {
- position: absolute;
- right: 0px;
- top: -20px;
- }
- .doclist-row .list-row-modified {
- margin-right: -10px;
- }
- .doclist-row .list-row-left {
- z-index: 1;
- }
- .doclist-row .list-row-right {
- float: right;
- }
- .doclist-row .list-row-right .list-row-indicator {
- top: 4px;
- }
- .doclist-row .list-row-right .list-row-indicator .indicator::before,
- .doclist-row .list-row-right .list-row-indicator .indicator::after {
- height: 12px;
- width: 12px;
- border-radius: 12px;
- }
- .doclist-row .list-row-right.no-right-column {
- position: absolute;
- top: 0;
- right: 10px;
- left: -10px;
- width: 100%;
- }
- body[data-route^="chat"] .navbar-center {
- display: block !important;
- position: absolute;
- top: 10px;
- left: 25%;
- right: 25%;
- text-align: center;
- }
- #page-chat .layout-side-section {
- position: relative;
- left: 0px;
- border-right: 1px solid #d1d8dd;
- padding-left: 0px;
- float: left;
- width: 76px;
- }
- #page-chat .layout-main-section-wrapper {
- position: absolute;
- left: 75px;
- right: 0px;
- border-left: 1px solid #d1d8dd;
- float: left;
- }
- #page-chat .module-sidebar-item {
- margin: 0px;
- }
- #page-chat .module-sidebar-item .chat-sidebar-link {
- padding: 15px;
- }
- #page-chat .timeline-head {
- padding: 15px 15px 7px;
- }
- #page-chat .list-row {
- padding: 7px 0px;
- }
- #page-chat .message-row-right {
- margin-top: 10px;
- text-align: left;
- }
- body[data-route^="Form"] .page-head .sub-heading {
- right: 90px;
- }
- .timeline::before {
- content: none;
- }
- .timeline .timeline-new-email {
- margin: 20px 0;
- padding-left: 15px;
- }
- .timeline .timeline-new-email::before {
- content: none;
- }
- .timeline .timeline-item.user-content {
- margin: 20px 15px;
- }
- .timeline .timeline-item.user-content .media-body {
- margin-left: 0;
- max-width: 100%;
- overflow: hidden;
- }
- .timeline .timeline-item.user-content .media-body:before {
- content: none;
- }
- .timeline .timeline-item.user-content .action-btns {
- padding: 7px 10px 2px 5px;
- }
- .timeline .timeline-item.user-content .action-btns .edit-btn-container {
- margin-right: 0;
- }
- .timeline .timeline-item.user-content .comment-header {
- padding: 7px 10px;
- }
- .timeline .timeline-item.user-content .comment-header .links-active {
- padding-right: 10px;
- }
- .timeline .timeline-item.user-content .comment-header .reply-link {
- margin-left: 0;
- }
- .timeline .timeline-item.user-content .comment-header .asset-details {
- width: calc(100% - 30px);
- }
- .timeline .timeline-item.user-content .avatar-medium {
- margin-right: 10px;
- }
- .timeline .timeline-item.user-content .reply {
- padding: 10px;
- }
- .timeline .timeline-item.user-content .commented-on-small {
- display: inline-block;
- }
- .timeline .timeline-item.user-content .commented-on-small {
- display: inline-block;
- }
- .timeline .timeline-item.notification-content {
- padding-left: 15px;
- margin: 20px 0;
- }
- .timeline .timeline-item.notification-content::before {
- content: none;
- }
- .timeline .timeline-item.notification-content .small {
- padding-left: 0;
- }
- .timeline .timeline-item .delivery-status-indicator {
- float: left;
- margin: 0 5px 0 0;
- }
- .timeline .asset-details {
- line-height: 24px;
- /*Height of avtar image -36px to align text center vertically*/
- }
-}
diff --git a/frappe/public/css/variables.css b/frappe/public/css/variables.css
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/public/icons/timeless/symbol-defs.svg b/frappe/public/icons/timeless/symbol-defs.svg
index ed02f91a46..2b0cc8b696 100644
--- a/frappe/public/icons/timeless/symbol-defs.svg
+++ b/frappe/public/icons/timeless/symbol-defs.svg
@@ -1,4 +1,4 @@
-
+
@@ -138,7 +138,10 @@
-
+
+
+
+
+ fill="var(--icon-stroke)" stroke="none">
@@ -684,4 +687,10 @@
+
+
+
+
+
+
diff --git a/frappe/public/images/favicon.png b/frappe/public/images/favicon.png
deleted file mode 100644
index d66d3920f8..0000000000
Binary files a/frappe/public/images/favicon.png and /dev/null differ
diff --git a/frappe/public/js/docs.js b/frappe/public/js/docs.js
deleted file mode 100644
index c216de67f9..0000000000
--- a/frappe/public/js/docs.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// used in documenation site built via document generator
-
-$(function() {
- if(window.hljs) {
- $('pre code').each(function(i, block) {
- hljs.highlightBlock(block);
- });
- }
-
- // search
- $('.sidebar-navbar-items .octicon-search, .navbar .octicon-search').parent().on("click", function() {
- var modal = frappe.get_modal("Search",
- '
\
- Search via Google
');
- modal.find(".search-input").on("keyup", function(e) {
- if(e.which===13) {
- modal.find(".btn-search").trigger("click");
- }
- if(e.which===9) {
- e.preventDefault();
- modal.find(".btn-search").focus();
- return false;
- }
- var text = $(this).val();
- modal.find(".btn-search").attr("href", "https://google.com/search?q="
- + text + "+site:" + (window.docs_base_url || ""));
- });
- modal.modal("show");
- return false;
- });
-
-});
-
-frappe = {
- get_modal: function(title, body_html) {
- var modal = $('\
-
\
-
\
- \
-
'+body_html+'\
-
\
-
\
-
\
-
').appendTo(document.body);
-
- return modal;
- },
-};
diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js
index 813205ecd0..fd440dcbbc 100644
--- a/frappe/public/js/frappe/chat.js
+++ b/frappe/public/js/frappe/chat.js
@@ -2781,7 +2781,8 @@ frappe.chat.setup = () => {
}
}
-$(document).on('ready toolbar_setup', () =>
-{
- frappe.chat.setup()
-})
+// TODO: Re-enable after re-designing chat
+// $(document).on('ready toolbar_setup', () =>
+// {
+// frappe.chat.setup()
+// })
diff --git a/frappe/public/js/frappe/data_import/import_preview.js b/frappe/public/js/frappe/data_import/import_preview.js
index 477cfb0786..786692e552 100644
--- a/frappe/public/js/frappe/data_import/import_preview.js
+++ b/frappe/public/js/frappe/data_import/import_preview.js
@@ -188,8 +188,8 @@ frappe.data_import.ImportPreview = class ImportPreview {
.join(',');
this.datatable.style.setStyle(row_classes, {
pointerEvents: 'none',
- backgroundColor: frappe.ui.color.get_color_shade('white', 'light'),
- color: frappe.ui.color.get_color_shade('black', 'extra-light')
+ backgroundColor: frappe.ui.color.get_color_shade('gray', 'extra-light'),
+ color: frappe.ui.color.get_color_shade('gray', 'dark')
});
}
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index cac2e65885..3912373bde 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -45,10 +45,7 @@ frappe.Application = Class.extend({
this.setup_frappe_vue();
this.load_bootinfo();
this.load_user_permissions();
- this.set_app_logo_url()
- .then(() => {
- this.make_nav_bar();
- });
+ this.make_nav_bar();
this.set_favicon();
this.setup_analytics();
this.set_fullwidth_if_enabled();
@@ -82,8 +79,11 @@ frappe.Application = Class.extend({
}
if (frappe.user_roles.includes('System Manager')) {
- this.show_change_log();
- this.show_update_available();
+ // delayed following requests to make boot faster
+ setTimeout(() => {
+ this.show_change_log();
+ this.show_update_available();
+ }, 1000);
}
if (!frappe.boot.developer_mode) {
@@ -470,19 +470,6 @@ frappe.Application = Class.extend({
$(' ').appendTo("head");
$(' ').appendTo("head");
},
-
- set_app_logo_url: function() {
- return frappe.call('frappe.core.doctype.navbar_settings.navbar_settings.get_app_logo')
- .then(r => {
- frappe.app.logo_url = r.message;
- if (window.cordova) {
- let host = frappe.request.url;
- host = host.slice(0, host.length - 1);
- frappe.app.logo_url = host + frappe.app.logo_url;
- }
- });
- },
-
trigger_primary_action: function() {
if(window.cur_dialog && cur_dialog.display) {
// trigger primary
@@ -498,6 +485,7 @@ frappe.Application = Class.extend({
if (frappe.utils.is_rtl()) {
var ls = document.createElement('link');
ls.rel="stylesheet";
+ ls.type = "text/css";
ls.href= "assets/css/frappe-rtl.css";
document.getElementsByTagName('head')[0].appendChild(ls);
$('body').addClass('frappe-rtl');
diff --git a/frappe/public/js/frappe/file_uploader/FilePreview.vue b/frappe/public/js/frappe/file_uploader/FilePreview.vue
index 7161dc8dc5..cca7dfde2a 100644
--- a/frappe/public/js/frappe/file_uploader/FilePreview.vue
+++ b/frappe/public/js/frappe/file_uploader/FilePreview.vue
@@ -11,17 +11,18 @@
+
{{ file.file_obj.size | file_size }}
@@ -30,7 +31,7 @@
-
@@ -217,15 +209,19 @@ export default {
on_file_input(e) {
this.add_files(this.$refs.file_input.files);
},
- remove_file(i) {
- this.files = this.files.filter((file, j) => i !== j);
+ remove_file(file) {
+ this.files = this.files.filter(f => f !== file);
},
- toggle_private(i) {
- this.files[i].private = !this.files[i].private;
- },
- toggle_all_private(flag) {
- if (flag == null) {
- flag = this.files.every(file => file.private);
+ toggle_all_private() {
+ let flag;
+ let private_values = this.files.filter(file => file.private);
+ if (private_values.length < this.files.length) {
+ // there are some private and some public
+ // set all to private
+ flag = true;
+ } else {
+ // all are private, set all to public
+ flag = false;
}
this.files = this.files.map(file => {
file.private = flag;
diff --git a/frappe/public/js/frappe/file_uploader/index.js b/frappe/public/js/frappe/file_uploader/index.js
index 0a822971e1..28ce96cd44 100644
--- a/frappe/public/js/frappe/file_uploader/index.js
+++ b/frappe/public/js/frappe/file_uploader/index.js
@@ -48,6 +48,13 @@ export default class FileUploader {
this.uploader = this.$fileuploader.$children[0];
+ this.uploader.$watch('files', (files) => {
+ let all_private = files.every(file => file.private);
+ if (this.dialog) {
+ this.dialog.set_secondary_action_label(all_private ? __('Set all public') : __('Set all private'));
+ }
+ }, { deep: true });
+
if (files && files.length) {
this.uploader.add_files(files);
}
@@ -66,8 +73,10 @@ export default class FileUploader {
title: __('Upload'),
primary_action_label: __('Upload'),
primary_action: () => this.upload_files(),
- secondary_action_label: __('Toggle Private'),
- secondary_action: () => this.uploader.toggle_all_private()
+ secondary_action_label: __('Set all private'),
+ secondary_action: () => {
+ this.uploader.toggle_all_private();
+ }
});
this.wrapper = this.dialog.body;
diff --git a/frappe/public/js/frappe/form/controls/autocomplete.js b/frappe/public/js/frappe/form/controls/autocomplete.js
index 27ebad24c3..30eb277f08 100644
--- a/frappe/public/js/frappe/form/controls/autocomplete.js
+++ b/frappe/public/js/frappe/form/controls/autocomplete.js
@@ -1,6 +1,7 @@
import Awesomplete from 'awesomplete';
frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
+ trigger_change_on_input_event: false,
make_input() {
this._super();
this.setup_awesomplete();
diff --git a/frappe/public/js/frappe/form/controls/barcode.js b/frappe/public/js/frappe/form/controls/barcode.js
index c2314d6664..8ac812c0ed 100644
--- a/frappe/public/js/frappe/form/controls/barcode.js
+++ b/frappe/public/js/frappe/form/controls/barcode.js
@@ -8,7 +8,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
this.default_svg = '
';
let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
this.barcode_area = $(
- `
${this.default_svg}
`
+ `
${this.default_svg}
`
);
this.barcode_area.appendTo($input_wrapper);
},
@@ -55,7 +55,14 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
get_options(value) {
// get JsBarcode options
- let options = JSON.parse('{ "height" : 40 }');
+ let options = {};
+ options.background = "var(--control-bg)";
+ options.lineColor = "var(--text-color)";
+ options.font = "var(--font-stack)";
+ options.fontSize = "16";
+ options.width = "3";
+ options.height = "50";
+
if (frappe.utils.is_json(this.df.options)) {
options = JSON.parse(this.df.options);
if (options.format && options.format === 'EAN') {
diff --git a/frappe/public/js/frappe/form/controls/base_control.js b/frappe/public/js/frappe/form/controls/base_control.js
index d7f873bee0..9981398b84 100644
--- a/frappe/public/js/frappe/form/controls/base_control.js
+++ b/frappe/public/js/frappe/form/controls/base_control.js
@@ -74,7 +74,7 @@ frappe.ui.form.Control = Class.extend({
frappe.model.get_doc(this.doctype, this.docname), this.perm || (this.frm && this.frm.perm), explain);
// Match parent grid controls read only status
- if (status === 'Write' && (this.grid || (this.layout && this.layout.grid))) {
+ if (status === 'Write' && (this.grid || (this.layout && this.layout.grid) && !cint(this.df.allow_on_submit))) {
var grid = this.grid || this.layout.grid;
if (grid.display_status == 'Read') {
status = 'Read';
diff --git a/frappe/public/js/frappe/form/controls/image.js b/frappe/public/js/frappe/form/controls/image.js
index b70822377d..90de22138a 100644
--- a/frappe/public/js/frappe/form/controls/image.js
+++ b/frappe/public/js/frappe/form/controls/image.js
@@ -14,7 +14,7 @@ frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({
this.$img = $("
")
.appendTo(this.$body);
} else {
- this.$buffer = $("
")
+ this.$buffer = $(`
${frappe.utils.icon('restriction', 'md')}
`)
.appendTo(this.$body);
}
return false;
diff --git a/frappe/public/js/frappe/form/controls/int.js b/frappe/public/js/frappe/form/controls/int.js
index 9b59444fd3..aca3a85603 100644
--- a/frappe/public/js/frappe/form/controls/int.js
+++ b/frappe/public/js/frappe/form/controls/int.js
@@ -1,4 +1,5 @@
frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
+ trigger_change_on_input_event: false,
make: function () {
this._super();
// $(this.label_area).addClass('pull-right');
diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js
index 670bb8b3e0..e0a72ed8c1 100644
--- a/frappe/public/js/frappe/form/controls/link.js
+++ b/frappe/public/js/frappe/form/controls/link.js
@@ -136,7 +136,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
return $('
')
.data('item.autocomplete', d)
.prop('aria-selected', 'false')
- .html('
' + html + '
')
+ .html(`
${html}
`)
.get(0);
},
sort: function() {
diff --git a/frappe/public/js/frappe/form/controls/multiselect_list.js b/frappe/public/js/frappe/form/controls/multiselect_list.js
index 5884a18753..f1ebd06350 100644
--- a/frappe/public/js/frappe/form/controls/multiselect_list.js
+++ b/frappe/public/js/frappe/form/controls/multiselect_list.js
@@ -1,4 +1,5 @@
frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
+ trigger_change_on_input_event: false,
make_input() {
let template = `
diff --git a/frappe/public/js/frappe/form/controls/multiselect_pills.js b/frappe/public/js/frappe/form/controls/multiselect_pills.js
index e73810c4dc..a0b4a1e2d8 100644
--- a/frappe/public/js/frappe/form/controls/multiselect_pills.js
+++ b/frappe/public/js/frappe/form/controls/multiselect_pills.js
@@ -84,12 +84,12 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
- return `
- ${__(value)}
-
- ${frappe.utils.icon('close')}
+ return `
+
+ ${__(value)}
+ ${frappe.utils.icon('close')}
-
`;
+ `;
},
get_awesomplete_settings() {
diff --git a/frappe/public/js/frappe/form/controls/rating.js b/frappe/public/js/frappe/form/controls/rating.js
index 191db35538..8117bf24bf 100644
--- a/frappe/public/js/frappe/form/controls/rating.js
+++ b/frappe/public/js/frappe/form/controls/rating.js
@@ -1,22 +1,24 @@
frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
make_input() {
this._super();
+ let stars = '';
+ [1, 2, 3, 4, 5].forEach(i => {
+ stars += `
+
+ `;
+ });
const star_template = `
-
-
-
-
-
+ ${stars}
`;
$(this.input_area).html(star_template);
- $(this.input_area).find('i').hover((ev) => {
+ $(this.input_area).find('svg').hover((ev) => {
const el = $(ev.currentTarget);
let star_value = el.data('rating');
- el.parent().children('i.fa').each( function(e) {
+ el.parent().children('svg').each( function(e) {
if (e < star_value) {
$(this).addClass('star-hover');
} else {
@@ -25,16 +27,16 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
});
}, (ev) => {
const el = $(ev.currentTarget);
- el.parent().children('i.fa').each( function() {
+ el.parent().children('svg').each( function() {
$(this).removeClass('star-hover');
});
});
- $(this.input_area).find('i').click((ev) => {
+ $(this.input_area).find('svg').click((ev) => {
const el = $(ev.currentTarget);
let star_value = el.data('rating');
- el.parent().children('i.fa').each( function(e) {
- if (e < star_value){
+ el.parent().children('svg').each( function(e) {
+ if (e < star_value) {
$(this).addClass('star-click');
} else {
$(this).removeClass('star-click');
@@ -50,8 +52,8 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
return cint(this.value, null);
},
set_formatted_input(value) {
- let el = $(this.input_area).find('i');
- el.children('i.fa').prevObject.each( function(e) {
+ let el = $(this.input_area).find('svg');
+ el.children('svg').prevObject.each( function(e) {
if (e < value) {
$(this).addClass('star-click');
} else {
@@ -59,4 +61,4 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
}
});
}
-});
\ No newline at end of file
+});
diff --git a/frappe/public/js/frappe/form/controls/signature.js b/frappe/public/js/frappe/form/controls/signature.js
index 82dcb8f341..51ddf0d557 100644
--- a/frappe/public/js/frappe/form/controls/signature.js
+++ b/frappe/public/js/frappe/form/controls/signature.js
@@ -18,7 +18,7 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
this.img_wrapper = $(`
-
+ ${frappe.utils.icon('restriction', 'md')}
`)
.appendTo(this.wrapper);
this.img = $("
")
@@ -29,15 +29,21 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
let width = this.body.width();
if (width > 0 && !this.$pad) {
this.$pad = this.body.jSignature({
- height: 300,
+ height: 200,
+ color: "var(--text-color)",
width: this.body.width(),
- lineWidth: 3
+ lineWidth: 2,
+ "background-color": "var(--control-bg)"
}).on('change',
this.on_save_sign.bind(this));
this.load_pad();
- this.$reset_button_wrapper = $(`
-
- `)
+ this.$reset_button_wrapper = $(`
+
+ `)
.appendTo(this.$pad)
.on("click", '.signature-reset', () => {
this.on_reset_sign();
diff --git a/frappe/public/js/frappe/form/controls/table_multiselect.js b/frappe/public/js/frappe/form/controls/table_multiselect.js
index 10e22eacb6..c306146f90 100644
--- a/frappe/public/js/frappe/form/controls/table_multiselect.js
+++ b/frappe/public/js/frappe/form/controls/table_multiselect.js
@@ -123,12 +123,12 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
},
get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
- return `
- ${__(value)}
-
- ${frappe.utils.icon('close')}
+ return `
+
+ ${__(value)}
+ ${frappe.utils.icon('close')}
-
`;
+ `;
},
get_options() {
return (this.get_link_field() || {}).options;
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index a70797e295..8d96054d16 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -1498,7 +1498,7 @@ frappe.ui.form.Form = class FrappeForm {
const escaped_name = encodeURIComponent(value);
- return `
${label} '`;
+ return `
${label} `;
} else {
return '';
}
diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js
index 30ed7f15e4..5386f97528 100644
--- a/frappe/public/js/frappe/form/formatters.js
+++ b/frappe/public/js/frappe/form/formatters.js
@@ -61,11 +61,14 @@ frappe.form.formatters = {
return frappe.form.formatters._right(flt(value, precision) + "%", options);
},
Rating: function(value) {
- return `
- ${Array.from(new Array(5)).map((_, i) =>
- ` `
- ).join('')}
- `;
+ const rating_html = `${[1, 2, 3, 4, 5].map(i =>
+ `
+
+ `
+ ).join('')}`;
+ return `
+ ${rating_html}
+
`;
},
Currency: function (value, docfield, options, doc) {
var currency = frappe.meta.get_field_currency(docfield, doc);
diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index 921ad1cdb5..3bde525fff 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -268,7 +268,7 @@ export default class Grid {
}
refresh(force) {
- if (this.frm.setting_dependency) return;
+ if (this.frm && this.frm.setting_dependency) return;
this.data = this.get_data();
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index 675cb6f77c..9fdd4a8e36 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -229,7 +229,7 @@ export default class GridRow {
this.open_form_button = $(`
`)
.appendTo($('
').appendTo(this.row))
diff --git a/frappe/public/js/frappe/form/script_manager.js b/frappe/public/js/frappe/form/script_manager.js
index 7ac3673b08..770319ba53 100644
--- a/frappe/public/js/frappe/form/script_manager.js
+++ b/frappe/public/js/frappe/form/script_manager.js
@@ -176,7 +176,7 @@ frappe.ui.form.ScriptManager = Class.extend({
eval(doctype.__custom_js);
} catch(e) {
frappe.msgprint({
- title: __('Error in Custom Script'),
+ title: __('Error in Client Script'),
indicator: 'orange',
message: '
' + e.stack + ''
});
diff --git a/frappe/public/js/frappe/form/sidebar/form_sidebar.js b/frappe/public/js/frappe/form/sidebar/form_sidebar.js
index 40f9e65bb0..d6a9d95801 100644
--- a/frappe/public/js/frappe/form/sidebar/form_sidebar.js
+++ b/frappe/public/js/frappe/form/sidebar/form_sidebar.js
@@ -210,7 +210,7 @@ frappe.ui.form.Sidebar = class {
if (follow == null) {
follow = this.frm.get_docinfo().is_document_followed;
}
- this.follow_button.text(follow ? "Unfollow" : "Follow");
+ this.follow_button.text(follow ? __("Unfollow") : __("Follow"));
}
refresh_like() {
diff --git a/frappe/public/js/frappe/list/list_sidebar.html b/frappe/public/js/frappe/list/list_sidebar.html
index cd80280d7b..0428f32e60 100644
--- a/frappe/public/js/frappe/list/list_sidebar.html
+++ b/frappe/public/js/frappe/list/list_sidebar.html
@@ -56,7 +56,7 @@
`;
} else {
+ const page_name = this.get_page_name();
items.map(item => {
- if (item.name == this.get_page_name()) {
+ if (item.name.toLowerCase() == page_name.toLowerCase()) {
placeholder = item.name;
}
html += `
${
@@ -212,7 +218,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
const report_type =
r.report_type === "Report Builder"
? `/app/list/${r.ref_doctype}/report`
- : "query-report";
+ : "/app/query-report";
const route =
r.route || report_type + "/" + (r.title || r.name);
diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js
index a2e872085e..9ec7b0e931 100644
--- a/frappe/public/js/frappe/model/model.js
+++ b/frappe/public/js/frappe/model/model.js
@@ -15,7 +15,7 @@ $.extend(frappe.model, {
core_doctypes_list: ['DocType', 'DocField', 'DocPerm', 'User', 'Role', 'Has Role',
'Page', 'Module Def', 'Print Format', 'Report', 'Customize Form',
- 'Customize Form Field', 'Property Setter', 'Custom Field', 'Custom Script'],
+ 'Customize Form Field', 'Property Setter', 'Custom Field', 'Client Script'],
std_fields: [
{fieldname:'name', fieldtype:'Link', label:__('ID')},
diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js
index 7f0d883983..88912e12da 100644
--- a/frappe/public/js/frappe/request.js
+++ b/frappe/public/js/frappe/request.js
@@ -492,7 +492,7 @@ frappe.request.report_error = function(xhr, request_opts) {
if (!frappe.error_dialog) {
frappe.error_dialog = new frappe.ui.Dialog({
- title: 'Server Error',
+ title: __('Server Error'),
primary_action_label: __('Report'),
primary_action: () => {
if (error_report_email) {
diff --git a/frappe/public/js/frappe/ui/colors.js b/frappe/public/js/frappe/ui/colors.js
index 9ce71abae4..b26ca224d1 100644
--- a/frappe/public/js/frappe/ui/colors.js
+++ b/frappe/public/js/frappe/ui/colors.js
@@ -39,7 +39,8 @@ frappe.ui.color = {
};
if(Object.keys(shades).includes(shade)) {
- return frappe.ui.color_map[color_name][shades[shade]];
+ const color = this.get_color(color_name);
+ return color ? color[shades[shade]] : color_name;
} else {
// eslint-disable-next-line
console.warn(`'shade' can be one of ${Object.keys(shades)} and not ${shade}`);
diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js
index 31c12a2fd1..59836fae23 100644
--- a/frappe/public/js/frappe/ui/dialog.js
+++ b/frappe/public/js/frappe/ui/dialog.js
@@ -35,6 +35,8 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
$(this.wrapper).addClass("modal-sm");
else if (this.size == "large" )
$(this.wrapper).addClass("modal-lg");
+ else if (this.size == "extra-large" )
+ $(this.wrapper).addClass("modal-xl");
this.make_head();
this.modal_body = this.$wrapper.find(".modal-body");
diff --git a/frappe/public/js/frappe/ui/dropzone.js b/frappe/public/js/frappe/ui/dropzone.js
deleted file mode 100644
index c2bb92293d..0000000000
--- a/frappe/public/js/frappe/ui/dropzone.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// DropZone
-frappe.ui.DropZone = class
-{
- constructor (selector, options) {
- this.options = Object.assign({ }, frappe.ui.DropZone.OPTIONS, options);
- this.$container = $(selector);
- this.$wrapper = $(frappe.ui.DropZone.TEMPLATE);
-
- this.make();
- }
-
- make ( ) {
- const me = this;
- const $dropzone = this.$wrapper.find('.panel-body');
- const $title = $dropzone.find('.dropzone-title');
- $title.html(this.options.title);
-
- $dropzone.on('dragover', function (e) {
- e.preventDefault();
-
- $title.html(__('Drop'));
- });
- $dropzone.on('dragleave', function (e) {
- e.preventDefault();
-
- $title.html(me.options.title);
- });
- $dropzone.on('drop', function (e) {
- e.preventDefault();
-
- const files = e.originalEvent.dataTransfer.files;
- me.options.drop(files);
-
- $title.html(me.options.title);
- });
-
- this.$container.html(this.$wrapper);
- }
-};
-frappe.ui.DropZone.TEMPLATE =
-`
-
-`;
-frappe.ui.DropZone.OPTIONS =
-{
- title: __('Drop Here')
-};
diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js
index 9bca44a916..945115af82 100644
--- a/frappe/public/js/frappe/ui/filters/filter.js
+++ b/frappe/public/js/frappe/ui/filters/filter.js
@@ -214,6 +214,7 @@ frappe.ui.Filter = class {
df.read_only = 0;
df.hidden = 0;
df.is_filter = true;
+ delete df.hidden_due_to_dependency;
let c = condition ? condition : this.utils.get_default_condition(df);
this.set_condition(c);
diff --git a/frappe/public/js/frappe/ui/filters/filter_list.js b/frappe/public/js/frappe/ui/filters/filter_list.js
index 7f79f8511a..0b2218ceda 100644
--- a/frappe/public/js/frappe/ui/filters/filter_list.js
+++ b/frappe/public/js/frappe/ui/filters/filter_list.js
@@ -74,8 +74,8 @@ frappe.ui.FilterGroup = class {
}
this.set_filter_events();
}
-
- hide_empty_filters && this.toggle_empty_filters(false);
+ this.toggle_empty_filters(false);
+ !hide_empty_filters && this.add_filter(this.doctype, 'name');
});
this.filter_button.on('hidden.bs.popover', () => {
@@ -286,7 +286,9 @@ frappe.ui.FilterGroup = class {
return $(`
-
${__('No filters selected')}
+
+ ${__('No filters selected')}
+