From 68829ab2e6d2ca8238bd9d5bd44844e032cee089 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Thu, 21 Jan 2021 19:06:33 +0100
Subject: [PATCH 001/623] feat: default_email_template
---
frappe/core/doctype/doctype/doctype.json | 13 ++++++++++++-
frappe/public/js/frappe/views/communication.js | 1 +
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json
index 215ef8cd62..55c74a4e63 100644
--- a/frappe/core/doctype/doctype/doctype.json
+++ b/frappe/core/doctype/doctype/doctype.json
@@ -55,6 +55,8 @@
"show_preview_popup",
"show_name_in_global_search",
"email_settings_sb",
+ "default_email_template",
+ "column_break_51",
"email_append_to",
"sender_field",
"subject_field",
@@ -528,6 +530,15 @@
"fieldname": "index_web_pages_for_search",
"fieldtype": "Check",
"label": "Index Web Pages for Search"
+ },
+ {
+ "fieldname": "default_email_template",
+ "fieldtype": "Data",
+ "label": "Default Email Template"
+ },
+ {
+ "fieldname": "column_break_51",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-bolt",
@@ -609,7 +620,7 @@
"link_fieldname": "reference_doctype"
}
],
- "modified": "2020-09-24 13:13:58.227153",
+ "modified": "2021-01-21 18:09:47.135696",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index c69be04347..7b9668a96e 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -159,6 +159,7 @@ frappe.views.CommunicationComposer = Class.extend({
this.setup_last_edited_communication();
this.setup_email_template();
+ this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
this.dialog.set_value("recipients", this.recipients || '');
this.dialog.set_value("cc", this.cc || '');
this.dialog.set_value("bcc", this.bcc || '');
From 2618ee74d898f48a0899691c045e2ce1e0a4b4da Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 27 Jan 2021 18:55:54 +0100
Subject: [PATCH 002/623] feat: add default_email_template to Customize Form
---
.../doctype/customize_form/customize_form.json | 13 ++++++++++++-
.../custom/doctype/customize_form/customize_form.py | 1 +
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json
index ff102b3c08..dee2dfce0d 100644
--- a/frappe/custom/doctype/customize_form/customize_form.json
+++ b/frappe/custom/doctype/customize_form/customize_form.json
@@ -31,6 +31,8 @@
"show_preview_popup",
"image_view",
"email_settings_section",
+ "default_email_template",
+ "column_break_26",
"email_append_to",
"sender_field",
"subject_field",
@@ -261,6 +263,15 @@
"fieldtype": "Table",
"label": "Actions",
"options": "DocType Action"
+ },
+ {
+ "fieldname": "default_email_template",
+ "fieldtype": "Data",
+ "label": "Default Email Template"
+ },
+ {
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
@@ -269,7 +280,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2020-09-24 14:16:49.594012",
+ "modified": "2021-01-27 18:26:59.705786",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form",
diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py
index 82513783c7..0718f5d84c 100644
--- a/frappe/custom/doctype/customize_form/customize_form.py
+++ b/frappe/custom/doctype/customize_form/customize_form.py
@@ -479,6 +479,7 @@ doctype_properties = {
'allow_auto_repeat': 'Check',
'allow_import': 'Check',
'show_preview_popup': 'Check',
+ 'default_email_template': 'Data',
'email_append_to': 'Check',
'subject_field': 'Data',
'sender_field': 'Data'
From b14b28d7650001af5d7812bda07c15cb74e883ff Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 27 Jan 2021 18:59:00 +0100
Subject: [PATCH 003/623] fix: check if frm is available
Prevents error when creating new Communication from list view.
---
frappe/public/js/frappe/views/communication.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 7b9668a96e..073ce44206 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -159,7 +159,10 @@ frappe.views.CommunicationComposer = Class.extend({
this.setup_last_edited_communication();
this.setup_email_template();
- this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
+ if ('frm' in this) {
+ this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
+ }
+
this.dialog.set_value("recipients", this.recipients || '');
this.dialog.set_value("cc", this.cc || '');
this.dialog.set_value("bcc", this.bcc || '');
From fa39484571d993ed5562149b6c85615e39cdc27b Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 27 Jan 2021 18:59:47 +0100
Subject: [PATCH 004/623] fix: check if email_template is set
Prevents error on empty email_template.
---
frappe/public/js/frappe/views/communication.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 073ce44206..c5c6cdced9 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -232,6 +232,9 @@ frappe.views.CommunicationComposer = Class.extend({
this.dialog.fields_dict["email_template"].df.onchange = () => {
var email_template = me.dialog.fields_dict.email_template.get_value();
+ if (email_template === '') {
+ return;
+ }
var prepend_reply = function(reply) {
if(me.reply_added===email_template) {
From 885d198622703ef50b0f6443f3a00ee76b0c2d58 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Thu, 4 Feb 2021 12:20:12 +0100
Subject: [PATCH 005/623] fix: don't apply default email template for reply
---
frappe/public/js/frappe/views/communication.js | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index f1feb4f6a3..66e050f3d1 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -196,10 +196,6 @@ frappe.views.CommunicationComposer = Class.extend({
this.setup_last_edited_communication();
this.setup_email_template();
- if ('frm' in this) {
- this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
- }
-
this.dialog.set_value("recipients", this.recipients || '');
this.dialog.set_value("cc", this.cc || '');
this.dialog.set_value("bcc", this.bcc || '');
@@ -210,6 +206,11 @@ frappe.views.CommunicationComposer = Class.extend({
this.dialog.fields_dict.subject.set_value(this.subject || '');
this.setup_earlier_reply();
+
+ if ('frm' in this && !this.is_a_reply) {
+ // set default email template for the first email in a document
+ this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
+ }
},
setup_subject_and_recipients: function() {
From cb211c6272669662d1012aa7331538ba856c1579 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 8 Feb 2021 12:51:47 +0100
Subject: [PATCH 006/623] fix: signature should be an empty string by default
(would become undefined if the server message was empty)
---
frappe/public/js/frappe/views/communication.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 66e050f3d1..5329967e12 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -726,7 +726,7 @@ frappe.views.CommunicationComposer = Class.extend({
if (!signature) {
const res = await this.get_default_outgoing_email_account_signature();
- signature = res.message.signature;
+ signature = res.message.signature || "";
}
if(!frappe.utils.is_html(signature)) {
From 87326625fed3f0ce0b72977f2e988783e59741c8 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 22 Mar 2021 12:31:58 +0100
Subject: [PATCH 007/623] fix: make Default Email Template a link field
---
frappe/core/doctype/doctype/doctype.json | 7 ++++---
frappe/custom/doctype/customize_form/customize_form.json | 7 ++++---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json
index 7bf91892ee..fb24c095f3 100644
--- a/frappe/core/doctype/doctype/doctype.json
+++ b/frappe/core/doctype/doctype/doctype.json
@@ -533,8 +533,9 @@
},
{
"fieldname": "default_email_template",
- "fieldtype": "Data",
- "label": "Default Email Template"
+ "fieldtype": "Link",
+ "label": "Default Email Template",
+ "options": "Email Template"
},
{
"fieldname": "column_break_51",
@@ -620,7 +621,7 @@
"link_fieldname": "reference_doctype"
}
],
- "modified": "2021-02-23 15:10:09.227205",
+ "modified": "2021-03-22 12:26:41.031135",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",
diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json
index dee2dfce0d..f8db73137e 100644
--- a/frappe/custom/doctype/customize_form/customize_form.json
+++ b/frappe/custom/doctype/customize_form/customize_form.json
@@ -266,8 +266,9 @@
},
{
"fieldname": "default_email_template",
- "fieldtype": "Data",
- "label": "Default Email Template"
+ "fieldtype": "Link",
+ "label": "Default Email Template",
+ "options": "Email Template"
},
{
"fieldname": "column_break_26",
@@ -280,7 +281,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2021-01-27 18:26:59.705786",
+ "modified": "2021-03-22 12:27:15.462727",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customize Form",
From 6df8479525c4e7af1cfd3b0428700c40cad0c9a9 Mon Sep 17 00:00:00 2001
From: Richard Case
Date: Thu, 11 Mar 2021 01:18:16 +0000
Subject: [PATCH 008/623] fix: build priority on computers with low memory
fixes:frappe/bench#1135
---
frappe/commands/__init__.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/frappe/commands/__init__.py b/frappe/commands/__init__.py
index b9ae02e112..61ee62d352 100644
--- a/frappe/commands/__init__.py
+++ b/frappe/commands/__init__.py
@@ -62,11 +62,24 @@ def popen(command, *args, **kwargs):
if env:
env = dict(environ, **env)
+ def set_low_prio():
+ import psutil
+ if psutil.LINUX:
+ psutil.Process().nice(19)
+ psutil.Process().ionice(psutil.IOPRIO_CLASS_IDLE)
+ elif psutil.WINDOWS:
+ psutil.Process().nice(psutil.IDLE_PRIORITY_CLASS)
+ psutil.Process().ionice(psutil.IOPRIO_VERYLOW)
+ else:
+ psutil.Process().nice(19)
+ # ionice not supported
+
proc = subprocess.Popen(command,
stdout=None if output else subprocess.PIPE,
stderr=None if output else subprocess.PIPE,
shell=shell,
cwd=cwd,
+ preexec_fn=set_low_prio,
env=env
)
From 5290b4c65f15642c5bc7c84d70fcfc4c14c3d883 Mon Sep 17 00:00:00 2001
From: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
Date: Sat, 27 Mar 2021 15:01:37 +0100
Subject: [PATCH 009/623] fix: add back column break that was lost in merge
---
frappe/custom/doctype/customize_form/customize_form.json | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json
index fc74f0881b..442b8dbb31 100644
--- a/frappe/custom/doctype/customize_form/customize_form.json
+++ b/frappe/custom/doctype/customize_form/customize_form.json
@@ -272,6 +272,10 @@
"label": "Default Email Template",
"options": "Email Template"
},
+ {
+ "fieldname": "column_break_26",
+ "fieldtype": "Column Break"
+ },
{
"collapsible": 1,
"fieldname": "naming_section",
@@ -312,4 +316,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
From 08d8e67946d02d01bf4e385171e8f2df5c8cebed Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Tue, 6 Apr 2021 14:56:28 +0530
Subject: [PATCH 010/623] fix(backups): ensure delete_temp_backups always
respects config
---
frappe/utils/backups.py | 30 ++++--------------------------
1 file changed, 4 insertions(+), 26 deletions(-)
diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py
index 77c5761527..3c14cd9d5e 100644
--- a/frappe/utils/backups.py
+++ b/frappe/utils/backups.py
@@ -15,7 +15,7 @@ import click
# imports - module imports
import frappe
from frappe import _, conf
-from frappe.utils import get_file_size, get_url, now, now_datetime
+from frappe.utils import get_file_size, get_url, now, now_datetime, cint
# backup variable for backwards compatibility
verbose = False
@@ -474,29 +474,6 @@ download only after 24 hours.""" % {
return recipient_list
-@frappe.whitelist()
-def get_backup():
- """
- This function is executed when the user clicks on
- Toos > Download Backup
- """
- delete_temp_backups()
- odb = BackupGenerator(
- frappe.conf.db_name,
- frappe.conf.db_name,
- frappe.conf.db_password,
- db_host=frappe.db.host,
- db_type=frappe.conf.db_type,
- db_port=frappe.conf.db_port,
- )
- odb.get_backup()
- recipient_list = odb.send_email()
- frappe.msgprint(
- _(
- "Download link for your backup will be emailed on the following email address: {0}"
- ).format(", ".join(recipient_list))
- )
-
@frappe.whitelist()
def fetch_latest_backups(partial=False):
"""Fetches paths of the latest backup taken in the last 30 days
@@ -570,7 +547,7 @@ def new_backup(
force=False,
verbose=False,
):
- delete_temp_backups(older_than=frappe.conf.keep_backups_for_hours or 24)
+ delete_temp_backups()
odb = BackupGenerator(
frappe.conf.db_name,
frappe.conf.db_name,
@@ -593,10 +570,11 @@ def new_backup(
return odb
-def delete_temp_backups(older_than=24):
+def delete_temp_backups():
"""
Cleans up the backup_link_path directory by deleting files older than 24 hours
"""
+ older_than = cint(frappe.conf.keep_backups_for_hours) or 24
backup_path = get_backup_path()
if os.path.exists(backup_path):
file_list = os.listdir(get_backup_path())
From c6497abcd143946c72d0b04fdc029b0edd853df3 Mon Sep 17 00:00:00 2001
From: walstanb
Date: Fri, 9 Apr 2021 13:06:58 +0530
Subject: [PATCH 011/623] fix: minor changes
---
frappe/utils/backups.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py
index 3c14cd9d5e..9a6747a0cf 100644
--- a/frappe/utils/backups.py
+++ b/frappe/utils/backups.py
@@ -570,11 +570,11 @@ def new_backup(
return odb
-def delete_temp_backups():
+def delete_temp_backups(older_than=24):
"""
- Cleans up the backup_link_path directory by deleting files older than 24 hours
+ Cleans up the backup_link_path directory by deleting older files
"""
- older_than = cint(frappe.conf.keep_backups_for_hours) or 24
+ older_than = cint(frappe.conf.keep_backups_for_hours) or older_than
backup_path = get_backup_path()
if os.path.exists(backup_path):
file_list = os.listdir(get_backup_path())
From 6004125469cc78053e753546324a9d145e7f1161 Mon Sep 17 00:00:00 2001
From: "hasnain2808@gmail.com"
Date: Wed, 14 Apr 2021 13:52:43 +0530
Subject: [PATCH 012/623] feat: allow button of different sizes in df
---
frappe/public/js/frappe/form/controls/button.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/controls/button.js b/frappe/public/js/frappe/form/controls/button.js
index b44c9d9dcd..d09e9c3a95 100644
--- a/frappe/public/js/frappe/form/controls/button.js
+++ b/frappe/public/js/frappe/form/controls/button.js
@@ -6,7 +6,10 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
make_input: function() {
var me = this;
const btn_type = this.df.primary ? 'btn-primary': 'btn-default';
- this.$input = $(``)
+ const btn_size = this.df.btn_size
+ ? `btn-${this.df.btn_size}`
+ : "btn-xs";
+ this.$input = $(``)
.prependTo(me.input_area)
.on("click", function() {
me.onclick();
From 86851028ea472029b74628a3202b766ad3fa3418 Mon Sep 17 00:00:00 2001
From: Rohan Bansal
Date: Fri, 2 Apr 2021 15:33:12 +0530
Subject: [PATCH 013/623] feat: manage Python 3 compatiblity with dependencies
---
.github/workflows/ci-tests.yml | 6 +-
frappe/commands/site.py | 6 +-
.../scheduled_job_type/scheduled_job_type.py | 11 +-
frappe/database/mariadb/database.py | 42 +++--
frappe/email/receive.py | 33 ++--
.../dropbox_settings/dropbox_settings.py | 54 ++++---
.../google_calendar/google_calendar.py | 34 ++--
.../google_contacts/google_contacts.py | 23 +--
.../doctype/google_drive/google_drive.py | 37 +++--
frappe/utils/xlsxutils.py | 21 +--
.../website_settings/google_indexing.py | 24 +--
requirements.txt | 152 +++++++++---------
12 files changed, 238 insertions(+), 205 deletions(-)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index bfe2002f69..08a2823dca 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -149,9 +149,9 @@ jobs:
run: |
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
cd ${GITHUB_WORKSPACE}
- pip install coveralls==2.2.0
- pip install coverage==4.5.4
- coveralls
+ pip install coveralls==3.0.1
+ pip install coverage==5.5
+ coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index 0fadf2a294..0102d3ac40 100755
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -676,10 +676,8 @@ def start_ngrok(context):
frappe.init(site=site)
port = frappe.conf.http_port or frappe.conf.webserver_port
- public_url = ngrok.connect(port=port, options={
- 'host_header': site
- })
- print(f'Public URL: {public_url}')
+ tunnel = ngrok.connect(addr=str(port), host_header=site)
+ print(f'Public URL: {tunnel.public_url}')
print('Inspect logs at http://localhost:4040')
ngrok_process = ngrok.get_ngrok_process()
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 92493a593a..59089d12ad 100644
--- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
+++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
@@ -2,14 +2,15 @@
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
+import json
+from datetime import datetime
from typing import Dict, List
-import frappe, json
-from frappe.model.document import Document
-from frappe.utils import now_datetime, get_datetime
-from datetime import datetime
from croniter import croniter
+
+import frappe
+from frappe.model.document import Document
+from frappe.utils import get_datetime, now_datetime
from frappe.utils.background_jobs import enqueue, get_jobs
diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py
index f9997d1526..7d1d92408c 100644
--- a/frappe/database/mariadb/database.py
+++ b/frappe/database/mariadb/database.py
@@ -1,17 +1,13 @@
-from __future__ import unicode_literals
-
-import frappe
import warnings
import pymysql
-from pymysql.times import TimeDelta
-from pymysql.constants import ER, FIELD_TYPE
-from pymysql.converters import conversions
+from pymysql.constants import ER, FIELD_TYPE
+from pymysql.converters import conversions, escape_string
-from frappe.utils import get_datetime, cstr, UnicodeWithAttrs
+import frappe
from frappe.database.database import Database
-from six import PY2, binary_type, text_type, string_types
from frappe.database.mariadb.schema import MariaDBTable
+from frappe.utils import UnicodeWithAttrs, cstr, get_datetime
class MariaDBDatabase(Database):
@@ -72,22 +68,20 @@ class MariaDBDatabase(Database):
conversions.update({
FIELD_TYPE.NEWDECIMAL: float,
FIELD_TYPE.DATETIME: get_datetime,
- UnicodeWithAttrs: conversions[text_type]
+ UnicodeWithAttrs: conversions[str]
})
- if PY2:
- conversions.update({
- TimeDelta: conversions[binary_type]
- })
-
- if usessl:
- conn = pymysql.connect(self.host, self.user or '', self.password or '',
- port=self.port, charset='utf8mb4', use_unicode = True, ssl=ssl_params,
- conv = conversions, local_infile = frappe.conf.local_infile)
- else:
- conn = pymysql.connect(self.host, self.user or '', self.password or '',
- port=self.port, charset='utf8mb4', use_unicode = True, conv = conversions,
- local_infile = frappe.conf.local_infile)
+ conn = pymysql.connect(
+ user=self.user or '',
+ password=self.password or '',
+ host=self.host,
+ port=self.port,
+ charset='utf8mb4',
+ use_unicode=True,
+ ssl=ssl_params if usessl else None,
+ conv=conversions,
+ local_infile=frappe.conf.local_infile
+ )
# MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1
# # self._conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)
@@ -111,7 +105,7 @@ class MariaDBDatabase(Database):
def escape(s, percent=True):
"""Excape quotes and percent in given string."""
# pymysql expects unicode argument to escape_string with Python 3
- s = frappe.as_unicode(pymysql.escape_string(frappe.as_unicode(s)), "utf-8").replace("`", "\\`")
+ s = frappe.as_unicode(escape_string(frappe.as_unicode(s)), "utf-8").replace("`", "\\`")
# NOTE separating % escape, because % escape should only be done when using LIKE operator
# or when you use python format string to generate query that already has a %s
@@ -260,7 +254,7 @@ class MariaDBDatabase(Database):
ADD INDEX `%s`(%s)""" % (table_name, index_name, ", ".join(fields)))
def add_unique(self, doctype, fields, constraint_name=None):
- if isinstance(fields, string_types):
+ if isinstance(fields, str):
fields = [fields]
if not constraint_name:
constraint_name = "unique_" + "_".join(fields)
diff --git a/frappe/email/receive.py b/frappe/email/receive.py
index cf6c13ee76..949da4a343 100644
--- a/frappe/email/receive.py
+++ b/frappe/email/receive.py
@@ -1,18 +1,27 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
-from __future__ import unicode_literals
-import six
-from six import iteritems, text_type
-from six.moves import range
-import time, _socket, poplib, imaplib, email, email.utils, datetime, chardet, re
-from email_reply_parser import EmailReplyParser
+import datetime
+import email
+import email.utils
+import imaplib
+import poplib
+import re
+import time
from email.header import decode_header
+
+import _socket
+import chardet
+import six
+from email_reply_parser import EmailReplyParser
+
import frappe
from frappe import _, safe_decode, safe_encode
-from frappe.utils import (extract_email_id, convert_utc_to_user_timezone, now,
- cint, cstr, strip, markdown, parse_addr)
-from frappe.core.doctype.file.file import get_random_filename, MaxFileSizeReachedError
+from frappe.core.doctype.file.file import (MaxFileSizeReachedError,
+ get_random_filename)
+from frappe.utils import (cint, convert_utc_to_user_timezone, cstr,
+ extract_email_id, markdown, now, parse_addr, strip)
+
class EmailSizeExceededError(frappe.ValidationError): pass
class EmailTimeoutError(frappe.ValidationError): pass
@@ -337,7 +346,7 @@ class EmailServer:
return
self.imap.select("Inbox")
- for uid, operation in iteritems(uid_list):
+ for uid, operation in uid_list.items():
if not uid: continue
op = "+FLAGS" if operation == "Read" else "-FLAGS"
@@ -473,7 +482,7 @@ class Email:
self.html_content += markdown(text_content)
def get_charset(self, part):
- """Detect chartset."""
+ """Detect charset."""
charset = part.get_content_charset()
if not charset:
charset = chardet.detect(safe_encode(cstr(part)))['encoding']
@@ -484,7 +493,7 @@ class Email:
charset = self.get_charset(part)
try:
- return text_type(part.get_payload(decode=True), str(charset), "ignore")
+ return str(part.get_payload(decode=True), str(charset), "ignore")
except LookupError:
return part.get_payload()
diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py
index 09da1ecc42..53f0935c80 100644
--- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py
+++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py
@@ -2,22 +2,23 @@
# Copyright (c) 2015, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import dropbox
import json
-import frappe
import os
-from frappe import _
-from frappe.model.document import Document
-from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size, get_chunk_site
-from frappe.integrations.utils import make_post_request
-from frappe.utils import (cint, get_request_site_address,
- get_files_path, get_backups_path, get_url, encode)
-from frappe.utils.backups import new_backup
-from frappe.utils.background_jobs import enqueue
-from six.moves.urllib.parse import urlparse, parse_qs
+from urllib.parse import parse_qs, urlparse
+
+import dropbox
from rq.timeouts import JobTimeoutException
-from six import text_type
+
+import frappe
+from frappe import _
+from frappe.integrations.offsite_backup_utils import (get_chunk_site,
+ get_latest_backup_file, send_email, validate_file_size)
+from frappe.integrations.utils import make_post_request
+from frappe.model.document import Document
+from frappe.utils import (cint, encode, get_backups_path, get_files_path,
+ get_request_site_address, get_url)
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.backups import new_backup
ignore_list = [".DS_Store"]
@@ -91,7 +92,10 @@ def backup_to_dropbox(upload_db_backup=True):
dropbox_settings['access_token'] = access_token['oauth2_token']
set_dropbox_access_token(access_token['oauth2_token'])
- dropbox_client = dropbox.Dropbox(dropbox_settings['access_token'], timeout=None)
+ dropbox_client = dropbox.Dropbox(
+ oauth2_access_token=dropbox_settings['access_token'],
+ timeout=None
+ )
if upload_db_backup:
if frappe.flags.create_new_backup:
@@ -127,7 +131,7 @@ def upload_from_folder(path, is_private, dropbox_folder, dropbox_client, did_not
else:
response = frappe._dict({"entries": []})
- path = text_type(path)
+ path = str(path)
for f in frappe.get_all("File", filters={"is_folder": 0, "is_private": is_private,
"uploaded_to_dropbox": 0}, fields=['file_url', 'name', 'file_name']):
@@ -286,11 +290,11 @@ def get_redirect_url():
def get_dropbox_authorize_url():
app_details = get_dropbox_settings(redirect_uri=True)
dropbox_oauth_flow = dropbox.DropboxOAuth2Flow(
- app_details["app_key"],
- app_details["app_secret"],
- app_details["redirect_uri"],
- {},
- "dropbox-auth-csrf-token"
+ consumer_key=app_details["app_key"],
+ redirect_uri=app_details["redirect_uri"],
+ session={},
+ csrf_token_session_key="dropbox-auth-csrf-token",
+ consumer_secret=app_details["app_secret"]
)
auth_url = dropbox_oauth_flow.start()
@@ -307,13 +311,13 @@ def dropbox_auth_finish(return_access_token=False):
close = '' + _('Please close this window') + '
'
dropbox_oauth_flow = dropbox.DropboxOAuth2Flow(
- app_details["app_key"],
- app_details["app_secret"],
- app_details["redirect_uri"],
- {
+ consumer_key=app_details["app_key"],
+ redirect_uri=app_details["redirect_uri"],
+ session={
'dropbox-auth-csrf-token': callback.state
},
- "dropbox-auth-csrf-token"
+ csrf_token_session_key="dropbox-auth-csrf-token",
+ consumer_secret=app_details["app_secret"]
)
if callback.state or callback.code:
diff --git a/frappe/integrations/doctype/google_calendar/google_calendar.py b/frappe/integrations/doctype/google_calendar/google_calendar.py
index fbedd75029..f93be35aa7 100644
--- a/frappe/integrations/doctype/google_calendar/google_calendar.py
+++ b/frappe/integrations/doctype/google_calendar/google_calendar.py
@@ -2,22 +2,23 @@
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe
-import requests
-import googleapiclient.discovery
-import google.oauth2.credentials
-from frappe import _
-from frappe.model.document import Document
-from frappe.utils import get_request_site_address
-from googleapiclient.errors import HttpError
-from frappe.utils.password import set_encrypted_password
-from frappe.utils import add_days, get_datetime, get_weekdays, now_datetime, add_to_date, get_time_zone
-from dateutil import parser
from datetime import datetime, timedelta
-from six.moves.urllib.parse import quote
+from urllib.parse import quote
+
+import google.oauth2.credentials
+import requests
+from dateutil import parser
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+import frappe
+from frappe import _
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url
+from frappe.model.document import Document
+from frappe.utils import (add_days, add_to_date, get_datetime,
+ get_request_site_address, get_time_zone, get_weekdays, now_datetime)
+from frappe.utils.password import set_encrypted_password
SCOPES = "https://www.googleapis.com/auth/calendar"
@@ -171,7 +172,12 @@ def get_google_calendar_object(g_calendar):
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
- google_calendar = googleapiclient.discovery.build("calendar", "v3", credentials=credentials)
+ google_calendar = build(
+ serviceName="calendar",
+ version="v3",
+ credentials=credentials,
+ static_discovery=False
+ )
check_google_calendar(account, google_calendar)
diff --git a/frappe/integrations/doctype/google_contacts/google_contacts.py b/frappe/integrations/doctype/google_contacts/google_contacts.py
index 4c8c3b67f6..1705f98e91 100644
--- a/frappe/integrations/doctype/google_contacts/google_contacts.py
+++ b/frappe/integrations/doctype/google_contacts/google_contacts.py
@@ -2,17 +2,17 @@
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe
-import requests
-import googleapiclient.discovery
-import google.oauth2.credentials
-from frappe.model.document import Document
-from frappe import _
+import google.oauth2.credentials
+import requests
+from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
-from frappe.utils import get_request_site_address
+
+import frappe
+from frappe import _
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url
+from frappe.model.document import Document
+from frappe.utils import get_request_site_address
SCOPES = "https://www.googleapis.com/auth/contacts"
@@ -118,7 +118,12 @@ def get_google_contacts_object(g_contact):
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
- google_contacts = googleapiclient.discovery.build("people", "v1", credentials=credentials)
+ google_contacts = build(
+ serviceName="people",
+ version="v1",
+ credentials=credentials,
+ static_discovery=False
+ )
return google_contacts, account
diff --git a/frappe/integrations/doctype/google_drive/google_drive.py b/frappe/integrations/doctype/google_drive/google_drive.py
index 859c769018..93b6fa3f8d 100644
--- a/frappe/integrations/doctype/google_drive/google_drive.py
+++ b/frappe/integrations/doctype/google_drive/google_drive.py
@@ -2,27 +2,29 @@
# Copyright (c) 2019, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe
-import requests
-import googleapiclient.discovery
-import google.oauth2.credentials
import os
+from urllib.parse import quote
-from frappe import _
-from googleapiclient.errors import HttpError
-from frappe.model.document import Document
-from frappe.utils import get_request_site_address
-from frappe.utils.background_jobs import enqueue
-from six.moves.urllib.parse import quote
+import google.oauth2.credentials
+import requests
from apiclient.http import MediaFileUpload
-from frappe.utils import get_backups_path, get_bench_path
-from frappe.utils.backups import new_backup
+from googleapiclient.discovery import build
+from googleapiclient.errors import HttpError
+
+import frappe
+from frappe import _
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url
-from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size
+from frappe.integrations.offsite_backup_utils import (get_latest_backup_file,
+ send_email, validate_file_size)
+from frappe.model.document import Document
+from frappe.utils import (get_backups_path, get_bench_path,
+ get_request_site_address)
+from frappe.utils.background_jobs import enqueue
+from frappe.utils.backups import new_backup
SCOPES = "https://www.googleapis.com/auth/drive"
+
class GoogleDrive(Document):
def validate(self):
@@ -126,7 +128,12 @@ def get_google_drive_object():
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
- google_drive = googleapiclient.discovery.build("drive", "v3", credentials=credentials)
+ google_drive = build(
+ serviceName="drive",
+ version="v3",
+ credentials=credentials,
+ static_discovery=False
+ )
return google_drive, account
diff --git a/frappe/utils/xlsxutils.py b/frappe/utils/xlsxutils.py
index 3c7b027470..356e2ddfdb 100644
--- a/frappe/utils/xlsxutils.py
+++ b/frappe/utils/xlsxutils.py
@@ -1,18 +1,19 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
-from __future__ import unicode_literals
-
-import frappe
+import re
+from io import BytesIO
import openpyxl
import xlrd
-import re
-from openpyxl.styles import Font
from openpyxl import load_workbook
+from openpyxl.styles import Font
from openpyxl.utils import get_column_letter
-from six import BytesIO, string_types
+
+import frappe
ILLEGAL_CHARACTERS_RE = re.compile(r'[\000-\010]|[\013-\014]|[\016-\037]')
+
+
# return xlsx file object
def make_xlsx(data, sheet_name, wb=None, column_widths=None):
column_widths = column_widths or []
@@ -31,12 +32,12 @@ def make_xlsx(data, sheet_name, wb=None, column_widths=None):
for row in data:
clean_row = []
for item in row:
- if isinstance(item, string_types) and (sheet_name not in ['Data Import Template', 'Data Export']):
+ if isinstance(item, str) and (sheet_name not in ['Data Import Template', 'Data Export']):
value = handle_html(item)
else:
value = item
- if isinstance(item, string_types) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
+ if isinstance(item, str) and next(ILLEGAL_CHARACTERS_RE.finditer(value), None):
# Remove illegal characters from the string
value = re.sub(ILLEGAL_CHARACTERS_RE, '', value)
@@ -80,12 +81,12 @@ def handle_html(data):
return value
+
def read_xlsx_file_from_attached_file(file_url=None, fcontent=None, filepath=None):
if file_url:
_file = frappe.get_doc("File", {"file_url": file_url})
filename = _file.get_full_path()
elif fcontent:
- from io import BytesIO
filename = BytesIO(fcontent)
elif filepath:
filename = filepath
@@ -102,6 +103,7 @@ def read_xlsx_file_from_attached_file(file_url=None, fcontent=None, filepath=Non
rows.append(tmp_list)
return rows
+
def read_xls_file_from_attached_file(content):
book = xlrd.open_workbook(file_contents=content)
sheets = book.sheets()
@@ -111,6 +113,7 @@ def read_xls_file_from_attached_file(content):
rows.append(sheet.row_values(i))
return rows
+
def build_xlsx_response(data, filename):
xlsx_file = make_xlsx(data, filename)
# write out response as a xlsx type
diff --git a/frappe/website/doctype/website_settings/google_indexing.py b/frappe/website/doctype/website_settings/google_indexing.py
index 599de5a2b6..75095bd7df 100644
--- a/frappe/website/doctype/website_settings/google_indexing.py
+++ b/frappe/website/doctype/website_settings/google_indexing.py
@@ -2,17 +2,18 @@
# Copyright (c) 2020, Frappe Technologies and contributors
# For license information, please see license.txt
-from __future__ import unicode_literals
-import frappe
-import requests
-import googleapiclient.discovery
-import google.oauth2.credentials
-from frappe import _
+from urllib.parse import quote
+
+import google.oauth2.credentials
+import requests
+from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
-from frappe.utils import get_request_site_address
-from six.moves.urllib.parse import quote
+
+import frappe
+from frappe import _
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url
+from frappe.utils import get_request_site_address
SCOPES = "https://www.googleapis.com/auth/indexing"
@@ -82,7 +83,12 @@ def get_google_indexing_object():
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
- google_indexing = googleapiclient.discovery.build("indexing", "v3", credentials=credentials)
+ google_indexing = build(
+ serviceName="indexing",
+ version="v3",
+ credentials=credentials,
+ static_discovery=False
+ )
return google_indexing
diff --git a/requirements.txt b/requirements.txt
index 0f88a48f73..8cbe0e800b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,79 +1,79 @@
-Babel==2.6.0
-beautifulsoup4==4.8.2
-bleach-whitelist==0.0.10
-bleach==3.3.0
-boto3==1.10.18
-braintree==3.57.1
-chardet==3.0.4
-Click==7.0
-coverage==4.5.4
-croniter==0.3.31
-cryptography==3.3.2
-dropbox==9.1.0
-email-reply-parser==0.5.9
-Faker==2.0.4
+Babel~=2.9.0
+beautifulsoup4~=4.9.3
+bleach-whitelist~=0.0.11
+bleach~=3.3.0
+boto3~=1.17.48
+braintree~=4.8.0
+chardet~=4.0.0
+Click~=7.1.2
+coverage~=5.5
+croniter~=1.0.11
+cryptography~=3.4.7
+dropbox~=11.6.0
+email-reply-parser~=0.5.12
+Faker~=8.1.0
future==0.18.2
-gitdb2==2.0.6;python_version<'3.4'
-GitPython==2.1.15
-git-url-parse==1.2.2
-google-api-python-client==1.9.3
-google-auth-httplib2==0.0.3
-google-auth-oauthlib==0.4.1
-google-auth==1.18.0
-googlemaps==3.1.1
-gunicorn==19.10.0
-html2text==2016.9.19
-html5lib==1.0.1
-ipython==7.14.0
-jedi==0.17.2 # not directly required. Pinned to fix upstream issue with ipython.
-Jinja2==2.11.3
-ldap3==2.7
-markdown2==2.4.0
+git-url-parse~=1.2.2
+gitdb~=4.0.7
+GitPython~=3.1.14
+google-api-python-client~=2.2.0
+google-auth-httplib2~=0.1.0
+google-auth-oauthlib~=0.4.4
+google-auth~=1.28.1
+googlemaps~=4.4.5
+gunicorn~=20.1.0
+html2text==2020.1.16
+html5lib~=1.1
+ipython~=7.16.1
+jedi==0.17.2 # not directly required. Pinned to fix upstream IPython issue (https://github.com/ipython/ipython/issues/12740)
+Jinja2~=2.11.3
+ldap3~=2.9
+markdown2~=2.4.0
maxminddb-geolite2==2018.703
-ndg-httpsclient==0.5.1
-num2words==0.5.10
-oauthlib==3.1.0
-openpyxl==2.6.4
-passlib==1.7.3
-pdfkit==0.6.1
-Pillow>=8.0.0
-premailer==3.6.1
-psutil==5.7.2
-psycopg2-binary==2.8.4
-pyasn1==0.4.8
-PyJWT==1.7.1
-PyMySQL==0.9.3
-pyngrok==4.1.6
-pyOpenSSL==19.1.0
-pyotp==2.3.0
-PyPDF2==1.26.0
-pypng==0.0.20
-PyQRCode==1.2.1
-python-dateutil==2.8.1
-pytz==2019.3
-PyYAML==5.4
-rauth==0.7.3
-redis==3.5.3
-requests-oauthlib==1.3.0
-requests==2.23.0
-RestrictedPython==5.0
-rq>=1.1.0
-schedule==0.6.0
-semantic-version==2.8.4
-simple-chalk==0.1.0
-six==1.14.0
-sqlparse==0.2.4
-stripe==2.40.0
-terminaltables==3.1.0
-unittest-xml-reporting==2.5.2
-urllib3==1.25.9
-watchdog==0.8.0
-Werkzeug==0.16.1
-Whoosh==2.7.4
-xlrd==1.2.0
-zxcvbn-python==4.4.24
-pycryptodome==3.9.8
-paytmchecksum==1.7.0
-wrapt==1.10.11
-razorpay==1.2.0
+ndg-httpsclient~=0.5.1
+num2words~=0.5.10
+oauthlib~=3.1.0
+openpyxl~=3.0.7
+passlib~=1.7.4
+paytmchecksum~=1.7.0
+pdfkit~=0.6.1
+Pillow~=8.2.0
+premailer~=3.7.0
+psutil~=5.8.0
+psycopg2-binary~=2.8.6
+pyasn1~=0.4.8
+pycryptodome~=3.10.1
+PyJWT~=1.7.1
+PyMySQL~=1.0.2
+pyngrok~=5.0.5
+pyOpenSSL~=20.0.1
+pyotp~=2.6.0
+PyPDF2~=1.26.0
+pypng~=0.0.20
+PyQRCode~=1.2.1
+python-dateutil~=2.8.1
+pytz==2021.1
+PyYAML~=5.4.1
+rauth~=0.7.3
+razorpay~=1.2.0
+redis~=3.5.3
+requests-oauthlib~=1.3.0
+requests~=2.25.1
+RestrictedPython~=5.1
+rq~=1.8.0
rsa>=4.1 # not directly required, pinned by Snyk to avoid a vulnerability
+schedule~=1.1.0
+semantic-version~=2.8.5
+simple-chalk~=0.1.0
+six~=1.15.0
+sqlparse~=0.4.1
+stripe~=2.56.0
+terminaltables~=3.1.0
+unittest-xml-reporting~=3.0.4
+urllib3~=1.26.4
+watchdog~=2.0.2
+Werkzeug~=0.16.1
+Whoosh~=2.7.4
+wrapt~=1.12.1
+xlrd~=2.0.1
+zxcvbn-python~=4.4.24
From 82b98330fd0f0cbfcbd62b6775fc3955796e4d01 Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Wed, 14 Apr 2021 19:50:08 +0530
Subject: [PATCH 014/623] feat: Add URL option for data type fields
---
frappe/model/__init__.py | 3 ++-
frappe/model/base_document.py | 3 +++
frappe/public/js/frappe/form/controls/data.js | 3 +++
frappe/public/js/frappe/utils/datatype.js | 4 ++++
frappe/utils/__init__.py | 15 ++++++++++++++-
5 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
index af06696621..205b451336 100644
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -71,7 +71,8 @@ numeric_fieldtypes = (
data_field_options = (
'Email',
'Name',
- 'Phone'
+ 'Phone',
+ 'URL'
)
default_fields = (
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 983511f7a4..cf63aa98b6 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -666,6 +666,9 @@ class BaseDocument(object):
if data_field_options == "Phone":
frappe.utils.validate_phone_number(data, throw=True)
+ if data_field_options == "URL":
+ frappe.utils.validate_url(data, throw=True)
+
def _validate_constants(self):
if frappe.flags.in_import or self.is_new() or self.flags.ignore_validate_constants:
return
diff --git a/frappe/public/js/frappe/form/controls/data.js b/frappe/public/js/frappe/form/controls/data.js
index f381d1b4a2..b4d24d9a8f 100644
--- a/frappe/public/js/frappe/form/controls/data.js
+++ b/frappe/public/js/frappe/form/controls/data.js
@@ -126,6 +126,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
this.df.invalid = email_invalid;
return v;
}
+ } else if (this.df.options == 'URL') {
+ this.df.invalid = !validate_url(v);
+ return v;
} else {
return v;
}
diff --git a/frappe/public/js/frappe/utils/datatype.js b/frappe/public/js/frappe/utils/datatype.js
index 1b9206f434..ad0fd4324c 100644
--- a/frappe/public/js/frappe/utils/datatype.js
+++ b/frappe/public/js/frappe/utils/datatype.js
@@ -52,6 +52,10 @@ window.validate_name = function(txt) {
return frappe.utils.validate_type(txt, "name");
};
+window.validate_url = function(txt) {
+ return frappe.utils.validate_type(txt, "url");
+}
+
window.nth = function(number) {
number = cint(number);
var s = 'th';
diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py
index efa69d4453..3e397afee6 100644
--- a/frappe/utils/__init__.py
+++ b/frappe/utils/__init__.py
@@ -19,7 +19,7 @@ from gzip import GzipFile
from typing import Generator, Iterable
from six import string_types, text_type
-from six.moves.urllib.parse import quote
+from six.moves.urllib.parse import quote, urlparse
from werkzeug.test import Client
import frappe
@@ -161,6 +161,19 @@ def split_emails(txt):
return email_list
+def validate_url(txt, throw=False):
+ try:
+ url = urlparse(txt).netloc
+ if not url:
+ raise frappe.ValidationError
+ except Exception as e:
+ if throw:
+ frappe.throw(
+ frappe._("'{0}' is not a valid URL").format(txt)
+ )
+
+ return False
+
def random_string(length):
"""generate a random string"""
import string
From ce2dabed78b5da6e4b428d600c208ec8fc6e1a14 Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Thu, 15 Apr 2021 06:02:29 +0530
Subject: [PATCH 015/623] fix: Call to translate function
---
frappe/utils/__init__.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py
index 3e397afee6..5992fdb6db 100644
--- a/frappe/utils/__init__.py
+++ b/frappe/utils/__init__.py
@@ -169,7 +169,9 @@ def validate_url(txt, throw=False):
except Exception as e:
if throw:
frappe.throw(
- frappe._("'{0}' is not a valid URL").format(txt)
+ frappe._(
+ "'{0}' is not a valid URL"
+ ).format('' + +' ')
)
return False
From 73662a50feab196e71e7f4903a3b94f19a3ae1c1 Mon Sep 17 00:00:00 2001
From: leela
Date: Fri, 16 Apr 2021 16:21:19 +0530
Subject: [PATCH 016/623] fix: kanban board sync issue
Recent refactoring introduced an issue of not syncing board data(comes from
reference doctype) into kanban board columns db. Changed to sync it at time
of creating kanban board.
---
frappe/public/js/frappe/views/kanban/kanban_board.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/frappe/public/js/frappe/views/kanban/kanban_board.js b/frappe/public/js/frappe/views/kanban/kanban_board.js
index f563f64cb4..bbc2051e4c 100644
--- a/frappe/public/js/frappe/views/kanban/kanban_board.js
+++ b/frappe/public/js/frappe/views/kanban/kanban_board.js
@@ -306,6 +306,7 @@ frappe.provide("frappe.views");
store.on('change:cur_list', setup_restore_columns);
store.on('change:columns', setup_restore_columns);
store.on('change:empty_state', show_empty_state);
+ fluxify.doAction('update_order');
}
function prepare() {
From d12c47681e05e7ce6db7097d82a1963ece82563e Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 01:34:11 +0530
Subject: [PATCH 017/623] refactor: frappe.views.CommunicationComposer
---
.../js/frappe/form/controls/multiselect.js | 2 +-
.../public/js/frappe/views/communication.js | 521 +++++++++---------
2 files changed, 258 insertions(+), 265 deletions(-)
diff --git a/frappe/public/js/frappe/form/controls/multiselect.js b/frappe/public/js/frappe/form/controls/multiselect.js
index 64ca4fc83d..bbd7aef822 100644
--- a/frappe/public/js/frappe/form/controls/multiselect.js
+++ b/frappe/public/js/frappe/form/controls/multiselect.js
@@ -68,7 +68,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
let data;
if(this.df.get_data) {
data = this.df.get_data();
- this.set_data(data);
+ if (data) this.set_data(data);
} else {
data = this._super();
}
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 0c294d5869..7cf7b32797 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -2,16 +2,15 @@
// MIT License. See license.txt
frappe.last_edited_communication = {};
-frappe.standard_replies = {};
-frappe.separator_element = '---
';
+const separator_element = '---
';
frappe.views.CommunicationComposer = Class.extend({
- init: function(opts) {
+ init(opts) {
$.extend(this, opts);
this.make();
},
- make: function() {
- var me = this;
+ make() {
+ const me = this;
this.dialog = new frappe.ui.Dialog({
title: (this.title || this.subject || __("New Email")),
@@ -19,56 +18,35 @@ frappe.views.CommunicationComposer = Class.extend({
fields: this.get_fields(),
primary_action_label: __("Send"),
size: 'large',
- primary_action: function() {
- me.delete_saved_draft();
+ primary_action() {
me.send_action();
+ me.clear_cache();
+ },
+ secondary_action_label: __("Discard"),
+ secondary_action() {
+ me.dialog.hide();
+ me.clear_cache();
},
minimizable: true
});
this.dialog.sections[0].wrapper.addClass('to_section');
- ['recipients', 'cc', 'bcc'].forEach(field => {
- this.dialog.fields_dict[field].get_data = function() {
- const data = me.dialog.fields_dict[field].get_value();
- const txt = data.match(/[^,\s*]*$/)[0] || '';
- let options = [];
-
- frappe.call({
- method: "frappe.email.get_contact_list",
- args: {
- txt: txt,
- },
- callback: (r) => {
- options = r.message;
- me.dialog.fields_dict[field].set_data(options);
- }
- });
- return options;
- }
- });
-
this.prepare();
this.dialog.show();
if (this.frm) {
$(document).trigger('form-typing', [this.frm]);
}
-
- if (this.cc || this.bcc) {
- this.toggle_more_options(true);
- }
},
- get_fields: function() {
- let contactList = [];
- let fields = [
+ get_fields() {
+ const fields = [
{
label: __("To"),
fieldtype: "MultiSelect",
reqd: 0,
fieldname: "recipients",
- options: contactList
},
{
fieldtype: "Button",
@@ -87,13 +65,11 @@ frappe.views.CommunicationComposer = Class.extend({
label: __("CC"),
fieldtype: "MultiSelect",
fieldname: "cc",
- options: contactList
},
{
label: __("BCC"),
fieldtype: "MultiSelect",
fieldname: "bcc",
- options: contactList
},
{
label: __("Email Template"),
@@ -163,18 +139,16 @@ frappe.views.CommunicationComposer = Class.extend({
);
});
- if (frappe.boot.email_accounts && email_accounts.length > 1) {
- fields = [
- {
- label: __("From"),
- fieldtype: "Select",
- reqd: 1,
- fieldname: "sender",
- options: email_accounts.map(function(e) {
- return e.email_id;
- })
- }
- ].concat(fields);
+ if (email_accounts.length > 1) {
+ fields.unshift({
+ label: __("From"),
+ fieldtype: "Select",
+ reqd: 1,
+ fieldname: "sender",
+ options: email_accounts.map(function(e) {
+ return e.email_id;
+ })
+ });
}
return fields;
@@ -183,56 +157,58 @@ frappe.views.CommunicationComposer = Class.extend({
toggle_more_options(show_options) {
show_options = show_options || this.dialog.fields_dict.more_options.df.hidden;
this.dialog.set_df_property('more_options', 'hidden', !show_options);
- let label = frappe.utils.icon(show_options ? 'up-line': 'down');
+
+ const label = frappe.utils.icon(show_options ? 'up-line': 'down');
this.dialog.get_field('option_toggle_button').set_label(label);
},
- prepare: function() {
+ prepare() {
+ this.setup_multiselect_queries();
this.setup_subject_and_recipients();
this.setup_print_language();
this.setup_print();
this.setup_attach();
this.setup_email();
- this.setup_last_edited_communication();
this.setup_email_template();
-
- this.dialog.set_value("recipients", this.recipients || '');
- this.dialog.set_value("cc", this.cc || '');
- this.dialog.set_value("bcc", this.bcc || '');
-
- if(this.dialog.fields_dict.sender) {
- this.dialog.fields_dict.sender.set_value(this.sender || '');
- }
- this.dialog.fields_dict.subject.set_value(
- frappe.utils.html2text(this.subject) || ''
- );
-
- this.setup_earlier_reply();
-
- if ('frm' in this && !this.is_a_reply) {
- // set default email template for the first email in a document
- this.dialog.set_value("email_template", this.frm.meta.default_email_template || '');
- }
+ this.setup_last_edited_communication();
+ this.set_values();
},
- setup_subject_and_recipients: function() {
+ setup_multiselect_queries() {
+ ['recipients', 'cc', 'bcc'].forEach(field => {
+ this.dialog.fields_dict[field].get_data = () => {
+ const data = this.dialog.fields_dict[field].get_value();
+ const txt = data.match(/[^,\s*]*$/)[0] || '';
+
+ frappe.call({
+ method: "frappe.email.get_contact_list",
+ args: {txt},
+ callback: (r) => {
+ this.dialog.fields_dict[field].set_data(r.message);
+ }
+ });
+ }
+ });
+ },
+
+ setup_subject_and_recipients() {
this.subject = this.subject || "";
- if(!this.forward && !this.recipients && this.last_email) {
+ if (!this.forward && !this.recipients && this.last_email) {
this.recipients = this.last_email.sender;
this.cc = this.last_email.cc;
this.bcc = this.last_email.bcc;
}
- if(!this.forward && !this.recipients) {
+ if (!this.forward && !this.recipients) {
this.recipients = this.frm && this.frm.timeline.get_recipient();
}
- if(!this.subject && this.frm) {
+ if (!this.subject && this.frm) {
// get subject from last communication
- var last = this.frm.timeline.get_last_email();
+ const last = this.frm.timeline.get_last_email();
- if(last) {
+ if (last) {
this.subject = last.subject;
if(!this.recipients) {
this.recipients = last.sender;
@@ -256,7 +232,7 @@ frappe.views.CommunicationComposer = Class.extend({
// always add an identifier to catch a reply
// some email clients (outlook) may not send the message id to identify
// the thread. So as a backup we use the name of the document as identifier
- let identifier = `#${this.frm.doc.name}`;
+ const identifier = `#${this.frm.doc.name}`;
if (!this.subject.includes(identifier)) {
this.subject = `${this.subject} (${identifier})`;
}
@@ -267,34 +243,23 @@ frappe.views.CommunicationComposer = Class.extend({
}
},
- setup_email_template: function() {
- var me = this;
+ setup_email_template() {
+ const me = this;
this.dialog.fields_dict["email_template"].df.onchange = () => {
- var email_template = me.dialog.fields_dict.email_template.get_value();
- if (email_template === '') {
- return;
- }
+ const email_template = me.dialog.fields_dict.email_template.get_value();
+ if (!email_template) return;
- var prepend_reply = function(reply) {
- if(me.reply_added===email_template) {
- return;
- }
- var content_field = me.dialog.fields_dict.content;
- var subject_field = me.dialog.fields_dict.subject;
- var content = content_field.get_value() || "";
- var subject = subject_field.get_value() || "";
+ function prepend_reply(reply) {
+ if (me.reply_added === email_template) return;
- var parts = content.split('');
+ const content_field = me.dialog.fields_dict.content;
+ const subject_field = me.dialog.fields_dict.subject;
- if(parts.length===2) {
- content = [reply.message, " ", parts[1]];
- } else {
- content = [reply.message, " ", content];
- }
-
- content_field.set_value(content.join(''));
+ let content = content_field.get_value() || "";
+ content = content.split('')[1] || content;
+ content_field.set_value(`${reply.message} ${content}`);
subject_field.set_value(reply.subject);
me.reply_added = email_template;
@@ -307,83 +272,105 @@ frappe.views.CommunicationComposer = Class.extend({
doc: me.frm.doc,
_lang: me.dialog.get_value("language_sel")
},
- callback: function(r) {
+ callback(r) {
prepend_reply(r.message);
},
});
}
},
- setup_last_edited_communication: function() {
- var me = this;
- if (!this.doc){
- if (cur_frm){
- this.doc = cur_frm.doctype;
- }else{
- this.doc = "Inbox";
- }
- }
- if (cur_frm && cur_frm.docname) {
- this.key = cur_frm.docname;
+ setup_last_edited_communication() {
+ if (this.frm) {
+ this.doctype = this.frm.doctype;
+ this.key = this.frm.docname;
} else {
- this.key = "Inbox";
+ this.doctype = this.key = "Inbox";
}
- if(this.last_email) {
+
+ if (this.last_email) {
this.key = this.key + ":" + this.last_email.name;
}
- if(this.subject){
+
+ if (this.subject) {
this.key = this.key + ":" + this.subject;
}
- this.dialog.onhide = function() {
- var last_edited_communication = me.get_last_edited_communication();
- $.extend(last_edited_communication, {
- sender: me.dialog.get_value("sender"),
- recipients: me.dialog.get_value("recipients"),
- cc: me.dialog.get_value("cc"),
- bcc: me.dialog.get_value("bcc"),
- subject: me.dialog.get_value("subject"),
- content: me.dialog.get_value("content"),
- });
- if (me.frm) {
- $(document).trigger("form-stopped-typing", [me.frm]);
+ this.dialog.on_hide = () => {
+ $.extend(
+ this.get_last_edited_communication(true),
+ this.dialog.get_values(true)
+ );
+
+ if (this.frm) {
+ $(document).trigger("form-stopped-typing", [this.frm]);
}
}
+ },
- this.dialog.on_page_show = function() {
- if (!me.txt) {
- var last_edited_communication = me.get_last_edited_communication();
- if(last_edited_communication.content) {
- me.dialog.set_value("sender", last_edited_communication.sender || "");
- me.dialog.set_value("subject", last_edited_communication.subject || "");
- me.dialog.set_value("recipients", last_edited_communication.recipients || "");
- me.dialog.set_value("cc", last_edited_communication.cc || "");
- me.dialog.set_value("bcc", last_edited_communication.bcc || "");
- me.dialog.set_value("content", last_edited_communication.content || "");
- }
+ get_last_edited_communication(clear) {
+ if (!frappe.last_edited_communication[this.doctype]) {
+ frappe.last_edited_communication[this.doctype] = {};
+ }
+
+ if (clear || !frappe.last_edited_communication[this.doctype][this.key]) {
+ frappe.last_edited_communication[this.doctype][this.key] = {};
+ console.log('cleared!');
+ }
+
+ return frappe.last_edited_communication[this.doctype][this.key];
+ },
+
+ set_values: async function () {
+ for (const fieldname of ["recipients", "cc", "bcc", "sender"]) {
+ await this.dialog.set_value(fieldname, this[fieldname] || "");
+ }
+
+ const subject = frappe.utils.html2text(this.subject) || '';
+ await this.dialog.set_value("subject", subject);
+
+ await this.set_values_from_last_edited_communication();
+ await this.set_content();
+
+ // set default email template for the first email in a document
+ if (this.frm && !this.is_a_reply && !this.content_set) {
+ const email_template = this.frm.meta.default_email_template || '';
+ await this.dialog.set_value("email_template", email_template);
+ }
+
+ for (const fieldname of ['email_template', 'cc', 'bcc']) {
+ if (this.dialog.get_value(fieldname)) {
+ this.toggle_more_options(true);
+ break;
}
-
}
-
},
- get_last_edited_communication: function() {
- if (!frappe.last_edited_communication[this.doc]) {
- frappe.last_edited_communication[this.doc] = {};
+ set_values_from_last_edited_communication: async function () {
+ if (this.txt) return;
+
+ const last_edited = this.get_last_edited_communication();
+ if (!last_edited.content) return;
+
+ // prevent re-triggering of email template
+ if (last_edited.email_template) {
+ const template_field = this.dialog.fields_dict.email_template;
+ await template_field.set_model_value(last_edited.email_template);
+ delete last_edited.email_template;
}
- if(!frappe.last_edited_communication[this.doc][this.key]) {
- frappe.last_edited_communication[this.doc][this.key] = {};
- }
-
- return frappe.last_edited_communication[this.doc][this.key];
+ await this.dialog.set_values(last_edited);
+ this.content_set = true;
},
- selected_format: function() {
- return this.dialog.fields_dict.select_print_format.input.value || (this.frm && this.frm.meta.default_print_format) || "Standard";
+ selected_format() {
+ return (
+ this.dialog.fields_dict.select_print_format.input.value
+ || this.frm && this.frm.meta.default_print_format
+ || "Standard"
+ );
},
- get_print_format: function(format) {
+ get_print_format(format) {
if (!format) {
format = this.selected_format();
}
@@ -395,9 +382,9 @@ frappe.views.CommunicationComposer = Class.extend({
}
},
- setup_print_language: function() {
- var doc = this.doc || cur_frm.doc;
- var fields = this.dialog.fields_dict;
+ setup_print_language() {
+ const doc = this.frm && this.frm.doc;
+ const fields = this.dialog.fields_dict;
//Load default print language from doctype
this.lang_code = doc.language
@@ -407,7 +394,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
//On selection of language retrieve language code
- var me = this;
+ const me = this;
$(fields.language_sel.input).change(function(){
me.lang_code = this.value
})
@@ -422,9 +409,9 @@ frappe.views.CommunicationComposer = Class.extend({
}
},
- setup_print: function() {
+ setup_print() {
// print formats
- var fields = this.dialog.fields_dict;
+ const fields = this.dialog.fields_dict;
// toggle print format
$(fields.attach_document_print.input).click(function() {
@@ -434,8 +421,8 @@ frappe.views.CommunicationComposer = Class.extend({
// select print format
$(fields.select_print_format.wrapper).toggle(false);
- if (cur_frm) {
- const print_formats = frappe.meta.get_print_formats(cur_frm.meta.name);
+ if (this.frm) {
+ const print_formats = frappe.meta.get_print_formats(this.frm.meta.name);
$(fields.select_print_format.input)
.empty()
.add_options(print_formats)
@@ -446,9 +433,9 @@ frappe.views.CommunicationComposer = Class.extend({
},
- setup_attach: function() {
- var fields = this.dialog.fields_dict;
- var attach = $(fields.select_attachments.wrapper);
+ setup_attach() {
+ const fields = this.dialog.fields_dict;
+ const attach = $(fields.select_attachments.wrapper);
if (!this.attachments) {
this.attachments = [];
@@ -493,7 +480,7 @@ frappe.views.CommunicationComposer = Class.extend({
this.render_attachment_rows();
},
- render_attachment_rows: function(attachment) {
+ render_attachment_rows(attachment) {
const select_attachments = this.dialog.fields_dict.select_attachments;
const attachment_rows = $(select_attachments.wrapper).find(".attach-list");
if (attachment) {
@@ -536,9 +523,9 @@ frappe.views.CommunicationComposer = Class.extend({
`);
},
- setup_email: function() {
+ setup_email() {
// email
- var fields = this.dialog.fields_dict;
+ const fields = this.dialog.fields_dict;
if(this.attach_document_print) {
$(fields.attach_document_print.input).click();
@@ -547,21 +534,20 @@ frappe.views.CommunicationComposer = Class.extend({
$(fields.send_me_a_copy.input).on('click', () => {
// update send me a copy (make it sticky)
- let val = fields.send_me_a_copy.get_value();
+ const val = fields.send_me_a_copy.get_value();
frappe.db.set_value('User', frappe.session.user, 'send_me_a_copy', val);
frappe.boot.user.send_me_a_copy = val;
});
},
- send_action: function() {
- var me = this;
- var btn = me.dialog.get_primary_btn();
-
- var form_values = this.get_values();
+ send_action() {
+ const me = this;
+ const btn = me.dialog.get_primary_btn();
+ const form_values = this.get_values();
if(!form_values) return;
- var selected_attachments =
+ const selected_attachments =
$.map($(me.dialog.wrapper).find("[data-file-name]:checked"), function (element) {
return $(element).attr("data-file-name");
});
@@ -574,16 +560,16 @@ frappe.views.CommunicationComposer = Class.extend({
}
},
- get_values: function() {
- var form_values = this.dialog.get_values();
+ get_values() {
+ const form_values = this.dialog.get_values();
// cc
- for ( var i=0, l=this.dialog.fields.length; i < l; i++ ) {
- var df = this.dialog.fields[i];
+ for (let i = 0, l = this.dialog.fields.length; i < l; i++) {
+ const df = this.dialog.fields[i];
- if ( df.is_cc_checkbox ) {
+ if (df.is_cc_checkbox) {
// concat in cc
- if ( form_values[df.fieldname] ) {
+ if (form_values[df.fieldname]) {
form_values.cc = ( form_values.cc ? (form_values.cc + ", ") : "" ) + df.fieldname;
form_values.bcc = ( form_values.bcc ? (form_values.bcc + ", ") : "" ) + df.fieldname;
}
@@ -595,35 +581,40 @@ frappe.views.CommunicationComposer = Class.extend({
return form_values;
},
- save_as_draft: function() {
+ save_as_draft() {
if (this.dialog && this.frm) {
let message = this.dialog.get_value('content');
- message = message.split(frappe.separator_element)[0];
+ message = message.split(separator_element)[0];
localforage.setItem(this.frm.doctype + this.frm.docname, message).catch(e => {
if (e) {
// silently fail
console.log(e); // eslint-disable-line
- console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
+ console.warn('[Communication] IndexedDB is full. Cannot save message as draft'); // eslint-disable-line
}
});
}
},
+ clear_cache() {
+ this.delete_saved_draft();
+ this.get_last_edited_communication(true);
+ },
+
delete_saved_draft() {
if (this.dialog && this.frm) {
localforage.removeItem(this.frm.doctype + this.frm.docname).catch(e => {
if (e) {
// silently fail
console.log(e); // eslint-disable-line
- console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
+ console.warn('[Communication] IndexedDB is full. Cannot save message as draft'); // eslint-disable-line
}
});
}
},
- send_email: function(btn, form_values, selected_attachments, print_html, print_format) {
- var me = this;
+ send_email(btn, form_values, selected_attachments, print_html, print_format) {
+ const me = this;
me.dialog.hide();
if(!form_values.recipients) {
@@ -637,7 +628,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
- if(cur_frm && !frappe.model.can_email(me.doc.doctype, cur_frm)) {
+ if(this.frm && !frappe.model.can_email(me.doc.doctype, this.frm)) {
frappe.msgprint(__("You are not allowed to send emails related to this document"));
return;
}
@@ -658,15 +649,17 @@ frappe.views.CommunicationComposer = Class.extend({
send_me_a_copy: form_values.send_me_a_copy,
print_format: print_format,
sender: form_values.sender,
- sender_full_name: form_values.sender?frappe.user.full_name():undefined,
+ sender_full_name: form_values.sender
+ ? frappe.user.full_name()
+ : undefined,
email_template: form_values.email_template,
attachments: selected_attachments,
_lang : me.lang_code,
read_receipt:form_values.send_read_receipt,
print_letterhead: me.is_print_letterhead_checked(),
},
- btn: btn,
- callback: function(r) {
+ btn,
+ callback(r) {
if(!r.exc) {
frappe.utils.play_sound("email");
@@ -678,8 +671,8 @@ frappe.views.CommunicationComposer = Class.extend({
if ((frappe.last_edited_communication[me.doc] || {})[me.key]) {
delete frappe.last_edited_communication[me.doc][me.key];
}
- if (cur_frm) {
- cur_frm.reload_doc();
+ if (this.frm) {
+ this.frm.reload_doc();
}
// try the success callback if it exists
@@ -707,7 +700,7 @@ frappe.views.CommunicationComposer = Class.extend({
});
},
- is_print_letterhead_checked: function() {
+ is_print_letterhead_checked() {
if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){
return $(this.frm.wrapper).find('.print-letterhead').prop('checked') ? 1 : 0;
} else {
@@ -716,96 +709,96 @@ frappe.views.CommunicationComposer = Class.extend({
}
},
- get_default_outgoing_email_account_signature: function() {
- return frappe.db.get_value('Email Account', { 'default_outgoing': 1, 'add_signature': 1 }, 'signature');
- },
+ set_content: async function() {
+ if (this.content_set) return;
- setup_earlier_reply: async function() {
- let fields = this.dialog.fields_dict;
- let signature = frappe.boot.user.email_signature || "";
-
- if (!signature) {
- const res = await this.get_default_outgoing_email_account_signature();
- signature = "" + res.message.signature;
+ let message = this.txt || "";
+ if (!message && this.frm) {
+ const { doctype, docname } = this.frm;
+ message = await localforage.getItem(doctype + docname) || "";
}
- if (signature && !frappe.utils.is_html(signature)) {
- signature = signature.replace(/\n/g, " ");
+ if (message) {
+ this.content_set = true;
}
- if(this.txt) {
- this.message = this.txt + (this.message ? (" " + this.message) : "");
- } else {
- // saved draft in localStorage
- const { doctype, docname } = this.frm || {};
- if (doctype && docname) {
- this.message = await localforage.getItem(doctype + docname) || '';
- }
- }
-
- if(this.real_name) {
- this.message = ''+__('Dear') +' '
- + this.real_name + ",
" + (this.message || "");
- }
-
- if(this.message && signature && this.message.includes(signature)) {
- signature = "";
- }
-
- let reply = (this.message || "") + (signature ? (" " + signature) : "");
- let content = '';
-
- if (this.is_a_reply === 'undefined') {
- this.is_a_reply = true;
+ message += await this.get_signature();
+ if (this.real_name && !message.includes("")) {
+ message = `${__('Dear')} ${this.real_name},
+ ${message}`;
}
if (this.is_a_reply) {
- let last_email = this.last_email;
-
- if (!last_email) {
- last_email = this.frm && this.frm.timeline.get_last_email(true);
- }
-
- if (!last_email) return;
-
- let last_email_content = last_email.original_comment || last_email.content;
-
- // convert the email context to text as we are enclosing
- // this inside
- last_email_content = this.html2text(last_email_content).replace(/\n/g, ' ');
-
- // clip last email for a maximum of 20k characters
- // to prevent the email content from getting too large
- if (last_email_content.length > 20 * 1024) {
- last_email_content += '' + __('Message clipped') + '
' + last_email_content;
- last_email_content = last_email_content.slice(0, 20 * 1024);
- }
-
- let communication_date = last_email.communication_date || last_email.creation;
- content = `
- ${reply}
-
- ${frappe.separator_element || ''}
- ${__("On {0}, {1} wrote:", [frappe.datetime.global_date_format(communication_date) , last_email.sender])}
-
- ${last_email_content}
-
- `;
- } else {
- content = reply;
+ message += this.get_earlier_reply();
}
- fields.content.set_value(content);
+
+ await this.dialog.set_value("content", message);
},
- html2text: function(html) {
+ get_signature: async function () {
+ let signature = frappe.boot.user.email_signature;
+
+ if (!signature) {
+ const response = await frappe.db.get_value(
+ 'Email Account',
+ {'default_outgoing': 1, 'add_signature': 1},
+ 'signature'
+ );
+
+ signature = response.message.signature;
+ }
+
+ if (!signature) return "";
+
+ if (!frappe.utils.is_html(signature)) {
+ signature = signature.replace(/\n/g, " ");
+ }
+
+ return " " + signature;
+ },
+
+ get_earlier_reply() {
+ const last_email = (
+ this.last_email
+ || this.frm && this.frm.timeline.get_last_email(true)
+ );
+
+ if (!last_email) return "";
+ let last_email_content = last_email.original_comment || last_email.content;
+
+ // convert the email context to text as we are enclosing
+ // this inside
+ last_email_content = this.html2text(last_email_content).replace(/\n/g, ' ');
+
+ // clip last email for a maximum of 20k characters
+ // to prevent the email content from getting too large
+ if (last_email_content.length > 20 * 1024) {
+ last_email_content += '' + __('Message clipped') + '
' + last_email_content;
+ last_email_content = last_email_content.slice(0, 20 * 1024);
+ }
+
+ const communication_date = last_email.communication_date || last_email.creation;
+ return `
+
+ ${separator_element || ''}
+ ${__("On {0}, {1} wrote:", [
+ frappe.datetime.global_date_format(communication_date),
+ last_email.sender
+ ])}
+
+ ${last_email_content}
+
+ `;
+ },
+
+ html2text(html) {
// convert HTML to text and try and preserve whitespace
- var d = document.createElement( 'div' );
+ const d = document.createElement( 'div' );
d.innerHTML = html.replace(/<\/div>/g, ' ') // replace end of blocks
.replace(/<\/p>/g, ' ') // replace end of paragraphs
.replace(/ /g, '\n');
- let text = d.textContent;
// replace multiple empty lines with just one
- return text.replace(/\n{3,}/g, '\n\n');
+ return d.textContent.replace(/\n{3,}/g, '\n\n');
}
});
From e4527284d735e7b472bbbf0fad1ed7d299d5335a Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 02:12:12 +0530
Subject: [PATCH 018/623] fix: sider issues
---
.../public/js/frappe/views/communication.js | 41 ++++++++++---------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 7cf7b32797..c3e6dfe00a 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -187,7 +187,7 @@ frappe.views.CommunicationComposer = Class.extend({
this.dialog.fields_dict[field].set_data(r.message);
}
});
- }
+ };
});
},
@@ -210,12 +210,12 @@ frappe.views.CommunicationComposer = Class.extend({
if (last) {
this.subject = last.subject;
- if(!this.recipients) {
+ if (!this.recipients) {
this.recipients = last.sender;
}
// prepend "Re:"
- if(strip(this.subject.toLowerCase().split(":")[0])!="re") {
+ if (strip(this.subject.toLowerCase().split(":")[0])!="re") {
this.subject = __("Re: {0}", [this.subject]);
}
}
@@ -304,7 +304,7 @@ frappe.views.CommunicationComposer = Class.extend({
if (this.frm) {
$(document).trigger("form-stopped-typing", [this.frm]);
}
- }
+ };
},
get_last_edited_communication(clear) {
@@ -314,7 +314,6 @@ frappe.views.CommunicationComposer = Class.extend({
if (clear || !frappe.last_edited_communication[this.doctype][this.key]) {
frappe.last_edited_communication[this.doctype][this.key] = {};
- console.log('cleared!');
}
return frappe.last_edited_communication[this.doctype][this.key];
@@ -527,7 +526,7 @@ frappe.views.CommunicationComposer = Class.extend({
// email
const fields = this.dialog.fields_dict;
- if(this.attach_document_print) {
+ if (this.attach_document_print) {
$(fields.attach_document_print.input).click();
$(fields.select_print_format.wrapper).toggle(true);
}
@@ -545,7 +544,7 @@ frappe.views.CommunicationComposer = Class.extend({
const me = this;
const btn = me.dialog.get_primary_btn();
const form_values = this.get_values();
- if(!form_values) return;
+ if (!form_values) return;
const selected_attachments =
$.map($(me.dialog.wrapper).find("[data-file-name]:checked"), function (element) {
@@ -553,7 +552,7 @@ frappe.views.CommunicationComposer = Class.extend({
});
- if(form_values.attach_document_print) {
+ if (form_values.attach_document_print) {
me.send_email(btn, form_values, selected_attachments, null, form_values.select_print_format || "");
} else {
me.send_email(btn, form_values, selected_attachments);
@@ -617,18 +616,18 @@ frappe.views.CommunicationComposer = Class.extend({
const me = this;
me.dialog.hide();
- if(!form_values.recipients) {
+ if (!form_values.recipients) {
frappe.msgprint(__("Enter Email Recipient(s)"));
return;
}
- if(!form_values.attach_document_print) {
+ if (!form_values.attach_document_print) {
print_html = null;
print_format = null;
}
- if(this.frm && !frappe.model.can_email(me.doc.doctype, this.frm)) {
+ if (this.frm && !frappe.model.can_email(me.doc.doctype, this.frm)) {
frappe.msgprint(__("You are not allowed to send emails related to this document"));
return;
}
@@ -660,10 +659,10 @@ frappe.views.CommunicationComposer = Class.extend({
},
btn,
callback(r) {
- if(!r.exc) {
+ if (!r.exc) {
frappe.utils.play_sound("email");
- if(r.message["emails_not_sent_to"]) {
+ if (r.message["emails_not_sent_to"]) {
frappe.msgprint(__("Email not sent to {0} (unsubscribed / disabled)",
[ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) );
}
@@ -680,7 +679,7 @@ frappe.views.CommunicationComposer = Class.extend({
try {
me.success(r);
} catch (e) {
- console.log(e);
+ console.log(e); // eslint-disable-line
}
}
@@ -692,7 +691,7 @@ frappe.views.CommunicationComposer = Class.extend({
try {
me.error(r);
} catch (e) {
- console.log(e);
+ console.log(e); // eslint-disable-line
}
}
}
@@ -777,14 +776,16 @@ frappe.views.CommunicationComposer = Class.extend({
last_email_content = last_email_content.slice(0, 20 * 1024);
}
- const communication_date = last_email.communication_date || last_email.creation;
+ const communication_date = frappe.datetime.global_date_format(
+ last_email.communication_date || last_email.creation
+ );
+
return `
${separator_element || ''}
- ${__("On {0}, {1} wrote:", [
- frappe.datetime.global_date_format(communication_date),
- last_email.sender
- ])}
+
+ ${__("On {0}, {1} wrote:", [communication_date, last_email.sender])}
+
${last_email_content}
From 4a28b2f20285fe4d481a28f50b0473c20147e095 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 02:36:52 +0530
Subject: [PATCH 019/623] fix: set lang to frappe.boot.lang by default
---
frappe/public/js/frappe/views/communication.js | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index c3e6dfe00a..34201a7900 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -387,10 +387,8 @@ frappe.views.CommunicationComposer = Class.extend({
//Load default print language from doctype
this.lang_code = doc.language
-
- if (!this.lang_code && this.get_print_format().default_print_language) {
- this.lang_code = this.get_print_format().default_print_language;
- }
+ || this.get_print_format().default_print_language
+ || frappe.boot.lang;
//On selection of language retrieve language code
const me = this;
From 354e89f4c60e241bbc16b64d0fd6c8dd995f1130 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 03:24:01 +0530
Subject: [PATCH 020/623] fix: clear_cache only on success; use me instead of
this
---
frappe/public/js/frappe/views/communication.js | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 34201a7900..ef05ef5857 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -17,16 +17,15 @@ frappe.views.CommunicationComposer = Class.extend({
no_submit_on_enter: true,
fields: this.get_fields(),
primary_action_label: __("Send"),
- size: 'large',
primary_action() {
me.send_action();
- me.clear_cache();
},
secondary_action_label: __("Discard"),
secondary_action() {
me.dialog.hide();
me.clear_cache();
},
+ size: 'large',
minimizable: true
});
@@ -665,11 +664,10 @@ frappe.views.CommunicationComposer = Class.extend({
[ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) );
}
- if ((frappe.last_edited_communication[me.doc] || {})[me.key]) {
- delete frappe.last_edited_communication[me.doc][me.key];
- }
- if (this.frm) {
- this.frm.reload_doc();
+ me.clear_cache();
+
+ if (me.frm) {
+ me.frm.reload_doc();
}
// try the success callback if it exists
From 01cd2308bbc6a5e7029eecc67dd4ab3ac55dd4e5 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 03:53:41 +0530
Subject: [PATCH 021/623] fix: Cannot read property `current` of undefined
---
frappe/public/js/frappe/form/form_viewers.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index 3d488e4729..964576ef8a 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -7,6 +7,11 @@ frappe.ui.form.FormViewers = class FormViewers {
refresh() {
let users = this.frm.get_docinfo()['viewers'];
+ if (!users || !users.current || !users.current.length) {
+ this.parent.empty();
+ return;
+ }
+
let currently_viewing = users.current.filter(user => user != frappe.session.user);
let avatar_group = frappe.avatar_group(currently_viewing, 5, {'align': 'left', 'overlap': true});
this.parent.empty().append(avatar_group);
From 47d13a40c754949fc2110ab667dfaad6716c3f3d Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 12:21:19 +0530
Subject: [PATCH 022/623] style: use ES6 class
---
.../public/js/frappe/views/communication.js | 75 ++++++++++---------
1 file changed, 38 insertions(+), 37 deletions(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index ef05ef5857..77cc91b4ba 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -4,11 +4,12 @@
frappe.last_edited_communication = {};
const separator_element = '---
';
-frappe.views.CommunicationComposer = Class.extend({
- init(opts) {
+frappe.views.CommunicationComposer = class {
+ constructor(opts) {
$.extend(this, opts);
this.make();
- },
+ }
+
make() {
const me = this;
@@ -37,7 +38,7 @@ frappe.views.CommunicationComposer = Class.extend({
if (this.frm) {
$(document).trigger('form-typing', [this.frm]);
}
- },
+ }
get_fields() {
const fields = [
@@ -151,7 +152,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
return fields;
- },
+ }
toggle_more_options(show_options) {
show_options = show_options || this.dialog.fields_dict.more_options.df.hidden;
@@ -159,7 +160,7 @@ frappe.views.CommunicationComposer = Class.extend({
const label = frappe.utils.icon(show_options ? 'up-line': 'down');
this.dialog.get_field('option_toggle_button').set_label(label);
- },
+ }
prepare() {
this.setup_multiselect_queries();
@@ -171,7 +172,7 @@ frappe.views.CommunicationComposer = Class.extend({
this.setup_email_template();
this.setup_last_edited_communication();
this.set_values();
- },
+ }
setup_multiselect_queries() {
['recipients', 'cc', 'bcc'].forEach(field => {
@@ -188,7 +189,7 @@ frappe.views.CommunicationComposer = Class.extend({
});
};
});
- },
+ }
setup_subject_and_recipients() {
this.subject = this.subject || "";
@@ -240,7 +241,7 @@ frappe.views.CommunicationComposer = Class.extend({
if (this.frm && !this.recipients) {
this.recipients = this.frm.doc[this.frm.email_field];
}
- },
+ }
setup_email_template() {
const me = this;
@@ -276,7 +277,7 @@ frappe.views.CommunicationComposer = Class.extend({
},
});
}
- },
+ }
setup_last_edited_communication() {
if (this.frm) {
@@ -304,7 +305,7 @@ frappe.views.CommunicationComposer = Class.extend({
$(document).trigger("form-stopped-typing", [this.frm]);
}
};
- },
+ }
get_last_edited_communication(clear) {
if (!frappe.last_edited_communication[this.doctype]) {
@@ -316,9 +317,9 @@ frappe.views.CommunicationComposer = Class.extend({
}
return frappe.last_edited_communication[this.doctype][this.key];
- },
+ }
- set_values: async function () {
+ async set_values() {
for (const fieldname of ["recipients", "cc", "bcc", "sender"]) {
await this.dialog.set_value(fieldname, this[fieldname] || "");
}
@@ -341,9 +342,9 @@ frappe.views.CommunicationComposer = Class.extend({
break;
}
}
- },
+ }
- set_values_from_last_edited_communication: async function () {
+ async set_values_from_last_edited_communication() {
if (this.txt) return;
const last_edited = this.get_last_edited_communication();
@@ -358,7 +359,7 @@ frappe.views.CommunicationComposer = Class.extend({
await this.dialog.set_values(last_edited);
this.content_set = true;
- },
+ }
selected_format() {
return (
@@ -366,7 +367,7 @@ frappe.views.CommunicationComposer = Class.extend({
|| this.frm && this.frm.meta.default_print_format
|| "Standard"
);
- },
+ }
get_print_format(format) {
if (!format) {
@@ -378,7 +379,7 @@ frappe.views.CommunicationComposer = Class.extend({
} else {
return {};
}
- },
+ }
setup_print_language() {
const doc = this.frm && this.frm.doc;
@@ -403,7 +404,7 @@ frappe.views.CommunicationComposer = Class.extend({
if (this.lang_code) {
$(fields.language_sel.input).val(this.lang_code);
}
- },
+ }
setup_print() {
// print formats
@@ -427,7 +428,7 @@ frappe.views.CommunicationComposer = Class.extend({
$(fields.attach_document_print.wrapper).toggle(false);
}
- },
+ }
setup_attach() {
const fields = this.dialog.fields_dict;
@@ -474,7 +475,7 @@ frappe.views.CommunicationComposer = Class.extend({
.find(".add-more-attachments button")
.on('click', () => new frappe.ui.FileUploader(args));
this.render_attachment_rows();
- },
+ }
render_attachment_rows(attachment) {
const select_attachments = this.dialog.fields_dict.select_attachments;
@@ -500,7 +501,7 @@ frappe.views.CommunicationComposer = Class.extend({
});
}
}
- },
+ }
get_attachment_row(attachment, checked) {
return $(`
@@ -517,7 +518,7 @@ frappe.views.CommunicationComposer = Class.extend({
${frappe.utils.icon('link-url')}
`);
- },
+ }
setup_email() {
// email
@@ -535,7 +536,7 @@ frappe.views.CommunicationComposer = Class.extend({
frappe.boot.user.send_me_a_copy = val;
});
- },
+ }
send_action() {
const me = this;
@@ -554,7 +555,7 @@ frappe.views.CommunicationComposer = Class.extend({
} else {
me.send_email(btn, form_values, selected_attachments);
}
- },
+ }
get_values() {
const form_values = this.dialog.get_values();
@@ -575,7 +576,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
return form_values;
- },
+ }
save_as_draft() {
if (this.dialog && this.frm) {
@@ -590,12 +591,12 @@ frappe.views.CommunicationComposer = Class.extend({
});
}
- },
+ }
clear_cache() {
this.delete_saved_draft();
this.get_last_edited_communication(true);
- },
+ }
delete_saved_draft() {
if (this.dialog && this.frm) {
@@ -607,7 +608,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
});
}
- },
+ }
send_email(btn, form_values, selected_attachments, print_html, print_format) {
const me = this;
@@ -693,7 +694,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
}
});
- },
+ }
is_print_letterhead_checked() {
if (this.frm && $(this.frm.wrapper).find('.form-print-wrapper').is(':visible')){
@@ -702,9 +703,9 @@ frappe.views.CommunicationComposer = Class.extend({
return (frappe.model.get_doc(":Print Settings", "Print Settings") ||
{ with_letterhead: 1 }).with_letterhead ? 1 : 0;
}
- },
+ }
- set_content: async function() {
+ async set_content() {
if (this.content_set) return;
let message = this.txt || "";
@@ -728,9 +729,9 @@ frappe.views.CommunicationComposer = Class.extend({
}
await this.dialog.set_value("content", message);
- },
+ }
- get_signature: async function () {
+ async get_signature() {
let signature = frappe.boot.user.email_signature;
if (!signature) {
@@ -750,7 +751,7 @@ frappe.views.CommunicationComposer = Class.extend({
}
return " " + signature;
- },
+ }
get_earlier_reply() {
const last_email = (
@@ -786,7 +787,7 @@ frappe.views.CommunicationComposer = Class.extend({
${last_email_content}
`;
- },
+ }
html2text(html) {
// convert HTML to text and try and preserve whitespace
@@ -798,4 +799,4 @@ frappe.views.CommunicationComposer = Class.extend({
// replace multiple empty lines with just one
return d.textContent.replace(/\n{3,}/g, '\n\n');
}
-});
+};
From c02fbb27b641153be54dd5025e7b183e19ac181a Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 12:24:00 +0530
Subject: [PATCH 023/623] fix: sider issue
---
frappe/public/js/frappe/views/communication.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 77cc91b4ba..0479ec6d31 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -276,7 +276,7 @@ frappe.views.CommunicationComposer = class {
prepend_reply(r.message);
},
});
- }
+ };
}
setup_last_edited_communication() {
From 513835a92ce755d5361e1ef8e52269f7561a7983 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sat, 17 Apr 2021 13:12:19 +0530
Subject: [PATCH 024/623] test: no need to blur text editor
---
cypress/integration/form.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cypress/integration/form.js b/cypress/integration/form.js
index 5302ed0964..20ed7a61cd 100644
--- a/cypress/integration/form.js
+++ b/cypress/integration/form.js
@@ -8,7 +8,7 @@ context('Form', () => {
});
it('create a new form', () => {
cy.visit('/app/todo/new');
- cy.fill_field('description', 'this is a test todo', 'Text Editor').blur();
+ cy.fill_field('description', 'this is a test todo', 'Text Editor');
cy.wait(300);
cy.get('.page-title').should('contain', 'Not Saved');
cy.intercept({
From 1fd08d39606d71b9fc2a3be368e3558d65cf8b36 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 07:31:24 +0530
Subject: [PATCH 025/623] refactor: Jinja hooks
- Rename hook from "jenv" to "jinja"
- You can now pass the path to the module and all of the methods in that
module will be added as methods
- You can also pass module path of a method
BREAKING CHANGE: Previous use of "jenv" hook won't work anymore
---
frappe/hooks.py | 4 ++
frappe/utils/jinja.py | 111 +++++++++-------------------------
frappe/utils/jinja_globals.py | 71 ++++++++++++++++++++++
3 files changed, 102 insertions(+), 84 deletions(-)
create mode 100644 frappe/utils/jinja_globals.py
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 74c538c5df..c47afadf58 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -130,6 +130,10 @@ has_website_permission = {
"Address": "frappe.contacts.doctype.address.address.has_website_permission"
}
+jinja = {
+ "methods": "frappe.utils.jinja_globals"
+}
+
standard_queries = {
"User": "frappe.core.doctype.user.user.user_query"
}
diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py
index cd74b2a283..1b2ef9f47f 100644
--- a/frappe/utils/jinja.py
+++ b/frappe/utils/jinja.py
@@ -18,13 +18,10 @@ def get_jenv():
set_filters(jenv)
jenv.globals.update(get_safe_globals())
- jenv.globals.update(get_jenv_customization('methods'))
- jenv.globals.update({
- 'resolve_class': resolve_class,
- 'inspect': inspect,
- 'web_blocks': web_blocks,
- 'web_block': web_block
- })
+
+ methods, filters = get_jinja_hooks('methods')
+ jenv.globals.update(methods or {})
+ jenv.filters.update(filters or {})
frappe.local.jenv = jenv
@@ -143,88 +140,34 @@ def set_filters(jenv):
if frappe.flags.in_setup_help:
return
- jenv.filters.update(get_jenv_customization('filters'))
-
-
-def get_jenv_customization(customization_type):
- '''Returns a dict with filter/method name as key and definition as value'''
+def get_jinja_hooks():
+ """Returns a tuple of (methods, filters) each containing a dict of method name and method definition pair."""
import frappe
- out = {}
if not getattr(frappe.local, "site", None):
+ return (None, None)
+
+ from types import FunctionType, ModuleType
+ from inspect import getmembers, isfunction
+
+ def get_obj_dict_from_paths(object_paths):
+ out = {}
+ for obj_path in object_paths:
+ obj = frappe.get_attr(obj_path)
+ if isinstance(obj, ModuleType):
+ functions = getmembers(obj, isfunction)
+ for function_name, function in functions:
+ out[function_name] = function
+ elif isinstance(obj, FunctionType):
+ function_name = obj.__name__
+ out[function_name] = obj
return out
- values = frappe.get_hooks("jenv", {}).get(customization_type)
- if not values:
- return out
+ values = frappe.get_hooks("jinja")
+ methods, filters = values.get("methods", []), values.get("filters", [])
- for value in values:
- fn_name, fn_string = value.split(":")
- out[fn_name] = frappe.get_attr(fn_string)
+ method_dict = get_obj_dict_from_paths(methods)
+ filter_dict = get_obj_dict_from_paths(filters)
- return out
-
-
-def resolve_class(classes):
- import frappe
-
- if classes is None:
- return ''
-
- if isinstance(classes, frappe.string_types):
- return classes
-
- if isinstance(classes, (list, tuple)):
- return ' '.join([resolve_class(c) for c in classes]).strip()
-
- if isinstance(classes, dict):
- return ' '.join([classname for classname in classes if classes[classname]]).strip()
-
- return classes
-
-
-def inspect(var, render=True):
- context = { "var": var }
- if render:
- html = "{{ var | pprint | e }} "
- else:
- html = ""
- return get_jenv().from_string(html).render(context)
-
-
-def web_block(template, values=None, **kwargs):
- options = {"template": template, "values": values}
- options.update(kwargs)
- return web_blocks([options])
-
-
-def web_blocks(blocks):
- from frappe import throw, _dict
- from frappe.website.doctype.web_page.web_page import get_web_blocks_html
-
- web_blocks = []
- for block in blocks:
- if not block.get('template'):
- throw('Web Template is not specified')
-
- doc = _dict({
- 'doctype': 'Web Page Block',
- 'web_template': block['template'],
- 'web_template_values': block.get('values', {}),
- 'add_top_padding': 1,
- 'add_bottom_padding': 1,
- 'add_container': 1,
- 'hide_block': 0,
- 'css_class': ''
- })
- doc.update(block)
- web_blocks.append(doc)
-
- out = get_web_blocks_html(web_blocks)
-
- html = out.html
- for script in out.scripts:
- html += ''.format(script)
-
- return html
+ return method_dict, filter_dict
diff --git a/frappe/utils/jinja_globals.py b/frappe/utils/jinja_globals.py
new file mode 100644
index 0000000000..e63926a109
--- /dev/null
+++ b/frappe/utils/jinja_globals.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+from frappe.utils.jinja import get_jenv
+import frappe
+
+
+def resolve_class(classes):
+ if classes is None:
+ return ""
+
+ if isinstance(classes, frappe.string_types):
+ return classes
+
+ if isinstance(classes, (list, tuple)):
+ return " ".join([resolve_class(c) for c in classes]).strip()
+
+ if isinstance(classes, dict):
+ return " ".join([classname for classname in classes if classes[classname]]).strip()
+
+ return classes
+
+
+def inspect(var, render=True):
+ context = {"var": var}
+ if render:
+ html = "{{ var | pprint | e }} "
+ else:
+ return ""
+ return get_jenv().from_string(html).render(context)
+
+
+def web_block(template, values=None, **kwargs):
+ options = {"template": template, "values": values}
+ options.update(kwargs)
+ return web_blocks([options])
+
+
+def web_blocks(blocks):
+ from frappe import throw, _dict
+ from frappe.website.doctype.web_page.web_page import get_web_blocks_html
+
+ web_blocks = []
+ for block in blocks:
+ if not block.get("template"):
+ throw("Web Template is not specified")
+
+ doc = _dict(
+ {
+ "doctype": "Web Page Block",
+ "web_template": block["template"],
+ "web_template_values": block.get("values", {}),
+ "add_top_padding": 1,
+ "add_bottom_padding": 1,
+ "add_container": 1,
+ "hide_block": 0,
+ "css_class": "",
+ }
+ )
+ doc.update(block)
+ web_blocks.append(doc)
+
+ out = get_web_blocks_html(web_blocks)
+
+ html = out.html
+ for script in out.scripts:
+ html += "".format(script)
+
+ return html
+
From a62ef80cddedec855e592fbe77a4ab7cdede8bad Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 07:41:04 +0530
Subject: [PATCH 026/623] fix: Add jinja hook boilerplate
---
frappe/utils/boilerplate.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py
index e59f579f75..80eda0af13 100755
--- a/frappe/utils/boilerplate.py
+++ b/frappe/utils/boilerplate.py
@@ -190,6 +190,15 @@ app_license = "{app_license}"
# automatically create page for each record of this doctype
# website_generators = ["Web Page"]
+# Jinja
+# ----------
+
+# add methods and filters to jinja environment
+# jinja = {{
+# "methods": "{app_name}.utils.jinja_methods",
+# "filters": "{app_name}.utils.jinja_filters"
+# }}
+
# Installation
# ------------
From a78fed4ffccbe3faa628eb7d6a25affc9887023e Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 07:52:04 +0530
Subject: [PATCH 027/623] fix: Move standard filters to jinja hooks
---
frappe/hooks.py | 8 +++++++-
frappe/utils/jinja.py | 7 +------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/frappe/hooks.py b/frappe/hooks.py
index c47afadf58..1c78d47755 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -131,7 +131,13 @@ has_website_permission = {
}
jinja = {
- "methods": "frappe.utils.jinja_globals"
+ "methods": "frappe.utils.jinja_globals",
+ "filters": [
+ "frappe.utils.data.global_date_format",
+ "frappe.utils.markdown",
+ "frappe.website.utils.get_shade",
+ "frappe.website.utils.abs_url",
+ ]
}
standard_queries = {
diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py
index 1b2ef9f47f..6d25f4a405 100644
--- a/frappe/utils/jinja.py
+++ b/frappe/utils/jinja.py
@@ -124,18 +124,13 @@ def get_jloader():
def set_filters(jenv):
import frappe
- from frappe.utils import global_date_format, cint, cstr, flt, markdown
- from frappe.website.utils import get_shade, abs_url
+ from frappe.utils import cint, cstr, flt
- jenv.filters["global_date_format"] = global_date_format
- jenv.filters["markdown"] = markdown
jenv.filters["json"] = frappe.as_json
- jenv.filters["get_shade"] = get_shade
jenv.filters["len"] = len
jenv.filters["int"] = cint
jenv.filters["str"] = cstr
jenv.filters["flt"] = flt
- jenv.filters["abs_url"] = abs_url
if frappe.flags.in_setup_help:
return
From b32db6e329a006c1e0eedd93ceb53930db1753f5 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 16:03:25 +0530
Subject: [PATCH 028/623] fix: method call
---
frappe/utils/jinja.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py
index 6d25f4a405..42ab267381 100644
--- a/frappe/utils/jinja.py
+++ b/frappe/utils/jinja.py
@@ -19,7 +19,7 @@ def get_jenv():
jenv.globals.update(get_safe_globals())
- methods, filters = get_jinja_hooks('methods')
+ methods, filters = get_jinja_hooks()
jenv.globals.update(methods or {})
jenv.filters.update(filters or {})
From edef0a467d2ad993a68bfd78e2ad844a210851ff Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Sat, 17 Apr 2021 18:31:43 +0200
Subject: [PATCH 029/623] fix: test_token_cache PermissionError
---
frappe/integrations/doctype/token_cache/test_token_cache.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/integrations/doctype/token_cache/test_token_cache.py b/frappe/integrations/doctype/token_cache/test_token_cache.py
index 73c9f38fce..7aa069647d 100644
--- a/frappe/integrations/doctype/token_cache/test_token_cache.py
+++ b/frappe/integrations/doctype/token_cache/test_token_cache.py
@@ -13,7 +13,7 @@ class TestTokenCache(unittest.TestCase):
def setUp(self):
self.token_cache = frappe.get_last_doc('Token Cache')
self.token_cache.update({'connected_app': frappe.get_last_doc('Connected App').name})
- self.token_cache.save()
+ self.token_cache.save(ignore_permissions=True)
def test_get_auth_header(self):
self.token_cache.get_auth_header()
From d927d393eeecd825189d6364af5ffbefcc912341 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 23:09:16 +0530
Subject: [PATCH 030/623] fix: Add autocompletion items in Server Script
- API to add autocompletion items in Code field
---
frappe/cache_manager.py | 2 +-
.../doctype/server_script/server_script.js | 6 +++
.../doctype/server_script/server_script.py | 23 ++++++++-
frappe/public/js/frappe/form/controls/code.js | 50 +++++++++++++++++++
4 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/frappe/cache_manager.py b/frappe/cache_manager.py
index bad879d2fa..4e0fe0cf44 100644
--- a/frappe/cache_manager.py
+++ b/frappe/cache_manager.py
@@ -18,7 +18,7 @@ global_cache_keys = ("app_hooks", "installed_apps", 'all_apps',
'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
'active_modules', 'assignment_rule', 'server_script_map', 'wkhtmltopdf_version',
'domain_restricted_doctypes', 'domain_restricted_pages', 'information_schema:counts',
- 'sitemap_routes', 'db_tables') + doctype_map_keys
+ 'sitemap_routes', 'db_tables', 'server_script_autocompletion_items') + doctype_map_keys
user_cache_keys = ("bootinfo", "user_recent", "roles", "user_doc", "lang",
"defaults", "user_permissions", "home_page", "linked_with",
diff --git a/frappe/core/doctype/server_script/server_script.js b/frappe/core/doctype/server_script/server_script.js
index 95a63780f8..e12200b6fc 100644
--- a/frappe/core/doctype/server_script/server_script.js
+++ b/frappe/core/doctype/server_script/server_script.js
@@ -9,6 +9,12 @@ frappe.ui.form.on('Server Script', {
if (frm.doc.script_type != 'Scheduler Event') {
frm.dashboard.hide();
}
+
+ frm.call('get_autocompletion_items')
+ .then(r => r.message)
+ .then(items => {
+ frm.set_df_property('script', 'autocompletions', items)
+ });
},
setup_help(frm) {
diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py
index 8838d9e954..6a8eb59c3a 100644
--- a/frappe/core/doctype/server_script/server_script.py
+++ b/frappe/core/doctype/server_script/server_script.py
@@ -5,11 +5,12 @@
from __future__ import unicode_literals
import ast
+from types import FunctionType, ModuleType
from typing import Dict, List
import frappe
from frappe.model.document import Document
-from frappe.utils.safe_exec import safe_exec
+from frappe.utils.safe_exec import get_safe_globals, safe_exec, NamespaceDict
from frappe import _
@@ -122,6 +123,26 @@ class ServerScript(Document):
if locals["conditions"]:
return locals["conditions"]
+ @frappe.whitelist()
+ def get_autocompletion_items(self):
+ def get_keys(obj):
+ out = []
+ for key in obj:
+ if key.startswith('_'):
+ continue
+ value = obj[key]
+ if isinstance(value, (FunctionType, ModuleType)):
+ out.append(key)
+ elif isinstance(value, (NamespaceDict, dict)):
+ out += [f'{key}.{subkey}' for subkey in get_keys(value)]
+ return out
+
+ items = frappe.cache().get_value('server_script_autocompletion_items')
+ if not items:
+ items = get_keys(get_safe_globals())
+ frappe.cache().set_value('server_script_autocompletion_items', items)
+ return items
+
@frappe.whitelist()
def setup_scheduler_events(script_name, frequency):
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index eec450b390..8d2609b836 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -31,6 +31,56 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
const input_value = this.get_input_value();
this.parse_validate_and_set_in_model(input_value);
}, 300));
+
+ // setup autocompletion when it is set the first time
+ Object.defineProperty(this.df, 'autocompletions', {
+ get() {
+ return this._autocompletions || [];
+ },
+ set: (value) => {
+ this.setup_autocompletion();
+ this.df._autocompletions = value;
+ }
+ });
+ },
+
+ setup_autocompletion() {
+ if (this._autocompletion_setup) return;
+
+ const ace = window.ace;
+ const get_autocompletions = () => this.df.autocompletions;
+
+ ace.config.loadModule("ace/ext/language_tools", langTools => {
+ this.editor.setOptions({
+ enableBasicAutocompletion: true,
+ enableSnippets: true,
+ enableLiveAutocompletion: true
+ });
+
+ let completer = {
+ getCompletions: function(editor, session, pos, prefix, callback) {
+ if (prefix.length === 0) {
+ callback(null, []);
+ return;
+ }
+ let autocompletions = get_autocompletions();
+ if (autocompletions.length) {
+ callback(
+ null,
+ autocompletions.map(a => ({
+ name: 'frappe',
+ value: a,
+ score: 100,
+ meta: 'Frappe API'
+ }))
+ );
+ }
+ }
+ }
+ langTools.addCompleter(completer);
+ });
+
+ this._autocompletion_setup = true;
},
refresh_height() {
From 75822a323a2553c2f2190e12269fd0e36ed1cecc Mon Sep 17 00:00:00 2001
From: mustafaelagamey
Date: Sun, 18 Apr 2021 06:46:19 +0200
Subject: [PATCH 031/623] fix: Remove `cmd` only if exist (#12886)
* only remove cmd if exist
When calling this function from backend this line raises key error as there's no such key called cmd
* style: Simplify code
Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
---
frappe/desk/treeview.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/desk/treeview.py b/frappe/desk/treeview.py
index 12fdb0dadc..d479b71b52 100644
--- a/frappe/desk/treeview.py
+++ b/frappe/desk/treeview.py
@@ -66,7 +66,7 @@ def add_node():
doc.save()
def make_tree_args(**kwarg):
- del kwarg['cmd']
+ kwarg.pop('cmd', None)
doctype = kwarg['doctype']
parent_field = 'parent_' + doctype.lower().replace(' ', '_')
From 2bf968e753bbd35cf9cc37399ffc34adc67c093b Mon Sep 17 00:00:00 2001
From: Ernesto Ruiz
Date: Sat, 17 Apr 2021 22:54:12 -0600
Subject: [PATCH 032/623] fix: Make strings translatable (#12877)
Make strings translatable.
---
.../desk/doctype/notification_settings/notification_settings.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/desk/doctype/notification_settings/notification_settings.js b/frappe/desk/doctype/notification_settings/notification_settings.js
index 88dc145be2..cc2fd95204 100644
--- a/frappe/desk/doctype/notification_settings/notification_settings.js
+++ b/frappe/desk/doctype/notification_settings/notification_settings.js
@@ -19,7 +19,7 @@ frappe.ui.form.on('Notification Settings', {
refresh: (frm) => {
if (frappe.user.has_role('System Manager')) {
- frm.add_custom_button('Go to Notification Settings List', () => {
+ frm.add_custom_button(__('Go to Notification Settings List'), () => {
frappe.set_route('List', 'Notification Settings');
});
}
From 0d87ad2133e730c326cc0b7b81565ff5b251b343 Mon Sep 17 00:00:00 2001
From: Rushabh Mehta
Date: Sun, 18 Apr 2021 11:58:20 +0530
Subject: [PATCH 033/623] fix(minor): Add a delete trigger in grid, and use it
to refresh labels in Website Settings
---
frappe/public/js/frappe/form/grid.js | 6 +++++-
.../website_settings/website_settings.js | 18 +++++++++---------
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index b211476e63..86feefed7a 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -194,7 +194,10 @@ export default class Grid {
}
tasks.push(() => {
- if (dirty) this.refresh();
+ if (dirty) {
+ this.refresh();
+ this.frm.script_manager.trigger(this.df.fieldname + "_delete", this.doctype);
+ }
});
frappe.run_serially(tasks);
@@ -210,6 +213,7 @@ export default class Grid {
this.frm.doc[this.df.fieldname] = [];
$(this.parent).find('.rows').empty();
this.grid_rows = [];
+ this.frm.script_manager.trigger(this.df.fieldname + "_delete", this.doctype);
this.wrapper.find('.grid-heading-row .grid-row-check:checked:first').prop('checked', 0);
this.refresh();
diff --git a/frappe/website/doctype/website_settings/website_settings.js b/frappe/website/doctype/website_settings/website_settings.js
index 422deb244e..2f15b4c00e 100644
--- a/frappe/website/doctype/website_settings/website_settings.js
+++ b/frappe/website/doctype/website_settings/website_settings.js
@@ -33,20 +33,12 @@ frappe.ui.form.on('Website Settings', {
frm.fields_dict.top_bar_items.grid.update_docfield_property(
'parent_label', 'options', frm.events.get_parent_options(frm, "top_bar_items")
);
-
- if ($(frm.fields_dict.top_bar_items.grid.wrapper).find(".grid-row-open")) {
- frm.fields_dict.top_bar_items.grid.refresh();
- }
},
set_parent_label_options_footer: function(frm) {
frm.fields_dict.footer_items.grid.update_docfield_property(
- 'parent_label', 'options', frm.events.get_parent_options(frm, "top_bar_items")
+ 'parent_label', 'options', frm.events.get_parent_options(frm, "footer_items")
);
-
- if ($(frm.fields_dict.footer_items.grid.wrapper).find(".grid-row-open")) {
- frm.fields_dict.footer_items.grid.refresh();
- }
},
authorize_api_indexing_access: function(frm) {
@@ -122,10 +114,18 @@ frappe.ui.form.on('Website Settings', {
});
frappe.ui.form.on('Top Bar Item', {
+ top_bar_items_delete(frm) {
+ frm.events.set_parent_label_options(frm);
+ },
+
footer_items_add(frm, cdt, cdn) {
frappe.model.set_value(cdt, cdn, 'right', 0);
},
+ footer_items_delete(frm) {
+ frm.events.set_parent_label_options_footer(frm);
+ },
+
parent_label: function(frm, doctype, name) {
frm.events.set_parent_options(frm, doctype, name);
},
From 33b12d91f988ae7dfb030d1bd30eeeb5acecc48e Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sun, 18 Apr 2021 12:38:19 +0530
Subject: [PATCH 034/623] fix: cannot read property `doc` of undefined (#12891)
---
.../doctype/communication/communication_list.js | 2 +-
frappe/public/js/frappe/views/communication.js | 13 ++++++++-----
frappe/public/js/frappe/views/inbox/inbox_view.js | 4 +---
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/frappe/core/doctype/communication/communication_list.js b/frappe/core/doctype/communication/communication_list.js
index 454897b865..315b74a39c 100644
--- a/frappe/core/doctype/communication/communication_list.js
+++ b/frappe/core/doctype/communication/communication_list.js
@@ -20,6 +20,6 @@ frappe.listview_settings['Communication'] = {
},
primary_action: function() {
- new frappe.views.CommunicationComposer({ doc: {} });
+ new frappe.views.CommunicationComposer();
}
};
diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js
index 0479ec6d31..6501018c88 100755
--- a/frappe/public/js/frappe/views/communication.js
+++ b/frappe/public/js/frappe/views/communication.js
@@ -7,6 +7,10 @@ const separator_element = '---
';
frappe.views.CommunicationComposer = class {
constructor(opts) {
$.extend(this, opts);
+ if (!this.doc) {
+ this.doc = this.frm && this.frm.doc || {};
+ }
+
this.make();
}
@@ -269,7 +273,7 @@ frappe.views.CommunicationComposer = class {
method: 'frappe.email.doctype.email_template.email_template.get_email_template',
args: {
template_name: email_template,
- doc: me.frm.doc,
+ doc: me.doc,
_lang: me.dialog.get_value("language_sel")
},
callback(r) {
@@ -382,11 +386,10 @@ frappe.views.CommunicationComposer = class {
}
setup_print_language() {
- const doc = this.frm && this.frm.doc;
const fields = this.dialog.fields_dict;
//Load default print language from doctype
- this.lang_code = doc.language
+ this.lang_code = this.doc.language
|| this.get_print_format().default_print_language
|| frappe.boot.lang;
@@ -612,7 +615,7 @@ frappe.views.CommunicationComposer = class {
send_email(btn, form_values, selected_attachments, print_html, print_format) {
const me = this;
- me.dialog.hide();
+ this.dialog.hide();
if (!form_values.recipients) {
frappe.msgprint(__("Enter Email Recipient(s)"));
@@ -625,7 +628,7 @@ frappe.views.CommunicationComposer = class {
}
- if (this.frm && !frappe.model.can_email(me.doc.doctype, this.frm)) {
+ if (this.frm && !frappe.model.can_email(this.doc.doctype, this.frm)) {
frappe.msgprint(__("You are not allowed to send emails related to this document"));
return;
}
diff --git a/frappe/public/js/frappe/views/inbox/inbox_view.js b/frappe/public/js/frappe/views/inbox/inbox_view.js
index 1085e93e6c..8b53bd49a9 100644
--- a/frappe/public/js/frappe/views/inbox/inbox_view.js
+++ b/frappe/public/js/frappe/views/inbox/inbox_view.js
@@ -204,9 +204,7 @@ frappe.views.InboxView = class InboxView extends frappe.views.ListView {
};
frappe.new_doc('Email Account');
} else {
- new frappe.views.CommunicationComposer({
- doc: {}
- });
+ new frappe.views.CommunicationComposer();
}
}
};
From c8763859aec2332040b2e0392cfcf5a5fdef327c Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Sun, 18 Apr 2021 13:22:43 +0530
Subject: [PATCH 035/623] test: multiple cypress fixes
---
cypress/integration/relative_time_filters.js | 3 ---
cypress/integration/table_multiselect.js | 2 +-
frappe/commands/utils.py | 11 +++++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/cypress/integration/relative_time_filters.js b/cypress/integration/relative_time_filters.js
index 80e6387d99..cbb0524c24 100644
--- a/cypress/integration/relative_time_filters.js
+++ b/cypress/integration/relative_time_filters.js
@@ -1,7 +1,4 @@
context('Relative Timeframe', () => {
- beforeEach(() => {
- cy.login();
- });
before(() => {
cy.login();
cy.visit('/app/website');
diff --git a/cypress/integration/table_multiselect.js b/cypress/integration/table_multiselect.js
index faa72d63a5..25cab78ba2 100644
--- a/cypress/integration/table_multiselect.js
+++ b/cypress/integration/table_multiselect.js
@@ -1,5 +1,5 @@
context('Table MultiSelect', () => {
- beforeEach(() => {
+ before(() => {
cy.login();
});
diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py
index 5ff66171fc..a203c8c6d9 100644
--- a/frappe/commands/utils.py
+++ b/frappe/commands/utils.py
@@ -11,7 +11,7 @@ import click
import frappe
from frappe.commands import get_site, pass_context
from frappe.exceptions import SiteNotSpecifiedError
-from frappe.utils import get_bench_path, update_progress_bar
+from frappe.utils import get_bench_path, update_progress_bar, cint
@click.command('build')
@@ -567,11 +567,14 @@ def run_ui_tests(context, app, headless=False):
node_bin = subprocess.getoutput("npm bin")
cypress_path = "{0}/cypress".format(node_bin)
- plugin_path = "{0}/cypress-file-upload".format(node_bin)
+ plugin_path = "{0}/../cypress-file-upload".format(node_bin)
# check if cypress in path...if not, install it.
- if not (os.path.exists(cypress_path) or os.path.exists(plugin_path)) \
- or not subprocess.getoutput("npm view cypress version").startswith("6."):
+ if not (
+ os.path.exists(cypress_path)
+ and os.path.exists(plugin_path)
+ and cint(subprocess.getoutput("npm view cypress version")[:1]) >= 6
+ ):
# install cypress
click.secho("Installing Cypress...", fg="yellow")
frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile")
From d309343c6fa43b8a2a28fa615a534647a6c3e069 Mon Sep 17 00:00:00 2001
From: Revant Nandgaonkar
Date: Sun, 18 Apr 2021 18:56:45 +0530
Subject: [PATCH 036/623] feat(hooks): auth hooks
hook for request authentication
---
frappe/api.py | 33 +++++++++++++++------------------
frappe/utils/boilerplate.py | 7 +++++++
2 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/frappe/api.py b/frappe/api.py
index 6a09b795b0..3a1be2593e 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -149,24 +149,17 @@ def get_request_form_data():
return frappe.parse_json(data)
def validate_auth():
- if frappe.get_request_header("Authorization") is None:
- return
-
VALID_AUTH_PREFIX_TYPES = ['basic', 'bearer', 'token']
VALID_AUTH_PREFIX_STRING = ", ".join(VALID_AUTH_PREFIX_TYPES).title()
authorization_header = frappe.get_request_header("Authorization", str()).split(" ")
authorization_type = authorization_header[0].lower()
- if len(authorization_header) == 1:
- frappe.throw(_('Invalid Authorization headers, add a token with a prefix from one of the following: {0}.').format(VALID_AUTH_PREFIX_STRING), frappe.InvalidAuthorizationHeader)
-
- if authorization_type == "bearer":
+ if len(authorization_header) == 2:
validate_oauth(authorization_header)
- elif authorization_type in VALID_AUTH_PREFIX_TYPES:
validate_auth_via_api_keys(authorization_header)
- else:
- frappe.throw(_('Invalid Authorization Type {0}, must be one of {1}.').format(authorization_type, VALID_AUTH_PREFIX_STRING), frappe.InvalidAuthorizationPrefix)
+
+ validate_auth_via_hooks()
def validate_oauth(authorization_header):
@@ -192,14 +185,13 @@ def validate_oauth(authorization_header):
try:
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(get_url_delimiter())
+ valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
+
+ if valid:
+ frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
+ frappe.local.form_dict = form_dict
except AttributeError:
- frappe.throw(_("Invalid Bearer token, please provide a valid access token with prefix 'Bearer'."), frappe.InvalidAuthorizationToken)
-
- valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
-
- if valid:
- frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
- frappe.local.form_dict = form_dict
+ pass
def validate_auth_via_api_keys(authorization_header):
@@ -222,7 +214,7 @@ def validate_auth_via_api_keys(authorization_header):
except binascii.Error:
frappe.throw(_("Failed to decode token, please provide a valid base64-encoded token."), frappe.InvalidAuthorizationToken)
except (AttributeError, TypeError, ValueError):
- frappe.throw(_("Invalid token, please provide a valid token with prefix 'Basic' or 'Token'."), frappe.InvalidAuthorizationToken)
+ pass
@@ -248,3 +240,8 @@ def validate_api_key_secret(api_key, api_secret, frappe_authorization_source=Non
if frappe.local.login_manager.user in ('', 'Guest'):
frappe.set_user(user)
frappe.local.form_dict = form_dict
+
+
+def validate_auth_via_hooks():
+ for auth_hook in frappe.get_hooks('auth_hooks', []):
+ frappe.get_attr(auth_hook)()
diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py
index e59f579f75..ffcb64cff2 100755
--- a/frappe/utils/boilerplate.py
+++ b/frappe/utils/boilerplate.py
@@ -303,6 +303,13 @@ user_data_fields = [
}}
]
+# Authentication and authorization
+# --------------------------------
+
+# auth_hooks = [
+# "{app_name}.auth.validate"
+# ]
+
"""
desktop_template = """# -*- coding: utf-8 -*-
From c16584bbf186183f970583d3793f2e7e670f60f8 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Mon, 19 Apr 2021 10:45:54 +0530
Subject: [PATCH 037/623] chore: Upgrade frappe-charts to rc13 (#12896)
---
package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index 3c8da66242..6e82890617 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
"driver.js": "^0.9.8",
"express": "^4.17.1",
"fast-deep-equal": "^2.0.1",
- "frappe-charts": "^2.0.0-rc11",
+ "frappe-charts": "^2.0.0-rc13",
"frappe-datatable": "^1.15.3",
"frappe-gantt": "^0.5.0",
"fuse.js": "^3.4.6",
diff --git a/yarn.lock b/yarn.lock
index 4f6f62ac0a..8ac348011d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2699,10 +2699,10 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
-frappe-charts@^2.0.0-rc11:
- version "2.0.0-rc11"
- resolved "https://registry.yarnpkg.com/frappe-charts/-/frappe-charts-2.0.0-rc11.tgz#0724fa0d43593362c075c3805ebbbe1a608fcef7"
- integrity sha512-DY3tThT1lNGcJlRMOtIhnILtSm5h1iKysWhZAyj7yrGiOnOWbZpYx/NZzXZYwtRrWwMlYiLX2ylV76qo31ONsg==
+frappe-charts@^2.0.0-rc13:
+ version "2.0.0-rc13"
+ resolved "https://registry.yarnpkg.com/frappe-charts/-/frappe-charts-2.0.0-rc13.tgz#fdb251d7ae311c41e38f90a3ae108070ec6b9072"
+ integrity sha512-Bv7IfllIrjRbKWHn5b769dOSenqdBixAr6m5kurf8ZUOJSLOgK4HOXItJ7BA8n9PvviH9/k5DaloisjLM2Bm1w==
frappe-datatable@^1.15.3:
version "1.15.3"
From 4d91f318f94781a74e2b0c6361460966e79ab154 Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Mon, 19 Apr 2021 12:32:19 +0530
Subject: [PATCH 038/623] test: UI with form validation
---
.../fixtures/data_field_validation_doctype.js | 57 +++++++++++++++++++
.../integration/data_field_form_validation.js | 39 +++++++++++++
2 files changed, 96 insertions(+)
create mode 100644 cypress/fixtures/data_field_validation_doctype.js
create mode 100644 cypress/integration/data_field_form_validation.js
diff --git a/cypress/fixtures/data_field_validation_doctype.js b/cypress/fixtures/data_field_validation_doctype.js
new file mode 100644
index 0000000000..75fa88554e
--- /dev/null
+++ b/cypress/fixtures/data_field_validation_doctype.js
@@ -0,0 +1,57 @@
+export default {
+ name: 'Validation Test',
+ custom: 1,
+ actions: [],
+ creation: '2019-03-15 06:29:07.215072',
+ doctype: 'DocType',
+ editable_grid: 1,
+ engine: 'InnoDB',
+ fields: [
+ {
+ fieldname: 'email',
+ fieldtype: 'Data',
+ label: 'Email',
+ options: 'Email'
+ },
+ {
+ fieldname: 'URL',
+ fieldtype: 'Data',
+ label: 'URL',
+ options: 'URL'
+ },
+ {
+ fieldname: 'Phone',
+ fieldtype: 'Data',
+ label: 'Phone',
+ options: 'Phone'
+ },
+ {
+ fieldname: 'person_name',
+ fieldtype: 'Data',
+ label: 'Person Name',
+ options: 'Name'
+ }
+ ],
+ issingle: 1,
+ links: [],
+ modified: '2021-04-19 14:40:53.127615',
+ modified_by: 'Administrator',
+ module: 'Custom',
+ owner: 'Administrator',
+ permissions: [
+ {
+ create: 1,
+ delete: 1,
+ email: 1,
+ print: 1,
+ read: 1,
+ role: 'System Manager',
+ share: 1,
+ write: 1
+ }
+ ],
+ quick_entry: 1,
+ sort_field: 'modified',
+ sort_order: 'ASC',
+ track_changes: 1
+};
diff --git a/cypress/integration/data_field_form_validation.js b/cypress/integration/data_field_form_validation.js
new file mode 100644
index 0000000000..17a7f8e154
--- /dev/null
+++ b/cypress/integration/data_field_form_validation.js
@@ -0,0 +1,39 @@
+import data_field_validation_doctype from '../fixtures/data_field_validation_doctype';
+const doctype_name = data_field_validation_doctype.name;
+
+
+context('Data Field Input Validation in New Form', () => {
+ before(() => {
+ cy.login();
+ cy.visit('/app/website');
+ return cy.insert_doc('DocType', data_field_validation_doctype, true);
+ });
+
+ function validateField(fieldname, invalid_value, valid_value) {
+ // Invalid, should have has-error class
+ cy.get_field(fieldname).type(invalid_value).blur();
+ cy.get(`.frappe-control[data-fieldname="${fieldname}"]`).should('have.class', 'has-error');
+ // Valid value, should not have has-error class
+ cy.get_field(fieldname).clear().type(valid_value);
+ cy.get(`.frappe-control[data-fieldname="${fieldname}"]`).should('not.have.class', 'has-error');
+ }
+
+ describe('Data Field Options', () => {
+ it('should validate email address', () => {
+ cy.new_form(doctype_name);
+ validateField('email', 'captian', 'hello@test.com');
+ });
+
+ it('should validate URL', () => {
+ validateField('url', 'jkl', 'https://frappe.io');
+ });
+
+ it('should validate phone number', () => {
+ validateField('phone', 'america', '89787878');
+ });
+
+ it('should validate name', () => {
+ validateField('person_name', ' 777Hello', 'James Bond');
+ });
+ });
+});
\ No newline at end of file
From f617bfeba6910f10fec7a03530f0ca848ee3f715 Mon Sep 17 00:00:00 2001
From: Rohan Bansal
Date: Mon, 19 Apr 2021 12:51:48 +0530
Subject: [PATCH 039/623] fix: update dependencies
---
requirements.txt | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index 8cbe0e800b..91f235159f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,14 +2,14 @@ Babel~=2.9.0
beautifulsoup4~=4.9.3
bleach-whitelist~=0.0.11
bleach~=3.3.0
-boto3~=1.17.48
+boto3~=1.17.53
braintree~=4.8.0
chardet~=4.0.0
Click~=7.1.2
coverage~=5.5
croniter~=1.0.11
cryptography~=3.4.7
-dropbox~=11.6.0
+dropbox~=11.7.0
email-reply-parser~=0.5.12
Faker~=8.1.0
future==0.18.2
@@ -19,7 +19,7 @@ GitPython~=3.1.14
google-api-python-client~=2.2.0
google-auth-httplib2~=0.1.0
google-auth-oauthlib~=0.4.4
-google-auth~=1.28.1
+google-auth~=1.29.0
googlemaps~=4.4.5
gunicorn~=20.1.0
html2text==2020.1.16
@@ -38,7 +38,7 @@ passlib~=1.7.4
paytmchecksum~=1.7.0
pdfkit~=0.6.1
Pillow~=8.2.0
-premailer~=3.7.0
+premailer~=3.8.0
psutil~=5.8.0
psycopg2-binary~=2.8.6
pyasn1~=0.4.8
From 557235471ed3540f12d5b9ac883e682f9dbf3daa Mon Sep 17 00:00:00 2001
From: Rohan Bansal
Date: Mon, 19 Apr 2021 13:39:39 +0530
Subject: [PATCH 040/623] fix: remove unused variables
---
frappe/api.py | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/frappe/api.py b/frappe/api.py
index 3a1be2593e..59f14b54c8 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -1,12 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
-from __future__ import unicode_literals
import base64
import binascii
import json
-
-from six.moves.urllib.parse import urlencode, urlparse
+from urllib.parse import urlencode, urlparse
import frappe
import frappe.client
@@ -14,6 +12,7 @@ import frappe.handler
from frappe import _
from frappe.utils.response import build_response
+
def handle():
"""
Handler for `/api` methods
@@ -38,7 +37,6 @@ def handle():
`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method
"""
-
validate_auth()
parts = frappe.request.path[1:].split("/",3)
@@ -116,7 +114,7 @@ def handle():
frappe.local.form_dict['fields'] = json.loads(frappe.local.form_dict['fields'])
frappe.local.form_dict.setdefault('limit_page_length', 20)
frappe.local.response.update({
- "data": frappe.call(
+ "data": frappe.call(
frappe.client.get_list,
doctype,
**frappe.local.form_dict
@@ -140,6 +138,7 @@ def handle():
return build_response("json")
+
def get_request_form_data():
if frappe.local.form_dict.data is None:
data = frappe.safe_decode(frappe.local.request.get_data())
@@ -148,12 +147,9 @@ def get_request_form_data():
return frappe.parse_json(data)
-def validate_auth():
- VALID_AUTH_PREFIX_TYPES = ['basic', 'bearer', 'token']
- VALID_AUTH_PREFIX_STRING = ", ".join(VALID_AUTH_PREFIX_TYPES).title()
+def validate_auth():
authorization_header = frappe.get_request_header("Authorization", str()).split(" ")
- authorization_type = authorization_header[0].lower()
if len(authorization_header) == 2:
validate_oauth(authorization_header)
@@ -170,8 +166,8 @@ def validate_oauth(authorization_header):
authorization_header (list of str): The 'Authorization' header containing the prefix and token
"""
- from frappe.oauth import get_url_delimiter
from frappe.integrations.oauth2 import get_oauth_server
+ from frappe.oauth import get_url_delimiter
form_dict = frappe.local.form_dict
token = authorization_header[1]
@@ -185,14 +181,14 @@ def validate_oauth(authorization_header):
try:
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(get_url_delimiter())
- valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
-
- if valid:
- frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
- frappe.local.form_dict = form_dict
except AttributeError:
pass
+ valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
+ if valid:
+ frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
+ frappe.local.form_dict = form_dict
+
def validate_auth_via_api_keys(authorization_header):
"""
@@ -217,7 +213,6 @@ def validate_auth_via_api_keys(authorization_header):
pass
-
def validate_api_key_secret(api_key, api_secret, frappe_authorization_source=None):
"""frappe_authorization_source to provide api key and secret for a doctype apart from User"""
doctype = frappe_authorization_source or 'User'
From 1600d852796a48b733f832cad0e67faa0e69ae66 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Mon, 19 Apr 2021 14:15:30 +0530
Subject: [PATCH 041/623] fix: Typo in get_all_language_with_name (#12902)
---
frappe/translate.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/translate.py b/frappe/translate.py
index 62ee733f5f..a65a1c28c1 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -827,7 +827,7 @@ def get_all_languages(with_language_name=False):
return frappe.db.sql_list('select name from tabLanguage')
def get_all_language_with_name():
- return frappe.db.get_all('language', ['language_code', 'language_name'])
+ return frappe.db.get_all('Language', ['language_code', 'language_name'])
if not frappe.db:
frappe.connect()
From fe73a0b22af3b29eb60f31ba5cc0b73c1bf7d828 Mon Sep 17 00:00:00 2001
From: leela
Date: Mon, 19 Apr 2021 14:43:44 +0530
Subject: [PATCH 042/623] refactor: removed unused code
---
frappe/www/login.py | 8 --------
1 file changed, 8 deletions(-)
diff --git a/frappe/www/login.py b/frappe/www/login.py
index 76b232f8ee..1ce25a81d9 100644
--- a/frappe/www/login.py
+++ b/frappe/www/login.py
@@ -95,14 +95,6 @@ def login_via_frappe(code, state):
def login_via_office365(code, state):
login_via_oauth2_id_token("office_365", code, state, decoder=decoder_compat)
-@frappe.whitelist(allow_guest=True)
-def login_oauth_user(data=None, provider=None, state=None, email_id=None, key=None, generate_login_token=False):
- if not ((data and provider and state) or (email_id and key)):
- frappe.respond_as_web_page(_("Invalid Request"), _("Missing parameters for login"), http_status_code=417)
- return
-
- _login_oauth_user(data, provider, state, email_id, key, generate_login_token)
-
@frappe.whitelist(allow_guest=True)
def login_via_token(login_token):
sid = frappe.cache().get_value("login_token:{0}".format(login_token), expires=True)
From 1c2d69fbe72aae0f4c146096ef4732fed624ecff Mon Sep 17 00:00:00 2001
From: leela
Date: Mon, 19 Apr 2021 14:45:38 +0530
Subject: [PATCH 043/623] fix: remove the token validation check
Let token be part of state to make state dynamic. But there is no need
to have validation for token.
---
frappe/utils/oauth.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/frappe/utils/oauth.py b/frappe/utils/oauth.py
index 6596701ee3..6a92737a0d 100644
--- a/frappe/utils/oauth.py
+++ b/frappe/utils/oauth.py
@@ -64,8 +64,6 @@ def get_oauth2_authorize_url(provider, redirect_to):
state = { "site": frappe.utils.get_url(), "token": frappe.generate_hash(), "redirect_to": redirect_to }
- frappe.cache().set_value("{0}:{1}".format(provider, state["token"]), True, expires_in_sec=120)
-
# relative to absolute url
data = {
"redirect_uri": get_redirect_uri(provider),
@@ -176,11 +174,6 @@ def login_oauth_user(data=None, provider=None, state=None, email_id=None, key=No
frappe.respond_as_web_page(_("Invalid Request"), _("Token is missing"), http_status_code=417)
return
- token = frappe.cache().get_value("{0}:{1}".format(provider, state["token"]), expires=True)
- if not token:
- frappe.respond_as_web_page(_("Invalid Request"), _("Invalid Token"), http_status_code=417)
- return
-
user = get_email(data)
if not user:
From 6ecbf55de5f5f050248432726dcd0e9e5d58d27f Mon Sep 17 00:00:00 2001
From: prssanna
Date: Mon, 19 Apr 2021 15:12:00 +0530
Subject: [PATCH 044/623] fix: do not empty viewers parent on form refresh
---
frappe/public/js/frappe/form/form.js | 1 +
frappe/public/js/frappe/form/toolbar.js | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index ef728e730e..de9331a726 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -360,6 +360,7 @@ frappe.ui.form.Form = class FrappeForm {
grid_obj.grid.grid_pagination.go_to_page(1, true);
});
frappe.ui.form.close_grid_form();
+ this.viewers && this.viewers.parent.empty();
this.docname = docname;
this.setup_docinfo_change_listener();
}
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index 145b8d3eed..22787b70c1 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -211,7 +211,6 @@ frappe.ui.form.Toolbar = class Toolbar {
make_viewers() {
if (this.frm.viewers) {
- this.frm.viewers.parent.empty();
return;
}
this.frm.viewers = new frappe.ui.form.FormViewers({
From 8c74df6cc3b5bf4b1664b6ba76f38d9fc8d6b19f Mon Sep 17 00:00:00 2001
From: Revant Nandgaonkar
Date: Mon, 19 Apr 2021 15:18:15 +0530
Subject: [PATCH 045/623] fix: duplicate validate_auth calls
---
frappe/api.py | 8 ++++----
frappe/handler.py | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/frappe/api.py b/frappe/api.py
index 59f14b54c8..4117c49333 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -181,13 +181,13 @@ def validate_oauth(authorization_header):
try:
required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(get_url_delimiter())
+ valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
+ if valid:
+ frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
+ frappe.local.form_dict = form_dict
except AttributeError:
pass
- valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)
- if valid:
- frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
- frappe.local.form_dict = form_dict
def validate_auth_via_api_keys(authorization_header):
diff --git a/frappe/handler.py b/frappe/handler.py
index 82c1ea65c6..1897abe019 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -24,7 +24,7 @@ ALLOWED_MIMETYPES = ('image/png', 'image/jpeg', 'application/pdf', 'application/
def handle():
"""handle request"""
- validate_auth()
+
cmd = frappe.local.form_dict.cmd
data = None
From 1d0e72834d3f67ec84089190a32ddb28b53963e5 Mon Sep 17 00:00:00 2001
From: Revant Nandgaonkar
Date: Mon, 19 Apr 2021 15:54:16 +0530
Subject: [PATCH 046/623] fix: remove unused imports
---
frappe/api.py | 5 +++--
frappe/app.py | 1 +
frappe/handler.py | 1 -
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/frappe/api.py b/frappe/api.py
index 4117c49333..4a120f228a 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -37,8 +37,6 @@ def handle():
`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method
"""
- validate_auth()
-
parts = frappe.request.path[1:].split("/",3)
call = doctype = name = None
@@ -149,6 +147,9 @@ def get_request_form_data():
def validate_auth():
+ """
+ Authenticate and sets user for the request.
+ """
authorization_header = frappe.get_request_header("Authorization", str()).split(" ")
if len(authorization_header) == 2:
diff --git a/frappe/app.py b/frappe/app.py
index 607479ad52..c9e993a853 100644
--- a/frappe/app.py
+++ b/frappe/app.py
@@ -56,6 +56,7 @@ def application(request):
frappe.recorder.record()
frappe.monitor.start()
frappe.rate_limiter.apply()
+ frappe.api.validate_auth()
if request.method == "OPTIONS":
response = Response()
diff --git a/frappe/handler.py b/frappe/handler.py
index 1897abe019..a38feb90fa 100755
--- a/frappe/handler.py
+++ b/frappe/handler.py
@@ -9,7 +9,6 @@ import frappe
import frappe.utils
import frappe.sessions
from frappe.utils import cint
-from frappe.api import validate_auth
from frappe import _, is_whitelisted
from frappe.utils.response import build_response
from frappe.utils.csvutils import build_csv_response
From 10d9611e6a0ae7983199628a651623f1a115c00e Mon Sep 17 00:00:00 2001
From: shariquerik
Date: Mon, 19 Apr 2021 16:05:01 +0530
Subject: [PATCH 047/623] fix: Grid Form buttons Insert Above, Insert Below not
hidden when cannot_add_rows is true
---
frappe/public/js/frappe/form/grid_row.js | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index 5e3a2b8ccd..0a88beaa37 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -555,6 +555,15 @@ export default class GridRow {
this.grid_form.render();
this.row.toggle(false);
// this.form_panel.toggle(true);
+
+ if (this.grid.cannot_add_rows || (this.grid.df && this.grid.df.cannot_add_rows)) {
+ this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
+ .addClass('hidden')
+ } else {
+ this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
+ .removeClass('hidden')
+ }
+
frappe.dom.freeze("", "dark");
if (cur_frm) cur_frm.cur_grid = this;
this.wrapper.addClass("grid-row-open");
From ccb76ce56bceaca3cbe72e932ec01f681b685758 Mon Sep 17 00:00:00 2001
From: shariquerik
Date: Mon, 19 Apr 2021 16:58:26 +0530
Subject: [PATCH 048/623] fix: sider fix
---
frappe/public/js/frappe/form/grid_row.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index 0a88beaa37..e0fe1b3b54 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -558,10 +558,10 @@ export default class GridRow {
if (this.grid.cannot_add_rows || (this.grid.df && this.grid.df.cannot_add_rows)) {
this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
- .addClass('hidden')
+ .addClass('hidden');
} else {
this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
- .removeClass('hidden')
+ .removeClass('hidden');
}
frappe.dom.freeze("", "dark");
From 46d68e252f03d4d7856ce85566938bd6c76cd3b3 Mon Sep 17 00:00:00 2001
From: Revant Nandgaonkar
Date: Mon, 19 Apr 2021 20:01:52 +0530
Subject: [PATCH 049/623] fix: id_token format
decode bytes to utf-8 string
---
frappe/integrations/oauth2.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/integrations/oauth2.py b/frappe/integrations/oauth2.py
index c444964a16..3ebaaffcff 100644
--- a/frappe/integrations/oauth2.py
+++ b/frappe/integrations/oauth2.py
@@ -133,7 +133,7 @@ def get_token(*args, **kwargs):
}
id_token_encoded = jwt.encode(id_token, client_secret, algorithm='HS256', headers=id_token_header)
- out.update({"id_token": str(id_token_encoded)})
+ out.update({"id_token": frappe.safe_decode(id_token_encoded)})
frappe.local.response = out
From e21b1e40c4aae7134e414afa127fe7de9a748c08 Mon Sep 17 00:00:00 2001
From: Abhishek Balam
Date: Mon, 19 Apr 2021 23:27:38 +0530
Subject: [PATCH 050/623] fix: whitelist login method to fetch session remotely
---
frappe/auth.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/frappe/auth.py b/frappe/auth.py
index ca97bbc17d..73cb8e8c15 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -120,6 +120,7 @@ class LoginManager:
self.make_session()
self.set_user_info()
+ @frappe.whitelist()
def login(self):
# clear cache
frappe.clear_cache(user = frappe.form_dict.get('usr'))
From a19207c2f12162aafb19752176dcee412fc0a67b Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 20 Apr 2021 14:21:25 +0530
Subject: [PATCH 051/623] fix: Pass aggregate_on_doctype to properly create the
query
---
frappe/desk/reportview.py | 13 +++++++------
frappe/public/js/frappe/ui/group_by/group_by.js | 3 ++-
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py
index 3d04c171a7..86f8ec0aa7 100644
--- a/frappe/desk/reportview.py
+++ b/frappe/desk/reportview.py
@@ -126,13 +126,14 @@ def setup_group_by(data):
if data.group_by:
if data.aggregate_function.lower() not in ('count', 'sum', 'avg'):
frappe.throw(_('Invalid aggregate function'))
- if '`' in data.aggregate_on:
- raise_invalid_field(data.aggregate_on)
- data.fields.append('{aggregate_function}(`tab{doctype}`.`{aggregate_on}`) AS _aggregate_column'.format(**data))
- if data.aggregate_on:
- data.fields.append(data.aggregate_on)
- data.pop('aggregate_on')
+ if frappe.db.has_column(data.aggregate_on_doctype, data.aggregate_on_field):
+ data.fields.append('{aggregate_function}(`tab{aggregate_on_doctype}`.`{aggregate_on_field}`) AS _aggregate_column'.format(**data))
+ else:
+ raise_invalid_field(data.aggregate_on_field)
+
+ data.pop('aggregate_on_doctype')
+ data.pop('aggregate_on_field')
data.pop('aggregate_function')
def raise_invalid_field(fieldname):
diff --git a/frappe/public/js/frappe/ui/group_by/group_by.js b/frappe/public/js/frappe/ui/group_by/group_by.js
index 53e4914f0d..3ebf9c9d3d 100644
--- a/frappe/public/js/frappe/ui/group_by/group_by.js
+++ b/frappe/public/js/frappe/ui/group_by/group_by.js
@@ -313,7 +313,8 @@ frappe.ui.GroupBy = class {
Object.assign(args, {
with_comment_count: false,
- aggregate_on: this.aggregate_on || 'name',
+ aggregate_on_field: this.aggregate_on_field || 'name',
+ aggregate_on_doctype: this.aggregate_on_doctype || this.doctype,
aggregate_function: this.aggregate_function || 'count',
group_by: this.report_view.group_by || null,
order_by: '_aggregate_column desc',
From b7e75e5305d247c592efba7a601726ba250108c9 Mon Sep 17 00:00:00 2001
From: prssanna
Date: Tue, 20 Apr 2021 14:36:41 +0530
Subject: [PATCH 052/623] fix: aggregate column in auto email report
---
frappe/core/doctype/report/report.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index af2c4e5dc2..8a0f9a99f5 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -325,9 +325,8 @@ def get_group_by_field(args, doctype):
if args['aggregate_function'] == 'count':
group_by_field = 'count(*) as _aggregate_column'
else:
- group_by_field = '{0}(`tab{1}`.{2}) as _aggregate_column'.format(
+ group_by_field = '{0}({1}) as _aggregate_column'.format(
args.aggregate_function,
- doctype,
args.aggregate_on
)
From 06ea52b9647781a888733766457f9807b7017d0e Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Tue, 20 Apr 2021 14:54:40 +0530
Subject: [PATCH 053/623] fix(treeview): Accept filters as kwargs to avoid
TypeError (#12920)
---
frappe/desk/treeview.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/desk/treeview.py b/frappe/desk/treeview.py
index d479b71b52..6f0d7d3d5f 100644
--- a/frappe/desk/treeview.py
+++ b/frappe/desk/treeview.py
@@ -36,7 +36,7 @@ def get_all_nodes(doctype, label, parent, tree_method, **filters):
return out
@frappe.whitelist()
-def get_children(doctype, parent=''):
+def get_children(doctype, parent='', **filters):
return _get_children(doctype, parent)
def _get_children(doctype, parent='', ignore_permissions=False):
From ea38895f1a45cd1c163254d10cfac1d5c3284cce Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Mon, 19 Apr 2021 13:17:20 +0530
Subject: [PATCH 054/623] fix: Sider Issues
---
.eslintrc | 2 ++
cypress/fixtures/data_field_validation_doctype.js | 4 ++--
cypress/integration/data_field_form_validation.js | 4 ++--
frappe/public/js/frappe/utils/datatype.js | 2 +-
frappe/utils/__init__.py | 4 ++--
5 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/.eslintrc b/.eslintrc
index d123023a68..2d17d7937b 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -80,6 +80,7 @@
"validate_email": true,
"validate_name": true,
"validate_phone": true,
+ "validate_url": true,
"get_number_format": true,
"format_number": true,
"format_currency": true,
@@ -144,6 +145,7 @@
"cy": true,
"it": true,
"expect": true,
+ "describe": true,
"context": true,
"before": true,
"beforeEach": true,
diff --git a/cypress/fixtures/data_field_validation_doctype.js b/cypress/fixtures/data_field_validation_doctype.js
index 75fa88554e..469ff8ca24 100644
--- a/cypress/fixtures/data_field_validation_doctype.js
+++ b/cypress/fixtures/data_field_validation_doctype.js
@@ -11,13 +11,13 @@ export default {
fieldname: 'email',
fieldtype: 'Data',
label: 'Email',
- options: 'Email'
+ options: 'Email'
},
{
fieldname: 'URL',
fieldtype: 'Data',
label: 'URL',
- options: 'URL'
+ options: 'URL'
},
{
fieldname: 'Phone',
diff --git a/cypress/integration/data_field_form_validation.js b/cypress/integration/data_field_form_validation.js
index 17a7f8e154..e6f6f13df6 100644
--- a/cypress/integration/data_field_form_validation.js
+++ b/cypress/integration/data_field_form_validation.js
@@ -18,7 +18,7 @@ context('Data Field Input Validation in New Form', () => {
cy.get(`.frappe-control[data-fieldname="${fieldname}"]`).should('not.have.class', 'has-error');
}
- describe('Data Field Options', () => {
+ describe('Data Field Options', () => {
it('should validate email address', () => {
cy.new_form(doctype_name);
validateField('email', 'captian', 'hello@test.com');
@@ -35,5 +35,5 @@ context('Data Field Input Validation in New Form', () => {
it('should validate name', () => {
validateField('person_name', ' 777Hello', 'James Bond');
});
- });
+ });
});
\ No newline at end of file
diff --git a/frappe/public/js/frappe/utils/datatype.js b/frappe/public/js/frappe/utils/datatype.js
index ad0fd4324c..944d3fca1a 100644
--- a/frappe/public/js/frappe/utils/datatype.js
+++ b/frappe/public/js/frappe/utils/datatype.js
@@ -54,7 +54,7 @@ window.validate_name = function(txt) {
window.validate_url = function(txt) {
return frappe.utils.validate_type(txt, "url");
-}
+};
window.nth = function(number) {
number = cint(number);
diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py
index 5992fdb6db..2fdaa05404 100644
--- a/frappe/utils/__init__.py
+++ b/frappe/utils/__init__.py
@@ -166,12 +166,12 @@ def validate_url(txt, throw=False):
url = urlparse(txt).netloc
if not url:
raise frappe.ValidationError
- except Exception as e:
+ except Exception:
if throw:
frappe.throw(
frappe._(
"'{0}' is not a valid URL"
- ).format('' + +' ')
+ ).format('' + txt +' ')
)
return False
From 8aa26c728609f7e6277b5abf9f8d1592f288f320 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 16:01:56 +0530
Subject: [PATCH 055/623] fix: Include all keys and sort by score
---
.../doctype/server_script/server_script.js | 2 +-
.../doctype/server_script/server_script.py | 40 +++++++++++++++----
frappe/public/js/frappe/form/controls/code.js | 7 +---
3 files changed, 36 insertions(+), 13 deletions(-)
diff --git a/frappe/core/doctype/server_script/server_script.js b/frappe/core/doctype/server_script/server_script.js
index e12200b6fc..dda39115bf 100644
--- a/frappe/core/doctype/server_script/server_script.js
+++ b/frappe/core/doctype/server_script/server_script.js
@@ -13,7 +13,7 @@ frappe.ui.form.on('Server Script', {
frm.call('get_autocompletion_items')
.then(r => r.message)
.then(items => {
- frm.set_df_property('script', 'autocompletions', items)
+ frm.set_df_property('script', 'autocompletions', items);
});
},
diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py
index 6a8eb59c3a..ea27a2ac83 100644
--- a/frappe/core/doctype/server_script/server_script.py
+++ b/frappe/core/doctype/server_script/server_script.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import ast
-from types import FunctionType, ModuleType
+from types import FunctionType, MethodType, ModuleType
from typing import Dict, List
import frappe
@@ -125,21 +125,47 @@ class ServerScript(Document):
@frappe.whitelist()
def get_autocompletion_items(self):
+ """Generates a list of a autocompletion strings from the context dict
+ that is used while executing a Server Script.
+
+ Returns:
+ list: Returns list of autocompletion items.
+ For e.g., ["frappe.utils.cint", "frappe.db.get_all", ...]
+ """
def get_keys(obj):
out = []
for key in obj:
if key.startswith('_'):
continue
value = obj[key]
- if isinstance(value, (FunctionType, ModuleType)):
- out.append(key)
- elif isinstance(value, (NamespaceDict, dict)):
- out += [f'{key}.{subkey}' for subkey in get_keys(value)]
+ if isinstance(value, (NamespaceDict, dict)) and value:
+ if key == 'form_dict':
+ out.append(['form_dict', 3])
+ continue
+ for subkey, score in get_keys(value):
+ fullkey = f'{key}.{subkey}'
+ out.append([fullkey, score])
+ else:
+ if isinstance(value, ModuleType):
+ score = 0
+ elif isinstance(value, (FunctionType, MethodType)):
+ score = 1
+ elif isinstance(value, type) and issubclass(value, Exception):
+ score = 9
+ elif isinstance(value, type):
+ score = 2
+ elif isinstance(value, dict):
+ score = 3
+ else:
+ score = 4
+ out.append([key, score])
return out
items = frappe.cache().get_value('server_script_autocompletion_items')
- if not items:
- items = get_keys(get_safe_globals())
+ if not items or True:
+ unsorted_items = get_keys(get_safe_globals())
+ sorted_items = sorted(unsorted_items, key=lambda k: k[1])
+ items = [d[0] for d in sorted_items]
frappe.cache().set_value('server_script_autocompletion_items', items)
return items
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index 8d2609b836..635146563e 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -53,11 +53,10 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
ace.config.loadModule("ace/ext/language_tools", langTools => {
this.editor.setOptions({
enableBasicAutocompletion: true,
- enableSnippets: true,
enableLiveAutocompletion: true
});
- let completer = {
+ langTools.addCompleter({
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
callback(null, []);
@@ -76,10 +75,8 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
);
}
}
- }
- langTools.addCompleter(completer);
+ });
});
-
this._autocompletion_setup = true;
},
From 8ca7ba6b5619df286609624f94923a38ae9ca1dd Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 16:08:11 +0530
Subject: [PATCH 056/623] fix: remove hardcoded value
---
frappe/core/doctype/server_script/server_script.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py
index ea27a2ac83..b791997a8b 100644
--- a/frappe/core/doctype/server_script/server_script.py
+++ b/frappe/core/doctype/server_script/server_script.py
@@ -162,7 +162,7 @@ class ServerScript(Document):
return out
items = frappe.cache().get_value('server_script_autocompletion_items')
- if not items or True:
+ if not items:
unsorted_items = get_keys(get_safe_globals())
sorted_items = sorted(unsorted_items, key=lambda k: k[1])
items = [d[0] for d in sorted_items]
From c309cb2d29d1dd791632d37cf5d5952728440703 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 16:23:20 +0530
Subject: [PATCH 057/623] fix: Pass score to ace to let it handle sorting
---
.../doctype/server_script/server_script.py | 19 +++++++++----------
frappe/public/js/frappe/form/controls/code.js | 16 ++++++++++------
2 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py
index b791997a8b..f80a067cf1 100644
--- a/frappe/core/doctype/server_script/server_script.py
+++ b/frappe/core/doctype/server_script/server_script.py
@@ -140,32 +140,31 @@ class ServerScript(Document):
value = obj[key]
if isinstance(value, (NamespaceDict, dict)) and value:
if key == 'form_dict':
- out.append(['form_dict', 3])
+ out.append(['form_dict', 7])
continue
for subkey, score in get_keys(value):
fullkey = f'{key}.{subkey}'
out.append([fullkey, score])
else:
- if isinstance(value, ModuleType):
+ if isinstance(value, type) and issubclass(value, Exception):
score = 0
+ elif isinstance(value, ModuleType):
+ score = 10
elif isinstance(value, (FunctionType, MethodType)):
- score = 1
- elif isinstance(value, type) and issubclass(value, Exception):
score = 9
elif isinstance(value, type):
- score = 2
+ score = 8
elif isinstance(value, dict):
- score = 3
+ score = 7
else:
- score = 4
+ score = 6
out.append([key, score])
return out
items = frappe.cache().get_value('server_script_autocompletion_items')
if not items:
- unsorted_items = get_keys(get_safe_globals())
- sorted_items = sorted(unsorted_items, key=lambda k: k[1])
- items = [d[0] for d in sorted_items]
+ items = get_keys(get_safe_globals())
+ items = [{'value': d[0], 'score': d[1]} for d in items]
frappe.cache().set_value('server_script_autocompletion_items', items)
return items
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index 635146563e..33579b3b88 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -66,12 +66,16 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
if (autocompletions.length) {
callback(
null,
- autocompletions.map(a => ({
- name: 'frappe',
- value: a,
- score: 100,
- meta: 'Frappe API'
- }))
+ autocompletions.map(a => {
+ if (typeof a === 'string') {
+ a = { value: a };
+ }
+ return {
+ name: 'frappe',
+ value: a.value,
+ score: a.score
+ }
+ })
);
}
}
From ec0c628c84bbb7481318f37e86f26c4231d03e8f Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Tue, 20 Apr 2021 21:39:59 +0530
Subject: [PATCH 058/623] fix: Get defaults from user_defaults based on
fieldname
---
frappe/public/js/frappe/model/create_new.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/model/create_new.js b/frappe/public/js/frappe/model/create_new.js
index dc6ee56fca..1b09a451eb 100644
--- a/frappe/public/js/frappe/model/create_new.js
+++ b/frappe/public/js/frappe/model/create_new.js
@@ -177,7 +177,9 @@ $.extend(frappe.model, {
// Use User Permission value when only when it has a single value
user_default = user_defaults[0];
}
- } else if (!user_default) {
+ }
+
+ if (!user_default) {
user_default = frappe.defaults.get_user_default(df.fieldname);
} else if (
!user_default &&
From 0dcf02c114f407bf5b8c8f1d0d46f3cffcbd5c36 Mon Sep 17 00:00:00 2001
From: Nabin Hait
Date: Tue, 20 Apr 2021 21:41:39 +0530
Subject: [PATCH 059/623] fix: Resolve value in promise while validating link
field
---
frappe/public/js/frappe/form/controls/link.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js
index 1a483c5968..1377ecc9ae 100644
--- a/frappe/public/js/frappe/form/controls/link.js
+++ b/frappe/public/js/frappe/form/controls/link.js
@@ -462,9 +462,10 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
if(this.frm && this.frm.fetch_dict[df.fieldname]) {
fetch = this.frm.fetch_dict[df.fieldname].columns.join(', ');
}
-
// if default and no fetch, no need to validate
- if (!fetch && df.__default_value && df.__default_value===value) return value;
+ if (!fetch && df.__default_value && df.__default_value===value) {
+ resolve(value);
+ };
this.fetch_and_validate_link(resolve, df, doctype, docname, value, fetch);
});
From 273e6b01db9f4c62e6f71b582da8eaaa97ca52b8 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 21:46:20 +0530
Subject: [PATCH 060/623] style: missing semicolon
---
frappe/public/js/frappe/form/controls/code.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index 33579b3b88..9600763588 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -74,7 +74,7 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
name: 'frappe',
value: a.value,
score: a.score
- }
+ };
})
);
}
From e784828fe0c0f32a9fb6f900548e68f3d4cc5e50 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Tue, 20 Apr 2021 22:03:43 +0530
Subject: [PATCH 061/623] style(sider): Remove unnecessary semicolon
---
frappe/public/js/frappe/form/controls/link.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js
index 1377ecc9ae..c0ff128088 100644
--- a/frappe/public/js/frappe/form/controls/link.js
+++ b/frappe/public/js/frappe/form/controls/link.js
@@ -465,7 +465,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
// if default and no fetch, no need to validate
if (!fetch && df.__default_value && df.__default_value===value) {
resolve(value);
- };
+ }
this.fetch_and_validate_link(resolve, df, doctype, docname, value, fetch);
});
From 87d8666c60bfdf3ea6c1ef375a99cb9db8bd3a2c Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Wed, 21 Apr 2021 11:42:01 +0530
Subject: [PATCH 062/623] fix: Handle error while session start (#12933)
- The occurs randomly at the time of boot
---
frappe/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/__init__.py b/frappe/__init__.py
index cab9b0da76..55cafa917a 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -975,7 +975,7 @@ def get_pymodule_path(modulename, *joins):
:param *joins: Join additional path elements using `os.path.join`."""
if not "public" in joins:
joins = [scrub(part) for part in joins]
- return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins)
+ return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__ or ''), *joins)
def get_module_list(app_name):
"""Get list of modules for given all via `app/modules.txt`."""
From 1ce0b898871bd5c35d18c48aabd9c90ffaa3fffa Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Wed, 21 Apr 2021 12:15:54 +0530
Subject: [PATCH 063/623] fix: Ignore non utf-8 files for translation scan
(#12935)
---
frappe/translate.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/frappe/translate.py b/frappe/translate.py
index a65a1c28c1..3565bbc32c 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -518,8 +518,13 @@ def get_messages_from_file(path):
apps_path = get_bench_dir()
if os.path.exists(path):
with open(path, 'r') as sourcefile:
+ try:
+ file_contents = sourcefile.read()
+ except Exception:
+ print("Could not scan file for translation: {0}".format(path))
+ return []
data = [(os.path.relpath(path, apps_path), message, context, line) \
- for line, message, context in extract_messages_from_code(sourcefile.read())]
+ for line, message, context in extract_messages_from_code(file_contents)]
return data
else:
# print "Translate: {0} missing".format(os.path.abspath(path))
From acfa1c1cca561c8e4880b0eaf8e554158f1c5656 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 21 Apr 2021 14:44:26 +0530
Subject: [PATCH 064/623] fix: Use grid docfield list while creating row
docfield copy
Previously, it was using doctype level docfield list
which did not had the updated docfields for a grid.
---
frappe/public/js/frappe/form/grid_row.js | 1 +
frappe/public/js/frappe/model/meta.js | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index e0fe1b3b54..4afa251c27 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -6,6 +6,7 @@ export default class GridRow {
this.on_grid_fields = [];
$.extend(this, opts);
if (this.doc && this.parent_df.options) {
+ frappe.meta.make_docfield_copy_for(this.parent_df.options, this.doc.name, this.docfields);
this.docfields = frappe.meta.get_docfields(this.parent_df.options, this.doc.name);
}
this.columns = {};
diff --git a/frappe/public/js/frappe/model/meta.js b/frappe/public/js/frappe/model/meta.js
index c2fd6b1ae6..6ee9084adc 100644
--- a/frappe/public/js/frappe/model/meta.js
+++ b/frappe/public/js/frappe/model/meta.js
@@ -38,14 +38,14 @@ $.extend(frappe.meta, {
frappe.meta.docfield_list[df.parent].push(df);
},
- make_docfield_copy_for: function(doctype, docname) {
+ make_docfield_copy_for: function(doctype, docname, docfield_list=null) {
var c = frappe.meta.docfield_copy;
if(!c[doctype])
c[doctype] = {};
if(!c[doctype][docname])
c[doctype][docname] = {};
- var docfield_list = frappe.meta.docfield_list[doctype] || [];
+ docfield_list = docfield_list || frappe.meta.docfield_list[doctype] || [];
for(var i=0, j=docfield_list.length; i
Date: Wed, 21 Apr 2021 15:22:41 +0530
Subject: [PATCH 065/623] ci: Fix coveralls (#12926)
---
.github/workflows/ci-tests.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 08a2823dca..363191fd05 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -151,7 +151,7 @@ jobs:
cd ${GITHUB_WORKSPACE}
pip install coveralls==3.0.1
pip install coverage==5.5
- coveralls --service=github
+ coveralls --service=github-actions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
From f84aee8abe858dd61210c21aa5b6d1642dba6ec1 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 21 Apr 2021 18:16:59 +0200
Subject: [PATCH 066/623] fix: translate report column labels
---
frappe/translate.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/frappe/translate.py b/frappe/translate.py
index 3565bbc32c..5989ff44aa 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -443,8 +443,12 @@ def get_messages_from_report(name):
messages = _get_messages_from_page_or_report("Report", name,
frappe.db.get_value("DocType", report.ref_doctype, "module"))
+ if report.columns:
+ messages.extend([(None, column.label) for column in report.columns])
+
if report.query:
messages.extend([(None, message) for message in re.findall('"([^:,^"]*):', report.query) if is_translatable(message)])
+
messages.append((None,report.report_name))
return messages
From bf4a73c3d4890a42016d49a34d455aad18307068 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 21 Apr 2021 18:28:02 +0200
Subject: [PATCH 067/623] fix: translate report filter labels
---
frappe/translate.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frappe/translate.py b/frappe/translate.py
index 5989ff44aa..a4128794ac 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -444,7 +444,10 @@ def get_messages_from_report(name):
frappe.db.get_value("DocType", report.ref_doctype, "module"))
if report.columns:
- messages.extend([(None, column.label) for column in report.columns])
+ messages.extend([(None, report_column.label) for report_column in report.columns])
+
+ if report.filters:
+ messages.extend([(None, report_filter.label) for report_filter in report.filters])
if report.query:
messages.extend([(None, message) for message in re.findall('"([^:,^"]*):', report.query) if is_translatable(message)])
From 6250c4ac9d62b943936e92cef15627534a8a1480 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 21 Apr 2021 19:46:33 +0200
Subject: [PATCH 068/623] fix: add context to filter columns
---
frappe/public/js/frappe/views/reports/query_report.js | 2 +-
frappe/translate.py | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js
index 834946b437..4e50210d0a 100644
--- a/frappe/public/js/frappe/views/reports/query_report.js
+++ b/frappe/public/js/frappe/views/reports/query_report.js
@@ -1094,7 +1094,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
return Object.assign(column, {
id: column.fieldname,
- name: __(column.label),
+ name: __(column.label, null, `Column of report '${this.report_name}'`), // context has to match context in get_messages_from_report in translate.py
width: parseInt(column.width) || null,
editable: false,
compareValue: compareFn,
diff --git a/frappe/translate.py b/frappe/translate.py
index a4128794ac..49e4a0855c 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -444,7 +444,8 @@ def get_messages_from_report(name):
frappe.db.get_value("DocType", report.ref_doctype, "module"))
if report.columns:
- messages.extend([(None, report_column.label) for report_column in report.columns])
+ context = "Column of report '%s'" % report.name # context has to match context in `prepare_columns` in query_report.js
+ messages.extend([(None, report_column.label, context) for report_column in report.columns])
if report.filters:
messages.extend([(None, report_filter.label) for report_filter in report.filters])
From 4d552c241f7b9a2e6b9a5dfa9bd6d430a6f2cbac Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Thu, 22 Apr 2021 00:24:22 +0530
Subject: [PATCH 069/623] fix: Form Dashboard reference link (#12945)
---
frappe/public/js/frappe/form/dashboard.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js
index 9b6d15c1fc..c1c95d94cf 100644
--- a/frappe/public/js/frappe/form/dashboard.js
+++ b/frappe/public/js/frappe/form/dashboard.js
@@ -290,7 +290,7 @@ frappe.ui.form.Dashboard = class FormDashboard {
// bind links
transactions_area_body.find(".badge-link").on('click', function() {
- me.open_document_list($(this).parent());
+ me.open_document_list($(this).closest('.document-link'));
});
// bind reports
From 6225f9b35eaa760e817793c2f42f40a1038d720e Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Thu, 22 Apr 2021 00:41:13 +0530
Subject: [PATCH 070/623] fix(query): Use single quotes for string constant
(#12948)
---
frappe/translate.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/translate.py b/frappe/translate.py
index 3565bbc32c..5be41f3568 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -115,7 +115,7 @@ def get_dict(fortype, name=None):
messages.extend(get_server_messages(app))
messages = deduplicate_messages(messages)
- messages += frappe.db.sql("""select "navbar", item_label from `tabNavbar Item` where item_label is not null""")
+ messages += frappe.db.sql("""select 'navbar', item_label from `tabNavbar Item` where item_label is not null""")
messages = get_messages_from_include_files()
messages += frappe.db.sql("select 'Print Format:', name from `tabPrint Format`")
messages += frappe.db.sql("select 'DocType:', name from tabDocType")
From 32d3f1f09986b139094eadb8c1319751294ee262 Mon Sep 17 00:00:00 2001
From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
Date: Thu, 22 Apr 2021 01:12:38 +0530
Subject: [PATCH 071/623] fix: build-message-files command (#12950)
---
frappe/translate.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/frappe/translate.py b/frappe/translate.py
index 5be41f3568..4baf4bdd89 100644
--- a/frappe/translate.py
+++ b/frappe/translate.py
@@ -606,11 +606,23 @@ def write_csv_file(path, app_messages, lang_dict):
from csv import writer
with open(path, 'w', newline='') as msgfile:
w = writer(msgfile, lineterminator='\n')
- for p, m in app_messages:
- t = lang_dict.get(m, '')
+
+ for app_message in app_messages:
+ context = None
+ if len(app_message) == 2:
+ path, message = app_message
+ elif len(app_message) == 3:
+ path, message, lineno = app_message
+ elif len(app_message) == 4:
+ path, message, context, lineno = app_message
+ else:
+ continue
+
+ t = lang_dict.get(message, '')
# strip whitespaces
- t = re.sub('{\s?([0-9]+)\s?}', "{\g<1>}", t)
- w.writerow([p if p else '', m, t])
+ translated_string = re.sub('{\s?([0-9]+)\s?}', "{\g<1>}", t)
+ if translated_string:
+ w.writerow([message, translated_string, context])
def get_untranslated(lang, untranslated_file, get_all=False):
"""Returns all untranslated strings for a language and writes in a file
From 976ebd5b2c2d4188db1bfe38b29f9badd709eb5b Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 22 Apr 2021 06:03:35 +0530
Subject: [PATCH 072/623] fix: Check if path is a module first then function
---
frappe/utils/jinja.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py
index 42ab267381..a77eca4977 100644
--- a/frappe/utils/jinja.py
+++ b/frappe/utils/jinja.py
@@ -149,7 +149,11 @@ def get_jinja_hooks():
def get_obj_dict_from_paths(object_paths):
out = {}
for obj_path in object_paths:
- obj = frappe.get_attr(obj_path)
+ try:
+ obj = frappe.get_module(obj_path)
+ except ModuleNotFoundError:
+ obj = frappe.get_attr(obj_path)
+
if isinstance(obj, ModuleType):
functions = getmembers(obj, isfunction)
for function_name, function in functions:
From 226ad1d91aacef25cf8c1736fa872b78940713a2 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 15:12:38 +0530
Subject: [PATCH 073/623] feat: New Build System based on esbuild
- Deprecate use of build.json
- *.bundle.js files placed anywhere in the public folder are bundled
- Built files are created in public/build folder which is gitignored
WIP
---
.gitignore | 1 +
esbuild/esbuild-plugin-html.js | 44 +
esbuild/esbuild-watch.js | 69 ++
esbuild/ignore-assets.js | 11 +
esbuild/index.js | 79 ++
esbuild/utils.js | 110 ++
frappe/hooks.py | 10 +-
frappe/public/js/controls.bundle.js | 20 +
frappe/public/js/desk.bundle.js | 107 ++
frappe/public/js/form.bundle.js | 18 +
frappe/public/js/frappe-web.bundle.js | 25 +
frappe/public/js/frappe/class.js | 2 +-
frappe/public/js/frappe/form/layout.js | 2 +-
frappe/public/js/frappe/utils/common.js | 3 +-
frappe/public/js/frappe/utils/utils.js | 8 +
.../js/frappe/views/reports/query_report.js | 2 +-
frappe/public/js/libs.bundle.js | 11 +
frappe/public/js/list.bundle.js | 42 +
frappe/public/js/report.bundle.js | 9 +
frappe/public/js/web/bootstrap-4.js | 65 +
frappe/public/scss/common/datepicker.scss | 2 +-
frappe/public/scss/common/quill.scss | 4 +-
frappe/templates/base.html | 3 +-
frappe/utils/jinja.py | 9 +-
frappe/website/js/website.js | 3 +-
frappe/www/app.html | 13 +-
package.json | 14 +-
yarn.lock | 1045 ++++++++++++++++-
28 files changed, 1676 insertions(+), 55 deletions(-)
create mode 100644 esbuild/esbuild-plugin-html.js
create mode 100644 esbuild/esbuild-watch.js
create mode 100644 esbuild/ignore-assets.js
create mode 100644 esbuild/index.js
create mode 100644 esbuild/utils.js
create mode 100644 frappe/public/js/controls.bundle.js
create mode 100644 frappe/public/js/desk.bundle.js
create mode 100644 frappe/public/js/form.bundle.js
create mode 100644 frappe/public/js/frappe-web.bundle.js
create mode 100644 frappe/public/js/libs.bundle.js
create mode 100644 frappe/public/js/list.bundle.js
create mode 100644 frappe/public/js/report.bundle.js
create mode 100644 frappe/public/js/web/bootstrap-4.js
diff --git a/.gitignore b/.gitignore
index 766288fe2e..08d9876242 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ locale
dist/
# build/
frappe/docs/current
+frappe/public/build
.vscode
node_modules
.kdev4/
diff --git a/esbuild/esbuild-plugin-html.js b/esbuild/esbuild-plugin-html.js
new file mode 100644
index 0000000000..9edd6b627a
--- /dev/null
+++ b/esbuild/esbuild-plugin-html.js
@@ -0,0 +1,44 @@
+module.exports = {
+ name: "frappe-html",
+ setup(build) {
+ let path = require("path");
+ let fs = require("fs/promises");
+
+ build.onResolve({ filter: /\.html$/ }, args => {
+ return {
+ path: path.join(args.resolveDir, args.path),
+ namespace: "frappe-html"
+ };
+ });
+
+ build.onLoad({ filter: /.*/, namespace: "frappe-html" }, args => {
+ let filepath = args.path;
+ let filename = path.basename(filepath).split(".")[0];
+
+ return fs
+ .readFile(filepath, "utf-8")
+ .then(content => {
+ content = scrub_html_template(content);
+ return {
+ contents: `\n\tfrappe.templates['${filename}'] = '${content}';\n`
+ };
+ })
+ .catch(() => {
+ return {
+ contents: "",
+ warnings: [
+ {
+ text: `There was an error importing ${filepath}`
+ }
+ ]
+ };
+ });
+ });
+ }
+};
+
+function scrub_html_template(content) {
+ content = content.replace(/\s/g, " ");
+ content = content.replace(/()/g, "");
+ return content.replace("'", "'"); // eslint-disable-line
+}
diff --git a/esbuild/esbuild-watch.js b/esbuild/esbuild-watch.js
new file mode 100644
index 0000000000..97d11024c2
--- /dev/null
+++ b/esbuild/esbuild-watch.js
@@ -0,0 +1,69 @@
+let esbuild = require("esbuild");
+let htmlPlugin = require("./esbuild-plugin-html");
+let vue = require("esbuild-vue");
+let http = require("http");
+let httpProxy = require("http-proxy");
+let path = require("path");
+
+const { get_public_path, apps_list } = require("../rollup/rollup.utils");
+
+let proxy = httpProxy.createProxyServer({});
+
+proxy.on("error", function(e) {
+ console.error(e);
+});
+
+let server = http.createServer((req, res) => {
+ if (req.url.includes("/public/")) {
+ buildAsset(req.url).then(result => {
+ if (!result) {
+ proxy_request();
+ return;
+ }
+ res.setHeader("Content-Header", "application/javascript");
+ res.writeHead(200);
+ res.end(result);
+ });
+ } else {
+ proxy_request();
+ }
+
+ function proxy_request() {
+ proxy.web(req, res, { target: "http://localhost:8000" });
+ }
+});
+
+server.listen(8080);
+
+server.on("listening", () => {
+ console.log("dev server started at http:localhost:8080");
+});
+
+function buildAsset(url) {
+ if (url.startsWith("/")) {
+ url = url.substr(1);
+ }
+ let app;
+ let parts = url.split(path.sep);
+ if (apps_list.includes(parts[0])) {
+ app = parts[0];
+ }
+ if (!app) return;
+
+ let filepath = path.resolve(get_public_path(app), url.split("public/")[1]);
+ console.log("building " + url);
+
+ return esbuild
+ .build({
+ entryPoints: [filepath],
+ write: false,
+ bundle: true,
+ plugins: [htmlPlugin, vue()],
+ define: {
+ "process.env.NODE_ENV": "'development'"
+ }
+ })
+ .then(result => {
+ return result.outputFiles[0].text;
+ });
+}
diff --git a/esbuild/ignore-assets.js b/esbuild/ignore-assets.js
new file mode 100644
index 0000000000..5edfef2110
--- /dev/null
+++ b/esbuild/ignore-assets.js
@@ -0,0 +1,11 @@
+module.exports = {
+ name: "frappe-ignore-asset",
+ setup(build) {
+ build.onResolve({ filter: /^\/assets\// }, args => {
+ return {
+ path: args.path,
+ external: true
+ };
+ });
+ }
+};
diff --git a/esbuild/index.js b/esbuild/index.js
new file mode 100644
index 0000000000..419b6eb641
--- /dev/null
+++ b/esbuild/index.js
@@ -0,0 +1,79 @@
+let glob = require("fast-glob");
+let esbuild = require("esbuild");
+let html_plugin = require("./esbuild-plugin-html");
+let vue = require("esbuild-vue");
+let postCssPlugin = require("esbuild-plugin-postcss2").default;
+let ignore_assets = require("./ignore-assets");
+let { get_options_for_scss } = require("../rollup/rollup.utils");
+
+console.time("Build time");
+
+glob(["frappe/public/js/**/*.bundle.js"]).then(entry_files => {
+ esbuild
+ .build({
+ entryPoints: entry_files,
+ outdir: "frappe/public/build",
+ outbase: "frappe/public",
+ sourcemap: true,
+ bundle: true,
+ metafile: true,
+ minify: true,
+ define: {
+ "process.env.NODE_ENV": "'development'"
+ },
+ plugins: [
+ html_plugin,
+ ignore_assets,
+ vue(),
+ postCssPlugin({
+ plugins: [require("autoprefixer")],
+ sassOptions: {
+ ...get_options_for_scss(),
+ importer: function(url) {
+ if (url.startsWith("~")) {
+ // strip ~ so that it can resolve from node_modules
+ url = url.slice(1);
+ }
+ if (url.endsWith(".css")) {
+ // strip .css from end of path
+ url = url.slice(0, -4);
+ }
+ // normal file, let it go
+ return {
+ file: url
+ };
+ }
+ }
+ })
+ ],
+
+ // watch: {
+ // onRebuild(error, result) {
+ // if (error) console.error("watch build failed:", error);
+ // else {
+ // console.log("watch build succeeded:");
+ // log_build_meta(result.metafile);
+ // }
+ // }
+ // }
+ })
+ .then(result => {
+ log_build_meta(result.metafile);
+
+ if (result.warnings.length) {
+ console.warn(result.warnings);
+ }
+ })
+ .catch(e => console.error("error"))
+ .finally(() => {
+ console.timeEnd("Build time");
+ });
+});
+
+function log_build_meta(metafile) {
+ for (let outfile in metafile.outputs) {
+ if (outfile.endsWith('.map')) continue;
+ let data = metafile.outputs[outfile];
+ console.log(outfile, data.bytes / 1000 + " Kb");
+ }
+}
diff --git a/esbuild/utils.js b/esbuild/utils.js
new file mode 100644
index 0000000000..6cecebcf59
--- /dev/null
+++ b/esbuild/utils.js
@@ -0,0 +1,110 @@
+const path = require("path");
+const fs = require("fs");
+
+const frappe_path = path.resolve(__dirname, "..");
+const bench_path = path.resolve(frappe_path, "..", "..");
+const sites_path = path.resolve(bench_path, "sites");
+const assets_path = path.resolve(sites_path, "assets");
+const app_list = get_apps_list();
+
+const app_paths = app_list.reduce((out, app) => {
+ out[app] = path.resolve(bench_path, "apps", app, app);
+ return out;
+}, {});
+const public_paths = app_list.reduce((out, app) => {
+ out[app] = path.resolve(app_paths[app], "public");
+ return out;
+}, {});
+const public_js_paths = app_list.reduce((out, app) => {
+ out[app] = path.resolve(app_paths[app], "public/js");
+ return out;
+}, {});
+
+const bundle_map = app_list.reduce((out, app) => {
+ const public_js_path = public_js_paths[app];
+ if (fs.existsSync(public_js_path)) {
+ const all_files = fs.readdirSync(public_js_path);
+ const js_files = all_files.filter(file => file.endsWith(".js"));
+
+ for (let js_file of js_files) {
+ const filename = path.basename(js_file).split(".")[0];
+ out[path.join(app, "js", filename)] = path.resolve(
+ public_js_path,
+ js_file
+ );
+ }
+ }
+
+ return out;
+}, {});
+
+const get_public_path = app => public_paths[app];
+
+const get_build_json_path = app =>
+ path.resolve(get_public_path(app), "build.json");
+
+function get_build_json(app) {
+ try {
+ return require(get_build_json_path(app));
+ } catch (e) {
+ // build.json does not exist
+ return null;
+ }
+}
+
+function delete_file(path) {
+ if (fs.existsSync(path)) {
+ fs.unlinkSync(path);
+ }
+}
+
+function run_serially(tasks) {
+ let result = Promise.resolve();
+ tasks.forEach(task => {
+ if (task) {
+ result = result.then ? result.then(task) : Promise.resolve();
+ }
+ });
+ return result;
+}
+
+const get_app_path = app => app_paths[app];
+
+const get_options_for_scss = () => {
+ const node_modules_path = path.resolve(
+ get_app_path("frappe"),
+ "..",
+ "node_modules"
+ );
+ const app_paths = app_list
+ .map(get_app_path)
+ .map(app_path => path.resolve(app_path, ".."));
+
+ return {
+ includePaths: [node_modules_path, ...app_paths]
+ };
+};
+
+function get_apps_list() {
+ return fs
+ .readFileSync(path.resolve(sites_path, "apps.txt"), {
+ encoding: "utf-8"
+ })
+ .split("\n")
+ .filter(Boolean);
+}
+
+module.exports = {
+ app_list,
+ bench_path,
+ assets_path,
+ sites_path,
+ bundle_map,
+ get_public_path,
+ get_build_json_path,
+ get_build_json,
+ get_app_path,
+ delete_file,
+ run_serially,
+ get_options_for_scss
+};
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 74c538c5df..967aed7f60 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -30,11 +30,11 @@ page_js = {
# website
app_include_js = [
"/assets/js/libs.min.js",
- "/assets/js/desk.min.js",
- "/assets/js/list.min.js",
- "/assets/js/form.min.js",
- "/assets/js/control.min.js",
- "/assets/js/report.min.js",
+ "frappe/public/js/desk.bundle.js",
+ "frappe/public/js/list.bundle.js",
+ "frappe/public/js/form.bundle.js",
+ "frappe/public/js/controls.bundle.js",
+ "frappe/public/js/report.bundle.js",
]
app_include_css = [
"/assets/css/desk.min.css",
diff --git a/frappe/public/js/controls.bundle.js b/frappe/public/js/controls.bundle.js
new file mode 100644
index 0000000000..f9a983ecae
--- /dev/null
+++ b/frappe/public/js/controls.bundle.js
@@ -0,0 +1,20 @@
+import "air-datepicker/dist/js/datepicker.min.js";
+import "air-datepicker/dist/js/i18n/datepicker.cs.js";
+import "air-datepicker/dist/js/i18n/datepicker.da.js";
+import "air-datepicker/dist/js/i18n/datepicker.de.js";
+import "air-datepicker/dist/js/i18n/datepicker.en.js";
+import "air-datepicker/dist/js/i18n/datepicker.es.js";
+import "air-datepicker/dist/js/i18n/datepicker.fi.js";
+import "air-datepicker/dist/js/i18n/datepicker.fr.js";
+import "air-datepicker/dist/js/i18n/datepicker.hu.js";
+import "air-datepicker/dist/js/i18n/datepicker.nl.js";
+import "air-datepicker/dist/js/i18n/datepicker.pl.js";
+import "air-datepicker/dist/js/i18n/datepicker.pt-BR.js";
+import "air-datepicker/dist/js/i18n/datepicker.pt.js";
+import "air-datepicker/dist/js/i18n/datepicker.ro.js";
+import "air-datepicker/dist/js/i18n/datepicker.sk.js";
+import "air-datepicker/dist/js/i18n/datepicker.zh.js";
+import "./frappe/ui/capture.js";
+import "./frappe/form/controls/control.js";
+
+console.log('controls')
diff --git a/frappe/public/js/desk.bundle.js b/frappe/public/js/desk.bundle.js
new file mode 100644
index 0000000000..469714158c
--- /dev/null
+++ b/frappe/public/js/desk.bundle.js
@@ -0,0 +1,107 @@
+import '../scss/desk.scss';
+import "./frappe/translate.js";
+import "./frappe/class.js";
+import "./frappe/polyfill.js";
+import "./frappe/provide.js";
+import "./frappe/assets.js";
+import "./frappe/format.js";
+import "./frappe/form/formatters.js";
+import "./frappe/dom.js";
+import "./frappe/ui/messages.js";
+import "./frappe/ui/keyboard.js";
+import "./frappe/ui/colors.js";
+import "./frappe/ui/sidebar.js";
+import "./frappe/ui/link_preview.js";
+
+import "./frappe/request.js";
+import "./frappe/socketio_client.js";
+import "./frappe/utils/utils.js";
+import "./frappe/event_emitter.js";
+import "./frappe/router.js";
+import "./frappe/router_history.js";
+import "./frappe/defaults.js";
+import "./frappe/roles_editor.js";
+import "./frappe/module_editor.js";
+import "./frappe/microtemplate.js";
+
+import "./frappe/ui/page.html";
+import "./frappe/ui/page.js";
+import "./frappe/ui/slides.js";
+// import "./frappe/ui/onboarding_dialog.js";
+import "./frappe/ui/find.js";
+import "./frappe/ui/iconbar.js";
+import "./frappe/form/layout.js";
+import "./frappe/ui/field_group.js";
+import "./frappe/form/link_selector.js";
+import "./frappe/form/multi_select_dialog.js";
+import "./frappe/ui/dialog.js";
+import "./frappe/ui/capture.js";
+import "./frappe/ui/app_icon.js";
+import "./frappe/ui/theme_switcher.js";
+
+import "./frappe/model/model.js";
+import "./frappe/db.js";
+import "./frappe/model/meta.js";
+import "./frappe/model/sync.js";
+import "./frappe/model/create_new.js";
+import "./frappe/model/perm.js";
+import "./frappe/model/workflow.js";
+import "./frappe/model/user_settings.js";
+
+import "./frappe/utils/user.js";
+import "./frappe/utils/common.js";
+import "./frappe/utils/urllib.js";
+import "./frappe/utils/pretty_date.js";
+import "./frappe/utils/test_utils.js";
+import "./frappe/utils/tools.js";
+import "./frappe/utils/datetime.js";
+import "./frappe/utils/number_format.js";
+import "./frappe/utils/help.js";
+import "./frappe/utils/help_links.js";
+import "./frappe/utils/address_and_contact.js";
+import "./frappe/utils/preview_email.js";
+import "./frappe/utils/file_manager.js";
+
+import "./frappe/upload.js";
+import "./frappe/ui/tree.js";
+
+import "./frappe/views/container.js";
+import "./frappe/views/breadcrumbs.js";
+import "./frappe/views/factory.js";
+import "./frappe/views/pageview.js";
+
+import "./frappe/ui/toolbar/awesome_bar.js";
+// import "./frappe/ui/toolbar/energy_points_notifications.js";
+import "./frappe/ui/notifications/notifications.js";
+import "./frappe/ui/toolbar/search.js";
+import "./frappe/ui/toolbar/tag_utils.js";
+import "./frappe/ui/toolbar/search.html";
+import "./frappe/ui/toolbar/search_utils.js";
+import "./frappe/ui/toolbar/about.js";
+import "./frappe/ui/toolbar/navbar.html";
+import "./frappe/ui/toolbar/toolbar.js";
+// import "./frappe/ui/toolbar/notifications.js";
+import "./frappe/views/communication.js";
+import "./frappe/views/translation_manager.js";
+import "./frappe/views/workspace/workspace.js";
+
+import "./frappe/widgets/widget_group.js";
+
+import "./frappe/ui/sort_selector.html";
+import "./frappe/ui/sort_selector.js";
+
+import "./frappe/change_log.html";
+import "./frappe/ui/workspace_loading_skeleton.html";
+import "./frappe/desk.js";
+import "./frappe/query_string.js";
+
+// import "./frappe/ui/comment.js";
+
+import "./frappe/chat.js";
+import "./frappe/utils/energy_point_utils.js";
+import "./frappe/utils/dashboard_utils.js";
+import "./frappe/ui/chart.js";
+import "./frappe/ui/datatable.js";
+import "./frappe/ui/driver.js";
+import "./frappe/ui/plyr.js";
+import "./frappe/barcode_scanner/index.js";
diff --git a/frappe/public/js/form.bundle.js b/frappe/public/js/form.bundle.js
new file mode 100644
index 0000000000..994a5437c3
--- /dev/null
+++ b/frappe/public/js/form.bundle.js
@@ -0,0 +1,18 @@
+import "./frappe/form/templates/address_list.html";
+import "./frappe/form/templates/attachment.html";
+import "./frappe/form/templates/contact_list.html";
+import "./frappe/form/templates/form_dashboard.html";
+import "./frappe/form/templates/form_footer.html";
+import "./frappe/form/templates/form_links.html";
+import "./frappe/form/templates/form_sidebar.html";
+import "./frappe/form/templates/print_layout.html";
+import "./frappe/form/templates/report_links.html";
+import "./frappe/form/templates/set_sharing.html";
+import "./frappe/form/templates/timeline_message_box.html";
+import "./frappe/form/templates/users_in_sidebar.html";
+
+import "./frappe/form/controls/control.js";
+import "./frappe/views/formview.js";
+import "./frappe/form/form.js";
+import "./frappe/meta_tag.js";
+
diff --git a/frappe/public/js/frappe-web.bundle.js b/frappe/public/js/frappe-web.bundle.js
new file mode 100644
index 0000000000..eef68b54c6
--- /dev/null
+++ b/frappe/public/js/frappe-web.bundle.js
@@ -0,0 +1,25 @@
+import "./frappe/class.js";
+import "./frappe/polyfill.js";
+import "./lib/md5.min.js";
+import "./frappe/provide.js";
+import "./frappe/format.js";
+import "./frappe/utils/number_format.js";
+import "./frappe/utils/utils.js";
+import "./frappe/utils/common.js";
+import "./frappe/ui/messages.js";
+import "./frappe/translate.js";
+import "./frappe/utils/pretty_date.js";
+import "./frappe/microtemplate.js";
+import "./frappe/query_string.js";
+
+import "./frappe/upload.js";
+
+import "./frappe/model/meta.js";
+import "./frappe/model/model.js";
+import "./frappe/model/perm.js";
+
+import "./web/bootstrap-4";
+
+
+import "../../website/js/website.js";
+import "./frappe/socketio_client.js";
diff --git a/frappe/public/js/frappe/class.js b/frappe/public/js/frappe/class.js
index 4f6dd0dc97..79ef2792ae 100644
--- a/frappe/public/js/frappe/class.js
+++ b/frappe/public/js/frappe/class.js
@@ -80,4 +80,4 @@ To subclass, use:
// export
global.Class = Class;
- })(this);
\ No newline at end of file
+ })(window);
diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js
index 8b6c627882..d1437623a6 100644
--- a/frappe/public/js/frappe/form/layout.js
+++ b/frappe/public/js/frappe/form/layout.js
@@ -543,7 +543,7 @@ frappe.ui.form.Layout = Class.extend({
} else if (expression.substr(0, 5)=='eval:') {
try {
- out = eval(expression.substr(5));
+ out = frappe.utils.eval(expression.substr(5), { doc });
if (parent && parent.istable && expression.includes('is_submittable')) {
out = true;
}
diff --git a/frappe/public/js/frappe/utils/common.js b/frappe/public/js/frappe/utils/common.js
index 8fec3b2611..cce356f6ca 100644
--- a/frappe/public/js/frappe/utils/common.js
+++ b/frappe/public/js/frappe/utils/common.js
@@ -1,4 +1,5 @@
// common file between desk and website
+import md5 from 'md5'
frappe.avatar = function (user, css_class, title, image_url=null, remove_color=false, filterable=false) {
let user_info;
@@ -375,4 +376,4 @@ frappe.utils.get_page_view_count = function (route) {
return frappe.call("frappe.website.doctype.web_page_view.web_page_view.get_page_view_count", {
path: route
});
-};
\ No newline at end of file
+};
diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js
index 7ce30a525c..fc3865a322 100644
--- a/frappe/public/js/frappe/utils/utils.js
+++ b/frappe/public/js/frappe/utils/utils.js
@@ -954,6 +954,14 @@ Object.assign(frappe.utils, {
return $el;
},
+ eval(code, context={}) {
+ let variable_names = Object.keys(context);
+ let variables = Object.values(context);
+ code = `return (${code})`;
+ let expression_function = new Function(...variable_names, code);
+ return expression_function(...variables);
+ },
+
get_browser() {
let ua = navigator.userAgent;
let tem;
diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js
index 834946b437..27aace1c75 100644
--- a/frappe/public/js/frappe/views/reports/query_report.js
+++ b/frappe/public/js/frappe/views/reports/query_report.js
@@ -445,7 +445,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
out = expression;
} else if (expression.substr(0, 5) == 'eval:') {
try {
- out = eval(expression.substr(5));
+ out = frappe.utils.eval(expression.substr(5), { doc });
} catch (e) {
frappe.throw(__('Invalid "depends_on" expression set in filter {0}', [filter_label]));
}
diff --git a/frappe/public/js/libs.bundle.js b/frappe/public/js/libs.bundle.js
new file mode 100644
index 0000000000..3d635e1f51
--- /dev/null
+++ b/frappe/public/js/libs.bundle.js
@@ -0,0 +1,11 @@
+import "bootstrap/dist/js/bootstrap.bundle.js";
+import Vue from "vue/dist/vue.esm.js";
+import moment from "moment/min/moment-with-locales.js";
+import momentTimezone from "moment-timezone/builds/moment-timezone-with-data.js";
+import "socket.io-client/dist/socket.io.slim.js";
+import "./lib/Sortable.min.js";
+import "./lib/jquery/jquery.hotkeys.js";
+import "./lib/jSignature.min.js";
+
+window.moment = momentTimezone;
+window.Vue = Vue;
diff --git a/frappe/public/js/list.bundle.js b/frappe/public/js/list.bundle.js
new file mode 100644
index 0000000000..e40ef94a81
--- /dev/null
+++ b/frappe/public/js/list.bundle.js
@@ -0,0 +1,42 @@
+import "./frappe/ui/listing.html";
+
+import "./frappe/model/indicator.js";
+import "./frappe/ui/filters/filter.js";
+import "./frappe/ui/filters/filter_list.js";
+import "./frappe/ui/filters/field_select.js";
+import "./frappe/ui/filters/edit_filter.html";
+import "./frappe/ui/tags.js";
+import "./frappe/ui/tag_editor.js";
+import "./frappe/ui/like.js";
+// import "./frappe/ui/liked_by.html";
+import "../html/print_template.html";
+
+import "./frappe/list/base_list.js";
+import "./frappe/list/list_view.js";
+import "./frappe/list/list_factory.js";
+
+import "./frappe/list/list_view_select.js";
+import "./frappe/list/list_sidebar.js";
+import "./frappe/list/list_sidebar.html";
+import "./frappe/list/list_sidebar_stat.html";
+import "./frappe/list/list_sidebar_group_by.js";
+import "./frappe/list/list_view_permission_restrictions.html";
+
+import "./frappe/views/gantt/gantt_view.js";
+import "./frappe/views/calendar/calendar.js";
+import "./frappe/views/dashboard/dashboard_view.js";
+import "./frappe/views/image/image_view.js";
+import "./frappe/views/map/map_view.js";
+import "./frappe/views/kanban/kanban_view.js";
+import "./frappe/views/inbox/inbox_view.js";
+import "./frappe/views/file/file_view.js";
+
+import "./frappe/views/treeview.js";
+import "./frappe/views/interaction.js";
+
+import "./frappe/views/image/image_view_item_row.html";
+import "./frappe/views/image/photoswipe_dom.html";
+
+import "./frappe/views/kanban/kanban_board.html";
+import "./frappe/views/kanban/kanban_column.html";
+import "./frappe/views/kanban/kanban_card.html";
diff --git a/frappe/public/js/report.bundle.js b/frappe/public/js/report.bundle.js
new file mode 100644
index 0000000000..3f2aa3b4c1
--- /dev/null
+++ b/frappe/public/js/report.bundle.js
@@ -0,0 +1,9 @@
+import "./lib/clusterize.min.js";
+import "./frappe/views/reports/report_factory.js";
+import "./frappe/views/reports/report_view.js";
+import "./frappe/views/reports/query_report.js";
+import "./frappe/views/reports/print_grid.html";
+import "./frappe/views/reports/print_tree.html";
+import "./frappe/ui/group_by/group_by.html";
+import "./frappe/ui/group_by/group_by.js";
+import "./frappe/views/reports/report_utils.js";
diff --git a/frappe/public/js/web/bootstrap-4.js b/frappe/public/js/web/bootstrap-4.js
new file mode 100644
index 0000000000..c12919c570
--- /dev/null
+++ b/frappe/public/js/web/bootstrap-4.js
@@ -0,0 +1,65 @@
+import 'bootstrap/dist/js/bootstrap.bundle';
+
+// multilevel dropdown
+$('.dropdown-menu a.dropdown-toggle').on('click', function (e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ if (!$(this).next().hasClass('show')) {
+ $(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
+ }
+ var $subMenu = $(this).next(".dropdown-menu");
+ $subMenu.toggleClass('show');
+
+
+ $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function () {
+ $('.dropdown-submenu .show').removeClass("show");
+ });
+
+ return false;
+});
+
+frappe.get_modal = function (title, content) {
+ return $(
+ ``
+ );
+};
+
+frappe.ui.Dialog = class Dialog extends frappe.ui.Dialog {
+ get_primary_btn() {
+ return this.$wrapper.find(".modal-footer .btn-primary");
+ }
+
+ set_primary_action(label, click) {
+ this.$wrapper.find('.modal-footer').removeClass('hidden');
+ return super.set_primary_action(label, click)
+ .removeClass('hidden');
+ }
+
+ make() {
+ super.make();
+ if (this.fields) {
+ this.$wrapper.find('.section-body').addClass('w-100');
+ }
+ }
+};
diff --git a/frappe/public/scss/common/datepicker.scss b/frappe/public/scss/common/datepicker.scss
index d159f27fc1..93bdfcc03d 100644
--- a/frappe/public/scss/common/datepicker.scss
+++ b/frappe/public/scss/common/datepicker.scss
@@ -1,4 +1,4 @@
-@import "~air-datepicker/dist/css/datepicker.min.css";
+@import "~air-datepicker/dist/css/datepicker.min";
.datepicker {
diff --git a/frappe/public/scss/common/quill.scss b/frappe/public/scss/common/quill.scss
index d15ca7e036..95942d7c61 100644
--- a/frappe/public/scss/common/quill.scss
+++ b/frappe/public/scss/common/quill.scss
@@ -1,5 +1,5 @@
-@import '~quill/dist/quill.snow.css';
-@import '~quill/dist/quill.bubble.css';
+@import '~quill/dist/quill.snow';
+@import '~quill/dist/quill.bubble';
.ql-toolbar.ql-snow,
.ql-container.ql-snow {
diff --git a/frappe/templates/base.html b/frappe/templates/base.html
index 78aa573c99..7eb4e5e8d6 100644
--- a/frappe/templates/base.html
+++ b/frappe/templates/base.html
@@ -97,8 +97,7 @@
{% block base_scripts %}
-
-
+
{% endblock %}
{%- for link in web_include_js %}
diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py
index cd74b2a283..8a80013887 100644
--- a/frappe/utils/jinja.py
+++ b/frappe/utils/jinja.py
@@ -23,7 +23,8 @@ def get_jenv():
'resolve_class': resolve_class,
'inspect': inspect,
'web_blocks': web_blocks,
- 'web_block': web_block
+ 'web_block': web_block,
+ 'js_asset': js_asset
})
frappe.local.jenv = jenv
@@ -228,3 +229,9 @@ def web_blocks(blocks):
html += ''.format(script)
return html
+
+def js_asset(path):
+ import frappe
+ if not frappe.local.dev_server or True:
+ path = path.replace('frappe/public/', '/assets/frappe/build/')
+ return f''
diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js
index ea0b9aedfa..9e800c8f1a 100644
--- a/frappe/website/js/website.js
+++ b/frappe/website/js/website.js
@@ -605,7 +605,8 @@ $(document).ready(function() {
$(document).on("page-change", function() {
$(document).trigger("apply_permissions");
- $('.dropdown-toggle').dropdown();
+ // TODO: esbuild
+ // $('.dropdown-toggle').dropdown();
//multilevel dropdown fix
$('.dropdown-menu .dropdown-submenu .dropdown-toggle').on('click', function(e) {
diff --git a/frappe/www/app.html b/frappe/www/app.html
index 8da4d11c00..419d3ffe07 100644
--- a/frappe/www/app.html
+++ b/frappe/www/app.html
@@ -52,11 +52,14 @@
- {% for include in include_js %}
-
- {% endfor %}
- {% include "templates/includes/app_analytics/google_analytics.html" %}
- {% include "templates/includes/app_analytics/mixpanel_analytics.html" %}
+ {% for include in include_js %}
+ {{ js_asset(include) }}
+ {% endfor %}
+
+ {{ js_asset('frappe/public/js/test.bundle.js') }}
+
+ {% include "templates/includes/app_analytics/google_analytics.html" %}
+ {% include "templates/includes/app_analytics/mixpanel_analytics.html" %}
{% for sound in (sounds or []) %}
diff --git a/package.json b/package.json
index 6e82890617..6d74cb8f8e 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,7 @@
"build": "node rollup/build.js",
"production": "FRAPPE_ENV=production node rollup/build.js",
"watch": "node rollup/watch.js",
- "snyk-protect": "snyk protect",
- "prepare": "yarn run snyk-protect"
+ "snyk-protect": "snyk protect"
},
"repository": {
"type": "git",
@@ -50,14 +49,20 @@
"socket.io": "^2.4.0",
"superagent": "^3.8.2",
"touch": "^3.1.0",
- "vue": "^2.6.11",
+ "vue": "2.6.12",
"vue-router": "^2.0.0"
},
"devDependencies": {
"babel-runtime": "^6.26.0",
"chalk": "^2.3.2",
+ "esbuild": "^0.11.11",
+ "esbuild-plugin-postcss2": "^0.0.9",
+ "esbuild-vue": "^0.2.0",
+ "fast-glob": "^3.2.5",
"graphlib": "^2.1.8",
+ "http-proxy": "^1.18.1",
"less": "^3.11.1",
+ "md5": "^2.3.0",
"rollup": "^1.2.2",
"rollup-plugin-buble": "^0.19.2",
"rollup-plugin-commonjs": "^8.3.0",
@@ -66,8 +71,7 @@
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-terser": "^4.0.4",
"rollup-plugin-vue": "4.2.0",
- "svg-sprite": "^1.5.0",
- "vue-template-compiler": "^2.6.11"
+ "svg-sprite": "^1.5.0"
},
"snyk": true
}
diff --git a/yarn.lock b/yarn.lock
index 8ac348011d..b52288e77e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,11 @@
# yarn lockfile v1
+"@assemblyscript/loader@^0.10.1":
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06"
+ integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==
+
"@babel/code-frame@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
@@ -388,6 +393,18 @@
dependencies:
defer-to-connect "^2.0.0"
+"@types/babel-types@*", "@types/babel-types@^7.0.0":
+ version "7.0.9"
+ resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41"
+ integrity sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA==
+
+"@types/babylon@^6.16.2":
+ version "6.16.5"
+ resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
+ integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
+ dependencies:
+ "@types/babel-types" "*"
+
"@types/braces@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb"
@@ -540,6 +557,22 @@
source-map "~0.6.1"
vue-template-es2015-compiler "^1.9.0"
+"@vue/component-compiler-utils@^3.0.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.2.0.tgz#8f85182ceed28e9b3c75313de669f83166d11e5d"
+ integrity sha512-lejBLa7xAMsfiZfNp7Kv51zOzifnb29FwdnMLa96z26kXErPFioSf9BMcePVIQ6/Gc6/mC0UrPpxAWIHyae0vw==
+ dependencies:
+ consolidate "^0.15.1"
+ hash-sum "^1.0.2"
+ lru-cache "^4.1.2"
+ merge-source-map "^1.1.0"
+ postcss "^7.0.14"
+ postcss-selector-parser "^6.0.2"
+ source-map "~0.6.1"
+ vue-template-es2015-compiler "^1.9.0"
+ optionalDependencies:
+ prettier "^1.18.2"
+
"@vue/component-compiler@^3.3.2":
version "3.6.0"
resolved "https://registry.yarnpkg.com/@vue/component-compiler/-/component-compiler-3.6.0.tgz#8db313e50eaa2903cef5aac68c37a09364dba79d"
@@ -551,6 +584,22 @@
postcss-modules-sync "^1.0.0"
source-map "0.6.*"
+"@vue/component-compiler@^4.2.3":
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/@vue/component-compiler/-/component-compiler-4.2.3.tgz#052855aea0f9a00eb0eb9786bdf447d29292ae37"
+ integrity sha512-B221AV3T/6PF37WnkoqUKIxBeHXmGuZsi/8pby89MAVSj9zmDdLCEZ7LDT8+DJWbElFrPELgnSvEadXxDRcrJQ==
+ dependencies:
+ "@vue/component-compiler-utils" "^3.0.0"
+ clean-css "^4.1.11"
+ hash-sum "^1.0.2"
+ postcss-modules-sync "^1.0.0"
+ source-map "0.6.*"
+ optionalDependencies:
+ less "^3.9.0"
+ pug "^2.0.3"
+ sass "^1.18.0"
+ stylus "^0.54.5"
+
"@yarnpkg/lockfile@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
@@ -574,6 +623,23 @@ ace-builds@^1.4.8:
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.8.tgz#d14be41d30294a2a12581f0bcfee4b696481ffdd"
integrity sha512-8ZVAxwyCGAxQX8mOp9imSXH0hoSPkGfy8igJy+WO/7axL30saRhKgg1XPACSmxxPA7nfHVwM+ShWXT+vKsNuFg==
+acorn-globals@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+ integrity sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=
+ dependencies:
+ acorn "^4.0.4"
+
+acorn@^3.1.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+ integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+
+acorn@^4.0.4, acorn@~4.0.2:
+ version "4.0.13"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
+ integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=
+
acorn@^5.2.1:
version "5.7.4"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
@@ -613,6 +679,15 @@ ajv@^6.12.3:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+align-text@^0.1.1, align-text@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+ integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
+ dependencies:
+ kind-of "^3.0.2"
+ longest "^1.0.1"
+ repeat-string "^1.5.2"
+
alphanum-sort@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
@@ -687,6 +762,14 @@ ansicolors@^0.3.2:
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=
+anymatch@~3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
+ integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -801,11 +884,28 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
-atob@^2.1.1:
+at-least-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
+ integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+
+atob@^2.1.1, atob@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+autoprefixer@^10.2.5:
+ version "10.2.5"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.2.5.tgz#096a0337dbc96c0873526d7fef5de4428d05382d"
+ integrity sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==
+ dependencies:
+ browserslist "^4.16.3"
+ caniuse-lite "^1.0.30001196"
+ colorette "^1.2.2"
+ fraction.js "^4.0.13"
+ normalize-range "^0.1.2"
+ postcss-value-parser "^4.1.0"
+
autoprefixer@^9.8.6:
version "9.8.6"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
@@ -856,6 +956,21 @@ babel-runtime@^6.26.0:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
+babel-types@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+ integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
+ dependencies:
+ babel-runtime "^6.26.0"
+ esutils "^2.0.2"
+ lodash "^4.17.4"
+ to-fast-properties "^1.0.3"
+
+babylon@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+ integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
+
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@@ -876,6 +991,11 @@ base64-js@^1.0.2:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+base64-js@^1.2.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
base64id@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
@@ -906,6 +1026,16 @@ big.js@^3.1.3:
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
bl@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.1.tgz#1cbb439299609e419b5a74d7fce2f8b37d8e5c6f"
@@ -1017,7 +1147,7 @@ braces@^2.3.1:
split-string "^3.0.2"
to-regex "^3.0.1"
-braces@^3.0.1:
+braces@^3.0.1, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -1055,6 +1185,17 @@ browserslist@^4.12.0:
escalade "^3.0.2"
node-releases "^1.1.60"
+browserslist@^4.16.3:
+ version "4.16.4"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.4.tgz#7ebf913487f40caf4637b892b268069951c35d58"
+ integrity sha512-d7rCxYV8I9kj41RH8UKYnvDYCRENUlHRgyXy/Rhr/1BaeLGfiCptEdFE8MIrvGfWbBFNjVYx76SQWvNX1j+/cQ==
+ dependencies:
+ caniuse-lite "^1.0.30001208"
+ colorette "^1.2.2"
+ electron-to-chromium "^1.3.712"
+ escalade "^3.1.1"
+ node-releases "^1.1.71"
+
buble@^0.19.6:
version "0.19.6"
resolved "https://registry.yarnpkg.com/buble/-/buble-0.19.6.tgz#915909b6bd5b11ee03b1c885ec914a8b974d34d3"
@@ -1141,6 +1282,14 @@ cacheable-request@^7.0.1:
normalize-url "^4.1.0"
responselike "^2.0.0"
+call-bind@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.2"
+
caller-callsite@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
@@ -1168,6 +1317,11 @@ camelcase-keys@^2.0.0:
camelcase "^2.0.0"
map-obj "^1.0.0"
+camelcase@^1.0.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+ integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
+
camelcase@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
@@ -1193,11 +1347,24 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30001109, can
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001191.tgz"
integrity sha512-xJJqzyd+7GCJXkcoBiQ1GuxEiOBCLQ0aVW9HMekifZsAVGdj5eJ4mFB9fEhSHipq9IOk/QXFJUiIr9lZT+EsGw==
+caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001208:
+ version "1.0.30001209"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001209.tgz#1bb4be0bd118e98e21cfb7ef617b1ef2164622f4"
+ integrity sha512-2Ktt4OeRM7EM/JaOZjuLzPYAIqmbwQMNnYbgooT+icoRGrKOyAxA1xhlnotBD1KArRSPsuJp3TdYcZYrL7qNxA==
+
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+center-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+ integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
+ dependencies:
+ align-text "^0.1.3"
+ lazy-cache "^1.0.3"
+
chalk@4.1.0, chalk@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
@@ -1234,16 +1401,43 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+character-parser@^2.1.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0"
+ integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A=
+ dependencies:
+ is-regex "^1.0.3"
+
chardet@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+charenc@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
+ integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+
child-process@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/child-process/-/child-process-1.0.2.tgz#98974dc7ed1ee4c6229f8e305fa7313a6885a7f2"
integrity sha1-mJdNx+0e5MYin44wX6cxOmiFp/I=
+"chokidar@>=3.0.0 <4.0.0":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
+ integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
+ dependencies:
+ anymatch "~3.1.1"
+ braces "~3.0.2"
+ glob-parent "~5.1.0"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.5.0"
+ optionalDependencies:
+ fsevents "~2.3.1"
+
chownr@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
@@ -1303,6 +1497,15 @@ cli-width@^3.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
+cliui@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+ integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
+ dependencies:
+ center-align "^0.1.1"
+ right-align "^0.1.1"
+ wordwrap "0.0.2"
+
cliui@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
@@ -1432,6 +1635,11 @@ colorette@^1.2.1:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
+colorette@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
+ integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
+
colors@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@@ -1528,6 +1736,16 @@ consolidate@^0.15.1:
dependencies:
bluebird "^3.1.1"
+constantinople@^3.0.1, constantinople@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647"
+ integrity sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==
+ dependencies:
+ "@types/babel-types" "^7.0.0"
+ "@types/babylon" "^6.16.2"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
@@ -1560,6 +1778,13 @@ cookiejar@^2.1.0:
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==
+copy-anything@^2.0.1:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.3.tgz#842407ba02466b0df844819bbe3baebbe5d45d87"
+ integrity sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ==
+ dependencies:
+ is-what "^3.12.0"
+
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
@@ -1620,6 +1845,11 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
+crypt@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
+ integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+
crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
@@ -1650,6 +1880,13 @@ css-modules-loader-core@^1.1.0:
postcss-modules-scope "1.1.0"
postcss-modules-values "1.3.0"
+css-parse@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4"
+ integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=
+ dependencies:
+ css "^2.0.0"
+
css-select-base-adapter@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
@@ -1726,6 +1963,16 @@ css-what@^2.1.2:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
+css@^2.0.0:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
+ integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==
+ dependencies:
+ inherits "^2.0.3"
+ source-map "^0.6.1"
+ source-map-resolve "^0.5.2"
+ urix "^0.1.0"
+
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@@ -1736,6 +1983,11 @@ cssesc@^2.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
cssmin@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/cssmin/-/cssmin-0.4.3.tgz#c9194077e0ebdacd691d5f59015b9d819f38d015"
@@ -1840,6 +2092,14 @@ custom-event-polyfill@^1.0.7:
resolved "https://registry.yarnpkg.com/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz#9bc993ddda937c1a30ccd335614c6c58c4f87aee"
integrity sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==
+cwd@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/cwd/-/cwd-0.10.0.tgz#172400694057c22a13b0cf16162c7e4b7a7fe567"
+ integrity sha1-FyQAaUBXwioTsM8WFix+S3p/5Wc=
+ dependencies:
+ find-pkg "^0.1.2"
+ fs-exists-sync "^0.1.0"
+
cwise-compiler@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/cwise-compiler/-/cwise-compiler-1.1.3.tgz#f4d667410e850d3a313a7d2db7b1e505bb034cc5"
@@ -1911,7 +2171,7 @@ debug@^4.2.0, debug@^4.3.1:
dependencies:
ms "2.1.2"
-decamelize@^1.1.2, decamelize@^1.2.0:
+decamelize@^1.0.0, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -2063,6 +2323,11 @@ dockerfile-ast@0.2.0:
dependencies:
vscode-languageserver-types "^3.16.0"
+doctypes@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9"
+ integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=
+
dom-serializer@0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
@@ -2158,6 +2423,11 @@ electron-to-chromium@^1.3.523:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.551.tgz#a94d243a4ca90705189bd4a5eca4e0f56b745a4f"
integrity sha512-11qcm2xvf2kqeFO5EIejaBx5cKXsW1quAyv3VctCMYwofnyVZLs97y6LCekss3/ghQpr7PYkSO3uId5FmxZsdw==
+electron-to-chromium@^1.3.712:
+ version "1.3.717"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.717.tgz#78d4c857070755fb58ab64bcc173db1d51cbc25f"
+ integrity sha512-OfzVPIqD1MkJ7fX+yTl2nKyOE4FReeVfMCzzxQS+Kp43hZYwHwThlGP+EGIZRXJsxCM7dqo8Y65NOX/HP12iXQ==
+
elfy@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/elfy/-/elfy-1.0.0.tgz#7a1c86af7d41e0a568cbb4a3fa5b685648d9efcd"
@@ -2185,6 +2455,11 @@ emojis-list@^2.0.0:
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
+emojis-list@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+ integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
enabled@2.0.x:
version "2.0.0"
resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
@@ -2336,11 +2611,45 @@ es6-promise@^4.0.3:
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+esbuild-plugin-postcss2@^0.0.9:
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/esbuild-plugin-postcss2/-/esbuild-plugin-postcss2-0.0.9.tgz#b889af46f703990988d47885632108901948673e"
+ integrity sha512-iDKxWohm9aD2s+++ihb6GJVcddebsxOaC+Oz8TV0xJnKy0yHz/xazX96HyP45cS6+SFvZwr+SzG+QHbMOuXfMg==
+ dependencies:
+ autoprefixer "^10.2.5"
+ fs-extra "^9.1.0"
+ less "^4.x"
+ postcss "8.x"
+ postcss-modules "^4.0.0"
+ resolve-file "^0.3.0"
+ sass "^1.x"
+ stylus "^0.x"
+ tmp "^0.2.1"
+
+esbuild-vue@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/esbuild-vue/-/esbuild-vue-0.2.0.tgz#8a3fde404bda57fe32b80e24917d14036e242bd3"
+ integrity sha512-CS0P1wXB8hTFCijWKMH4b1R2n66o/C588uhGZ8V6ff7G1z4U2xVS63C1ee0s76MXHTVlNNoCyyTH35iMgaTR7g==
+ dependencies:
+ "@vue/component-compiler" "^4.2.3"
+ piscina "^2.2.0"
+ vue-template-compiler "^2.6.12"
+
+esbuild@^0.11.11:
+ version "0.11.11"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.11.tgz#8f235e0a1a34253a47fd80d51f12084dd98074bd"
+ integrity sha512-iq5YdV63vY/nUAFIvY92BXVkYjMbOchnofLKoLKMPZIa4uuIJAJG9WRA+ZRjQBZbrsORUwvZcANeG2d3p46PJQ==
+
escalade@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4"
integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
@@ -2400,6 +2709,11 @@ event-loop-spinner@^2.1.0:
dependencies:
tslib "^2.1.0"
+eventemitter-asyncresource@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz#734ff2e44bf448e627f7748f905d6bdd57bdb65b"
+ integrity sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==
+
eventemitter3@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
@@ -2436,6 +2750,13 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+expand-tilde@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+ integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
+ dependencies:
+ os-homedir "^1.0.1"
+
expand-tilde@^2.0.0, expand-tilde@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
@@ -2562,6 +2883,18 @@ fast-diff@1.2.0:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
+fast-glob@^3.2.5:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661"
+ integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.0"
+ merge2 "^1.3.0"
+ micromatch "^4.0.2"
+ picomatch "^2.2.1"
+
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
@@ -2633,6 +2966,21 @@ finalhandler@~1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
+find-file-up@^0.1.2:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/find-file-up/-/find-file-up-0.1.3.tgz#cf68091bcf9f300a40da411b37da5cce5a2fbea0"
+ integrity sha1-z2gJG8+fMApA2kEbN9pczlovvqA=
+ dependencies:
+ fs-exists-sync "^0.1.0"
+ resolve-dir "^0.1.0"
+
+find-pkg@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/find-pkg/-/find-pkg-0.1.2.tgz#1bdc22c06e36365532e2a248046854b9788da557"
+ integrity sha1-G9wiwG42NlUy4qJIBGhUuXiNpVc=
+ dependencies:
+ find-file-up "^0.1.2"
+
find-up@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@@ -2653,7 +3001,7 @@ fn.name@1.x.x:
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
-follow-redirects@^1.10.0:
+follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.13.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
@@ -2692,6 +3040,11 @@ forwarded@~0.1.2:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+fraction.js@^4.0.13:
+ version "4.0.13"
+ resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe"
+ integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==
+
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -2728,6 +3081,11 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+fs-exists-sync@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+ integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
+
fs-extra@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950"
@@ -2737,6 +3095,16 @@ fs-extra@^1.0.0:
jsonfile "^2.1.0"
klaw "^1.0.0"
+fs-extra@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
+ dependencies:
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
@@ -2749,6 +3117,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+fsevents@~2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
+
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
@@ -2797,6 +3170,13 @@ generic-names@^1.0.2, generic-names@^1.0.3:
dependencies:
loader-utils "^0.2.16"
+generic-names@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872"
+ integrity sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==
+ dependencies:
+ loader-utils "^1.1.0"
+
get-caller-file@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
@@ -2807,6 +3187,15 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-intrinsic@^1.0.2:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
+
get-pixels@^3.2.3:
version "3.3.2"
resolved "https://registry.yarnpkg.com/get-pixels/-/get-pixels-3.3.2.tgz#3f62fb8811932c69f262bba07cba72b692b4ff03"
@@ -2870,6 +3259,13 @@ gl-vec3@^1.0.3:
resolved "https://registry.yarnpkg.com/gl-vec3/-/gl-vec3-1.1.3.tgz#a47c62f918774a06cbed1b65bcd0288ecbb03826"
integrity sha512-jduKUqT0SGH02l8Yl+mV1yVsDfYgQAJyXGxkJQGyxPLHRiW25DwVIRPt6uvhrEMHftJfqhqKthRcyZqNEl9Xdw==
+glob-parent@^5.1.0, glob-parent@~5.1.0:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
@@ -2914,6 +3310,14 @@ global-dirs@^2.0.1:
dependencies:
ini "^1.3.5"
+global-modules@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+ integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
+ dependencies:
+ global-prefix "^0.1.4"
+ is-windows "^0.2.0"
+
global-modules@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
@@ -2923,6 +3327,16 @@ global-modules@^1.0.0:
is-windows "^1.0.1"
resolve-dir "^1.0.0"
+global-prefix@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+ integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
+ dependencies:
+ homedir-polyfill "^1.0.0"
+ ini "^1.3.4"
+ is-windows "^0.2.0"
+ which "^1.2.12"
+
global-prefix@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
@@ -2989,6 +3403,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+graceful-fs@^4.2.0:
+ version "4.2.6"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
+ integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
+
graphlib@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da"
@@ -3147,6 +3566,20 @@ hcl-to-json@^0.1.1:
lodash.get "^4.4.2"
lodash.set "^4.3.2"
+hdr-histogram-js@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.1.tgz#ecb1ff2bcb6181c3e93ff4af9472c28c7e97284e"
+ integrity sha512-uPZxl1dAFnjUFHWLZmt93vUUvtHeaBay9nVNHu38SdOjMSF/4KqJUqa1Seuj08ptU1rEb6AHvB41X8n/zFZ74Q==
+ dependencies:
+ "@assemblyscript/loader" "^0.10.1"
+ base64-js "^1.2.0"
+ pako "^1.0.3"
+
+hdr-histogram-percentiles-obj@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c"
+ integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==
+
he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -3167,7 +3600,7 @@ highlight.js@^10.4.1:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0"
integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==
-homedir-polyfill@^1.0.1:
+homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
@@ -3235,6 +3668,15 @@ http-errors@~1.7.2:
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
+http-proxy@^1.18.1:
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
+ dependencies:
+ eventemitter3 "^4.0.0"
+ follow-redirects "^1.0.0"
+ requires-port "^1.0.0"
+
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -3269,6 +3711,11 @@ icss-replace-symbols@1.1.0, icss-replace-symbols@^1.0.2, icss-replace-symbols@^1
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
+icss-utils@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+ integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
ieee754@^1.1.4:
version "1.1.13"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
@@ -3425,12 +3872,19 @@ is-bigint@^1.0.0:
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4"
integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
is-boolean-object@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
-is-buffer@^1.0.2, is-buffer@^1.1.5:
+is-buffer@^1.0.2, is-buffer@^1.1.5, is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
@@ -3464,6 +3918,13 @@ is-color-stop@^1.0.0:
rgb-regex "^1.0.1"
rgba-regex "^1.0.0"
+is-core-module@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
+ integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
+ dependencies:
+ has "^1.0.3"
+
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -3521,6 +3982,14 @@ is-docker@^2.0.0:
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b"
integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==
+is-expression@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-3.0.0.tgz#39acaa6be7fd1f3471dc42c7416e61c24317ac9f"
+ integrity sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=
+ dependencies:
+ acorn "~4.0.2"
+ object-assign "^4.0.1"
+
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
@@ -3567,7 +4036,7 @@ is-glob@^3.0.0:
dependencies:
is-extglob "^2.1.0"
-is-glob@^4.0.1:
+is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -3646,6 +4115,19 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"
+is-promise@^2.0.0:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
+ integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
+
+is-regex@^1.0.3:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251"
+ integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==
+ dependencies:
+ call-bind "^1.0.2"
+ has-symbols "^1.0.1"
+
is-regex@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
@@ -3739,6 +4221,16 @@ is-weakset@^2.0.1:
resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83"
integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==
+is-what@^3.12.0:
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
+ integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
+
+is-windows@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+ integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
+
is-windows@^1.0.1, is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -3826,6 +4318,11 @@ js-sha256@^0.9.0:
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==
+js-stringify@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db"
+ integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds=
+
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -3889,6 +4386,13 @@ json5@^0.5.0:
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
+json5@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+ integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ dependencies:
+ minimist "^1.2.0"
+
jsonfile@^2.1.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
@@ -3896,6 +4400,15 @@ jsonfile@^2.1.0:
optionalDependencies:
graceful-fs "^4.1.6"
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@@ -3906,6 +4419,14 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
+jstransformer@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3"
+ integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=
+ dependencies:
+ is-promise "^2.0.0"
+ promise "^7.0.1"
+
jszip@3.4.0, jszip@^3.2.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.4.0.tgz#1a69421fa5f0bb9bc222a46bca88182fba075350"
@@ -3978,6 +4499,18 @@ latest-version@^5.0.0:
dependencies:
package-json "^6.3.0"
+lazy-cache@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+ integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
+
+lazy-cache@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
+ integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
+ dependencies:
+ set-getter "^0.1.0"
+
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -4002,6 +4535,39 @@ less@^3.11.1:
request "^2.83.0"
source-map "~0.6.0"
+less@^3.9.0:
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/less/-/less-3.13.1.tgz#0ebc91d2a0e9c0c6735b83d496b0ab0583077909"
+ integrity sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==
+ dependencies:
+ copy-anything "^2.0.1"
+ tslib "^1.10.0"
+ optionalDependencies:
+ errno "^0.1.1"
+ graceful-fs "^4.1.2"
+ image-size "~0.5.0"
+ make-dir "^2.1.0"
+ mime "^1.4.1"
+ native-request "^1.0.5"
+ source-map "~0.6.0"
+
+less@^4.x:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba"
+ integrity sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw==
+ dependencies:
+ copy-anything "^2.0.1"
+ parse-node-version "^1.0.1"
+ tslib "^1.10.0"
+ optionalDependencies:
+ errno "^0.1.1"
+ graceful-fs "^4.1.2"
+ image-size "~0.5.0"
+ make-dir "^2.1.0"
+ mime "^1.4.1"
+ needle "^2.5.2"
+ source-map "~0.6.0"
+
lie@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
@@ -4037,6 +4603,15 @@ loader-utils@^0.2.16:
json5 "^0.5.0"
object-assign "^4.0.1"
+loader-utils@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
+ integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^3.0.0"
+ json5 "^1.0.1"
+
loadjs@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/loadjs/-/loadjs-4.2.0.tgz#2a0336376397a6a43edf98c9ec3229ddd5abb6f6"
@@ -4426,6 +5001,11 @@ logform@^2.2.0:
ms "^2.1.1"
triple-beam "^1.3.0"
+longest@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+ integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
+
loud-rejection@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
@@ -4485,6 +5065,14 @@ magic-string@^0.25.1:
dependencies:
sourcemap-codec "^1.4.4"
+make-dir@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
+ integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
+ dependencies:
+ pify "^4.0.1"
+ semver "^5.6.0"
+
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -4535,6 +5123,15 @@ matcher@^3.0.0:
dependencies:
escape-string-regexp "^4.0.0"
+md5@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
+ integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
+ dependencies:
+ charenc "0.0.2"
+ crypt "0.0.2"
+ is-buffer "~1.1.6"
+
mdn-data@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
@@ -4751,7 +5348,7 @@ mkdirp@0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
-mkdirp@^1.0.3, mkdirp@^1.0.4:
+mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -4815,6 +5412,11 @@ nan@^2.13.2:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
+nanoid@^3.1.22:
+ version "3.1.22"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844"
+ integrity sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==
+
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -4832,6 +5434,11 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
+native-request@^1.0.5:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/native-request/-/native-request-1.0.8.tgz#8f66bf606e0f7ea27c0e5995eb2f5d03e33ae6fb"
+ integrity sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==
+
ndarray-linear-interpolate@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ndarray-linear-interpolate/-/ndarray-linear-interpolate-1.0.0.tgz#78bc92b85b9abc15b6e67ee65828f9e2137ae72b"
@@ -4853,7 +5460,7 @@ ndarray@^1.0.13, ndarray@^1.0.18:
iota-array "^1.0.0"
is-buffer "^1.0.2"
-needle@2.6.0:
+needle@2.6.0, needle@^2.5.2:
version "2.6.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe"
integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==
@@ -4885,16 +5492,34 @@ negotiator@0.6.2:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+nice-napi@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b"
+ integrity sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==
+ dependencies:
+ node-addon-api "^3.0.0"
+ node-gyp-build "^4.2.2"
+
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+node-addon-api@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
+ integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
+
node-bitmap@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091"
integrity sha1-GA6scAPgxwdhjvMTaPYvhLKmkJE=
+node-gyp-build@^4.2.2:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
+ integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==
+
node-gyp@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
@@ -4918,6 +5543,11 @@ node-releases@^1.1.60:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084"
integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==
+node-releases@^1.1.71:
+ version "1.1.71"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
+ integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
+
node-releases@^1.1.8:
version "1.1.9"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.9.tgz#70d0985ec4bf7de9f08fc481f5dae111889ca482"
@@ -4972,6 +5602,11 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
@@ -5271,16 +5906,16 @@ package-json@^6.3.0:
registry-url "^5.0.0"
semver "^6.2.0"
+pako@^1.0.3, pako@~1.0.2:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
+ integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
-pako@~1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
- integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
-
parchment@2.0.0-dev.2:
version "2.0.0-dev.2"
resolved "https://registry.yarnpkg.com/parchment/-/parchment-2.0.0-dev.2.tgz#9d6fe57b3721317bd1c481ea38ffa9b287d496b8"
@@ -5320,6 +5955,11 @@ parse-link-header@^1.0.1:
dependencies:
xtend "~4.0.1"
+parse-node-version@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
+ integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
+
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@@ -5420,6 +6060,11 @@ phantomjs-prebuilt@^2.1.16:
request-progress "^2.0.1"
which "^1.2.10"
+picomatch@^2.0.4:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d"
+ integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==
+
picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
@@ -5435,6 +6080,11 @@ pify@^3.0.0:
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+pify@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+ integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
@@ -5447,6 +6097,17 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+piscina@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/piscina/-/piscina-2.2.0.tgz#8fd5236f07aaa9676c4100a3e4d90b6b7aaabf4c"
+ integrity sha512-CQb0DfyTdC9FBIMYkVV/00fXRLKDjmWKA8S0N1zDg2JGEc5z3P9qHXtoq8OkJQ+vjCfXySkVonTNMqskMFOW/w==
+ dependencies:
+ eventemitter-asyncresource "^1.0.0"
+ hdr-histogram-js "^2.0.1"
+ hdr-histogram-percentiles-obj "^3.0.0"
+ optionalDependencies:
+ nice-napi "^1.0.2"
+
plyr@^3.6.2:
version "3.6.2"
resolved "https://registry.yarnpkg.com/plyr/-/plyr-3.6.2.tgz#5a55b608acd161262de1cc75ca843aa64355a051"
@@ -5602,6 +6263,11 @@ postcss-modules-extract-imports@1.1.0:
dependencies:
postcss "^6.0.1"
+postcss-modules-extract-imports@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
+ integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
+
postcss-modules-local-by-default@1.2.0, postcss-modules-local-by-default@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
@@ -5610,6 +6276,15 @@ postcss-modules-local-by-default@1.2.0, postcss-modules-local-by-default@^1.1.1:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
+postcss-modules-local-by-default@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c"
+ integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==
+ dependencies:
+ icss-utils "^5.0.0"
+ postcss-selector-parser "^6.0.2"
+ postcss-value-parser "^4.1.0"
+
postcss-modules-scope@1.1.0, postcss-modules-scope@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
@@ -5618,6 +6293,13 @@ postcss-modules-scope@1.1.0, postcss-modules-scope@^1.0.2:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
+postcss-modules-scope@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06"
+ integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==
+ dependencies:
+ postcss-selector-parser "^6.0.4"
+
postcss-modules-sync@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-sync/-/postcss-modules-sync-1.0.0.tgz#619a719cf78dd16a4834135140b324cf77334be1"
@@ -5638,6 +6320,13 @@ postcss-modules-values@1.3.0:
icss-replace-symbols "^1.1.0"
postcss "^6.0.1"
+postcss-modules-values@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+ integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+ dependencies:
+ icss-utils "^5.0.0"
+
postcss-modules@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-1.4.1.tgz#8aa35bd3461db67e27377a7ce770d77b654a84ef"
@@ -5649,6 +6338,20 @@ postcss-modules@^1.4.1:
postcss "^7.0.1"
string-hash "^1.1.1"
+postcss-modules@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.0.0.tgz#2bc7f276ab88f3f1b0fadf6cbd7772d43b5f3b9b"
+ integrity sha512-ghS/ovDzDqARm4Zj6L2ntadjyQMoyJmi0JkLlYtH2QFLrvNlxH5OAVRPWPeKilB0pY7SbuhO173KOWkPAxRJcw==
+ dependencies:
+ generic-names "^2.0.1"
+ icss-replace-symbols "^1.1.0"
+ lodash.camelcase "^4.3.0"
+ postcss-modules-extract-imports "^3.0.0"
+ postcss-modules-local-by-default "^4.0.0"
+ postcss-modules-scope "^3.0.0"
+ postcss-modules-values "^4.0.0"
+ string-hash "^1.1.1"
+
postcss-normalize-charset@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4"
@@ -5777,6 +6480,16 @@ postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.4:
indexes-of "^1.0.1"
uniq "^1.0.1"
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3"
+ integrity sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==
+ dependencies:
+ cssesc "^3.0.0"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+ util-deprecate "^1.0.2"
+
postcss-svgo@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258"
@@ -5815,6 +6528,15 @@ postcss@6.0.1:
source-map "^0.5.6"
supports-color "^3.2.3"
+postcss@8.x:
+ version "8.2.10"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b"
+ integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==
+ dependencies:
+ colorette "^1.2.2"
+ nanoid "^3.1.22"
+ source-map "^0.6.1"
+
postcss@^5.2.5:
version "5.2.18"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
@@ -5867,6 +6589,11 @@ prettier@^1.13.0:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==
+prettier@^1.18.2:
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
+ integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
+
prettysize@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/prettysize/-/prettysize-1.1.0.tgz#c6c52f87161ff172ea435f375f99831dd9a97bb0"
@@ -5904,7 +6631,7 @@ promise.series@^0.2.0:
resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd"
integrity sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=
-"promise@>=3.2 <8", promise@^7.1.1:
+"promise@>=3.2 <8", promise@^7.0.1, promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
@@ -5939,6 +6666,111 @@ psl@^1.1.24, psl@^1.1.28:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
+pug-attrs@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-2.0.4.tgz#b2f44c439e4eb4ad5d4ef25cac20d18ad28cc336"
+ integrity sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==
+ dependencies:
+ constantinople "^3.0.1"
+ js-stringify "^1.0.1"
+ pug-runtime "^2.0.5"
+
+pug-code-gen@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-2.0.3.tgz#122eb9ada9b5bf601705fe15aaa0a7d26bc134ab"
+ integrity sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA==
+ dependencies:
+ constantinople "^3.1.2"
+ doctypes "^1.1.0"
+ js-stringify "^1.0.1"
+ pug-attrs "^2.0.4"
+ pug-error "^1.3.3"
+ pug-runtime "^2.0.5"
+ void-elements "^2.0.1"
+ with "^5.0.0"
+
+pug-error@^1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-1.3.3.tgz#f342fb008752d58034c185de03602dd9ffe15fa6"
+ integrity sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==
+
+pug-filters@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-3.1.1.tgz#ab2cc82db9eeccf578bda89130e252a0db026aa7"
+ integrity sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==
+ dependencies:
+ clean-css "^4.1.11"
+ constantinople "^3.0.1"
+ jstransformer "1.0.0"
+ pug-error "^1.3.3"
+ pug-walk "^1.1.8"
+ resolve "^1.1.6"
+ uglify-js "^2.6.1"
+
+pug-lexer@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-4.1.0.tgz#531cde48c7c0b1fcbbc2b85485c8665e31489cfd"
+ integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==
+ dependencies:
+ character-parser "^2.1.1"
+ is-expression "^3.0.0"
+ pug-error "^1.3.3"
+
+pug-linker@^3.0.6:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-3.0.6.tgz#f5bf218b0efd65ce6670f7afc51658d0f82989fb"
+ integrity sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==
+ dependencies:
+ pug-error "^1.3.3"
+ pug-walk "^1.1.8"
+
+pug-load@^2.0.12:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-2.0.12.tgz#d38c85eb85f6e2f704dea14dcca94144d35d3e7b"
+ integrity sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==
+ dependencies:
+ object-assign "^4.1.0"
+ pug-walk "^1.1.8"
+
+pug-parser@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-5.0.1.tgz#03e7ada48b6840bd3822f867d7d90f842d0ffdc9"
+ integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==
+ dependencies:
+ pug-error "^1.3.3"
+ token-stream "0.0.1"
+
+pug-runtime@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.5.tgz#6da7976c36bf22f68e733c359240d8ae7a32953a"
+ integrity sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==
+
+pug-strip-comments@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz#cc1b6de1f6e8f5931cf02ec66cdffd3f50eaf8a8"
+ integrity sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==
+ dependencies:
+ pug-error "^1.3.3"
+
+pug-walk@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.8.tgz#b408f67f27912f8c21da2f45b7230c4bd2a5ea7a"
+ integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==
+
+pug@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pug/-/pug-2.0.4.tgz#ee7682ec0a60494b38d48a88f05f3b0ac931377d"
+ integrity sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==
+ dependencies:
+ pug-code-gen "^2.0.2"
+ pug-filters "^3.1.1"
+ pug-lexer "^4.1.0"
+ pug-linker "^3.0.6"
+ pug-load "^2.0.12"
+ pug-parser "^5.0.1"
+ pug-runtime "^2.0.5"
+ pug-strip-comments "^1.0.4"
+
pump@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
@@ -6161,6 +6993,13 @@ readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0, readable
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
+readdirp@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
+ integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
+ dependencies:
+ picomatch "^2.2.1"
+
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -6295,7 +7134,7 @@ repeat-element@^1.1.2:
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
-repeat-string@^1.6.1:
+repeat-string@^1.5.2, repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
@@ -6391,6 +7230,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+ integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
reserved-words@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1"
@@ -6401,6 +7245,14 @@ resolve-alpn@^1.0.0:
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c"
integrity sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA==
+resolve-dir@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+ integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
+ dependencies:
+ expand-tilde "^1.2.2"
+ global-modules "^0.2.3"
+
resolve-dir@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
@@ -6409,6 +7261,19 @@ resolve-dir@^1.0.0:
expand-tilde "^2.0.0"
global-modules "^1.0.0"
+resolve-file@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/resolve-file/-/resolve-file-0.3.0.tgz#11e1fb464566d3a7c500cb7e9481e8f0b00a14ef"
+ integrity sha1-EeH7RkVm06fFAMt+lIHo8LAKFO8=
+ dependencies:
+ cwd "^0.10.0"
+ expand-tilde "^2.0.2"
+ extend-shallow "^2.0.1"
+ fs-exists-sync "^0.1.0"
+ homedir-polyfill "^1.0.1"
+ lazy-cache "^2.0.2"
+ resolve "^1.2.0"
+
resolve-from@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
@@ -6419,6 +7284,14 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+resolve@^1.1.6, resolve@^1.2.0:
+ version "1.20.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
+ dependencies:
+ is-core-module "^2.2.0"
+ path-parse "^1.0.6"
+
resolve@^1.10.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
@@ -6475,6 +7348,13 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
+right-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+ integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
+ dependencies:
+ align-text "^0.1.1"
+
rimraf@2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -6633,7 +7513,7 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -6648,6 +7528,13 @@ sass-graph@2.2.5:
scss-tokenizer "^0.2.3"
yargs "^13.3.2"
+sass@^1.18.0, sass@^1.x:
+ version "1.32.10"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.10.tgz#d40da4e20031b450359ee1c7e69bc8cc89569241"
+ integrity sha512-Nx0pcWoonAkn7CRp0aE/hket1UP97GiR1IFw3kcjV3pnenhWgZEWUf0ZcfPOV2fK52fnOcK3JdC/YYZ9E47DTQ==
+ dependencies:
+ chokidar ">=3.0.0 <4.0.0"
+
sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -6673,7 +7560,7 @@ semver-diff@^3.1.1:
dependencies:
semver "^6.3.0"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1:
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -6741,6 +7628,13 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+set-getter@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
+ integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=
+ dependencies:
+ to-object-path "^0.3.0"
+
set-immediate-shim@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
@@ -7309,6 +8203,17 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
+source-map-resolve@^0.5.2:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+ dependencies:
+ atob "^2.1.2"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
source-map-support@^0.5.11, source-map-support@^0.5.7, source-map-support@~0.5.10:
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
@@ -7342,11 +8247,16 @@ source-map@^0.4.2:
dependencies:
amdefine ">=0.0.4"
-source-map@^0.5.3, source-map@^0.5.6:
+source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+source-map@^0.7.3:
+ version "0.7.3"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
+ integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
+
sourcemap-codec@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f"
@@ -7625,6 +8535,20 @@ stylehacks@^4.0.0:
postcss "^7.0.0"
postcss-selector-parser "^3.0.0"
+stylus@^0.54.5, stylus@^0.x:
+ version "0.54.8"
+ resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147"
+ integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==
+ dependencies:
+ css-parse "~2.0.0"
+ debug "~3.1.0"
+ glob "^7.1.6"
+ mkdirp "~1.0.4"
+ safer-buffer "^2.1.2"
+ sax "~1.2.4"
+ semver "^6.3.0"
+ source-map "^0.7.3"
+
superagent@^3.8.2:
version "3.8.3"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
@@ -7883,6 +8807,11 @@ to-array@0.1.4:
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
+to-fast-properties@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+ integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
+
to-object-path@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
@@ -7925,6 +8854,11 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+token-stream@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a"
+ integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=
+
toml@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee"
@@ -8047,6 +8981,21 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+uglify-js@^2.6.1:
+ version "2.8.29"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+ integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
+ dependencies:
+ source-map "~0.5.1"
+ yargs "~3.10.0"
+ optionalDependencies:
+ uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+ integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
+
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@@ -8097,6 +9046,11 @@ unique-string@^2.0.0:
dependencies:
crypto-random-string "^2.0.0"
+universalify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
+ integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -8168,7 +9122,7 @@ utf8@^3.0.0:
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
-util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
@@ -8255,6 +9209,11 @@ vlq@^1.0.0:
resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.0.tgz#8101be90843422954c2b13eb27f2f3122bdcc806"
integrity sha512-o3WmXySo+oI5thgqr7Qy8uBkT/v9Zr+sRyrh1lr8aWPUkgDWdWt4Nae2WKBrLsocgE8BuWWD0jLc+VW8LeU+2g==
+void-elements@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
+ integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+
vscode-languageserver-types@^3.16.0:
version "3.16.0"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247"
@@ -8265,10 +9224,10 @@ vue-router@^2.0.0:
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-2.8.1.tgz#9833c9ee57ac83beb0269056fefee71713f20695"
integrity sha512-MC4jacHBhTPKtmcfzvaj2N7g6jgJ/Z/eIjZdt+yUaUOM1iKC0OUIlO/xCtz6OZFFTNUJs/1YNro2GN/lE+nOXA==
-vue-template-compiler@^2.6.11:
- version "2.6.11"
- resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz#c04704ef8f498b153130018993e56309d4698080"
- integrity sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==
+vue-template-compiler@^2.6.12:
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
+ integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
@@ -8278,10 +9237,10 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
-vue@^2.6.11:
- version "2.6.11"
- resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
- integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
+vue@2.6.12:
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
+ integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
wcwidth@^1.0.1:
version "1.0.1"
@@ -8328,7 +9287,7 @@ which-typed-array@^1.1.2:
has-symbols "^1.0.1"
is-typed-array "^1.1.3"
-which@1, which@^1.2.10, which@^1.2.14, which@^1.2.9:
+which@1, which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -8349,6 +9308,11 @@ widest-line@^3.1.0:
dependencies:
string-width "^4.0.0"
+window-size@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+ integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
+
windows-release@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
@@ -8379,6 +9343,19 @@ winston@^3.1.0:
triple-beam "^1.3.0"
winston-transport "^4.4.0"
+with@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe"
+ integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=
+ dependencies:
+ acorn "^3.1.0"
+ acorn-globals "^3.0.0"
+
+wordwrap@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+ integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
+
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -8561,6 +9538,16 @@ yargs@^14.2:
y18n "^4.0.0"
yargs-parser "^15.0.0"
+yargs@~3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+ integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
+ dependencies:
+ camelcase "^1.0.2"
+ cliui "^2.1.0"
+ decamelize "^1.0.0"
+ window-size "0.1.0"
+
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
From a0a8f5cb42fd6b2cc1707bef529bf42cec45f11c Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Sat, 17 Apr 2021 17:28:15 +0530
Subject: [PATCH 074/623] fix: Build for all apps
---
esbuild/index.js | 64 +++++++++++++++++++++--------
frappe/public/js/controls.bundle.js | 2 -
2 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/esbuild/index.js b/esbuild/index.js
index 419b6eb641..aacff1d6d9 100644
--- a/esbuild/index.js
+++ b/esbuild/index.js
@@ -1,19 +1,54 @@
+let path = require("path");
let glob = require("fast-glob");
let esbuild = require("esbuild");
let html_plugin = require("./esbuild-plugin-html");
let vue = require("esbuild-vue");
let postCssPlugin = require("esbuild-plugin-postcss2").default;
let ignore_assets = require("./ignore-assets");
-let { get_options_for_scss } = require("../rollup/rollup.utils");
+let {
+ app_list,
+ get_options_for_scss,
+ get_public_path,
+ run_serially
+} = require("./utils");
-console.time("Build time");
+const TOTAL_BUILD_TIME = "Total Build Time";
-glob(["frappe/public/js/**/*.bundle.js"]).then(entry_files => {
- esbuild
+
+(async function() {
+ console.time(TOTAL_BUILD_TIME);
+ await run_build_for_apps(app_list);
+ console.timeEnd(TOTAL_BUILD_TIME);
+})();
+
+function run_build_for_apps(apps) {
+ return run_serially(apps.map(app => () => run_build_for_app(app)));
+}
+
+function run_build_for_app(app) {
+ let public_path = get_public_path(app);
+ let include_patterns = path.resolve(public_path, "**", "*.bundle.js");
+ let ignore_patterns = [
+ path.resolve(public_path, "node_modules"),
+ path.resolve(public_path, "build")
+ ];
+
+ return glob(include_patterns, { ignore: ignore_patterns }).then(files => {
+ console.log(`\nBuilding assets for ${app}...`);
+ return build_files({
+ files,
+ outdir: path.resolve(public_path, "build"),
+ outbase: public_path
+ });
+ });
+}
+
+function build_files({ files, outdir, outbase }) {
+ return esbuild
.build({
- entryPoints: entry_files,
- outdir: "frappe/public/build",
- outbase: "frappe/public",
+ entryPoints: files,
+ outdir,
+ outbase,
sourcemap: true,
bundle: true,
metafile: true,
@@ -45,7 +80,7 @@ glob(["frappe/public/js/**/*.bundle.js"]).then(entry_files => {
}
}
})
- ],
+ ]
// watch: {
// onRebuild(error, result) {
@@ -59,20 +94,15 @@ glob(["frappe/public/js/**/*.bundle.js"]).then(entry_files => {
})
.then(result => {
log_build_meta(result.metafile);
-
- if (result.warnings.length) {
- console.warn(result.warnings);
- }
})
- .catch(e => console.error("error"))
- .finally(() => {
- console.timeEnd("Build time");
+ .catch(e => {
+ console.error("Error during build");
});
-});
+}
function log_build_meta(metafile) {
for (let outfile in metafile.outputs) {
- if (outfile.endsWith('.map')) continue;
+ if (outfile.endsWith(".map")) continue;
let data = metafile.outputs[outfile];
console.log(outfile, data.bytes / 1000 + " Kb");
}
diff --git a/frappe/public/js/controls.bundle.js b/frappe/public/js/controls.bundle.js
index f9a983ecae..30b5d43905 100644
--- a/frappe/public/js/controls.bundle.js
+++ b/frappe/public/js/controls.bundle.js
@@ -16,5 +16,3 @@ import "air-datepicker/dist/js/i18n/datepicker.sk.js";
import "air-datepicker/dist/js/i18n/datepicker.zh.js";
import "./frappe/ui/capture.js";
import "./frappe/form/controls/control.js";
-
-console.log('controls')
From 4172e1ff97a2b771c6263a4f21fc06a83bd93597 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 05:59:19 +0530
Subject: [PATCH 075/623] fix: Compile ts, css, scss, sass, less, styl files
- add support for multiple file types
---
esbuild/index.js | 35 +++++++++--------------------------
esbuild/sass_options.js | 19 +++++++++++++++++++
2 files changed, 28 insertions(+), 26 deletions(-)
create mode 100644 esbuild/sass_options.js
diff --git a/esbuild/index.js b/esbuild/index.js
index aacff1d6d9..742f3ca2cc 100644
--- a/esbuild/index.js
+++ b/esbuild/index.js
@@ -5,16 +5,11 @@ let html_plugin = require("./esbuild-plugin-html");
let vue = require("esbuild-vue");
let postCssPlugin = require("esbuild-plugin-postcss2").default;
let ignore_assets = require("./ignore-assets");
-let {
- app_list,
- get_options_for_scss,
- get_public_path,
- run_serially
-} = require("./utils");
+let sass_options = require("./sass_options");
+let { app_list, get_public_path, run_serially } = require("./utils");
const TOTAL_BUILD_TIME = "Total Build Time";
-
(async function() {
console.time(TOTAL_BUILD_TIME);
await run_build_for_apps(app_list);
@@ -27,14 +22,18 @@ function run_build_for_apps(apps) {
function run_build_for_app(app) {
let public_path = get_public_path(app);
- let include_patterns = path.resolve(public_path, "**", "*.bundle.js");
+ let include_patterns = path.resolve(
+ public_path,
+ "**",
+ "*.bundle.{js,ts,css,sass,scss,less,styl}"
+ );
let ignore_patterns = [
path.resolve(public_path, "node_modules"),
path.resolve(public_path, "build")
];
return glob(include_patterns, { ignore: ignore_patterns }).then(files => {
- console.log(`\nBuilding assets for ${app}...`);
+ // console.log(`\nBuilding assets for ${app}...`);
return build_files({
files,
outdir: path.resolve(public_path, "build"),
@@ -62,23 +61,7 @@ function build_files({ files, outdir, outbase }) {
vue(),
postCssPlugin({
plugins: [require("autoprefixer")],
- sassOptions: {
- ...get_options_for_scss(),
- importer: function(url) {
- if (url.startsWith("~")) {
- // strip ~ so that it can resolve from node_modules
- url = url.slice(1);
- }
- if (url.endsWith(".css")) {
- // strip .css from end of path
- url = url.slice(0, -4);
- }
- // normal file, let it go
- return {
- file: url
- };
- }
- }
+ sassOptions: sass_options
})
]
diff --git a/esbuild/sass_options.js b/esbuild/sass_options.js
new file mode 100644
index 0000000000..a2d22c807d
--- /dev/null
+++ b/esbuild/sass_options.js
@@ -0,0 +1,19 @@
+let { get_options_for_scss } = require("./utils");
+
+module.exports = {
+ ...get_options_for_scss(),
+ importer: function(url) {
+ if (url.startsWith("~")) {
+ // strip ~ so that it can resolve from node_modules
+ url = url.slice(1);
+ }
+ if (url.endsWith(".css")) {
+ // strip .css from end of path
+ url = url.slice(0, -4);
+ }
+ // normal file, let it go
+ return {
+ file: url
+ };
+ }
+};
From 3c824bb92f5289ab1c7aa0ce0557c27a3422184a Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 06:49:52 +0530
Subject: [PATCH 076/623] refactor: Use hooks to load email css files
Previously email.css files were explicitly picked from hardcoded path
like public/css/email.css for all apps
---
frappe/email/email_body.py | 16 ++++------------
frappe/hooks.py | 2 ++
2 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py
index 3dcdf00a8e..e36cd2e651 100755
--- a/frappe/email/email_body.py
+++ b/frappe/email/email_body.py
@@ -292,17 +292,9 @@ def inline_style_in_html(html):
'''
from premailer import Premailer
- apps = frappe.get_installed_apps()
-
- # add frappe email css file
- css_files = ['assets/css/email.css']
- if 'frappe' in apps:
- apps.remove('frappe')
-
- for app in apps:
- path = 'assets/{0}/css/email.css'.format(app)
- css_files.append(path)
-
+ # get email css files from hooks
+ css_files = frappe.get_hooks('email_css')
+ css_files = [path.lstrip('/') for path in css_files]
css_files = [css_file for css_file in css_files if os.path.exists(os.path.abspath(css_file))]
p = Premailer(html=html, external_styles=css_files, strip_important=False)
@@ -480,4 +472,4 @@ def sanitize_email_header(str):
return str.replace('\r', '').replace('\n', '')
def get_brand_logo(email_account):
- return email_account.get('brand_logo')
\ No newline at end of file
+ return email_account.get('brand_logo')
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 967aed7f60..ba4176c3ed 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -52,6 +52,8 @@ web_include_js = [
web_include_css = []
+email_css = ['/assets/frappe/build/scss/email.css']
+
website_route_rules = [
{"from_route": "/blog/", "to_route": "Blog Post"},
{"from_route": "/kb/", "to_route": "Help Article"},
From 3b54dac489c345aeb5783d1cc388d869fa66db56 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Tue, 20 Apr 2021 06:52:06 +0530
Subject: [PATCH 077/623] fix: Create .bundle.* files that needs to bundled
---
frappe/public/js/barcode_scanner.bundle.js | 1 +
frappe/public/js/chat.bundle.js | 1 +
frappe/public/js/checkout.bundle.js | 1 +
frappe/public/js/data_import_tools.bundle.js | 1 +
frappe/public/js/desk.bundle.js | 1 -
frappe/public/js/dialog.bundle.js | 7 +++++++
frappe/public/js/form.bundle.js | 1 -
frappe/public/js/recorder.bundle.js | 1 +
.../js/user_profile_controller.bundle.js | 1 +
frappe/public/js/web_form.bundle.js | 2 ++
.../less/{chat.less => chat.bundle.less} | 5 ++++-
frappe/public/scss/desk.bundle.scss | 18 ++++++++++++++++++
frappe/public/scss/desk.scss | 1 -
.../scss/{email.scss => email.bundle.scss} | 0
frappe/public/scss/frappe-rtl.bundle.scss | 3 +++
.../scss/{login.scss => login.bundle.scss} | 0
.../scss/{print.scss => print.bundle.scss} | 2 +-
frappe/public/scss/report.bundle.scss | 2 ++
frappe/public/scss/web_form.bundle.scss | 3 +++
.../scss/{website.scss => website.bundle.scss} | 0
20 files changed, 46 insertions(+), 5 deletions(-)
create mode 100644 frappe/public/js/barcode_scanner.bundle.js
create mode 100644 frappe/public/js/chat.bundle.js
create mode 100644 frappe/public/js/checkout.bundle.js
create mode 100644 frappe/public/js/data_import_tools.bundle.js
create mode 100644 frappe/public/js/dialog.bundle.js
create mode 100644 frappe/public/js/recorder.bundle.js
create mode 100644 frappe/public/js/user_profile_controller.bundle.js
create mode 100644 frappe/public/js/web_form.bundle.js
rename frappe/public/less/{chat.less => chat.bundle.less} (99%)
create mode 100644 frappe/public/scss/desk.bundle.scss
delete mode 100644 frappe/public/scss/desk.scss
rename frappe/public/scss/{email.scss => email.bundle.scss} (100%)
create mode 100644 frappe/public/scss/frappe-rtl.bundle.scss
rename frappe/public/scss/{login.scss => login.bundle.scss} (100%)
rename frappe/public/scss/{print.scss => print.bundle.scss} (80%)
create mode 100644 frappe/public/scss/report.bundle.scss
create mode 100644 frappe/public/scss/web_form.bundle.scss
rename frappe/public/scss/{website.scss => website.bundle.scss} (100%)
diff --git a/frappe/public/js/barcode_scanner.bundle.js b/frappe/public/js/barcode_scanner.bundle.js
new file mode 100644
index 0000000000..294f20c08f
--- /dev/null
+++ b/frappe/public/js/barcode_scanner.bundle.js
@@ -0,0 +1 @@
+import "./frappe/barcode_scanner/quagga";
diff --git a/frappe/public/js/chat.bundle.js b/frappe/public/js/chat.bundle.js
new file mode 100644
index 0000000000..5f9a91ebb7
--- /dev/null
+++ b/frappe/public/js/chat.bundle.js
@@ -0,0 +1 @@
+import "./frappe/chat";
diff --git a/frappe/public/js/checkout.bundle.js b/frappe/public/js/checkout.bundle.js
new file mode 100644
index 0000000000..954e838fa8
--- /dev/null
+++ b/frappe/public/js/checkout.bundle.js
@@ -0,0 +1 @@
+import "./integrations/razorpay";
diff --git a/frappe/public/js/data_import_tools.bundle.js b/frappe/public/js/data_import_tools.bundle.js
new file mode 100644
index 0000000000..b6e4c11968
--- /dev/null
+++ b/frappe/public/js/data_import_tools.bundle.js
@@ -0,0 +1 @@
+import "./frappe/data_import";
diff --git a/frappe/public/js/desk.bundle.js b/frappe/public/js/desk.bundle.js
index 469714158c..193c87c132 100644
--- a/frappe/public/js/desk.bundle.js
+++ b/frappe/public/js/desk.bundle.js
@@ -1,4 +1,3 @@
-import '../scss/desk.scss';
import "./frappe/translate.js";
import "./frappe/class.js";
import "./frappe/polyfill.js";
diff --git a/frappe/public/js/dialog.bundle.js b/frappe/public/js/dialog.bundle.js
new file mode 100644
index 0000000000..3100b42ca7
--- /dev/null
+++ b/frappe/public/js/dialog.bundle.js
@@ -0,0 +1,7 @@
+import "./frappe/dom.js";
+import "./frappe/form/formatters.js";
+import "./frappe/form/layout.js";
+import "./frappe/ui/field_group.js";
+import "./frappe/form/link_selector.js";
+import "./frappe/form/multi_select_dialog.js";
+import "./frappe/ui/dialog.js";
diff --git a/frappe/public/js/form.bundle.js b/frappe/public/js/form.bundle.js
index 994a5437c3..5bed5c2cb8 100644
--- a/frappe/public/js/form.bundle.js
+++ b/frappe/public/js/form.bundle.js
@@ -1,5 +1,4 @@
import "./frappe/form/templates/address_list.html";
-import "./frappe/form/templates/attachment.html";
import "./frappe/form/templates/contact_list.html";
import "./frappe/form/templates/form_dashboard.html";
import "./frappe/form/templates/form_footer.html";
diff --git a/frappe/public/js/recorder.bundle.js b/frappe/public/js/recorder.bundle.js
new file mode 100644
index 0000000000..0772f0e44b
--- /dev/null
+++ b/frappe/public/js/recorder.bundle.js
@@ -0,0 +1 @@
+import "./frappe/recorder/recorder";
diff --git a/frappe/public/js/user_profile_controller.bundle.js b/frappe/public/js/user_profile_controller.bundle.js
new file mode 100644
index 0000000000..1bf0b517d7
--- /dev/null
+++ b/frappe/public/js/user_profile_controller.bundle.js
@@ -0,0 +1 @@
+import "../../desk/page/user_profile/user_profile_controller";
diff --git a/frappe/public/js/web_form.bundle.js b/frappe/public/js/web_form.bundle.js
new file mode 100644
index 0000000000..01969a489c
--- /dev/null
+++ b/frappe/public/js/web_form.bundle.js
@@ -0,0 +1,2 @@
+import "./frappe/utils/datetime.js";
+import "./frappe/web_form/webform_script.js";
diff --git a/frappe/public/less/chat.less b/frappe/public/less/chat.bundle.less
similarity index 99%
rename from frappe/public/less/chat.less
rename to frappe/public/less/chat.bundle.less
index a47cc027cb..1d4820435c 100644
--- a/frappe/public/less/chat.less
+++ b/frappe/public/less/chat.bundle.less
@@ -1,6 +1,9 @@
// Author - Achilles Rasquinha
// http://codeguide.co - @mdo (Author of Bootstrap)
+@import "../css/font-awesome.css";
+@import "../css/octicons/octicons.css";
+
// Typography
@font-weight-bold: 700;
@font-weight-heavy: 900;
@@ -455,4 +458,4 @@ textarea.form-control {
margin-top: 0px;
margin-left: 2px;
}
-}
\ No newline at end of file
+}
diff --git a/frappe/public/scss/desk.bundle.scss b/frappe/public/scss/desk.bundle.scss
new file mode 100644
index 0000000000..c0a876a5ec
--- /dev/null
+++ b/frappe/public/scss/desk.bundle.scss
@@ -0,0 +1,18 @@
+@import "frappe/public/js/lib/leaflet/leaflet.css";
+@import "frappe/public/js/lib/leaflet/leaflet.draw.css";
+@import "frappe/public/js/lib/leaflet/L.Control.Locate.css";
+@import "frappe/public/js/lib/leaflet/easy-button.css";
+@import "frappe/public/css/font-awesome.css";
+@import "frappe/public/css/octicons/octicons.css";
+// TODO: esbuild
+// @import "frappe/public/less/module.less";
+// @import "frappe/public/less/mobile.less";
+// @import "frappe/public/less/controls.less";
+
+// TODO: esbuild
+// chat has a separate bundle, so this shouldn't be needed
+// @import "frappe/public/less/chat.less";
+@import "frappe/public/css/fonts/inter/inter.css";
+@import "~frappe-charts/dist/frappe-charts.min";
+@import "~plyr/dist/plyr";
+@import "./desk/index";
diff --git a/frappe/public/scss/desk.scss b/frappe/public/scss/desk.scss
deleted file mode 100644
index 693c289418..0000000000
--- a/frappe/public/scss/desk.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import './desk/index';
\ No newline at end of file
diff --git a/frappe/public/scss/email.scss b/frappe/public/scss/email.bundle.scss
similarity index 100%
rename from frappe/public/scss/email.scss
rename to frappe/public/scss/email.bundle.scss
diff --git a/frappe/public/scss/frappe-rtl.bundle.scss b/frappe/public/scss/frappe-rtl.bundle.scss
new file mode 100644
index 0000000000..bc618270a8
--- /dev/null
+++ b/frappe/public/scss/frappe-rtl.bundle.scss
@@ -0,0 +1,3 @@
+@import "frappe/public/css/bootstrap-rtl.css";
+@import "frappe/public/css/desk-rtl.css";
+@import "frappe/public/css/report-rtl.css";
diff --git a/frappe/public/scss/login.scss b/frappe/public/scss/login.bundle.scss
similarity index 100%
rename from frappe/public/scss/login.scss
rename to frappe/public/scss/login.bundle.scss
diff --git a/frappe/public/scss/print.scss b/frappe/public/scss/print.bundle.scss
similarity index 80%
rename from frappe/public/scss/print.scss
rename to frappe/public/scss/print.bundle.scss
index a610299159..6ef31c06c8 100644
--- a/frappe/public/scss/print.scss
+++ b/frappe/public/scss/print.bundle.scss
@@ -1,4 +1,4 @@
-// @import "~bootstrap/scss/bootstrap";
+@import "frappe/public/css/bootstrap.css";
@import './common/quill';
@import "./desk/css_variables";
diff --git a/frappe/public/scss/report.bundle.scss b/frappe/public/scss/report.bundle.scss
new file mode 100644
index 0000000000..2c0701d904
--- /dev/null
+++ b/frappe/public/scss/report.bundle.scss
@@ -0,0 +1,2 @@
+@import "~frappe-datatable/dist/frappe-datatable";
+@import "frappe/public/css/tree_grid.css";
diff --git a/frappe/public/scss/web_form.bundle.scss b/frappe/public/scss/web_form.bundle.scss
new file mode 100644
index 0000000000..d119dd51c3
--- /dev/null
+++ b/frappe/public/scss/web_form.bundle.scss
@@ -0,0 +1,3 @@
+@import "frappe/website/css/web_form.css";
+@import "frappe/public/css/octicons/octicons.css";
+@import "~frappe-datatable/dist/frappe-datatable";
diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.bundle.scss
similarity index 100%
rename from frappe/public/scss/website.scss
rename to frappe/public/scss/website.bundle.scss
From 1a30e11b5f54cb7f13309ae3851c3e7f3394d7ab Mon Sep 17 00:00:00 2001
From: Anand Chitipothu
Date: Thu, 22 Apr 2021 09:01:59 +0530
Subject: [PATCH 078/623] fix: Invalid HTML generated by the base template
(#12953)
Closes #12952
---
frappe/templates/base.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/templates/base.html b/frappe/templates/base.html
index 78aa573c99..d59c4b0f2b 100644
--- a/frappe/templates/base.html
+++ b/frappe/templates/base.html
@@ -60,7 +60,7 @@
window.is_chat_enabled = {{ chat_enable }};
-
+
{% include "public/icons/timeless/symbol-defs.svg" %}
{%- block banner -%}
{% include "templates/includes/banner_extension.html" ignore missing %}
From edf92d4450b95fab8cce11e809570597c24ec167 Mon Sep 17 00:00:00 2001
From: gavin
Date: Thu, 22 Apr 2021 12:41:31 +0530
Subject: [PATCH 079/623] fix(cli): Trigger Scheduler Event (#12955)
* Triggers events via Scheduled Job Type's execute method
* Exits with code 1 if no event with that name found or process
termination
* Added feedback if event not found
---
frappe/commands/scheduler.py | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py
index bd9c9d2cb0..e9638800cd 100755
--- a/frappe/commands/scheduler.py
+++ b/frappe/commands/scheduler.py
@@ -18,22 +18,33 @@ def _is_scheduler_enabled():
return enable_scheduler
-@click.command('trigger-scheduler-event')
-@click.argument('event')
+
+@click.command("trigger-scheduler-event", help="Trigger a scheduler event")
+@click.argument("event")
@pass_context
def trigger_scheduler_event(context, event):
- "Trigger a scheduler event"
import frappe.utils.scheduler
+
+ exit_code = 0
+
for site in context.sites:
try:
frappe.init(site=site)
frappe.connect()
- frappe.utils.scheduler.trigger(site, event, now=True)
+ try:
+ frappe.get_doc("Scheduled Job Type", {"method": event}).execute()
+ except frappe.DoesNotExistError:
+ click.secho(f"Event {event} does not exist!", fg="red")
+ exit_code = 1
finally:
frappe.destroy()
+
if not context.sites:
raise SiteNotSpecifiedError
+ sys.exit(exit_code)
+
+
@click.command('enable-scheduler')
@pass_context
def enable_scheduler(context):
From 165607565ee29985490c6f3f059e0c6f6a05ad61 Mon Sep 17 00:00:00 2001
From: shariquerik
Date: Thu, 22 Apr 2021 12:43:30 +0530
Subject: [PATCH 080/623] fix: Hide grid Add Row & Add Multiple buttons when
document grid is not editable
---
frappe/public/js/frappe/form/grid.js | 2 ++
frappe/public/js/frappe/form/grid_row.js | 4 ++--
frappe/public/js/frappe/form/grid_row_form.js | 2 +-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index 86feefed7a..30a3597ec7 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -387,6 +387,8 @@ export default class Grid {
this.wrapper.find('.grid-footer').toggle(false);
}
+ this.wrapper.find('.grid-add-row, .grid-add-multiple-rows').toggle(this.is_editable())
+
}
truncate_rows() {
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index 4afa251c27..08267112de 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -558,10 +558,10 @@ export default class GridRow {
// this.form_panel.toggle(true);
if (this.grid.cannot_add_rows || (this.grid.df && this.grid.df.cannot_add_rows)) {
- this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
+ this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row, .grid-append-row')
.addClass('hidden');
} else {
- this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row')
+ this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row, .grid-append-row')
.removeClass('hidden');
}
diff --git a/frappe/public/js/frappe/form/grid_row_form.js b/frappe/public/js/frappe/form/grid_row_form.js
index 68e4178ae7..f5a4af206f 100644
--- a/frappe/public/js/frappe/form/grid_row_form.js
+++ b/frappe/public/js/frappe/form/grid_row_form.js
@@ -119,7 +119,7 @@ export default class GridRowForm {
});
}
toggle_add_delete_button_display($parent) {
- $parent.find(".row-actions")
+ $parent.find(".row-actions, .grid-append-row")
.toggle(this.row.grid.is_editable());
}
refresh_field(fieldname) {
From 9d3be5160fc21eaefcb655aa5ca38bc51e18b424 Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Thu, 22 Apr 2021 12:24:12 +0530
Subject: [PATCH 081/623] perf: low priority for backup processes
---
frappe/utils/__init__.py | 13 +++++++++++--
frappe/utils/backups.py | 14 ++++++--------
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py
index efa69d4453..251a095343 100644
--- a/frappe/utils/__init__.py
+++ b/frappe/utils/__init__.py
@@ -307,14 +307,23 @@ def unesc(s, esc_chars):
s = s.replace(esc_str, c)
return s
-def execute_in_shell(cmd, verbose=0):
+def execute_in_shell(cmd, verbose=0, low_priority=False):
# using Popen instead of os.system - as recommended by python docs
import tempfile
from subprocess import Popen
with tempfile.TemporaryFile() as stdout:
with tempfile.TemporaryFile() as stderr:
- p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
+ kwargs = {
+ "shell": True,
+ "stdout": stdout,
+ "stderr": stderr
+ }
+
+ if low_priority:
+ kwargs["preexec_fn"] = lambda: os.nice(10)
+
+ p = Popen(cmd, **kwargs)
p.wait()
stdout.seek(0)
diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py
index 9a6747a0cf..90a6b94ff0 100644
--- a/frappe/utils/backups.py
+++ b/frappe/utils/backups.py
@@ -315,8 +315,6 @@ class BackupGenerator:
print(template.format(_type.title(), info["path"], info["size"]))
def backup_files(self):
- import subprocess
-
for folder in ("public", "private"):
files_path = frappe.get_site_path(folder, "files")
backup_path = (
@@ -327,12 +325,12 @@ class BackupGenerator:
cmd_string = "tar cf - {1} | gzip > {0}"
else:
cmd_string = "tar -cf {0} {1}"
- output = subprocess.check_output(
- cmd_string.format(backup_path, files_path), shell=True
- )
- if self.verbose and output:
- print(output.decode("utf8"))
+ frappe.utils.execute_in_shell(
+ cmd_string.format(backup_path, files_path),
+ verbose=self.verbose,
+ low_priority=True
+ )
def copy_site_config(self):
site_config_backup_path = self.backup_path_conf
@@ -436,7 +434,7 @@ class BackupGenerator:
if self.verbose:
print(command + "\n")
- err, out = frappe.utils.execute_in_shell(command)
+ err, out = frappe.utils.execute_in_shell(command, low_priority=True)
def send_email(self):
"""
From ab3be339fdc6c6aef314f46e6bcb73e0f1cb8a6b Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Thu, 22 Apr 2021 12:56:21 +0530
Subject: [PATCH 082/623] fix: remove unsused variables
---
frappe/utils/backups.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py
index 90a6b94ff0..b21efc5e89 100644
--- a/frappe/utils/backups.py
+++ b/frappe/utils/backups.py
@@ -434,7 +434,7 @@ class BackupGenerator:
if self.verbose:
print(command + "\n")
- err, out = frappe.utils.execute_in_shell(command, low_priority=True)
+ frappe.utils.execute_in_shell(command, low_priority=True)
def send_email(self):
"""
From b4fa6d56df154f3b659a46243b2f73c733d85121 Mon Sep 17 00:00:00 2001
From: shariquerik
Date: Thu, 22 Apr 2021 13:34:45 +0530
Subject: [PATCH 083/623] refactor: Using toggle instead of
addClass-removeClass
---
frappe/public/js/frappe/form/grid.js | 2 +-
frappe/public/js/frappe/form/grid_row.js | 11 ++++-------
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index 30a3597ec7..4d381c9be7 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -387,7 +387,7 @@ export default class Grid {
this.wrapper.find('.grid-footer').toggle(false);
}
- this.wrapper.find('.grid-add-row, .grid-add-multiple-rows').toggle(this.is_editable())
+ this.wrapper.find('.grid-add-row, .grid-add-multiple-rows').toggle(this.is_editable());
}
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index 08267112de..9a689fabf4 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -557,13 +557,10 @@ export default class GridRow {
this.row.toggle(false);
// this.form_panel.toggle(true);
- if (this.grid.cannot_add_rows || (this.grid.df && this.grid.df.cannot_add_rows)) {
- this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row, .grid-append-row')
- .addClass('hidden');
- } else {
- this.wrapper.find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row, .grid-append-row')
- .removeClass('hidden');
- }
+ let cannot_add_rows = this.grid.cannot_add_rows || (this.grid.df && this.grid.df.cannot_add_rows);
+ this.wrapper
+ .find('.grid-insert-row-below, .grid-insert-row, .grid-duplicate-row, .grid-append-row')
+ .toggle(!cannot_add_rows);
frappe.dom.freeze("", "dark");
if (cur_frm) cur_frm.cur_grid = this;
From 162f191b7727bc2b8359aff2fcf5efe849d35e4a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 22 Apr 2021 14:21:05 +0530
Subject: [PATCH 084/623] fix(control): Check if same value is set to avoid
unnecessary change trigger
---
.eslintrc | 1 +
frappe/public/js/frappe/form/controls/base_control.js | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.eslintrc b/.eslintrc
index d123023a68..8a509f0df4 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -143,6 +143,7 @@
"Cypress": true,
"cy": true,
"it": true,
+ "describe": true,
"expect": true,
"context": true,
"before": true,
diff --git a/frappe/public/js/frappe/form/controls/base_control.js b/frappe/public/js/frappe/form/controls/base_control.js
index 9981398b84..b17ce973ec 100644
--- a/frappe/public/js/frappe/form/controls/base_control.js
+++ b/frappe/public/js/frappe/form/controls/base_control.js
@@ -159,9 +159,10 @@ frappe.ui.form.Control = Class.extend({
},
validate_and_set_in_model: function(value, e) {
var me = this;
- if(this.inside_change_event) {
+ if (this.inside_change_event || this.get_model_value() === value) {
return Promise.resolve();
}
+
this.inside_change_event = true;
var set = function(value) {
me.inside_change_event = false;
From d61f5afcdd1b71d9d7bc3c261369626e79fd550c Mon Sep 17 00:00:00 2001
From: Mohammad Hasnain Mohsin Rajan
Date: Thu, 22 Apr 2021 15:53:52 +0530
Subject: [PATCH 085/623] ci: Set COVERALLS_SERVICE_NAME as github (#12961)
Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com>
---
.github/workflows/ci-tests.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 363191fd05..d2a00ab05f 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -151,7 +151,8 @@ jobs:
cd ${GITHUB_WORKSPACE}
pip install coveralls==3.0.1
pip install coverage==5.5
- coveralls --service=github-actions
+ coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
+ COVERALLS_SERVICE_NAME: github
From 1ef4a58aa8b4720592124b991051363f1a98a2a2 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Thu, 22 Apr 2021 15:59:33 +0530
Subject: [PATCH 086/623] fix: Override get_model_value for table multiselect
---
frappe/public/js/frappe/form/controls/table_multiselect.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/frappe/public/js/frappe/form/controls/table_multiselect.js b/frappe/public/js/frappe/form/controls/table_multiselect.js
index c306146f90..eb3f1bce6e 100644
--- a/frappe/public/js/frappe/form/controls/table_multiselect.js
+++ b/frappe/public/js/frappe/form/controls/table_multiselect.js
@@ -66,6 +66,10 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
this._rows_list = this.rows.map(row => row[link_field.fieldname]);
return this.rows;
},
+ get_model_value() {
+ let value = this._super();
+ return value ? value.filter(d => !d.__islocal) : value;
+ },
validate(value) {
const rows = (value || []).slice();
From cf42986d8873e61238827e84bef7c74df12d5a3e Mon Sep 17 00:00:00 2001
From: Sagar Vora
Date: Thu, 22 Apr 2021 16:44:59 +0530
Subject: [PATCH 087/623] fix(UI): dont disable dialog scroll on focusing a
Link/Autocomplete field
---
.../public/js/frappe/form/controls/autocomplete.js | 6 ------
frappe/public/js/frappe/form/controls/link.js | 6 ------
frappe/public/js/frappe/ui/filters/field_select.js | 12 ------------
3 files changed, 24 deletions(-)
diff --git a/frappe/public/js/frappe/form/controls/autocomplete.js b/frappe/public/js/frappe/form/controls/autocomplete.js
index 30eb277f08..7b5680f394 100644
--- a/frappe/public/js/frappe/form/controls/autocomplete.js
+++ b/frappe/public/js/frappe/form/controls/autocomplete.js
@@ -90,16 +90,10 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
});
this.$input.on("awesomplete-open", () => {
- this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable');
- this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable');
-
this.autocomplete_open = true;
});
this.$input.on("awesomplete-close", () => {
- this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable', true);
- this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable', true);
-
this.autocomplete_open = false;
});
diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js
index c0ff128088..c32c99f0ed 100644
--- a/frappe/public/js/frappe/form/controls/link.js
+++ b/frappe/public/js/frappe/form/controls/link.js
@@ -241,16 +241,10 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
});
this.$input.on("awesomplete-open", () => {
- this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable');
- this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable');
-
this.autocomplete_open = true;
});
this.$input.on("awesomplete-close", () => {
- this.toggle_container_scroll('.modal-dialog', 'modal-dialog-scrollable', true);
- this.toggle_container_scroll('.grid-form-body .form-area', 'scrollable', true);
-
this.autocomplete_open = false;
});
diff --git a/frappe/public/js/frappe/ui/filters/field_select.js b/frappe/public/js/frappe/ui/filters/field_select.js
index c362214ce2..ed271a73aa 100644
--- a/frappe/public/js/frappe/ui/filters/field_select.js
+++ b/frappe/public/js/frappe/ui/filters/field_select.js
@@ -36,18 +36,6 @@ frappe.ui.FieldSelect = Class.extend({
var item = me.awesomplete.get_item(value);
me.$input.val(item.label);
});
- this.$input.on("awesomplete-open", () => {
- let modal = this.$input.parents('.modal-dialog')[0];
- if (modal) {
- $(modal).removeClass("modal-dialog-scrollable");
- }
- });
- this.$input.on("awesomplete-close", () => {
- let modal = this.$input.parents('.modal-dialog')[0];
- if (modal) {
- $(modal).addClass("modal-dialog-scrollable");
- }
- });
if(this.filter_fields) {
for(var i in this.filter_fields)
From aaa165c7840959e54d2905f9e050b5a765211017 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 22 Apr 2021 17:00:55 +0530
Subject: [PATCH 088/623] fix: Show upgrade message in patch
- Will only be shown if the old style "jenv" hook is being used
---
frappe/patches.txt | 1 +
frappe/patches/v13_0/jinja_hook.py | 13 +++++++++++++
2 files changed, 14 insertions(+)
create mode 100644 frappe/patches/v13_0/jinja_hook.py
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 516ddb6094..60c3112f4a 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -335,3 +335,4 @@ frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings
frappe.patches.v13_0.remove_twilio_settings
frappe.patches.v12_0.rename_uploaded_files_with_proper_name
frappe.patches.v13_0.queryreport_columns
+frappe.patches.v13_0.jinja_hook
diff --git a/frappe/patches/v13_0/jinja_hook.py b/frappe/patches/v13_0/jinja_hook.py
new file mode 100644
index 0000000000..3e9efc5896
--- /dev/null
+++ b/frappe/patches/v13_0/jinja_hook.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from click import secho
+
+def execute():
+ if frappe.get_hooks('jenv') or True:
+ print()
+ secho('WARNING: The hook "jenv" is deprecated. Follow the migration guide to use the new "jinja" hook.', fg='yellow')
+ secho('https://github.com/frappe/frappe/wiki/Migrating-to-Version-13', fg='yellow')
+ print()
From 87f3038272a33954437d50759caa05ec3916df12 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 22 Apr 2021 17:31:34 +0530
Subject: [PATCH 089/623] fix: remove hardcoding
---
frappe/patches/v13_0/jinja_hook.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/patches/v13_0/jinja_hook.py b/frappe/patches/v13_0/jinja_hook.py
index 3e9efc5896..84ed6e6cff 100644
--- a/frappe/patches/v13_0/jinja_hook.py
+++ b/frappe/patches/v13_0/jinja_hook.py
@@ -6,7 +6,7 @@ import frappe
from click import secho
def execute():
- if frappe.get_hooks('jenv') or True:
+ if frappe.get_hooks('jenv'):
print()
secho('WARNING: The hook "jenv" is deprecated. Follow the migration guide to use the new "jinja" hook.', fg='yellow')
secho('https://github.com/frappe/frappe/wiki/Migrating-to-Version-13', fg='yellow')
From a4a32fc4ed93dae32d1cf6c8cf20692a21f01548 Mon Sep 17 00:00:00 2001
From: Gavin D'souza
Date: Thu, 22 Apr 2021 17:58:21 +0530
Subject: [PATCH 090/623] feat(cli): Format Option for list-apps
---
frappe/commands/site.py | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index 0102d3ac40..6e334c59a8 100755
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -202,10 +202,13 @@ def install_app(context, apps):
@click.command("list-apps")
+@click.option("--format", "-f", type=click.Choice(["text", "json"]), default="text")
@pass_context
-def list_apps(context):
+def list_apps(context, format):
"List apps in site"
+ summary_dict = {}
+
def fix_whitespaces(text):
if site == context.sites[-1]:
text = text.rstrip()
@@ -234,18 +237,25 @@ def list_apps(context):
]
applications_summary = "\n".join(installed_applications)
summary = f"{site_title}\n{applications_summary}\n"
+ summary_dict[site] = [app.app_name for app in apps]
else:
- applications_summary = "\n".join(frappe.get_installed_apps())
+ installed_applications = frappe.get_installed_apps()
+ applications_summary = "\n".join(installed_applications)
summary = f"{site_title}\n{applications_summary}\n"
+ summary_dict[site] = installed_applications
summary = fix_whitespaces(summary)
- if applications_summary and summary:
+ if format == "text" and applications_summary and summary:
print(summary)
frappe.destroy()
+ if format == "json":
+ import json
+
+ print(json.dumps(summary_dict))
@click.command('add-system-manager')
@click.argument('email')
From c3b087643b4842d5c74654875f2bc157540b1a8f Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Thu, 22 Apr 2021 23:31:51 +0530
Subject: [PATCH 091/623] fix: Use node.string to extract style and script
- node.text stopped working in beautifulsoup 4.9.x
---
frappe/website/doctype/web_page/web_page.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/website/doctype/web_page/web_page.py b/frappe/website/doctype/web_page/web_page.py
index 86774c79c4..cce00564ff 100644
--- a/frappe/website/doctype/web_page/web_page.py
+++ b/frappe/website/doctype/web_page/web_page.py
@@ -242,11 +242,11 @@ def extract_script_and_style_tags(html):
styles = []
for script in soup.find_all('script'):
- scripts.append(script.text)
+ scripts.append(script.string)
script.extract()
for style in soup.find_all('style'):
- styles.append(style.text)
+ styles.append(style.string)
style.extract()
return str(soup), scripts, styles
From d8e91cae329d69f419d9ac4ea3bed57155a98d3a Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Fri, 23 Apr 2021 01:20:47 +0530
Subject: [PATCH 092/623] fix: Strip comments before sanitizing column_name
---
frappe/utils/data.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/frappe/utils/data.py b/frappe/utils/data.py
index 3ffa8dc874..dbf0d0665a 100644
--- a/frappe/utils/data.py
+++ b/frappe/utils/data.py
@@ -1278,7 +1278,9 @@ def make_filter_dict(filters):
def sanitize_column(column_name):
from frappe import _
+ import sqlparse
regex = re.compile("^.*[,'();].*")
+ column_name = sqlparse.format(column_name, strip_comments=True, keyword_case="lower")
blacklisted_keywords = ['select', 'create', 'insert', 'delete', 'drop', 'update', 'case', 'and', 'or']
def _raise_exception():
From fe20515c23a3ac41f1092bf0eaf0a0a452ec2e85 Mon Sep 17 00:00:00 2001
From: Faris Ansari
Date: Fri, 23 Apr 2021 06:17:47 +0530
Subject: [PATCH 093/623] refactor: Replace Class.extend with native class
---
frappe/desk/page/activity/activity.js | 15 +-
.../print_format_builder.js | 126 ++++----
frappe/public/js/frappe/desk.js | 108 +++----
.../public/js/frappe/form/controls/attach.js | 30 +-
.../js/frappe/form/controls/attach_image.js | 10 +-
.../js/frappe/form/controls/autocomplete.js | 22 +-
.../public/js/frappe/form/controls/barcode.js | 14 +-
.../js/frappe/form/controls/base_control.js | 60 ++--
.../js/frappe/form/controls/base_input.js | 70 ++---
.../public/js/frappe/form/controls/button.js | 32 +-
.../public/js/frappe/form/controls/check.js | 30 +-
frappe/public/js/frappe/form/controls/code.js | 24 +-
.../public/js/frappe/form/controls/color.js | 28 +-
.../public/js/frappe/form/controls/comment.js | 26 +-
.../js/frappe/form/controls/currency.js | 10 +-
frappe/public/js/frappe/form/controls/data.js | 48 +--
frappe/public/js/frappe/form/controls/date.js | 52 ++--
.../js/frappe/form/controls/date_range.js | 28 +-
.../js/frappe/form/controls/datetime.js | 24 +-
.../js/frappe/form/controls/duration.js | 42 +--
.../js/frappe/form/controls/dynamic_link.js | 8 +-
.../public/js/frappe/form/controls/float.js | 18 +-
.../js/frappe/form/controls/geolocation.js | 24 +-
.../public/js/frappe/form/controls/heading.js | 6 +-
frappe/public/js/frappe/form/controls/html.js | 24 +-
.../js/frappe/form/controls/html_editor.js | 10 +-
.../public/js/frappe/form/controls/image.js | 12 +-
frappe/public/js/frappe/form/controls/int.js | 28 +-
frappe/public/js/frappe/form/controls/link.js | 56 ++--
.../frappe/form/controls/markdown_editor.js | 20 +-
.../js/frappe/form/controls/multicheck.js | 40 +--
.../js/frappe/form/controls/multiselect.js | 20 +-
.../frappe/form/controls/multiselect_list.js | 30 +-
.../frappe/form/controls/multiselect_pills.js | 28 +-
.../js/frappe/form/controls/password.js | 24 +-
.../public/js/frappe/form/controls/rating.js | 10 +-
.../js/frappe/form/controls/read_only.js | 10 +-
.../public/js/frappe/form/controls/select.js | 36 +--
.../js/frappe/form/controls/signature.js | 48 +--
.../public/js/frappe/form/controls/table.js | 28 +-
.../frappe/form/controls/table_multiselect.js | 26 +-
frappe/public/js/frappe/form/controls/text.js | 26 +-
.../js/frappe/form/controls/text_editor.js | 26 +-
frappe/public/js/frappe/form/controls/time.js | 50 ++--
frappe/public/js/frappe/form/footer/footer.js | 22 +-
frappe/public/js/frappe/form/form.js | 6 +-
frappe/public/js/frappe/form/layout.js | 176 +++++------
frappe/public/js/frappe/form/link_selector.js | 18 +-
frappe/public/js/frappe/form/quick_entry.js | 70 ++---
.../public/js/frappe/form/script_manager.js | 34 +--
.../js/frappe/form/sidebar/assign_to.js | 44 +--
.../js/frappe/form/sidebar/attachments.js | 66 ++---
frappe/public/js/frappe/form/sidebar/share.js | 36 +--
frappe/public/js/frappe/form/workflow.js | 30 +-
frappe/public/js/frappe/module_editor.js | 18 +-
frappe/public/js/frappe/ui/field_group.js | 62 ++--
.../js/frappe/ui/filters/field_select.js | 20 +-
frappe/public/js/frappe/ui/iconbar.js | 34 +--
frappe/public/js/frappe/ui/page.js | 276 +++++++++---------
frappe/public/js/frappe/ui/sort_selector.js | 34 +--
frappe/public/js/frappe/ui/tag_editor.js | 22 +-
.../js/frappe/ui/toolbar/awesome_bar.js | 46 +--
.../js/frappe/views/calendar/calendar.js | 95 +++---
frappe/public/js/frappe/views/container.js | 23 +-
.../js/frappe/views/image/image_view.js | 30 +-
frappe/public/js/frappe/views/treeview.js | 70 ++---
66 files changed, 1320 insertions(+), 1319 deletions(-)
diff --git a/frappe/desk/page/activity/activity.js b/frappe/desk/page/activity/activity.js
index 39de414122..7b4e8ddc1a 100644
--- a/frappe/desk/page/activity/activity.js
+++ b/frappe/desk/page/activity/activity.js
@@ -67,8 +67,8 @@ frappe.pages['activity'].on_page_show = function () {
}
frappe.activity.last_feed_date = false;
-frappe.activity.Feed = Class.extend({
- init: function (row, data) {
+frappe.activity.Feed = class Feed {
+ constructor(row, data) {
this.scrub_data(data);
this.add_date_separator(row, data);
if (!data.add_class)
@@ -97,8 +97,9 @@ frappe.activity.Feed = Class.extend({
$(row)
.append(frappe.render_template("activity_row", data))
.find("a").addClass("grey");
- },
- scrub_data: function (data) {
+ }
+
+ scrub_data(data) {
data.by = frappe.user.full_name(data.owner);
data.avatar = frappe.avatar(data.owner);
@@ -113,9 +114,9 @@ frappe.activity.Feed = Class.extend({
data.when = comment_when(data.creation);
data.feed_type = data.comment_type || data.communication_medium;
- },
+ }
- add_date_separator: function (row, data) {
+ add_date_separator(row, data) {
var date = frappe.datetime.str_to_obj(data.creation);
var last = frappe.activity.last_feed_date;
@@ -137,7 +138,7 @@ frappe.activity.Feed = Class.extend({
}
frappe.activity.last_feed_date = date;
}
-});
+};
frappe.activity.render_heatmap = function (page) {
$('\
diff --git a/frappe/printing/page/print_format_builder/print_format_builder.js b/frappe/printing/page/print_format_builder/print_format_builder.js
index 7e58e295b5..70ee7f78d6 100644
--- a/frappe/printing/page/print_format_builder/print_format_builder.js
+++ b/frappe/printing/page/print_format_builder/print_format_builder.js
@@ -23,13 +23,13 @@ frappe.pages['print-format-builder'].on_page_show = function(wrapper) {
}
}
-frappe.PrintFormatBuilder = Class.extend({
- init: function(parent) {
+frappe.PrintFormatBuilder = class PrintFormatBuilder {
+ constructor(parent) {
this.parent = parent;
this.make();
this.refresh();
- },
- refresh: function() {
+ }
+ refresh() {
this.custom_html_count = 0;
if(!this.print_format) {
this.show_start();
@@ -37,8 +37,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.page.set_title(this.print_format.name);
this.setup_print_format();
}
- },
- make: function() {
+ }
+ make() {
this.page = frappe.ui.make_app_page({
parent: this.parent,
title: __("Print Format Builder"),
@@ -56,15 +56,15 @@ frappe.PrintFormatBuilder = Class.extend({
this.setup_edit_custom_html();
// $(this.page.sidebar).css({"position": 'fixed'});
// $(this.page.main).parent().css({"margin-left": '16.67%'});
- },
- show_start: function() {
+ }
+ show_start() {
this.page.main.html(frappe.render_template("print_format_builder_start", {}));
this.page.clear_actions();
this.page.set_title(__("Print Format Builder"));
this.start_edit_print_format();
this.start_new_print_format();
- },
- start_edit_print_format: function() {
+ }
+ start_edit_print_format() {
// print format control
var me = this;
this.print_format_input = frappe.ui.form.make_control({
@@ -89,8 +89,8 @@ frappe.PrintFormatBuilder = Class.extend({
frappe.set_route('print-format-builder', name);
});
});
- },
- start_new_print_format: function() {
+ }
+ start_new_print_format() {
var me = this;
this.doctype_input = frappe.ui.form.make_control({
parent: this.page.main.find(".doctype-selector"),
@@ -125,8 +125,8 @@ frappe.PrintFormatBuilder = Class.extend({
me.setup_new_print_format(doctype, name);
});
- },
- setup_new_print_format: function(doctype, name, based_on) {
+ }
+ setup_new_print_format(doctype, name, based_on) {
frappe.call({
method: 'frappe.printing.page.print_format_builder.print_format_builder.create_custom_format',
args: {
@@ -143,8 +143,8 @@ frappe.PrintFormatBuilder = Class.extend({
}
},
});
- },
- setup_print_format: function() {
+ }
+ setup_print_format() {
var me = this;
frappe.model.with_doctype(this.print_format.doc_type, function(doctype) {
me.meta = frappe.get_meta(me.print_format.doc_type);
@@ -163,23 +163,23 @@ frappe.PrintFormatBuilder = Class.extend({
frappe.set_route("Form", "Print Format", me.print_format.name);
});
});
- },
- setup_sidebar: function() {
+ }
+ setup_sidebar() {
// prepend custom HTML field
var fields = [this.get_custom_html_field()].concat(this.meta.fields);
this.page.sidebar.html(
$(frappe.render_template("print_format_builder_sidebar", {fields: fields}))
);
this.setup_field_filter();
- },
- get_custom_html_field: function() {
+ }
+ get_custom_html_field() {
return {
fieldtype: "Custom HTML",
fieldname: "_custom_html",
label: __("Custom HTML")
}
- },
- render_layout: function() {
+ }
+ render_layout() {
this.page.main.empty();
this.prepare_data();
$(frappe.render_template("print_format_builder_layout", {
@@ -190,8 +190,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.setup_edit_heading();
this.setup_field_settings();
this.setup_html_data();
- },
- prepare_data: function() {
+ }
+ prepare_data() {
this.print_heading_template = null;
this.data = JSON.parse(this.print_format.format_data || "[]");
if(!this.data.length) {
@@ -280,22 +280,22 @@ frappe.PrintFormatBuilder = Class.extend({
this.layout_data = $.map(this.layout_data, function(s) {
return s.has_fields ? s : null
});
- },
- get_new_section: function() {
+ }
+ get_new_section() {
return {columns: [], no_of_columns: 0, label:''};
- },
- get_new_column: function() {
+ }
+ get_new_column() {
return {fields: []}
- },
- add_table_properties: function(f) {
+ }
+ add_table_properties(f) {
// build table columns and widths in a dict
// visible_columns
var me = this;
if(!f.visible_columns) {
me.init_visible_columns(f);
}
- },
- init_visible_columns: function(f) {
+ }
+ init_visible_columns(f) {
f.visible_columns = []
$.each(frappe.get_meta(f.options).fields, function(i, _f) {
if(!in_list(["Section Break", "Column Break"], _f.fieldtype) &&
@@ -306,8 +306,8 @@ frappe.PrintFormatBuilder = Class.extend({
print_width: (_f.width || ""), print_hide:0});
}
});
- },
- setup_sortable: function() {
+ }
+ setup_sortable() {
var me = this;
// drag from fields library
@@ -332,8 +332,8 @@ frappe.PrintFormatBuilder = Class.extend({
Sortable.create(this.page.main.find(".print-format-builder-layout").get(0),
{ handle: ".print-format-builder-section-head" }
);
- },
- setup_sortable_for_column: function(col) {
+ }
+ setup_sortable_for_column(col) {
var me = this;
Sortable.create(col, {
group: {
@@ -363,8 +363,8 @@ frappe.PrintFormatBuilder = Class.extend({
}
});
- },
- setup_field_filter: function() {
+ }
+ setup_field_filter() {
var me = this;
this.page.sidebar.find(".filter-fields").on("keyup", function() {
var text = $(this).val();
@@ -373,8 +373,8 @@ frappe.PrintFormatBuilder = Class.extend({
$(this).parent().toggle(show);
})
});
- },
- setup_section_settings: function() {
+ }
+ setup_section_settings() {
var me = this;
this.page.main.on("click", ".section-settings", function() {
var section = $(this).parent().parent();
@@ -431,8 +431,8 @@ frappe.PrintFormatBuilder = Class.extend({
return false;
});
- },
- setup_field_settings: function() {
+ }
+ setup_field_settings() {
this.page.main.find(".field-settings").on("click", e => {
const field = $(e.currentTarget).parent();
// new dialog
@@ -482,8 +482,8 @@ frappe.PrintFormatBuilder = Class.extend({
return false;
});
- },
- setup_html_data: function() {
+ }
+ setup_html_data() {
// set JQuery `data` for Custom HTML fields, since editing the HTML
// directly causes problem becuase of HTML reformatting
//
@@ -496,8 +496,8 @@ frappe.PrintFormatBuilder = Class.extend({
var html = me.custom_html_dict[parseInt(content.attr('data-custom-html-id'))].options;
content.data('content', html);
})
- },
- update_columns_in_section: function(section, no_of_columns, new_no_of_columns) {
+ }
+ update_columns_in_section(section, no_of_columns, new_no_of_columns) {
var col_size = 12 / new_no_of_columns,
me = this,
resize = function() {
@@ -539,8 +539,8 @@ frappe.PrintFormatBuilder = Class.extend({
resize();
}
- },
- setup_add_section: function() {
+ }
+ setup_add_section() {
var me = this;
this.page.main.find(".print-format-builder-add-section").on("click", function() {
// boostrap new section info
@@ -554,8 +554,8 @@ frappe.PrintFormatBuilder = Class.extend({
me.setup_sortable_for_column($section.find(".print-format-builder-column").get(0));
});
- },
- setup_edit_heading: function() {
+ }
+ setup_edit_heading() {
var me = this;
var $heading = this.page.main.find(".print-format-builder-print-heading");
@@ -565,8 +565,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.page.main.find(".edit-heading").on("click", function() {
var d = me.get_edit_html_dialog(__("Edit Heading"), __("Heading"), $heading);
})
- },
- setup_column_selector: function() {
+ }
+ setup_column_selector() {
var me = this;
this.page.main.on("click", ".select-columns", function() {
var parent = $(this).parents(".print-format-builder-field:first"),
@@ -657,24 +657,24 @@ frappe.PrintFormatBuilder = Class.extend({
return false;
});
- },
- get_visible_columns_string: function(f) {
+ }
+ get_visible_columns_string(f) {
if(!f.visible_columns) {
this.init_visible_columns(f);
}
return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + (v.print_width || "") }).join(",");
- },
- get_no_content: function() {
+ }
+ get_no_content() {
return __("Edit to add content")
- },
- setup_edit_custom_html: function() {
+ }
+ setup_edit_custom_html() {
var me = this;
this.page.main.on("click", ".edit-html", function() {
me.get_edit_html_dialog(__("Edit Custom HTML"), __("Custom HTML"),
$(this).parents(".print-format-builder-field:first").find(".html-content"));
});
- },
- get_edit_html_dialog: function(title, label, $content) {
+ }
+ get_edit_html_dialog(title, label, $content) {
var me = this;
var d = new frappe.ui.Dialog({
title: title,
@@ -710,8 +710,8 @@ frappe.PrintFormatBuilder = Class.extend({
d.show();
return d;
- },
- save_print_format: function() {
+ }
+ save_print_format() {
var data = [],
me = this;
@@ -789,4 +789,4 @@ frappe.PrintFormatBuilder = Class.extend({
}
});
}
-});
+};
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index 216ec967a4..be39471ca0 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -24,12 +24,12 @@ $(document).ready(function() {
frappe.start_app();
});
-frappe.Application = Class.extend({
- init: function() {
+frappe.Application = class Application {
+ constructor() {
this.startup();
- },
+ }
- startup: function() {
+ startup() {
frappe.socketio.init();
frappe.model.init();
@@ -162,7 +162,7 @@ frappe.Application = Class.extend({
}, 600000); // check every 10 minutes
}
}
- },
+ }
set_route() {
frappe.flags.setting_original_route = true;
@@ -177,14 +177,14 @@ frappe.Application = Class.extend({
frappe.router.on('change', () => {
$(".tooltip").hide();
});
- },
+ }
setup_frappe_vue() {
Vue.prototype.__ = window.__;
Vue.prototype.frappe = window.frappe;
- },
+ }
- set_password: function(user) {
+ set_password(user) {
var me=this;
frappe.call({
method: 'frappe.core.doctype.user.user.get_email_awaiting',
@@ -201,9 +201,9 @@ frappe.Application = Class.extend({
}
}
});
- },
+ }
- email_password_prompt: function(email_account,user,i) {
+ email_password_prompt(email_account,user,i) {
var me = this;
let d = new frappe.ui.Dialog({
title: __('Password missing in Email Account'),
@@ -257,8 +257,8 @@ frappe.Application = Class.extend({
});
});
d.show();
- },
- load_bootinfo: function() {
+ }
+ load_bootinfo() {
if(frappe.boot) {
this.setup_workspaces();
frappe.model.sync(frappe.boot.docs);
@@ -280,7 +280,7 @@ frappe.Application = Class.extend({
} else {
this.set_as_guest();
}
- },
+ }
setup_workspaces() {
frappe.modules = {};
@@ -293,24 +293,24 @@ frappe.Application = Class.extend({
// default workspace is settings for Frappe
frappe.workspaces['home'] = frappe.workspaces['build'];
}
- },
+ }
- load_user_permissions: function() {
+ load_user_permissions() {
frappe.defaults.update_user_permissions();
frappe.realtime.on('update_user_permissions', frappe.utils.debounce(() => {
frappe.defaults.update_user_permissions();
}, 500));
- },
+ }
- check_metadata_cache_status: function() {
+ check_metadata_cache_status() {
if(frappe.boot.metadata_version != localStorage.metadata_version) {
frappe.assets.clear_local_storage();
frappe.assets.init_local_storage();
}
- },
+ }
- set_globals: function() {
+ set_globals() {
frappe.session.user = frappe.boot.user.name;
frappe.session.logged_in_user = frappe.boot.user.name;
frappe.session.user_email = frappe.boot.user.email;
@@ -362,8 +362,8 @@ frappe.Application = Class.extend({
}
}
});
- },
- sync_pages: function() {
+ }
+ sync_pages() {
// clear cached pages if timestamp is not found
if(localStorage["page_info"]) {
frappe.boot.allowed_pages = [];
@@ -378,8 +378,8 @@ frappe.Application = Class.extend({
frappe.boot.allowed_pages = Object.keys(frappe.boot.page_info);
}
localStorage["page_info"] = JSON.stringify(frappe.boot.page_info);
- },
- set_as_guest: function() {
+ }
+ set_as_guest() {
frappe.session.user = 'Guest';
frappe.session.user_email = '';
frappe.session.user_fullname = 'Guest';
@@ -387,23 +387,23 @@ frappe.Application = Class.extend({
frappe.user_defaults = {};
frappe.user_roles = ['Guest'];
frappe.sys_defaults = {};
- },
- make_page_container: function() {
+ }
+ make_page_container() {
if ($("#body").length) {
$(".splash").remove();
frappe.temp_container = $("
")
.appendTo("body");
frappe.container = new frappe.views.Container();
}
- },
- make_nav_bar: function() {
+ }
+ make_nav_bar() {
// toolbar
if(frappe.boot && frappe.boot.home_page!=='setup-wizard') {
frappe.frappe_toolbar = new frappe.ui.toolbar.Toolbar();
}
- },
- logout: function() {
+ }
+ logout() {
var me = this;
me.logged_out = true;
return frappe.call({
@@ -415,8 +415,8 @@ frappe.Application = Class.extend({
me.redirect_to_login();
}
});
- },
- handle_session_expired: function() {
+ }
+ handle_session_expired() {
if(!frappe.app.session_expired_dialog) {
var dialog = new frappe.ui.Dialog({
title: __('Session Expired'),
@@ -466,16 +466,16 @@ frappe.Application = Class.extend({
'background-color': '#4B4C9D'
});
}
- },
- redirect_to_login: function() {
+ }
+ redirect_to_login() {
window.location.href = '/';
- },
- set_favicon: function() {
+ }
+ set_favicon() {
var link = $('link[type="image/x-icon"]').remove().attr("href");
$('
').appendTo("head");
$('
').appendTo("head");
- },
- trigger_primary_action: function() {
+ }
+ trigger_primary_action() {
if(window.cur_dialog && cur_dialog.display) {
// trigger primary
cur_dialog.get_primary_btn().trigger("click");
@@ -484,9 +484,9 @@ frappe.Application = Class.extend({
} else if(frappe.container.page.save_action) {
frappe.container.page.save_action();
}
- },
+ }
- set_rtl: function() {
+ set_rtl() {
if (frappe.utils.is_rtl()) {
var ls = document.createElement('link');
ls.rel="stylesheet";
@@ -495,9 +495,9 @@ frappe.Application = Class.extend({
document.getElementsByTagName('head')[0].appendChild(ls);
$('body').addClass('frappe-rtl');
}
- },
+ }
- show_change_log: function() {
+ show_change_log() {
var me = this;
let change_log = frappe.boot.change_log;
@@ -528,15 +528,15 @@ frappe.Application = Class.extend({
});
me.show_notes();
};
- },
+ }
- show_update_available: () => {
+ show_update_available() {
frappe.call({
"method": "frappe.utils.change_log.show_update_popup"
});
- },
+ }
- setup_analytics: function() {
+ setup_analytics() {
if(window.mixpanel) {
window.mixpanel.identify(frappe.session.user);
window.mixpanel.people.set({
@@ -546,17 +546,17 @@ frappe.Application = Class.extend({
"$email": frappe.session.user
});
}
- },
+ }
add_browser_class() {
$('html').addClass(frappe.utils.get_browser().name.toLowerCase());
- },
+ }
set_fullwidth_if_enabled() {
frappe.ui.toolbar.set_fullwidth_if_enabled();
- },
+ }
- show_notes: function() {
+ show_notes() {
var me = this;
if(frappe.boot.notes.length) {
frappe.boot.notes.forEach(function(note) {
@@ -583,7 +583,7 @@ frappe.Application = Class.extend({
}
});
}
- },
+ }
setup_build_error_listener() {
if (frappe.boot.developer_mode) {
@@ -591,7 +591,7 @@ frappe.Application = Class.extend({
console.log(data);
});
}
- },
+ }
setup_user_group_listeners() {
frappe.realtime.on('user_group_added', (user_group) => {
@@ -600,13 +600,13 @@ frappe.Application = Class.extend({
frappe.realtime.on('user_group_deleted', (user_group) => {
frappe.boot.user_groups = (frappe.boot.user_groups || []).filter(el => el !== user_group);
});
- },
+ }
setup_energy_point_listeners() {
frappe.realtime.on('energy_point_alert', (message) => {
frappe.show_alert(message);
});
- },
+ }
setup_copy_doc_listener() {
$('body').on('paste', (e) => {
@@ -640,7 +640,7 @@ frappe.Application = Class.extend({
}
});
}
-});
+}
frappe.get_module = function(m, default_module) {
var module = frappe.modules[m] || default_module;
diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js
index 604510bb52..672087ddc2 100644
--- a/frappe/public/js/frappe/form/controls/attach.js
+++ b/frappe/public/js/frappe/form/controls/attach.js
@@ -1,5 +1,5 @@
-frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
- make_input: function() {
+frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.ControlData {
+ make_input() {
let me = this;
this.$input = $('
')
.html(__("Attach"))
@@ -26,8 +26,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
frappe.utils.bind_actions_with_object(this.$value, this);
this.toggle_reload_button();
- },
- clear_attachment: function() {
+ }
+ clear_attachment() {
let me = this;
if(this.frm) {
me.parse_validate_and_set_in_model(null);
@@ -44,16 +44,16 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.parse_validate_and_set_in_model(null);
this.refresh();
}
- },
+ }
reload_attachment() {
if (this.file_uploader) {
this.file_uploader.uploader.upload_files();
}
- },
+ }
on_attach_click() {
this.set_upload_options();
this.file_uploader = new frappe.ui.FileUploader(this.upload_options);
- },
+ }
set_upload_options() {
let options = {
allow_multiple: false,
@@ -73,9 +73,9 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
Object.assign(options, this.df.options);
}
this.upload_options = options;
- },
+ }
- set_input: function(value, dataurl) {
+ set_input(value, dataurl) {
this.value = value;
if(this.value) {
this.$input.toggle(false);
@@ -94,23 +94,23 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.$input.toggle(true);
this.$value.toggle(false);
}
- },
+ }
- get_value: function() {
+ get_value() {
return this.value || null;
- },
+ }
- on_upload_complete: function(attachment) {
+ on_upload_complete(attachment) {
if(this.frm) {
this.parse_validate_and_set_in_model(attachment.file_url);
this.frm.attachments.update_attachment(attachment);
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
}
this.set_value(attachment.file_url);
- },
+ }
toggle_reload_button() {
this.$value.find('[data-action="reload_attachment"]')
.toggle(this.file_uploader && this.file_uploader.uploader.files.length > 0);
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/attach_image.js b/frappe/public/js/frappe/form/controls/attach_image.js
index 17e43d4683..7c24ec9551 100644
--- a/frappe/public/js/frappe/form/controls/attach_image.js
+++ b/frappe/public/js/frappe/form/controls/attach_image.js
@@ -1,6 +1,6 @@
-frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
+frappe.ui.form.ControlAttachImage = class ControlAttachImage extends frappe.ui.form.ControlAttach {
make_input() {
- this._super();
+ super.make_input();
let $file_link = this.$value.find('.attached-file-link');
$file_link.popover({
@@ -16,10 +16,10 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
},
html: true
});
- },
+ }
set_upload_options() {
- this._super();
+ super.set_upload_options();
this.upload_options.restrictions = {};
this.upload_options.restrictions.allowed_file_types = ['image/*'];
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/autocomplete.js b/frappe/public/js/frappe/form/controls/autocomplete.js
index 30eb277f08..6af9eb96f1 100644
--- a/frappe/public/js/frappe/form/controls/autocomplete.js
+++ b/frappe/public/js/frappe/form/controls/autocomplete.js
@@ -1,19 +1,19 @@
import Awesomplete from 'awesomplete';
-frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
- trigger_change_on_input_event: false,
+frappe.ui.form.ControlAutocomplete = class ControlAutoComplete extends frappe.ui.form.ControlData {
+ trigger_change_on_input_event = false
make_input() {
- this._super();
+ super.make_input();
this.setup_awesomplete();
this.set_options();
- },
+ }
set_options() {
if (this.df.options) {
let options = this.df.options || [];
this._data = this.parse_options(options);
}
- },
+ }
get_awesomplete_settings() {
var me = this;
@@ -63,7 +63,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
return 0;
}
};
- },
+ }
setup_awesomplete() {
this.awesomplete = new Awesomplete(
@@ -106,7 +106,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
this.$input.on('awesomplete-selectcomplete', () => {
this.$input.trigger('change');
});
- },
+ }
validate(value) {
if (this.df.ignore_validation) {
@@ -121,7 +121,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
} else {
return '';
}
- },
+ }
parse_options(options) {
if (typeof options === 'string') {
@@ -131,11 +131,11 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
options = options.map(o => ({ label: o, value: o }));
}
return options;
- },
+ }
get_data() {
return this._data || [];
- },
+ }
set_data(data) {
data = this.parse_options(data);
@@ -144,4 +144,4 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
}
this._data = data;
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/barcode.js b/frappe/public/js/frappe/form/controls/barcode.js
index 8ac812c0ed..04bdb3f19e 100644
--- a/frappe/public/js/frappe/form/controls/barcode.js
+++ b/frappe/public/js/frappe/form/controls/barcode.js
@@ -1,9 +1,9 @@
import JsBarcode from 'jsbarcode';
-frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
+frappe.ui.form.ControlBarcode = class ControlBarcode extends frappe.ui.form.ControlData {
make_wrapper() {
// Create the elements for barcode area
- this._super();
+ super.make_wrapper();
this.default_svg = ' ';
let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
@@ -11,7 +11,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
`${this.default_svg}
`
);
this.barcode_area.appendTo($input_wrapper);
- },
+ }
parse(value) {
// Parse raw value
@@ -22,7 +22,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
return this.get_barcode_html(value);
}
return '';
- },
+ }
set_formatted_input(value) {
// Set values to display
@@ -40,7 +40,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
this.$input.val(barcode_value || value);
this.barcode_area.html(svg || this.default_svg);
- },
+ }
get_barcode_html(value) {
if (value) {
@@ -51,7 +51,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
$(svg).attr('width', '100%');
return this.barcode_area.html();
}
- },
+ }
get_options(value) {
// get JsBarcode options
@@ -76,4 +76,4 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
}
return options;
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/base_control.js b/frappe/public/js/frappe/form/controls/base_control.js
index 9981398b84..d98bc97915 100644
--- a/frappe/public/js/frappe/form/controls/base_control.js
+++ b/frappe/public/js/frappe/form/controls/base_control.js
@@ -1,5 +1,5 @@
-frappe.ui.form.Control = Class.extend({
- init: function(opts) {
+frappe.ui.form.Control = class BaseControl {
+ constructor(opts) {
$.extend(this, opts);
this.make();
@@ -11,31 +11,31 @@ frappe.ui.form.Control = Class.extend({
if(this.render_input) {
this.refresh();
}
- },
- make: function() {
+ }
+ make() {
this.make_wrapper();
this.$wrapper
.attr("data-fieldtype", this.df.fieldtype)
.attr("data-fieldname", this.df.fieldname);
this.wrapper = this.$wrapper.get(0);
this.wrapper.fieldobj = this; // reference for event handlers
- },
+ }
- make_wrapper: function() {
+ make_wrapper() {
this.$wrapper = $("
").appendTo(this.parent);
// alias
this.wrapper = this.$wrapper;
- },
+ }
- toggle: function(show) {
+ toggle(show) {
this.df.hidden = show ? 0 : 1;
this.refresh();
- },
+ }
// returns "Read", "Write" or "None"
// as strings based on permissions
- get_status: function(explain) {
+ get_status(explain) {
if (this.df.get_status) {
return this.df.get_status(this);
}
@@ -93,8 +93,8 @@ frappe.ui.form.Control = Class.extend({
}
return status;
- },
- refresh: function() {
+ }
+ refresh() {
this.disp_status = this.get_status();
this.$wrapper
&& this.$wrapper.toggleClass("hide-control", this.disp_status=="None")
@@ -104,7 +104,7 @@ frappe.ui.form.Control = Class.extend({
var value = this.get_value();
this.show_translatable_button(value);
- },
+ }
show_translatable_button(value) {
// Disable translation non-string fields or special string fields
if (!frappe.model
@@ -138,26 +138,26 @@ frappe.ui.form.Control = Class.extend({
}
});
- },
- get_doc: function() {
+ }
+ get_doc() {
return this.doctype && this.docname
&& locals[this.doctype] && locals[this.doctype][this.docname] || {};
- },
- get_model_value: function() {
+ }
+ get_model_value() {
if(this.doc) {
return this.doc[this.df.fieldname];
}
- },
- set_value: function(value) {
+ }
+ set_value(value) {
return this.validate_and_set_in_model(value);
- },
- parse_validate_and_set_in_model: function(value, e) {
+ }
+ parse_validate_and_set_in_model(value, e) {
if(this.parse) {
value = this.parse(value);
}
return this.validate_and_set_in_model(value, e);
- },
- validate_and_set_in_model: function(value, e) {
+ }
+ validate_and_set_in_model(value, e) {
var me = this;
if(this.inside_change_event) {
return Promise.resolve();
@@ -189,8 +189,8 @@ frappe.ui.form.Control = Class.extend({
// all clear
return set(value);
}
- },
- get_value: function() {
+ }
+ get_value() {
if(this.get_status()==='Write') {
return this.get_input_value ?
(this.parse ? this.parse(this.get_input_value()) : this.get_input_value()) :
@@ -198,8 +198,8 @@ frappe.ui.form.Control = Class.extend({
} else {
return this.value || undefined;
}
- },
- set_model_value: function(value) {
+ }
+ set_model_value(value) {
if(this.frm) {
this.last_value = value;
return frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
@@ -211,11 +211,11 @@ frappe.ui.form.Control = Class.extend({
this.set_input(value);
return Promise.resolve();
}
- },
- set_focus: function() {
+ }
+ set_focus() {
if(this.$input) {
this.$input.get(0).focus();
return true;
}
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/base_input.js b/frappe/public/js/frappe/form/controls/base_input.js
index 46ab62b717..c61f87c1eb 100644
--- a/frappe/public/js/frappe/form/controls/base_input.js
+++ b/frappe/public/js/frappe/form/controls/base_input.js
@@ -1,14 +1,14 @@
-frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
- horizontal: true,
- make: function() {
+frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control {
+ horizontal = true
+ make() {
// parent element
- this._super();
+ super.make();
this.set_input_areas();
// set description
this.set_max_width();
- },
- make_wrapper: function() {
+ }
+ make_wrapper() {
if(this.only_input) {
this.$wrapper = $('').appendTo(this.parent);
} else {
@@ -25,14 +25,14 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
\
').appendTo(this.parent);
}
- },
- toggle_label: function(show) {
+ }
+ toggle_label(show) {
this.$wrapper.find(".control-label").toggleClass("hide", !show);
- },
- toggle_description: function(show) {
+ }
+ toggle_description(show) {
this.$wrapper.find(".help-box").toggleClass("hide", !show);
- },
- set_input_areas: function() {
+ }
+ set_input_areas() {
if(this.only_input) {
this.input_area = this.wrapper;
} else {
@@ -43,17 +43,17 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
// like links, currencies, HTMLs etc.
this.disp_area = this.$wrapper.find(".control-value").get(0);
}
- },
- set_max_width: function() {
+ }
+ set_max_width() {
if(this.horizontal) {
this.$wrapper.addClass("input-max-width");
}
- },
+ }
// update input value, label, description
// display (show/hide/read-only),
// mandatory style on refresh
- refresh_input: function() {
+ refresh_input() {
var me = this;
var make_input = function() {
if (!me.has_input) {
@@ -106,13 +106,13 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
me.set_bold();
me.set_required();
}
- },
+ }
can_write() {
return this.disp_status == "Write";
- },
+ }
- set_disp_area: function(value) {
+ set_disp_area(value) {
if(in_list(["Currency", "Int", "Float"], this.df.fieldtype)
&& (this.value === 0 || value === 0)) {
// to set the 0 value in readonly for currency, int, float field
@@ -126,8 +126,8 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
let doc = this.doc || (this.frm && this.frm.doc);
let display_value = frappe.format(value, this.df, { no_icon: true, inline: true }, doc);
this.disp_area && $(this.disp_area).html(display_value);
- },
- set_label: function(label) {
+ }
+ set_label(label) {
if(label) this.df.label = label;
if(this.only_input || this.df.label==this._label)
@@ -137,8 +137,8 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
this.label_span.innerHTML = (icon ? '
' : "") +
__(this.df.label) || " ";
this._label = this.df.label;
- },
- set_description: function(description) {
+ }
+ set_description(description) {
if (description !== undefined) {
this.df.description = description;
}
@@ -151,17 +151,17 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
this.set_empty_description();
}
this._description = this.df.description;
- },
- set_new_description: function(description) {
+ }
+ set_new_description(description) {
this.$wrapper.find(".help-box").html(description);
- },
- set_empty_description: function() {
+ }
+ set_empty_description() {
this.$wrapper.find(".help-box").html("");
- },
- set_mandatory: function(value) {
+ }
+ set_mandatory(value) {
this.$wrapper.toggleClass("has-error", Boolean(this.df.reqd && is_null(value)));
- },
- set_invalid: function () {
+ }
+ set_invalid () {
let invalid = !!this.df.invalid;
if (this.grid) {
this.$wrapper.parents('.grid-static-col').toggleClass('invalid', invalid);
@@ -170,11 +170,11 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
} else {
this.$wrapper.toggleClass('has-error', invalid);
}
- },
+ }
set_required() {
this.label_area && $(this.label_area).toggleClass('reqd', Boolean(this.df.reqd));
- },
- set_bold: function() {
+ }
+ set_bold() {
if(this.$input) {
this.$input.toggleClass("bold", !!(this.df.bold || this.df.reqd));
}
@@ -182,4 +182,4 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
$(this.disp_area).toggleClass("bold", !!(this.df.bold || this.df.reqd));
}
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/button.js b/frappe/public/js/frappe/form/controls/button.js
index b44c9d9dcd..ab679377e9 100644
--- a/frappe/public/js/frappe/form/controls/button.js
+++ b/frappe/public/js/frappe/form/controls/button.js
@@ -1,9 +1,9 @@
-frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
+frappe.ui.form.ControlButton = class ControlButton extends frappe.ui.form.ControlData {
can_write() {
// should be always true in case of button
return true;
- },
- make_input: function() {
+ }
+ make_input() {
var me = this;
const btn_type = this.df.primary ? 'btn-primary': 'btn-default';
this.$input = $(`
`)
@@ -15,8 +15,8 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
this.set_input_attributes();
this.has_input = true;
this.toggle_label(false);
- },
- onclick: function() {
+ }
+ onclick() {
if (this.frm && this.frm.doc) {
if (this.frm.script_manager.has_handlers(this.df.fieldname, this.doctype)) {
this.frm.script_manager.trigger(this.df.fieldname, this.doctype, this.docname);
@@ -28,8 +28,8 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
} else if (this.df.click) {
this.df.click();
}
- },
- run_server_script: function() {
+ }
+ run_server_script() {
// DEPRECATE
var me = this;
if(this.frm && this.frm.docname) {
@@ -44,18 +44,18 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
}
});
}
- },
+ }
hide() {
this.$input.hide();
- },
- set_input_areas: function() {
- this._super();
+ }
+ set_input_areas() {
+ super.set_input_areas();
$(this.disp_area).removeClass().addClass("hide");
- },
- set_empty_description: function() {
+ }
+ set_empty_description() {
this.$wrapper.find(".help-box").empty().toggle(false);
- },
- set_label: function(label) {
+ }
+ set_label(label) {
if (label) {
this.df.label = label;
}
@@ -63,4 +63,4 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
$(this.label_span).html(" ");
this.$input && this.$input.html(label);
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/check.js b/frappe/public/js/frappe/form/controls/check.js
index c8dc0df962..e3790cdd73 100644
--- a/frappe/public/js/frappe/form/controls/check.js
+++ b/frappe/public/js/frappe/form/controls/check.js
@@ -1,6 +1,6 @@
-frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
- input_type: "checkbox",
- make_wrapper: function() {
+frappe.ui.form.ControlCheck = class ControlCheck extends frappe.ui.form.ControlData {
+ input_type = "checkbox"
+ make_wrapper() {
this.$wrapper = $(``).appendTo(this.parent);
- },
- set_input_areas: function() {
+ }
+ set_input_areas() {
this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0);
this.input_area = this.$wrapper.find(".input-area").get(0);
this.disp_area = this.$wrapper.find(".disp-area").get(0);
- },
- make_input: function() {
- this._super();
+ }
+ make_input() {
+ super.make_input();
this.$input.removeClass("form-control");
- },
- get_input_value: function() {
+ }
+ get_input_value() {
return this.input && this.input.checked ? 1 : 0;
- },
- validate: function(value) {
+ }
+ validate(value) {
return cint(value);
- },
- set_input: function(value) {
+ }
+ set_input(value) {
value = cint(value);
if(this.input) {
this.input.checked = (value ? 1 : 0);
@@ -36,4 +36,4 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
this.set_mandatory(value);
this.set_disp_area(value);
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index 9600763588..e04a451c98 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -1,8 +1,8 @@
-frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
+frappe.ui.form.ControlCode = class ControlCode extends frappe.ui.form.ControlText {
make_input() {
if (this.editor) return;
this.load_lib().then(() => this.make_ace_editor());
- },
+ }
make_ace_editor() {
if (this.editor) return;
@@ -42,7 +42,7 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
this.df._autocompletions = value;
}
});
- },
+ }
setup_autocompletion() {
if (this._autocompletion_setup) return;
@@ -82,20 +82,20 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
});
});
this._autocompletion_setup = true;
- },
+ }
refresh_height() {
this.ace_editor_target.css('height', this.expanded ? 600 : 300);
this.editor.resize();
- },
+ }
toggle_label() {
this.$expand_button && this.$expand_button.text(this.get_button_label());
- },
+ }
get_button_label() {
return this.expanded ? __('Collapse', null, 'Shrink code field.') : __('Expand', null, 'Enlarge code field.');
- },
+ }
set_language() {
const language_map = {
@@ -122,14 +122,14 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
const ace_language_mode = language_map[language] || '';
this.editor.session.setMode(ace_language_mode);
this.editor.setKeyboardHandler('ace/keyboard/vscode');
- },
+ }
parse(value) {
if (value == null) {
value = "";
}
return value;
- },
+ }
set_formatted_input(value) {
return this.load_lib().then(() => {
@@ -138,11 +138,11 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
if (value === this.get_input_value()) return;
this.editor.session.setValue(value);
});
- },
+ }
get_input_value() {
return this.editor ? this.editor.session.getValue() : '';
- },
+ }
load_lib() {
if (this.library_loaded) return this.library_loaded;
@@ -162,4 +162,4 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
return this.library_loaded;
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/color.js b/frappe/public/js/frappe/form/controls/color.js
index bf04581abd..802aad371a 100644
--- a/frappe/public/js/frappe/form/controls/color.js
+++ b/frappe/public/js/frappe/form/controls/color.js
@@ -1,11 +1,11 @@
import Picker from '../../color_picker/color_picker';
-frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
- make_input: function () {
- this._super();
+frappe.ui.form.ControlColor = class ControlColor extends frappe.ui.form.ControlData {
+ make_input () {
+ super.make_input();
this.make_color_input();
- },
- make_color_input: function () {
+ }
+ make_color_input () {
let picker_wrapper = $('');
this.picker = new Picker({
parent: picker_wrapper[0],
@@ -72,28 +72,28 @@ frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
this.selected_color = $(`
`);
this.selected_color.insertAfter(this.$input);
}
- },
+ }
refresh() {
- this._super();
+ super.refresh();
let color = this.get_color();
if (this.picker && this.picker.color !== color) {
this.picker.color = color;
this.picker.refresh();
}
- },
- set_formatted_input: function(value) {
- this._super(value);
+ }
+ set_formatted_input(value) {
+ super.set_formatted_input(value);
this.$input.val(value || __('Choose a color'));
this.selected_color.css({
"background-color": value || 'transparent',
});
this.selected_color.toggleClass('no-value', !value);
- },
+ }
get_color() {
return this.validate(this.get_value());
- },
- validate: function (value) {
+ }
+ validate (value) {
if (value === '') {
return '';
}
@@ -103,4 +103,4 @@ frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
}
return null;
}
-});
+};
diff --git a/frappe/public/js/frappe/form/controls/comment.js b/frappe/public/js/frappe/form/controls/comment.js
index 59b53bf59e..6d1664747f 100644
--- a/frappe/public/js/frappe/form/controls/comment.js
+++ b/frappe/public/js/frappe/form/controls/comment.js
@@ -3,7 +3,7 @@ import Mention from './quill-mention/quill.mention';
Quill.register('modules/mention', Mention, true);
-frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
+frappe.ui.form.ControlComment = class ControlComment extends frappe.ui.form.ControlTextEditor {
make_wrapper() {
this.comment_wrapper = !this.no_wrapper ? $(`