From 2ef5e6bd1d2bba43de3c2b9ecb02838db88cd596 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Tue, 2 May 2023 17:40:09 +0200
Subject: [PATCH 01/97] fix: file permissions
---
frappe/core/doctype/file/file.json | 8 +-----
frappe/core/doctype/file/file.py | 44 +++++++++++++++---------------
frappe/hooks.py | 1 +
3 files changed, 24 insertions(+), 29 deletions(-)
diff --git a/frappe/core/doctype/file/file.json b/frappe/core/doctype/file/file.json
index d6c4a99bc3..6c64bfe274 100644
--- a/frappe/core/doctype/file/file.json
+++ b/frappe/core/doctype/file/file.json
@@ -174,7 +174,7 @@
"icon": "fa fa-file",
"idx": 1,
"links": [],
- "modified": "2022-09-13 15:50:15.508251",
+ "modified": "2023-05-02 15:42:14.274901",
"modified_by": "Administrator",
"module": "Core",
"name": "File",
@@ -196,14 +196,8 @@
{
"create": 1,
"delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 1,
- "print": 1,
"read": 1,
- "report": 1,
"role": "All",
- "share": 1,
"write": 1
}
],
diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py
index 1323359030..2e88591f94 100755
--- a/frappe/core/doctype/file/file.py
+++ b/frappe/core/doctype/file/file.py
@@ -16,6 +16,7 @@ import frappe
from frappe import _
from frappe.database.schema import SPECIAL_CHAR_PATTERN
from frappe.model.document import Document
+from frappe.permissions import get_doctypes_with_read
from frappe.utils import call_hook_method, cint, get_files_path, get_hook_method, get_url
from frappe.utils.file_manager import is_safe_path
from frappe.utils.image import optimize_image, strip_exif_data
@@ -703,40 +704,39 @@ def on_doctype_update():
def has_permission(doc, ptype=None, user=None):
- has_access = False
user = user or frappe.session.user
if ptype == "create":
- has_access = frappe.has_permission("File", "create", user=user)
+ return frappe.has_permission("File", "create", user=user)
- if not doc.is_private or doc.owner in [user, "Guest"] or user == "Administrator":
- has_access = True
+ if not doc.is_private or doc.owner == user or user == "Administrator":
+ return True
if doc.attached_to_doctype and doc.attached_to_name:
attached_to_doctype = doc.attached_to_doctype
attached_to_name = doc.attached_to_name
- try:
- ref_doc = frappe.get_doc(attached_to_doctype, attached_to_name)
+ ref_doc = frappe.get_doc(attached_to_doctype, attached_to_name)
- if ptype in ["write", "create", "delete"]:
- has_access = ref_doc.has_permission("write")
+ if ptype in ["write", "create", "delete"]:
+ return ref_doc.has_permission("write")
+ else:
+ return ref_doc.has_permission("read")
- if ptype == "delete" and not has_access:
- frappe.throw(
- _(
- "Cannot delete file as it belongs to {0} {1} for which you do not have permissions"
- ).format(doc.attached_to_doctype, doc.attached_to_name),
- frappe.PermissionError,
- )
- else:
- has_access = ref_doc.has_permission("read")
- except frappe.DoesNotExistError:
- # if parent doc is not created before file is created
- # we cannot check its permission so we will use file's permission
- pass
+ return False
- return has_access
+
+def get_permission_query_conditions(user: str = None) -> str:
+ user = user or frappe.session.user
+ if user == "Administrator":
+ return ""
+
+ readable_doctypes = ", ".join(repr(dt) for dt in get_doctypes_with_read())
+ return f"""
+ (`tabFile`.`is_private` = 0)
+ OR (`tabFile`.`attached_to_doctype` IS NULL AND `tabFile`.`owner` = {user !r})
+ OR (`tabFile`.`attached_to_doctype` IN ({readable_doctypes}))
+ """
# Note: kept at the end to not cause circular, partial imports & maintain backwards compatibility
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 5967486824..e30b300a58 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -108,6 +108,7 @@ permission_query_conditions = {
"Communication": "frappe.core.doctype.communication.communication.get_permission_query_conditions_for_communication",
"Workflow Action": "frappe.workflow.doctype.workflow_action.workflow_action.get_permission_query_conditions",
"Prepared Report": "frappe.core.doctype.prepared_report.prepared_report.get_permission_query_condition",
+ "File": "frappe.core.doctype.file.file.get_permission_query_conditions",
}
has_permission = {
From 9c785569f9d4d6cb3d8b03739d6c149f683ae947 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 3 May 2023 11:28:20 +0200
Subject: [PATCH 02/97] test: file permissions
---
frappe/core/doctype/file/test_file.py | 66 +++++++++++++++++++++------
1 file changed, 53 insertions(+), 13 deletions(-)
diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py
index 51e065f710..dbab111257 100644
--- a/frappe/core/doctype/file/test_file.py
+++ b/frappe/core/doctype/file/test_file.py
@@ -601,25 +601,27 @@ class TestAttachmentsAccess(FrappeTestCase):
def setUp(self) -> None:
frappe.db.delete("File", {"is_folder": 0})
- def test_attachments_access(self):
+ def test_list_private_attachments(self):
frappe.set_user("test4@example.com")
self.attached_to_doctype, self.attached_to_docname = make_test_doc()
frappe.get_doc(
{
"doctype": "File",
- "file_name": "test_user.txt",
+ "file_name": "test_user_attachment.txt",
"attached_to_doctype": self.attached_to_doctype,
"attached_to_name": self.attached_to_docname,
"content": "Testing User",
+ "is_private": 1,
}
).insert()
frappe.get_doc(
{
"doctype": "File",
- "file_name": "test_user_home.txt",
+ "file_name": "test_user_standalone.txt",
"content": "User Home",
+ "is_private": 1,
}
).insert()
@@ -628,18 +630,20 @@ class TestAttachmentsAccess(FrappeTestCase):
frappe.get_doc(
{
"doctype": "File",
- "file_name": "test_system_manager.txt",
+ "file_name": "test_sm_attachment.txt",
"attached_to_doctype": self.attached_to_doctype,
"attached_to_name": self.attached_to_docname,
"content": "Testing System Manager",
+ "is_private": 1,
}
).insert()
frappe.get_doc(
{
"doctype": "File",
- "file_name": "test_sm_home.txt",
+ "file_name": "test_sm_standalone.txt",
"content": "System Manager Home",
+ "is_private": 1,
}
).insert()
@@ -654,15 +658,51 @@ class TestAttachmentsAccess(FrappeTestCase):
file.file_name for file in get_files_in_folder("Home/Attachments")["files"]
]
- self.assertIn("test_sm_home.txt", system_manager_files)
- self.assertNotIn("test_sm_home.txt", user_files)
- self.assertIn("test_user_home.txt", system_manager_files)
- self.assertIn("test_user_home.txt", user_files)
+ self.assertIn("test_sm_standalone.txt", system_manager_files)
+ self.assertNotIn("test_sm_standalone.txt", user_files)
- self.assertIn("test_system_manager.txt", system_manager_attachments_files)
- self.assertNotIn("test_system_manager.txt", user_attachments_files)
- self.assertIn("test_user.txt", system_manager_attachments_files)
- self.assertIn("test_user.txt", user_attachments_files)
+ self.assertIn("test_user_standalone.txt", user_files)
+ self.assertNotIn("test_user_standalone.txt", system_manager_files)
+
+ self.assertIn("test_sm_attachment.txt", system_manager_attachments_files)
+ self.assertIn("test_sm_attachment.txt", user_attachments_files)
+ self.assertIn("test_user_attachment.txt", system_manager_attachments_files)
+ self.assertIn("test_user_attachment.txt", user_attachments_files)
+
+ def test_list_public_single_file(self):
+ """Ensure that users are able to list public standalone files."""
+ frappe.set_user("test@example.com")
+ frappe.get_doc(
+ {
+ "doctype": "File",
+ "file_name": "test_public_single.txt",
+ "content": "Public single File",
+ "is_private": 0,
+ }
+ ).insert()
+
+ frappe.set_user("test4@example.com")
+ files = [file.file_name for file in get_files_in_folder("Home")["files"]]
+ self.assertIn("test_public_single.txt", files)
+
+ def test_list_public_attachment(self):
+ """Ensure that users are able to list public attachments."""
+ frappe.set_user("test@example.com")
+ self.attached_to_doctype, self.attached_to_docname = make_test_doc()
+ frappe.get_doc(
+ {
+ "doctype": "File",
+ "file_name": "test_public_attachment.txt",
+ "attached_to_doctype": self.attached_to_doctype,
+ "attached_to_name": self.attached_to_docname,
+ "content": "Public Attachment",
+ "is_private": 0,
+ }
+ ).insert()
+
+ frappe.set_user("test4@example.com")
+ files = [file.file_name for file in get_files_in_folder("Home/Attachments")["files"]]
+ self.assertIn("test_public_attachment.txt", files)
def tearDown(self) -> None:
frappe.set_user("Administrator")
From bcdc483a13ec61f83aac4230ce262bd42e6b8fff Mon Sep 17 00:00:00 2001
From: Corentin Flr <10946971+cogk@users.noreply.github.com>
Date: Thu, 15 Jun 2023 18:36:30 +0200
Subject: [PATCH 03/97] fix(test): Fix test_never_render to get path as string,
exclude PYC files from static downloads
This test code never actually tested the behaviour for two reasons:
- first, the page had an error which meant that a 500 Error page was returned (because `path` is not a string)
- second, every page contains the string "400" because it's contained in some of the icons.svg icons!
I also found a minor related bug in static_page.py, allowing people to download PYC files (pycache)
---
frappe/tests/test_website.py | 5 +++--
frappe/website/page_renderers/static_page.py | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py
index 6c319fff0a..1031a46c80 100644
--- a/frappe/tests/test_website.py
+++ b/frappe/tests/test_website.py
@@ -340,8 +340,9 @@ class TestWebsite(FrappeTestCase):
FILES_TO_SKIP = choices(list(WWW.glob("**/*.py*")), k=10)
for suffix in FILES_TO_SKIP:
- content = get_response_content(suffix.relative_to(WWW))
- self.assertIn("404", content)
+ path: str = suffix.relative_to(WWW).as_posix()
+ content = get_response_content(path)
+ self.assertIn("
Not Found", content)
def test_metatags(self):
content = get_response_content("/_test/_test_metatags")
diff --git a/frappe/website/page_renderers/static_page.py b/frappe/website/page_renderers/static_page.py
index 04e58ff217..d6de2f2991 100644
--- a/frappe/website/page_renderers/static_page.py
+++ b/frappe/website/page_renderers/static_page.py
@@ -8,7 +8,7 @@ import frappe
from frappe.website.page_renderers.base_renderer import BaseRenderer
from frappe.website.utils import is_binary_file
-UNSUPPORTED_STATIC_PAGE_TYPES = ("html", "md", "js", "xml", "css", "txt", "py", "json")
+UNSUPPORTED_STATIC_PAGE_TYPES = ("html", "md", "js", "xml", "css", "txt", "py", "pyc", "json")
class StaticPage(BaseRenderer):
From 9afedfae253896be463d52efe35eac035ac5f313 Mon Sep 17 00:00:00 2001
From: Corentin Flr <10946971+cogk@users.noreply.github.com>
Date: Fri, 16 Jun 2023 13:27:49 +0200
Subject: [PATCH 04/97] fix(test): Remove frappe.local.request between requests
`frappe.local.request` was not cleared between tests, which would not be a problem if all tests did set it to another Request object. But, some tests directly fetch the response content using get_response_content without first setting the frappe.local.request object (using set_request).
---
frappe/tests/test_website.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py
index 1031a46c80..16e82850de 100644
--- a/frappe/tests/test_website.py
+++ b/frappe/tests/test_website.py
@@ -11,10 +11,16 @@ from frappe.website.utils import build_response, clear_website_cache, get_home_p
class TestWebsite(FrappeTestCase):
def setUp(self):
frappe.set_user("Guest")
+ self._clearRequest()
def tearDown(self):
frappe.db.delete("Access Log")
frappe.set_user("Administrator")
+ self._clearRequest()
+
+ def _clearRequest(self):
+ if hasattr(frappe.local, "request"):
+ delattr(frappe.local, "request")
def test_home_page(self):
frappe.set_user("Administrator")
From 23846434ee03223f2460fa95b55974c06c51ab8a Mon Sep 17 00:00:00 2001
From: Corentin Flr <10946971+cogk@users.noreply.github.com>
Date: Fri, 16 Jun 2023 14:39:03 +0200
Subject: [PATCH 05/97] fix(path_resolver): Avoid 200 OK for NotFoundPage
renderer
---
frappe/website/path_resolver.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/frappe/website/path_resolver.py b/frappe/website/path_resolver.py
index 37bfb3ee56..50ef2afcb4 100644
--- a/frappe/website/path_resolver.py
+++ b/frappe/website/path_resolver.py
@@ -51,7 +51,6 @@ class PathResolver:
TemplatePage,
ListPage,
PrintPage,
- NotFoundPage,
]
for renderer in renderers:
From 85ac64ddd9794f3f77115b25e51f441041ad0acc Mon Sep 17 00:00:00 2001
From: Shariq Ansari
Date: Mon, 19 Jun 2023 13:18:25 +0530
Subject: [PATCH 06/97] fix: log errors while getting headers and data
---
.../integrations/doctype/webhook/webhook.py | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py
index 6fa24bfb67..711a565971 100644
--- a/frappe/integrations/doctype/webhook/webhook.py
+++ b/frappe/integrations/doctype/webhook/webhook.py
@@ -112,16 +112,21 @@ def get_context(doc):
def enqueue_webhook(doc, webhook) -> None:
- webhook: Webhook = frappe.get_doc("Webhook", webhook.get("name"))
- headers = get_webhook_headers(doc, webhook)
- data = get_webhook_data(doc, webhook)
+ try:
+ webhook: Webhook = frappe.get_doc("Webhook", webhook.get("name"))
+ headers = get_webhook_headers(doc, webhook)
+ data = get_webhook_data(doc, webhook)
- if webhook.is_dynamic_url:
- request_url = frappe.render_template(webhook.request_url, get_context(doc))
- else:
- request_url = webhook.request_url
+ if webhook.is_dynamic_url:
+ request_url = frappe.render_template(webhook.request_url, get_context(doc))
+ else:
+ request_url = webhook.request_url
+
+ r = None
+ except Exception as e:
+ frappe.logger().debug({"enqueue_webhook_error": e})
+ log_request(webhook.name, doc.name, request_url, headers, data, r)
- r = None
for i in range(3):
try:
r = requests.request(
From 74cc21013fbd954229d98cf8d802ad56706562d3 Mon Sep 17 00:00:00 2001
From: Shariq Ansari
Date: Mon, 19 Jun 2023 13:46:27 +0530
Subject: [PATCH 07/97] fix: validate webhook secret
---
frappe/integrations/doctype/webhook/webhook.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py
index 711a565971..2431fe2886 100644
--- a/frappe/integrations/doctype/webhook/webhook.py
+++ b/frappe/integrations/doctype/webhook/webhook.py
@@ -26,6 +26,7 @@ class Webhook(Document):
self.validate_request_url()
self.validate_request_body()
self.validate_repeating_fields()
+ self.validate_secret()
self.preview_document = None
def on_update(self):
@@ -74,6 +75,13 @@ class Webhook(Document):
if len(webhook_data) != len(set(webhook_data)):
frappe.throw(_("Same Field is entered more than once"))
+ def validate_secret(self):
+ if self.enable_security and self.webhook_secret:
+ try:
+ self.get_password("webhook_secret", False).encode("utf8")
+ except Exception:
+ frappe.throw(_("Invalid Webhook Secret"))
+
@frappe.whitelist()
def generate_preview(self):
# This function doesn't need to do anything specific as virtual fields
From ba8f97e7891ce4eff610e3184f94402d5494c4b6 Mon Sep 17 00:00:00 2001
From: Rucha Mahabal
Date: Thu, 22 Jun 2023 16:06:59 +0530
Subject: [PATCH 08/97] feat: before/after hooks for any app install/uninstall
---
frappe/installer.py | 12 ++++++++++++
frappe/utils/boilerplate.py | 16 ++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/frappe/installer.py b/frappe/installer.py
index 9c2807d7cd..4f02e207bd 100644
--- a/frappe/installer.py
+++ b/frappe/installer.py
@@ -287,6 +287,9 @@ def install_app(name, verbose=False, set_as_patched=True, force=False):
if out is False:
return
+ for fn in frappe.get_hooks("before_app_install"):
+ frappe.get_attr(fn)(name)
+
if name != "frappe":
add_module_defs(name, ignore_if_duplicate=force)
@@ -302,6 +305,9 @@ def install_app(name, verbose=False, set_as_patched=True, force=False):
for after_install in app_hooks.after_install or []:
frappe.get_attr(after_install)()
+ for fn in frappe.get_hooks("after_app_install"):
+ frappe.get_attr(fn)(name)
+
sync_jobs()
sync_fixtures(name)
sync_customizations(name)
@@ -369,6 +375,9 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False)
for before_uninstall in app_hooks.before_uninstall or []:
frappe.get_attr(before_uninstall)()
+ for fn in frappe.get_hooks("before_app_uninstall"):
+ frappe.get_attr(fn)(app_name)
+
modules = frappe.get_all("Module Def", filters={"app_name": app_name}, pluck="name")
drop_doctypes = _delete_modules(modules, dry_run=dry_run)
@@ -382,6 +391,9 @@ def remove_app(app_name, dry_run=False, yes=False, no_backup=False, force=False)
for after_uninstall in app_hooks.after_uninstall or []:
frappe.get_attr(after_uninstall)()
+ for fn in frappe.get_hooks("after_app_uninstall"):
+ frappe.get_attr(fn)(app_name)
+
click.secho(f"Uninstalled App {app_name} from Site {site}", fg="green")
frappe.flags.in_uninstall = False
diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py
index 2cb1a6ab80..befa02e9d7 100644
--- a/frappe/utils/boilerplate.py
+++ b/frappe/utils/boilerplate.py
@@ -372,6 +372,22 @@ app_license = "{app_license}"
# before_uninstall = "{app_name}.uninstall.before_uninstall"
# after_uninstall = "{app_name}.uninstall.after_uninstall"
+# Integration Setup
+# ------------------
+# To set up dependencies/integrations with other apps
+# Name of the app being installed is passed as an argument
+
+# before_app_install = "{app_name}.utils.before_app_install"
+# after_app_install = "{app_name}.utils.after_app_install"
+
+# Integration Cleanup
+# -------------------
+# To clean up dependencies/integrations with other apps
+# Name of the app being uninstalled is passed as an argument
+
+# before_app_uninstall = "{app_name}.utils.before_app_uninstall"
+# after_app_uninstall = "{app_name}.utils.after_app_uninstall"
+
# Desk Notifications
# ------------------
# See frappe.core.notifications.get_notification_config
From 3f792a80b1036a7e2c1c28cdd9f1e3f817968f42 Mon Sep 17 00:00:00 2001
From: Shariq Ansari
Date: Fri, 23 Jun 2023 16:29:39 +0530
Subject: [PATCH 09/97] fix: return if exception occur before executing webhook
---
frappe/integrations/doctype/webhook/webhook.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py
index 2431fe2886..c798c64c2c 100644
--- a/frappe/integrations/doctype/webhook/webhook.py
+++ b/frappe/integrations/doctype/webhook/webhook.py
@@ -130,10 +130,10 @@ def enqueue_webhook(doc, webhook) -> None:
else:
request_url = webhook.request_url
- r = None
except Exception as e:
frappe.logger().debug({"enqueue_webhook_error": e})
- log_request(webhook.name, doc.name, request_url, headers, data, r)
+ log_request(webhook.name, doc.name, request_url, headers, data)
+ return
for i in range(3):
try:
From fe27b8c7e0c622365fe2b034ca5b7bf37bcd7464 Mon Sep 17 00:00:00 2001
From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com>
Date: Fri, 23 Jun 2023 16:31:55 +0530
Subject: [PATCH 10/97] fix: removed redundant condition
Co-authored-by: Ankush Menat
---
frappe/integrations/doctype/webhook/webhook.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py
index c798c64c2c..5b8c653198 100644
--- a/frappe/integrations/doctype/webhook/webhook.py
+++ b/frappe/integrations/doctype/webhook/webhook.py
@@ -76,7 +76,7 @@ class Webhook(Document):
frappe.throw(_("Same Field is entered more than once"))
def validate_secret(self):
- if self.enable_security and self.webhook_secret:
+ if self.enable_security:
try:
self.get_password("webhook_secret", False).encode("utf8")
except Exception:
From 0e84fdaa6c69aaeacb1fb98f140fd2bb03bf467a Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sun, 25 Jun 2023 17:43:11 +0530
Subject: [PATCH 11/97] build: bump RQ
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index b9c1823794..f2ce88f294 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -62,7 +62,7 @@ dependencies = [
"hiredis~=2.2.3",
"requests-oauthlib~=1.3.1",
"requests~=2.31.0",
- "rq~=1.15.0",
+ "rq~=1.15.1",
"rsa>=4.1",
"semantic-version~=2.10.0",
"sqlparse~=0.4.4",
From c44db90bed7f61572890f9cbadc0fd17a797ebd0 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 13 Jun 2023 15:42:04 +0530
Subject: [PATCH 12/97] chore: Upgrade minimum required node version to 18
- Also update all the node packages
---
package.json | 2 +-
yarn.lock | 2296 +++++++++++++++++++++++---------------------------
2 files changed, 1037 insertions(+), 1261 deletions(-)
diff --git a/package.json b/package.json
index 6cf9d1d60b..d84fb30fdf 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"url": "https://github.com/frappe/frappe/issues"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"homepage": "https://frappeframework.com",
"dependencies": {
diff --git a/yarn.lock b/yarn.lock
index 04ba608423..603e4b4bcb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,44 +2,44 @@
# yarn lockfile v1
-"@babel/helper-validator-identifier@^7.16.7":
- version "7.16.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
- integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+"@adobe/css-tools@^4.0.1":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855"
+ integrity sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==
-"@babel/parser@^7.16.4":
- version "7.19.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
- integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
-"@babel/parser@^7.6.0", "@babel/parser@^7.9.6":
- version "7.18.5"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c"
- integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==
+"@babel/helper-validator-identifier@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
+ integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
+
+"@babel/parser@^7.16.4", "@babel/parser@^7.20.15", "@babel/parser@^7.21.3", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.5.tgz#721fd042f3ce1896238cf1b341c77eb7dee7dbea"
+ integrity sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==
"@babel/types@^7.6.1", "@babel/types@^7.9.6":
- version "7.18.4"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354"
- integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe"
+ integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==
dependencies:
- "@babel/helper-validator-identifier" "^7.16.7"
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.5"
to-fast-properties "^2.0.0"
-"@codexteam/icons@^0.0.4":
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.0.4.tgz#8b72dcd3f3a1b0d880bdceb2abebd74b46d3ae13"
- integrity sha512-V8N/TY2TGyas4wLrPIFq7bcow68b3gu8DfDt1+rrHPtXxcexadKauRJL6eQgfG7Z0LCrN4boLRawR4S9gjIh/Q==
-
"@editorjs/editorjs@^2.26.3":
- version "2.26.3"
- resolved "https://registry.yarnpkg.com/@editorjs/editorjs/-/editorjs-2.26.3.tgz#91b1a44003a5635aa29919ff1439d797e68a60e2"
- integrity sha512-ztR+fwXagfAnlc86A3p8K0bI/XQTvnGjmKY0P+c18aUB4OW3BjkX6OAPb4PH/Ym8G16fBKtJG//sITck6CD1lA==
- dependencies:
- "@codexteam/icons" "^0.0.4"
- codex-notifier "^1.1.2"
- codex-tooltip "^1.0.5"
- html-janitor "^2.0.4"
- nanoid "^3.1.22"
+ version "2.27.0"
+ resolved "https://registry.yarnpkg.com/@editorjs/editorjs/-/editorjs-2.27.0.tgz#ec2d6e2f42d1aa84d13eaea6a9c48b4324972c59"
+ integrity sha512-XyPnvu61Ynk4k7R/1gVYUJjrtuf9Tf0A+CZuvp2suW4z5TNHqNjBa9vRdr3ngHzhNSoZvgstrOO3zCVqVTezPg==
+
+"@esbuild/linux-loong64@0.14.54":
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
+ integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
"@frappe/esbuild-plugin-postcss2@^0.1.3":
version "0.1.3"
@@ -55,25 +55,30 @@
stylus "^0.x"
tmp "^0.2.1"
-"@nodelib/fs.scandir@2.1.4":
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
- integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==
+"@jridgewell/sourcemap-codec@^1.4.13":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
- "@nodelib/fs.stat" "2.0.4"
+ "@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
-"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655"
- integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063"
- integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
- "@nodelib/fs.scandir" "2.1.4"
+ "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@socket.io/component-emitter@~3.1.0":
@@ -86,11 +91,6 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
-"@types/component-emitter@^1.2.10":
- version "1.2.11"
- resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506"
- integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==
-
"@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
@@ -104,26 +104,31 @@
"@types/node" "*"
"@types/node@*", "@types/node@>=10.0.0":
- version "18.11.11"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.11.tgz#1d455ac0211549a8409d3cdb371cd55cc971e8dc"
- integrity sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==
+ version "20.3.1"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe"
+ integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==
"@types/web-bluetooth@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
+"@types/web-bluetooth@^0.0.17":
+ version "0.0.17"
+ resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.17.tgz#5c9f3c617f64a9735d7b72a7cc671e166d900c40"
+ integrity sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==
+
"@vue-flow/background@^1.1.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@vue-flow/background/-/background-1.2.0.tgz#6b7c283fd679838df90dda8dd98f322c368b7e59"
integrity sha512-ZqmYhOM/0aRmA5dA3KSHJNYpHnhmG2e6tzjmttoibo4JBI3KNbdyOX+OTlqt7Ic0LYUC6NWzRLAwv4gjJuc6Mg==
"@vue-flow/core@^1.16.2":
- version "1.19.2"
- resolved "https://registry.yarnpkg.com/@vue-flow/core/-/core-1.19.2.tgz#35b471b652165b8beb4933d94292a89f19250320"
- integrity sha512-ThlxpN3n5CPgyfDTwnAZ5I4vv0v7zDbfl9dV3Wcx7Ryxl2U3n4R8feuvRzR7B3eb3Cqb2VokxSFHsLGfyyv4dQ==
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/@vue-flow/core/-/core-1.20.1.tgz#29c5cfc307c99a6fb96cd066189f426a661af4a9"
+ integrity sha512-e856C2/eJRAOUf/tvfEDsQ4EQ9Ug1QO2WbF/gtuRkpDMHc3KtIMkWG5oedD1MlHAmow3vNarDU40br03sRTvmg==
dependencies:
- "@vueuse/core" "^9.13.0"
+ "@vueuse/core" "^10.1.2"
d3-drag "^3.0.0"
d3-selection "^3.0.0"
d3-zoom "^3.0.0"
@@ -138,15 +143,15 @@
estree-walker "^2.0.2"
source-map "^0.6.1"
-"@vue/compiler-core@3.2.40", "@vue/compiler-core@^3.2.22":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.40.tgz#c785501f09536748121e937fb87605bbb1ada8e5"
- integrity sha512-2Dc3Stk0J/VyQ4OUr2yEC53kU28614lZS+bnrCbFSAIftBJ40g/2yQzf4mPBiFuqguMB7hyHaujdgZAQ67kZYA==
+"@vue/compiler-core@3.3.4", "@vue/compiler-core@^3.2.26":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128"
+ integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==
dependencies:
- "@babel/parser" "^7.16.4"
- "@vue/shared" "3.2.40"
+ "@babel/parser" "^7.21.3"
+ "@vue/shared" "3.3.4"
estree-walker "^2.0.2"
- source-map "^0.6.1"
+ source-map-js "^1.0.2"
"@vue/compiler-dom@3.2.39":
version "3.2.39"
@@ -156,13 +161,13 @@
"@vue/compiler-core" "3.2.39"
"@vue/shared" "3.2.39"
-"@vue/compiler-dom@3.2.40":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.40.tgz#c225418773774db536174d30d3f25ba42a33e7e4"
- integrity sha512-OZCNyYVC2LQJy4H7h0o28rtk+4v+HMQygRTpmibGoG9wZyomQiS5otU7qo3Wlq5UfHDw2RFwxb9BJgKjVpjrQw==
+"@vue/compiler-dom@3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151"
+ integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
dependencies:
- "@vue/compiler-core" "3.2.40"
- "@vue/shared" "3.2.40"
+ "@vue/compiler-core" "3.3.4"
+ "@vue/shared" "3.3.4"
"@vue/compiler-sfc@3.2.39":
version "3.2.39"
@@ -180,21 +185,21 @@
postcss "^8.1.10"
source-map "^0.6.1"
-"@vue/compiler-sfc@^3.2.22":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.40.tgz#61823283efc84d25d9d2989458f305d32a2ed141"
- integrity sha512-tzqwniIN1fu1PDHC3CpqY/dPCfN/RN1thpBC+g69kJcrl7mbGiHKNwbA6kJ3XKKy8R6JLKqcpVugqN4HkeBFFg==
+"@vue/compiler-sfc@^3.2.26":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz#b19d942c71938893535b46226d602720593001df"
+ integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==
dependencies:
- "@babel/parser" "^7.16.4"
- "@vue/compiler-core" "3.2.40"
- "@vue/compiler-dom" "3.2.40"
- "@vue/compiler-ssr" "3.2.40"
- "@vue/reactivity-transform" "3.2.40"
- "@vue/shared" "3.2.40"
+ "@babel/parser" "^7.20.15"
+ "@vue/compiler-core" "3.3.4"
+ "@vue/compiler-dom" "3.3.4"
+ "@vue/compiler-ssr" "3.3.4"
+ "@vue/reactivity-transform" "3.3.4"
+ "@vue/shared" "3.3.4"
estree-walker "^2.0.2"
- magic-string "^0.25.7"
+ magic-string "^0.30.0"
postcss "^8.1.10"
- source-map "^0.6.1"
+ source-map-js "^1.0.2"
"@vue/compiler-ssr@3.2.39":
version "3.2.39"
@@ -204,29 +209,29 @@
"@vue/compiler-dom" "3.2.39"
"@vue/shared" "3.2.39"
-"@vue/compiler-ssr@3.2.40":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.40.tgz#67df95a096c63e9ec4b50b84cc6f05816793629c"
- integrity sha512-80cQcgasKjrPPuKcxwuCx7feq+wC6oFl5YaKSee9pV3DNq+6fmCVwEEC3vvkf/E2aI76rIJSOYHsWSEIxK74oQ==
+"@vue/compiler-ssr@3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz#9d1379abffa4f2b0cd844174ceec4a9721138777"
+ integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==
dependencies:
- "@vue/compiler-dom" "3.2.40"
- "@vue/shared" "3.2.40"
+ "@vue/compiler-dom" "3.3.4"
+ "@vue/shared" "3.3.4"
"@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==
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz#f9f5fb53464b0c37b2c8d2f3fbfe44df60f61dc9"
+ integrity sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==
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 "^7.0.36"
postcss-selector-parser "^6.0.2"
source-map "~0.6.1"
vue-template-es2015-compiler "^1.9.0"
optionalDependencies:
- prettier "^1.18.2"
+ prettier "^1.18.2 || ^2.0.0"
"@vue/component-compiler@^4.2.4":
version "4.2.4"
@@ -244,10 +249,10 @@
sass "^1.18.0"
stylus "^0.54.5"
-"@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.1.4", "@vue/devtools-api@^6.4.4":
- version "6.4.4"
- resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.4.4.tgz#0b024fc8ca91bb4b6035abaf53c5aecc17119b3b"
- integrity sha512-Ku31WzpOV/8cruFaXaEZKF81WkNnvCSlBY4eOGtz5WMSdJvX1v1WWlSMGZeqUwPtQ27ZZz7B62erEMq8JDjcXw==
+"@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
+ integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
"@vue/reactivity-transform@3.2.39":
version "3.2.39"
@@ -260,16 +265,16 @@
estree-walker "^2.0.2"
magic-string "^0.25.7"
-"@vue/reactivity-transform@3.2.40":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.40.tgz#dc24b9074b26f0d9dd2034c6349f5bb2a51c86ac"
- integrity sha512-HQUCVwEaacq6fGEsg2NUuGKIhUveMCjOk8jGHqLXPI2w6zFoPrlQhwWEaINTv5kkZDXKEnCijAp+4gNEHG03yw==
+"@vue/reactivity-transform@3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz#52908476e34d6a65c6c21cd2722d41ed8ae51929"
+ integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==
dependencies:
- "@babel/parser" "^7.16.4"
- "@vue/compiler-core" "3.2.40"
- "@vue/shared" "3.2.40"
+ "@babel/parser" "^7.20.15"
+ "@vue/compiler-core" "3.3.4"
+ "@vue/shared" "3.3.4"
estree-walker "^2.0.2"
- magic-string "^0.25.7"
+ magic-string "^0.30.0"
"@vue/reactivity@3.2.39":
version "3.2.39"
@@ -308,12 +313,22 @@
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.39.tgz#302df167559a1a5156da162d8cc6760cef67f8e3"
integrity sha512-D3dl2ZB9qE6mTuWPk9RlhDeP1dgNRUKC3NJxji74A4yL8M2MwlhLKUC/49WHjrNzSPug58fWx/yFbaTzGAQSBw==
-"@vue/shared@3.2.40":
- version "3.2.40"
- resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.40.tgz#e57799da2a930b975321981fcee3d1e90ed257ae"
- integrity sha512-0PLQ6RUtZM0vO3teRfzGi4ltLUO5aO+kLgwh4Um3THSR03rpQWLTuRCkuO5A41ITzwdWeKdPHtSARuPkoo5pCQ==
+"@vue/shared@3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780"
+ integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
-"@vueuse/core@^9.13.0":
+"@vueuse/core@^10.1.2":
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.1.2.tgz#2499eadec36c5d7109338e3a2b73725040ae8011"
+ integrity sha512-roNn8WuerI56A5uiTyF/TEYX0Y+VKlhZAF94unUfdhbDUI+NfwQMn4FUnUscIRUhv3344qvAghopU4bzLPNFlA==
+ dependencies:
+ "@types/web-bluetooth" "^0.0.17"
+ "@vueuse/metadata" "10.1.2"
+ "@vueuse/shared" "10.1.2"
+ vue-demi ">=0.14.0"
+
+"@vueuse/core@^9.5.0":
version "9.13.0"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
@@ -323,25 +338,22 @@
"@vueuse/shared" "9.13.0"
vue-demi "*"
-"@vueuse/core@^9.5.0":
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.5.0.tgz#6726e952e8f92b465457d3bc95deb385aacd9a41"
- integrity sha512-6GsWBsJHEb3sYw15mbLrcbslAVY45pkzjJYTKYKCXv88z7srAF0VEW0q+oXKsl58tCbqooplInahXFg8Yo1m4w==
- dependencies:
- "@types/web-bluetooth" "^0.0.16"
- "@vueuse/metadata" "9.5.0"
- "@vueuse/shared" "9.5.0"
- vue-demi "*"
+"@vueuse/metadata@10.1.2":
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.1.2.tgz#d8ffe557b1042efd03a0aa88540a00c25d193ee3"
+ integrity sha512-3mc5BqN9aU2SqBeBuWE7ne4OtXHoHKggNgxZR2K+zIW4YLsy6xoZ4/9vErQs6tvoKDX6QAqm3lvsrv0mczAwIQ==
"@vueuse/metadata@9.13.0":
version "9.13.0"
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
-"@vueuse/metadata@9.5.0":
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.5.0.tgz#b01c84230261ddee4d439ae5d9c21343dc5ae565"
- integrity sha512-4M1AyPZmIv41pym+K5+4wup3bKuYebbH8w8BROY1hmT7rIwcyS4tEL+UsGz0Hiu1FCOxcoBrwtAizc0YmBJjyQ==
+"@vueuse/shared@10.1.2":
+ version "10.1.2"
+ resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.1.2.tgz#31d8733a217a6396eb67706319133bf62cdd8baa"
+ integrity sha512-1uoUTPBlgyscK9v6ScGeVYDDzlPSFXBlxuK7SfrDGyUTBiznb3mNceqhwvZHjtDRELZEN79V5uWPTF1VDV8svA==
+ dependencies:
+ vue-demi ">=0.14.0"
"@vueuse/shared@9.13.0":
version "9.13.0"
@@ -350,13 +362,6 @@
dependencies:
vue-demi "*"
-"@vueuse/shared@9.5.0":
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.5.0.tgz#f5306548af0dc9f2b3a0d4da74e62bfdd6211241"
- integrity sha512-HnnCWU1Vg9CVWRCcI8ohDKDRB2Sc4bTgT1XAIaoLSfVHHn+TKbrox6pd3klCSw4UDxkhDfOk8cAdcK+Z5KleCA==
- dependencies:
- vue-demi "*"
-
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -371,9 +376,9 @@ accepts@~1.3.4:
negotiator "0.6.3"
ace-builds@^1.4.8:
- version "1.4.8"
- resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.8.tgz#d14be41d30294a2a12581f0bcfee4b696481ffdd"
- integrity sha512-8ZVAxwyCGAxQX8mOp9imSXH0hoSPkGfy8igJy+WO/7axL30saRhKgg1XPACSmxxPA7nfHVwM+ShWXT+vKsNuFg==
+ version "1.22.1"
+ resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.22.1.tgz#3d765d1cfffc79226e372b6353750fd997816154"
+ integrity sha512-o5RGTPBIiRxguWNors3pT6KuLqj0a2NvNLoqir7/2LLiFm34PJV3BMq4sl9kjPayo4+lmd99m6zAq+XPdhyHQA==
acorn@^7.1.1:
version "7.4.1"
@@ -389,12 +394,7 @@ acorn@^7.1.1:
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
- integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ansi-regex@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
- integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+ integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==
ansi-regex@^5.0.1:
version "5.0.1"
@@ -404,7 +404,7 @@ ansi-regex@^5.0.1:
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
- integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+ integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==
ansi-styles@^3.2.1:
version "3.2.1"
@@ -413,30 +413,33 @@ ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
-ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ansi-styles@^4.0.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
-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==
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-array-filter@^1.0.0:
+array-buffer-byte-length@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
- integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
+ resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead"
+ integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==
+ dependencies:
+ call-bind "^1.0.2"
+ is-array-buffer "^3.0.1"
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
- integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
assert-never@^1.2.1:
version "1.2.1"
@@ -446,7 +449,7 @@ assert-never@^1.2.1:
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
at-least-node@^1.0.0:
version "1.0.0"
@@ -458,36 +461,22 @@ atob@^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:
- version "10.4.2"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b"
- integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==
+autoprefixer@10, autoprefixer@^10.2.5:
+ version "10.4.14"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d"
+ integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==
dependencies:
- browserslist "^4.19.1"
- caniuse-lite "^1.0.30001297"
- fraction.js "^4.1.2"
+ browserslist "^4.21.5"
+ caniuse-lite "^1.0.30001464"
+ fraction.js "^4.2.0"
normalize-range "^0.1.2"
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
-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"
-
-available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
- integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==
- dependencies:
- array-filter "^1.0.0"
+available-typed-arrays@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
+ integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
awesomplete@^1.1.5:
version "1.1.5"
@@ -502,9 +491,9 @@ babel-walk@3.0.0-canary-5:
"@babel/types" "^7.9.6"
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64id@2.0.0, base64id@~2.0.0:
version "2.0.0"
@@ -516,20 +505,15 @@ 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==
bluebird@^3.1.1:
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
- integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
+ integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
boolbase@^1.0.0:
version "1.0.0"
@@ -549,44 +533,22 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
-braces@^3.0.1, braces@~3.0.2:
+braces@^3.0.2, 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==
dependencies:
fill-range "^7.0.1"
-browserslist@^4.0.0, browserslist@^4.16.6, browserslist@^4.20.3:
- version "4.21.0"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.0.tgz#7ab19572361a140ecd1e023e2c1ed95edda0cefe"
- integrity sha512-UQxE0DIhRB5z/zDz9iA03BOfxaN2+GQdBYH/2WrSIWEUrnpzTPJbhqt+umq6r3acaPRTW1FNTkrcp0PXgtFkvA==
+browserslist@^4.0.0, browserslist@^4.21.4, browserslist@^4.21.5:
+ version "4.21.8"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.8.tgz#db2498e1f4b80ed199c076248a094935860b6017"
+ integrity sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==
dependencies:
- caniuse-lite "^1.0.30001358"
- electron-to-chromium "^1.4.164"
- node-releases "^2.0.5"
- update-browserslist-db "^1.0.0"
-
-browserslist@^4.16.3:
- version "4.16.6"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
- integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
- dependencies:
- caniuse-lite "^1.0.30001219"
- colorette "^1.2.2"
- electron-to-chromium "^1.3.723"
- escalade "^3.1.1"
- node-releases "^1.1.71"
-
-browserslist@^4.19.1:
- version "4.20.0"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9"
- integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ==
- dependencies:
- caniuse-lite "^1.0.30001313"
- electron-to-chromium "^1.4.76"
- escalade "^3.1.1"
- node-releases "^2.0.2"
- picocolors "^1.0.0"
+ caniuse-lite "^1.0.30001502"
+ electron-to-chromium "^1.4.428"
+ node-releases "^2.0.12"
+ update-browserslist-db "^1.0.11"
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
@@ -606,15 +568,15 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001196, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001297, caniuse-lite@^1.0.30001313, caniuse-lite@^1.0.30001358:
- version "1.0.30001431"
- resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz"
- integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001502:
+ version "1.0.30001502"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz#f7e4a76eb1d2d585340f773767be1fefc118dca8"
+ integrity sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==
chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
- integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+ integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
@@ -622,7 +584,7 @@ chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
+chalk@^2.3.2, chalk@^2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -631,14 +593,6 @@ chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.1.0:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
- integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
character-parser@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0"
@@ -649,31 +603,31 @@ character-parser@^2.2.0:
charenc@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
- integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+ integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==
"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==
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
- anymatch "~3.1.1"
+ anymatch "~3.1.2"
braces "~3.0.2"
- glob-parent "~5.1.0"
+ glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
- readdirp "~3.5.0"
+ readdirp "~3.6.0"
optionalDependencies:
- fsevents "~2.3.1"
+ fsevents "~2.3.2"
clean-css@^4.1.11:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
- integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178"
+ integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==
dependencies:
source-map "~0.6.0"
-cliui@^7.0.2, cliui@^7.0.4:
+cliui@^7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
@@ -682,20 +636,19 @@ cliui@^7.0.2, cliui@^7.0.4:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
clone@^2.1.1, clone@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
- integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
-
-codex-notifier@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/codex-notifier/-/codex-notifier-1.1.2.tgz#a733079185f4c927fa296f1d71eb8753fe080895"
- integrity sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg==
-
-codex-tooltip@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/codex-tooltip/-/codex-tooltip-1.0.5.tgz#ba25fd5b3a58ba2f73fd667c2b46987ffd1edef2"
- integrity sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag==
+ integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
color-convert@^1.9.0:
version "1.9.3"
@@ -722,14 +675,9 @@ color-name@~1.1.4:
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colord@^2.9.1:
- version "2.9.2"
- resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
- integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==
-
-colorette@^1.2.2:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
- integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
+ version "2.9.3"
+ resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
+ integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
combined-stream@^1.0.6:
version "1.0.8"
@@ -744,11 +692,11 @@ commander@^7.2.0:
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
commander@^9.0.0:
- version "9.3.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-9.3.0.tgz#f619114a5a2d2054e0d9ff1b31d5ccf89255e26b"
- integrity sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==
+ version "9.5.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
+ integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
-component-emitter@^1.2.0, component-emitter@~1.3.0:
+component-emitter@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
@@ -756,7 +704,7 @@ component-emitter@^1.2.0, component-emitter@~1.3.0:
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
consolidate@^0.15.1:
version "0.15.1"
@@ -784,21 +732,21 @@ cookiejar@^2.1.0:
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
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==
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
+ integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
dependencies:
- is-what "^3.12.0"
+ is-what "^3.14.1"
-core-js@^3.22.0:
- version "3.22.5"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.5.tgz#a5f5a58e663d5c0ebb4e680cd7be37536fb2a9cf"
- integrity sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA==
+core-js@^3.26.1:
+ version "3.31.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.31.0.tgz#4471dd33e366c79d8c0977ed2d940821719db344"
+ integrity sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==
core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
cors@~2.8.5:
version "2.8.5"
@@ -809,24 +757,24 @@ cors@~2.8.5:
vary "^1"
cropperjs@^1.5.12:
- version "1.5.12"
- resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50"
- integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.13.tgz#eb1682f01d17c70ed5244317091d745c9a249ef8"
+ integrity sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA==
crypt@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
- integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+ integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==
-css-declaration-sorter@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz#72ebd995c8f4532ff0036631f7365cce9759df14"
- integrity sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og==
+css-declaration-sorter@^6.3.1:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad"
+ integrity sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==
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=
+ integrity sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==
dependencies:
css "^2.0.0"
@@ -842,13 +790,12 @@ css-select@^4.1.3:
nth-check "^2.0.1"
css-selector-tokenizer@^0.7.0:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d"
- integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==
+ version "0.7.3"
+ resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1"
+ integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==
dependencies:
- cssesc "^0.1.0"
- fastparse "^1.1.1"
- regexpu-core "^1.0.0"
+ cssesc "^3.0.0"
+ fastparse "^1.1.2"
css-tree@^1.1.2, css-tree@^1.1.3:
version "1.1.3"
@@ -873,35 +820,30 @@ css@^2.0.0:
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"
- integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=
-
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==
-cssnano-preset-default@^5.2.12:
- version "5.2.12"
- resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.12.tgz#ebe6596ec7030e62c3eb2b3c09f533c0644a9a97"
- integrity sha512-OyCBTZi+PXgylz9HAA5kHyoYhfGcYdwFmyaJzWnzxuGRtnMw/kR6ilW9XzlzlRAtB6PLT/r+prYgkef7hngFew==
+cssnano-preset-default@^5.2.14:
+ version "5.2.14"
+ resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8"
+ integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==
dependencies:
- css-declaration-sorter "^6.3.0"
+ css-declaration-sorter "^6.3.1"
cssnano-utils "^3.1.0"
postcss-calc "^8.2.3"
- postcss-colormin "^5.3.0"
- postcss-convert-values "^5.1.2"
+ postcss-colormin "^5.3.1"
+ postcss-convert-values "^5.1.3"
postcss-discard-comments "^5.1.2"
postcss-discard-duplicates "^5.1.0"
postcss-discard-empty "^5.1.1"
postcss-discard-overridden "^5.1.0"
- postcss-merge-longhand "^5.1.6"
- postcss-merge-rules "^5.1.2"
+ postcss-merge-longhand "^5.1.7"
+ postcss-merge-rules "^5.1.4"
postcss-minify-font-values "^5.1.0"
postcss-minify-gradients "^5.1.1"
- postcss-minify-params "^5.1.3"
+ postcss-minify-params "^5.1.4"
postcss-minify-selectors "^5.2.1"
postcss-normalize-charset "^5.1.0"
postcss-normalize-display-values "^5.1.0"
@@ -909,11 +851,11 @@ cssnano-preset-default@^5.2.12:
postcss-normalize-repeat-style "^5.1.1"
postcss-normalize-string "^5.1.0"
postcss-normalize-timing-functions "^5.1.0"
- postcss-normalize-unicode "^5.1.0"
+ postcss-normalize-unicode "^5.1.1"
postcss-normalize-url "^5.1.0"
postcss-normalize-whitespace "^5.1.1"
postcss-ordered-values "^5.1.3"
- postcss-reduce-initial "^5.1.0"
+ postcss-reduce-initial "^5.1.2"
postcss-reduce-transforms "^5.1.0"
postcss-svgo "^5.1.0"
postcss-unique-selectors "^5.1.1"
@@ -924,11 +866,11 @@ cssnano-utils@^3.1.0:
integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==
cssnano@^5.0.0:
- version "5.1.12"
- resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.12.tgz#bcd0b64d6be8692de79332c501daa7ece969816c"
- integrity sha512-TgvArbEZu0lk/dvg2ja+B7kYoD7BBCmn3+k58xD0qjrGHsFzXY/wKTo9M5egcUCabPol05e/PVoIu79s2JN4WQ==
+ version "5.1.15"
+ resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf"
+ integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==
dependencies:
- cssnano-preset-default "^5.2.12"
+ cssnano-preset-default "^5.2.14"
lilconfig "^2.0.3"
yaml "^1.10.2"
@@ -952,7 +894,7 @@ custom-event-polyfill@^1.0.7:
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=
+ integrity sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==
dependencies:
find-pkg "^0.1.2"
fs-exists-sync "^0.1.0"
@@ -1026,6 +968,13 @@ debug@^3.1.0, debug@^3.2.6:
dependencies:
ms "^2.1.1"
+debug@^4.3.2, debug@~4.3.1, debug@~4.3.2:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -1033,64 +982,69 @@ debug@~3.1.0:
dependencies:
ms "2.0.0"
-debug@~4.3.1, debug@~4.3.2:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
- dependencies:
- ms "2.1.2"
-
decode-uri-component@^0.2.0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
deep-equal@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
- integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
+ integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
+ dependencies:
+ is-arguments "^1.0.4"
+ is-date-object "^1.0.1"
+ is-regex "^1.0.4"
+ object-is "^1.0.1"
+ object-keys "^1.1.1"
+ regexp.prototype.flags "^1.2.0"
deep-equal@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.3.tgz#cad1c15277ad78a5c01c49c2dee0f54de8a6a7b0"
- integrity sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.1.tgz#c72ab22f3a7d3503a4ca87dde976fe9978816739"
+ integrity sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==
dependencies:
- es-abstract "^1.17.5"
- es-get-iterator "^1.1.0"
- is-arguments "^1.0.4"
- is-date-object "^1.0.2"
- is-regex "^1.0.5"
+ array-buffer-byte-length "^1.0.0"
+ call-bind "^1.0.2"
+ es-get-iterator "^1.1.3"
+ get-intrinsic "^1.2.0"
+ is-arguments "^1.1.1"
+ is-array-buffer "^3.0.2"
+ is-date-object "^1.0.5"
+ is-regex "^1.1.4"
+ is-shared-array-buffer "^1.0.2"
isarray "^2.0.5"
- object-is "^1.1.2"
+ object-is "^1.1.5"
object-keys "^1.1.1"
- object.assign "^4.1.0"
- regexp.prototype.flags "^1.3.0"
- side-channel "^1.0.2"
- which-boxed-primitive "^1.0.1"
+ object.assign "^4.1.4"
+ regexp.prototype.flags "^1.5.0"
+ side-channel "^1.0.4"
+ which-boxed-primitive "^1.0.2"
which-collection "^1.0.1"
- which-typed-array "^1.1.2"
+ which-typed-array "^1.1.9"
-define-properties@^1.1.2, define-properties@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
- integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
+ integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==
dependencies:
- object-keys "^1.0.12"
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
- integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
denque@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de"
- integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf"
+ integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==
doctypes@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9"
- integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=
+ integrity sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==
dom-serializer@^1.0.1:
version "1.4.1"
@@ -1132,15 +1086,10 @@ editorjs-undo@0.1.6:
resolved "https://registry.yarnpkg.com/editorjs-undo/-/editorjs-undo-0.1.6.tgz#823349a1e9a78d8bc68ba8570a2b854063bc804a"
integrity sha512-zVHPnBf2mcI8hWT9Eu8H3bGDEcMj4gppXbQjJW11Aa8Kdy2SVBGhM6fS59OUlBsm8iHWLxuoG2NUIfy9Rd30sw==
-electron-to-chromium@^1.3.723, electron-to-chromium@^1.4.164:
- version "1.4.169"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.169.tgz#d4b8cf9816566c7e9518128f1a97f39de9c7af9d"
- integrity sha512-Yb7UFva1sLlAaRyCkgoFF3qWvwZacFDtsGKi44rZsk8vnhL0DMhsUdhI4Dz9CCJQfftncDMGSI3AYiDtg8mD/w==
-
-electron-to-chromium@^1.4.76:
- version "1.4.84"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.84.tgz#2700befbcb49c42c4ee162e137ff392c07658249"
- integrity sha512-b+DdcyOiZtLXHdgEG8lncYJdxbdJWJvclPNMg0eLUDcSOSO876WA/pYjdSblUTd7eJdIs4YdIxHWGazx7UPSJw==
+electron-to-chromium@^1.4.428:
+ version "1.4.428"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.428.tgz#c31fc88e854f49d8305cdabf6ec934ff1588a902"
+ integrity sha512-L7uUknyY286of0AYC8CKfgWstD0Smk2DvHDi9F0GWQhSH90Bzi7iDrmCbZKz75tYJxeGSAc7TYeKpmbjMDoh1w==
emoji-regex@^8.0.0:
version "8.0.0"
@@ -1150,33 +1099,28 @@ emoji-regex@^8.0.0:
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
- integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
+ integrity sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==
-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==
-
-engine.io-client@~6.2.1:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.2.2.tgz#c6c5243167f5943dcd9c4abee1bfc634aa2cbdd0"
- integrity sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==
+engine.io-client@~6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91"
+ integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
engine.io-parser "~5.0.3"
- ws "~8.2.3"
+ ws "~8.11.0"
xmlhttprequest-ssl "~2.0.0"
engine.io-parser@~5.0.3:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0"
- integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==
+ version "5.0.7"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.7.tgz#ed5eae76c71f398284c578ab6deafd3ba7e4e4f6"
+ integrity sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==
-engine.io@~6.2.0:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.1.tgz#e3f7826ebc4140db9bbaa9021ad6b1efb175878f"
- integrity sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==
+engine.io@~6.4.2:
+ version "6.4.2"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.4.2.tgz#ffeaf68f69b1364b0286badddf15ff633476473f"
+ integrity sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==
dependencies:
"@types/cookie" "^0.4.1"
"@types/cors" "^2.8.12"
@@ -1187,7 +1131,7 @@ engine.io@~6.2.0:
cors "~2.8.5"
debug "~4.3.1"
engine.io-parser "~5.0.3"
- ws "~8.2.3"
+ ws "~8.11.0"
entities@^2.0.0:
version "2.2.0"
@@ -1195,190 +1139,163 @@ entities@^2.0.0:
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
errno@^0.1.1:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
- integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
+ integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
dependencies:
prr "~1.0.1"
-es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5:
- version "1.17.5"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9"
- integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==
+es-get-iterator@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6"
+ integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==
dependencies:
- es-to-primitive "^1.2.1"
- function-bind "^1.1.1"
- has "^1.0.3"
- has-symbols "^1.0.1"
- is-callable "^1.1.5"
- is-regex "^1.0.5"
- object-inspect "^1.7.0"
- object-keys "^1.1.1"
- object.assign "^4.1.0"
- string.prototype.trimleft "^2.1.1"
- string.prototype.trimright "^2.1.1"
-
-es-get-iterator@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8"
- integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==
- dependencies:
- es-abstract "^1.17.4"
- has-symbols "^1.0.1"
- is-arguments "^1.0.4"
- is-map "^2.0.1"
- is-set "^2.0.1"
- is-string "^1.0.5"
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.3"
+ has-symbols "^1.0.3"
+ is-arguments "^1.1.1"
+ is-map "^2.0.2"
+ is-set "^2.0.2"
+ is-string "^1.0.7"
isarray "^2.0.5"
+ stop-iteration-iterator "^1.0.0"
-es-to-primitive@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
- integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
- dependencies:
- is-callable "^1.1.4"
- is-date-object "^1.0.1"
- is-symbol "^1.0.2"
+esbuild-android-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
+ integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
-esbuild-android-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.29.tgz#c0960c84c9b832bade20831515e89d32549d4769"
- integrity sha512-tJuaN33SVZyiHxRaVTo1pwW+rn3qetJX/SRuc/83rrKYtyZG0XfsQ1ao1nEudIt9w37ZSNXR236xEfm2C43sbw==
+esbuild-android-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
+ integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
-esbuild-android-arm64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.29.tgz#8eceb3abe5abde5489d6a5cbe6a7c1044f71115f"
- integrity sha512-D74dCv6yYnMTlofVy1JKiLM5JdVSQd60/rQfJSDP9qvRAI0laPXIG/IXY1RG6jobmFMUfL38PbFnCqyI/6fPXg==
+esbuild-darwin-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
+ integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
-esbuild-darwin-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.29.tgz#26f3f14102310ecb8f2d9351c5b7a47a60d2cc8a"
- integrity sha512-+CJaRvfTkzs9t+CjGa0Oa28WoXa7EeLutQhxus+fFcu0MHhsBhlmeWHac3Cc/Sf/xPi1b2ccDFfzGYJCfV0RrA==
+esbuild-darwin-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
+ integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
-esbuild-darwin-arm64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.29.tgz#6d2d89dfd937992649239711ed5b86e51b13bd89"
- integrity sha512-5Wgz/+zK+8X2ZW7vIbwoZ613Vfr4A8HmIs1XdzRmdC1kG0n5EG5fvKk/jUxhNlrYPx1gSY7XadQ3l4xAManPSw==
+esbuild-freebsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
+ integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
-esbuild-freebsd-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.29.tgz#2cb41a0765d0040f0838280a213c81bbe62d6394"
- integrity sha512-VTfS7Bm9QA12JK1YXF8+WyYOfvD7WMpbArtDj6bGJ5Sy5xp01c/q70Arkn596aGcGj0TvQRplaaCIrfBG1Wdtg==
+esbuild-freebsd-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
+ integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
-esbuild-freebsd-arm64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.29.tgz#e1b79fbb63eaeff324cf05519efa7ff12ce4586a"
- integrity sha512-WP5L4ejwLWWvd3Fo2J5mlXvG3zQHaw5N1KxFGnUc4+2ZFZknP0ST63i0IQhpJLgEJwnQpXv2uZlU1iWZjFqEIg==
+esbuild-linux-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
+ integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
-esbuild-linux-32@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.29.tgz#a4a5a0b165b15081bc3227986e10dd4943edb7d6"
- integrity sha512-4myeOvFmQBWdI2U1dEBe2DCSpaZyjdQtmjUY11Zu2eQg4ynqLb8Y5mNjNU9UN063aVsCYYfbs8jbken/PjyidA==
+esbuild-linux-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
+ integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
-esbuild-linux-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.29.tgz#4c450088c84f8bfd22c51d116f59416864b85481"
- integrity sha512-iaEuLhssReAKE7HMwxwFJFn7D/EXEs43fFy5CJeA4DGmU6JHh0qVJD2p/UP46DvUXLRKXsXw0i+kv5TdJ1w5pg==
+esbuild-linux-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
+ integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
-esbuild-linux-arm64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.29.tgz#d1a23993b26cb1f63f740329b2fc09218e498bd1"
- integrity sha512-KYf7s8wDfUy+kjKymW3twyGT14OABjGHRkm9gPJ0z4BuvqljfOOUbq9qT3JYFnZJHOgkr29atT//hcdD0Pi7Mw==
+esbuild-linux-arm@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
+ integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
-esbuild-linux-arm@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.29.tgz#a7e2fea558525eab812b1fe27d7a2659cd1bb723"
- integrity sha512-OXa9D9QL1hwrAnYYAHt/cXAuSCmoSqYfTW/0CEY0LgJNyTxJKtqc5mlwjAZAvgyjmha0auS/sQ0bXfGf2wAokQ==
+esbuild-linux-mips64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
+ integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
-esbuild-linux-mips64le@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.29.tgz#e708c527f0785574e400828cdbed3d9b17b5ddff"
- integrity sha512-05jPtWQMsZ1aMGfHOvnR5KrTvigPbU35BtuItSSWLI2sJu5VrM8Pr9Owym4wPvA4153DFcOJ1EPN/2ujcDt54g==
+esbuild-linux-ppc64le@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
+ integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
-esbuild-linux-ppc64le@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.29.tgz#0137d1b38beae36a57176ef45e90740e734df502"
- integrity sha512-FYhBqn4Ir9xG+f6B5VIQVbRuM4S6qwy29dDNYFPoxLRnwTEKToIYIUESN1qHyUmIbfO0YB4phG2JDV2JDN9Kgw==
+esbuild-linux-riscv64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
+ integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
-esbuild-linux-riscv64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.29.tgz#a2f73235347a58029dcacf0fb91c9eb8bebc8abb"
- integrity sha512-eqZMqPehkb4nZcffnuOpXJQdGURGd6GXQ4ZsDHSWyIUaA+V4FpMBe+5zMPtXRD2N4BtyzVvnBko6K8IWWr36ew==
+esbuild-linux-s390x@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
+ integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
-esbuild-linux-s390x@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.29.tgz#0f7310ff1daec463ead9b9e26b7aa083a9f9f1ee"
- integrity sha512-o7EYajF1rC/4ho7kpSG3gENVx0o2SsHm7cJ5fvewWB/TEczWU7teDgusGSujxCYcMottE3zqa423VTglNTYhjg==
+esbuild-netbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
+ integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
-esbuild-netbsd-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.29.tgz#ba9a0d9cb8aed73b684825126927f75d4fe44ff9"
- integrity sha512-/esN6tb6OBSot6+JxgeOZeBk6P8V/WdR3GKBFeFpSqhgw4wx7xWUqPrdx4XNpBVO7X4Ipw9SAqgBrWHlXfddww==
-
-esbuild-openbsd-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.29.tgz#36dbe2c32d899106791b5f3af73f359213f71b8a"
- integrity sha512-jUTdDzhEKrD0pLpjmk0UxwlfNJNg/D50vdwhrVcW/D26Vg0hVbthMfb19PJMatzclbK7cmgk1Nu0eNS+abzoHw==
+esbuild-openbsd-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
+ integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
esbuild-plugin-vue3@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/esbuild-plugin-vue3/-/esbuild-plugin-vue3-0.3.0.tgz#5317252b8c9e474789ea570083a8b2f3618f99f4"
- integrity sha512-b8ypadGLuxJ02cPUXn/2yKhwMsEQ/JZMO3lN871X12ZKigXymZStBCexVI4C7lr7lguxa+IpU94pRQ/BtInMsQ==
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/esbuild-plugin-vue3/-/esbuild-plugin-vue3-0.3.2.tgz#06c8988832ac1fa89548cc7c00959296913cb800"
+ integrity sha512-KqZUPlIUS4vJLSexV3q5hgqIlsMWzlPtIuvZ1epZQvw/wJ/4vEPzEC1HQZduoHvUYvtnG703hsP1PsdpjTJ3ug==
dependencies:
- "@vue/compiler-core" "^3.2.22"
- "@vue/compiler-sfc" "^3.2.22"
- esbuild "^0.12.22"
+ "@vue/compiler-core" "^3.2.26"
+ "@vue/compiler-sfc" "^3.2.26"
+ esbuild "^0.14.8"
+ typescript "^4.7.4"
-esbuild-sunos-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.29.tgz#e5f857c121441ec63bf9b399a2131409a7d344e5"
- integrity sha512-EfhQN/XO+TBHTbkxwsxwA7EfiTHFe+MNDfxcf0nj97moCppD9JHPq48MLtOaDcuvrTYOcrMdJVeqmmeQ7doTcg==
+esbuild-sunos-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
+ integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
-esbuild-windows-32@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.29.tgz#9c2f1ab071a828f3901d1d79d205982a74bdda6e"
- integrity sha512-uoyb0YAJ6uWH4PYuYjfGNjvgLlb5t6b3zIaGmpWPOjgpr1Nb3SJtQiK4YCPGhONgfg2v6DcJgSbOteuKXhwqAw==
+esbuild-windows-32@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
+ integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
-esbuild-windows-64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.29.tgz#85fbce7c2492521896451b98d649a7db93e52667"
- integrity sha512-X9cW/Wl95QjsH8WUyr3NqbmfdU72jCp71cH3pwPvI4CgBM2IeOUDdbt6oIGljPu2bf5eGDIo8K3Y3vvXCCTd8A==
+esbuild-windows-64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
+ integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
-esbuild-windows-arm64@0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.29.tgz#0aa7a9a1bc43a63350bcf574d94b639176f065b5"
- integrity sha512-+O/PI+68fbUZPpl3eXhqGHTGK7DjLcexNnyJqtLZXOFwoAjaXlS5UBCvVcR3o2va+AqZTj8o6URaz8D2K+yfQQ==
+esbuild-windows-arm64@0.14.54:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
+ integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
-esbuild@^0.12.22:
- version "0.12.29"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.29.tgz#be602db7c4dc78944a9dbde0d1ea19d36c1f882d"
- integrity sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==
-
-esbuild@^0.14.29:
- version "0.14.29"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.29.tgz#24ad09c0674cbcb4aa2fe761485524eb1f6b1419"
- integrity sha512-SQS8cO8xFEqevYlrHt6exIhK853Me4nZ4aMW6ieysInLa0FMAL+AKs87HYNRtR2YWRcEIqoXAHh+Ytt5/66qpg==
+esbuild@^0.14.29, esbuild@^0.14.8:
+ version "0.14.54"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
+ integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
optionalDependencies:
- esbuild-android-64 "0.14.29"
- esbuild-android-arm64 "0.14.29"
- esbuild-darwin-64 "0.14.29"
- esbuild-darwin-arm64 "0.14.29"
- esbuild-freebsd-64 "0.14.29"
- esbuild-freebsd-arm64 "0.14.29"
- esbuild-linux-32 "0.14.29"
- esbuild-linux-64 "0.14.29"
- esbuild-linux-arm "0.14.29"
- esbuild-linux-arm64 "0.14.29"
- esbuild-linux-mips64le "0.14.29"
- esbuild-linux-ppc64le "0.14.29"
- esbuild-linux-riscv64 "0.14.29"
- esbuild-linux-s390x "0.14.29"
- esbuild-netbsd-64 "0.14.29"
- esbuild-openbsd-64 "0.14.29"
- esbuild-sunos-64 "0.14.29"
- esbuild-windows-32 "0.14.29"
- esbuild-windows-64 "0.14.29"
- esbuild-windows-arm64 "0.14.29"
+ "@esbuild/linux-loong64" "0.14.54"
+ esbuild-android-64 "0.14.54"
+ esbuild-android-arm64 "0.14.54"
+ esbuild-darwin-64 "0.14.54"
+ esbuild-darwin-arm64 "0.14.54"
+ esbuild-freebsd-64 "0.14.54"
+ esbuild-freebsd-arm64 "0.14.54"
+ esbuild-linux-32 "0.14.54"
+ esbuild-linux-64 "0.14.54"
+ esbuild-linux-arm "0.14.54"
+ esbuild-linux-arm64 "0.14.54"
+ esbuild-linux-mips64le "0.14.54"
+ esbuild-linux-ppc64le "0.14.54"
+ esbuild-linux-riscv64 "0.14.54"
+ esbuild-linux-s390x "0.14.54"
+ esbuild-netbsd-64 "0.14.54"
+ esbuild-openbsd-64 "0.14.54"
+ esbuild-sunos-64 "0.14.54"
+ esbuild-windows-32 "0.14.54"
+ esbuild-windows-64 "0.14.54"
+ esbuild-windows-arm64 "0.14.54"
escalade@^3.1.1:
version "3.1.1"
@@ -1398,31 +1315,31 @@ estree-walker@^2.0.2:
eventemitter3@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
- integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=
+ integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==
eventemitter3@^4.0.0:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384"
- integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
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=
+ integrity sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==
dependencies:
os-homedir "^1.0.1"
expand-tilde@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+ integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==
dependencies:
homedir-polyfill "^1.0.1"
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
- integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+ integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==
dependencies:
is-extendable "^0.1.0"
@@ -1434,7 +1351,7 @@ extend@^3.0.0, extend@^3.0.2:
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
- integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+ integrity sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==
fast-diff@1.1.2:
version "1.1.2"
@@ -1447,26 +1364,25 @@ fast-diff@1.2.0:
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==
+ version "3.2.12"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
+ integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.0"
+ glob-parent "^5.1.2"
merge2 "^1.3.0"
- micromatch "^4.0.2"
- picomatch "^2.2.1"
+ micromatch "^4.0.4"
-fastparse@^1.1.1:
+fastparse@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
fastq@^1.6.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858"
- integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
+ integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
dependencies:
reusify "^1.0.4"
@@ -1480,7 +1396,7 @@ fill-range@^7.0.1:
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=
+ integrity sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==
dependencies:
fs-exists-sync "^0.1.0"
resolve-dir "^0.1.0"
@@ -1488,7 +1404,7 @@ find-file-up@^0.1.2:
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=
+ integrity sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==
dependencies:
find-file-up "^0.1.2"
@@ -1500,31 +1416,28 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
-foreach@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
- integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
form-data@^2.3.1:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
- integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
+ integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
formidable@^1.2.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659"
- integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
+ integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==
-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==
-
-fraction.js@^4.1.2:
+fraction.js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
@@ -1544,14 +1457,14 @@ frappe-datatable@^1.17.2:
sortablejs "^1.7.0"
frappe-gantt@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/frappe-gantt/-/frappe-gantt-0.6.0.tgz#fece2fdecc0b8d6065d3c420d9681b719b827047"
- integrity sha512-/P7s9edP6EoLD09EX2HPqsy1u0v4zYcurMy4ByExArvj7t0UDJlpxp88nISFtMkQe+aofaO9dR0fd61ZwX0O6g==
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/frappe-gantt/-/frappe-gantt-0.6.1.tgz#57ae0b5f024101fc7cd5ba92f605de97dba9c9a1"
+ integrity sha512-1cSU9vLbwypjzaxnCfnEE03Xr3HlAV2S8dRtjxw62o+amkx1A8bBIFd2jp84mcDdTCM77Ij4LzZBslAKZB8oMg==
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=
+ integrity sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==
fs-extra@^9.1.0:
version "9.1.0"
@@ -1566,9 +1479,9 @@ fs-extra@^9.1.0:
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@~2.3.1:
+fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@@ -1578,35 +1491,41 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+functions-have-names@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+ integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
generic-names@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917"
- integrity sha1-LXhqEhruUIh2eWk56OO/+DbCCRc=
+ integrity sha512-b6OHfQuKasIKM9b6YPkX+KUj/TLBTx3B/1aT1T5F12FEuEqyFMdr59OMS53aoaSw8eVtapdqieX6lbg5opaOhA==
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==
+generic-names@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-4.0.0.tgz#0bd8a2fd23fe8ea16cbd0a279acd69c06933d9a3"
+ integrity sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==
dependencies:
- loader-utils "^1.1.0"
+ loader-utils "^3.2.0"
get-caller-file@^2.0.5:
version "2.0.5"
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.3"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
- integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
+ integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
+ has-proto "^1.0.1"
has-symbols "^1.0.3"
-glob-parent@^5.1.0, glob-parent@~5.1.0:
+glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
@@ -1614,21 +1533,21 @@ glob-parent@^5.1.0, glob-parent@~5.1.0:
is-glob "^4.0.1"
glob@^7.1.3, glob@^7.1.6:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
- integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
- minimatch "^3.0.4"
+ minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.0.0"
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=
+ integrity sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==
dependencies:
global-prefix "^0.1.4"
is-windows "^0.2.0"
@@ -1636,60 +1555,71 @@ global-modules@^0.2.3:
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=
+ integrity sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==
dependencies:
homedir-polyfill "^1.0.0"
ini "^1.3.4"
is-windows "^0.2.0"
which "^1.2.12"
-graceful-fs@^4.1.2, graceful-fs@^4.1.6:
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
- integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
-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==
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
- integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+ integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==
dependencies:
ansi-regex "^2.0.0"
+has-bigints@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
+ integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
- integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
+ integrity sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-symbols@^1.0.0:
+has-property-descriptors@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
- integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
+ integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+ dependencies:
+ get-intrinsic "^1.1.1"
-has-symbols@^1.0.1:
+has-proto@^1.0.1:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
-has-symbols@^1.0.3:
+has-symbols@^1.0.2, has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+has-tostringtag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+ dependencies:
+ has-symbols "^1.0.2"
+
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -1700,12 +1630,12 @@ has@^1.0.3:
hash-sum@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
- integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=
+ integrity sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==
highlight.js@^10.4.1:
- version "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==
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
+ integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
version "1.0.3"
@@ -1714,32 +1644,27 @@ homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
dependencies:
parse-passwd "^1.0.0"
-html-janitor@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/html-janitor/-/html-janitor-2.0.4.tgz#ae5a115cdf3331cd5501edd7b5471b18ea44cdbb"
- integrity sha512-92J5h9jNZRk30PMHapjHEJfkrBWKCOy0bq3oW2pBungky6lzYSoboBGPMvxl1XRKB2q+kniQmsLsPbdpY7RM2g==
-
html5-qrcode@^2.0.11:
- version "2.0.11"
- resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.0.11.tgz#2cc5f63e767be53dd6c6d56b6c4f180a12aa8075"
- integrity sha512-cCrVOK2yJGPGSTjchqRhkBJIrxvojEwF/pDKLNxmTH1wiAsVc61ZnIqyApIVyNfn5dKRFax70Qpr7pZwbUNiUw==
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz#0b0cdf7a9926cfd4be530e13a51db47592adfa0d"
+ integrity sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==
hyperlist@^1.0.0-beta:
- version "1.0.0-beta"
- resolved "https://registry.yarnpkg.com/hyperlist/-/hyperlist-1.0.0-beta.tgz#2cbbd77f4498c2ecc290b7f3c6745b3f0288247e"
- integrity sha1-LLvXf0SYwuzCkLfzxnRbPwKIJH4=
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/hyperlist/-/hyperlist-1.0.0.tgz#b211d41832643ca969e3087a86c912f93f82e5bb"
+ integrity sha512-1qAjO29EJW/mPyqY+9wFjruD2YWur1dPsPYmt9RvMX6P+8Cr2UmT75MCWjjK+1/4Jxc3sm/G3Kr8DzGgEDRG+Q==
-iconv-lite@^0.4.4:
- version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
- integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+iconv-lite@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
- safer-buffer ">= 2.1.2 < 3"
+ safer-buffer ">= 2.1.2 < 3.0.0"
icss-replace-symbols@^1.0.2, icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
- integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
+ integrity sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==
icss-utils@^5.0.0:
version "5.1.0"
@@ -1749,22 +1674,22 @@ icss-utils@^5.0.0:
image-size@~0.5.0:
version "0.5.5"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
- integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
+ integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
- integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
+ integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
immutable@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
- integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be"
+ integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
@@ -1779,15 +1704,38 @@ ini@^1.3.4:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
-is-arguments@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
- integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
+internal-slot@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986"
+ integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==
+ dependencies:
+ get-intrinsic "^1.2.0"
+ has "^1.0.3"
+ side-channel "^1.0.4"
-is-bigint@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4"
- integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==
+is-arguments@^1.0.4, is-arguments@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+ integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe"
+ integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.2.0"
+ is-typed-array "^1.1.10"
+
+is-bigint@^1.0.1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+ integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+ dependencies:
+ has-bigints "^1.0.1"
is-binary-path@~2.1.0:
version "2.1.0"
@@ -1796,49 +1744,37 @@ is-binary-path@~2.1.0:
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-boolean-object@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+ integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
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==
-is-callable@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
- integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
+is-callable@^1.1.3:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
-is-callable@^1.1.5:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
- integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
-
-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==
+is-core-module@^2.11.0:
+ version "2.12.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
+ integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
dependencies:
has "^1.0.3"
-is-core-module@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
- integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
+is-date-object@^1.0.1, is-date-object@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+ integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
dependencies:
- has "^1.0.3"
-
-is-date-object@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
- integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
-
-is-date-object@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
- integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+ has-tostringtag "^1.0.0"
is-expression@^4.0.0:
version "4.0.0"
@@ -1851,12 +1787,12 @@ is-expression@^4.0.0:
is-extendable@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
- integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+ integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
@@ -1864,21 +1800,23 @@ is-fullwidth-code-point@^3.0.0:
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
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==
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
-is-map@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1"
- integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==
+is-map@^2.0.1, is-map@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
+ integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==
-is-number-object@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197"
- integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
+is-number-object@^1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
+ integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
is-number@^7.0.0:
version "7.0.0"
@@ -1890,47 +1828,50 @@ is-promise@^2.0.0:
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==
+is-regex@^1.0.3, is-regex@^1.0.4, is-regex@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
- has-symbols "^1.0.1"
+ has-tostringtag "^1.0.0"
-is-regex@^1.0.5:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
- integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
- dependencies:
- has-symbols "^1.0.1"
+is-set@^2.0.1, is-set@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec"
+ integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==
-is-set@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43"
- integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==
-
-is-string@^1.0.4, is-string@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
- integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
-
-is-symbol@^1.0.2:
+is-shared-array-buffer@^1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
- integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
+ integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
dependencies:
- has-symbols "^1.0.0"
+ call-bind "^1.0.2"
-is-typed-array@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d"
- integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==
+is-string@^1.0.5, is-string@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+ integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
dependencies:
- available-typed-arrays "^1.0.0"
- es-abstract "^1.17.4"
- foreach "^2.0.5"
- has-symbols "^1.0.1"
+ has-tostringtag "^1.0.0"
+
+is-symbol@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+ integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+ dependencies:
+ has-symbols "^1.0.2"
+
+is-typed-array@^1.1.10:
+ version "1.1.10"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f"
+ integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==
+ dependencies:
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.2"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.0"
is-weakmap@^2.0.1:
version "2.0.1"
@@ -1938,11 +1879,14 @@ is-weakmap@^2.0.1:
integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
is-weakset@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83"
- integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d"
+ integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
-is-what@^3.12.0:
+is-what@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
@@ -1950,7 +1894,7 @@ is-what@^3.12.0:
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=
+ integrity sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==
isarray@^2.0.5:
version "2.0.5"
@@ -1960,12 +1904,12 @@ isarray@^2.0.5:
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
jquery@3.6.0:
version "3.6.0"
@@ -1973,14 +1917,14 @@ jquery@3.6.0:
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
"jquery@>=2.0.0 <4.0.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.0.tgz#9980b97d9e4194611c36530e7dc46a58d7340fc9"
- integrity sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.0.tgz#fe2c01a05da500709006d8790fe21c8a39d75612"
+ integrity sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==
js-base64@^2.1.9:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
- integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
+ integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
js-sha256@^0.9.0:
version "0.9.0"
@@ -1993,26 +1937,14 @@ js-stringify@^1.0.2:
integrity sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==
jsbarcode@^3.9.0:
- version "3.11.0"
- resolved "https://registry.yarnpkg.com/jsbarcode/-/jsbarcode-3.11.0.tgz#20623e008b101ef45d0cce9c8022cdf49be28547"
- integrity sha512-/ozCd7wsa+VIHo9sUc03HneVEQrH7cVWfJolUT/WOW1m8mJ2e3iYZje6C9X3LFHdczlesqFHRpxLtbVsNtjyow==
-
-jsesc@~0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
- integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+ version "3.11.5"
+ resolved "https://registry.yarnpkg.com/jsbarcode/-/jsbarcode-3.11.5.tgz#390b3efd0271f35b9d68c7b8af6e972445969014"
+ integrity sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==
json5@^0.5.0:
version "0.5.1"
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"
+ integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==
jsonfile@^6.0.1:
version "6.1.0"
@@ -2026,7 +1958,7 @@ jsonfile@^6.0.1:
jstransformer@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3"
- integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=
+ integrity sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==
dependencies:
is-promise "^2.0.0"
promise "^7.0.1"
@@ -2034,22 +1966,22 @@ jstransformer@1.0.0:
kind-of@^3.0.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
- integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==
dependencies:
is-buffer "^1.1.5"
launch-editor@^2.2.1:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.4.0.tgz#2849de434e4684da2298db48c4e5b8ca64291173"
- integrity sha512-mZ0BHeSn/ohL+Ib+b+JnxC59vcNz6v5IR9d0CuM8f0x8ni8oK3IIG6G0vMkpxc0gFsmvINkztGOHiWTaX4BmAg==
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7"
+ integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==
dependencies:
picocolors "^1.0.0"
- shell-quote "^1.6.1"
+ shell-quote "^1.7.3"
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=
+ integrity sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==
dependencies:
set-getter "^0.1.0"
@@ -2070,52 +2002,48 @@ less@^3.9.0:
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==
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/less/-/less-4.1.3.tgz#175be9ddcbf9b250173e0a00b4d6920a5b770246"
+ integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==
dependencies:
copy-anything "^2.0.1"
parse-node-version "^1.0.1"
- tslib "^1.10.0"
+ tslib "^2.3.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"
+ needle "^3.1.0"
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"
- integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=
+ integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==
dependencies:
immediate "~3.0.5"
lilconfig@^2.0.3:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
- integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
+ integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
loader-utils@^0.2.16:
version "0.2.17"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
- integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=
+ integrity sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==
dependencies:
big.js "^3.1.3"
emojis-list "^2.0.0"
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"
+loader-utils@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.1.tgz#4fb104b599daafd82ef3e1a41fb9265f87e1f576"
+ integrity sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==
loadjs@^4.2.0:
version "4.2.0"
@@ -2123,9 +2051,9 @@ loadjs@^4.2.0:
integrity sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==
localforage@^1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1"
- integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g==
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4"
+ integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==
dependencies:
lie "3.1.1"
@@ -2139,7 +2067,7 @@ locate-path@^6.0.0:
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
+ integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
lodash.memoize@^4.1.2:
version "4.1.2"
@@ -2171,6 +2099,13 @@ magic-string@^0.25.7:
dependencies:
sourcemap-codec "^1.4.8"
+magic-string@^0.30.0:
+ version "0.30.0"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529"
+ integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.4.13"
+
make-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
@@ -2208,34 +2143,22 @@ merge2@^1.3.0:
methods@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
- integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
-micromatch@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
- integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
dependencies:
- braces "^3.0.1"
- picomatch "^2.0.5"
-
-mime-db@1.44.0:
- version "1.44.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
- integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
+ braces "^3.0.2"
+ picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-mime-types@^2.1.12:
- version "2.1.27"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
- integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
- dependencies:
- mime-db "1.44.0"
-
-mime-types@~2.1.34:
+mime-types@^2.1.12, mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@@ -2247,31 +2170,26 @@ mime@^1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+minimatch@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.2.0:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-
-mkdirp@^1.0.4, 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==
moment-timezone@^0.5.35:
- version "0.5.35"
- resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.35.tgz#6fa2631bdbe8ff04f6b8753f7199516be6dc9839"
- integrity sha512-cY/pBOEXepQvlgli06ttCTKcIf8cD1nmNwOKQQAdHBqYApQSpAqotBMX0RJZNgMp6i0PlZuf1mFtnlyEkwyvFw==
+ version "0.5.43"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.43.tgz#3dd7f3d0c67f78c23cd1906b9b2137a09b3c4790"
+ integrity sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==
dependencies:
- moment ">= 2.9.0"
+ moment "^2.29.4"
-"moment@>= 2.9.0", moment@^2.29.4:
+moment@^2.29.4:
version "2.29.4"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
@@ -2279,40 +2197,35 @@ moment-timezone@^0.5.35:
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-ms@2.1.2, ms@^2.1.1:
+ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-nanoid@^3.1.22, nanoid@^3.3.4:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
- integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-nanoid@^3.1.23:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
- integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
-
-nanoid@^3.3.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
- integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==
+nanoid@^3.3.6:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
+ integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
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==
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/native-request/-/native-request-1.1.0.tgz#acdb30fe2eefa3e1bc8c54b3a6852e9c5c0d3cb0"
+ integrity sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==
-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==
+needle@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44"
+ integrity sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==
dependencies:
debug "^3.2.6"
- iconv-lite "^0.4.4"
+ iconv-lite "^0.6.3"
sax "^1.2.4"
negotiator@0.6.3:
@@ -2320,25 +2233,15 @@ negotiator@0.6.3:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
-node-releases@^1.1.71:
- version "1.1.77"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e"
- integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==
-
-node-releases@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
- integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
-
-node-releases@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
- integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
+node-releases@^2.0.12:
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039"
+ integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==
nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
- integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
+ integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
dependencies:
abbrev "1"
@@ -2350,7 +2253,7 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
- integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
+ integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
normalize-url@^4.5.0:
version "4.5.1"
@@ -2372,57 +2275,47 @@ nth-check@^2.0.1:
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-inspect@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
- integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-inspect@^1.9.0:
- version "1.12.2"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
- integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
+ version "1.12.3"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
+ integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
-object-is@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
- integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
+object-is@^1.0.1, object-is@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
+ integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
dependencies:
+ call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.17.5"
-object-keys@^1.0.11, object-keys@^1.1.1:
+object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-object-keys@^1.0.12:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032"
- integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==
-
-object.assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+object.assign@^4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
+ integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ has-symbols "^1.0.3"
+ object-keys "^1.1.1"
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
os-homedir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
- integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+ integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==
p-limit@^3.0.2:
version "3.1.0"
@@ -2456,7 +2349,7 @@ parse-node-version@^1.0.1:
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
- integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+ integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==
path-exists@^4.0.0:
version "4.0.0"
@@ -2466,27 +2359,27 @@ path-exists@^4.0.0:
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-path-parse@^1.0.6, path-parse@^1.0.7:
+path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+picocolors@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f"
+ integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==
+
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-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"
- integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^4.0.1:
version "4.0.1"
@@ -2494,19 +2387,19 @@ pify@^4.0.1:
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pinia@^2.0.23:
- version "2.0.23"
- resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.23.tgz#570f5f82160b656b412602789683faa95502d227"
- integrity sha512-N15hFf4o5STrxpNrib1IEb1GOArvPYf1zPvQVRGOO1G1d74Ak0J0lVyalX/SmrzdT4Q0nlEFjbURsmBmIGUR5Q==
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.1.3.tgz#50c70c7b4c94c109fade0ed4122231cbba72f8c5"
+ integrity sha512-XNA/z/ye4P5rU1pieVmh0g/hSuDO98/a5UC8oSP0DNdvt6YtetJNHTrXwpwsQuflkGT34qKxAEcp7lSxXNjf/A==
dependencies:
- "@vue/devtools-api" "^6.4.4"
- vue-demi "*"
+ "@vue/devtools-api" "^6.5.0"
+ vue-demi ">=0.14.5"
plyr@^3.7.2:
- version "3.7.2"
- resolved "https://registry.yarnpkg.com/plyr/-/plyr-3.7.2.tgz#183d2397e7401a577700c8319fe133692b4aff54"
- integrity sha512-I0ZC/OI4oJ0iWG9s2rrnO0YFO6aLyrPiQBq9kum0FqITYljwTPBbYL3TZZu8UJQJUq7tUWN18Q7ACwNCkGKABQ==
+ version "3.7.8"
+ resolved "https://registry.yarnpkg.com/plyr/-/plyr-3.7.8.tgz#b79bccc23687705b5d9a283b2a88c124bf7471ed"
+ integrity sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA==
dependencies:
- core-js "^3.22.0"
+ core-js "^3.26.1"
custom-event-polyfill "^1.0.7"
loadjs "^4.2.0"
rangetouch "^2.0.1"
@@ -2525,22 +2418,22 @@ postcss-calc@^8.2.3:
postcss-selector-parser "^6.0.9"
postcss-value-parser "^4.2.0"
-postcss-colormin@^5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a"
- integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==
+postcss-colormin@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f"
+ integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
caniuse-api "^3.0.0"
colord "^2.9.1"
postcss-value-parser "^4.2.0"
-postcss-convert-values@^5.1.2:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz#31586df4e184c2e8890e8b34a0b9355313f503ab"
- integrity sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g==
+postcss-convert-values@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393"
+ integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==
dependencies:
- browserslist "^4.20.3"
+ browserslist "^4.21.4"
postcss-value-parser "^4.2.0"
postcss-discard-comments@^5.1.2:
@@ -2563,20 +2456,20 @@ postcss-discard-overridden@^5.1.0:
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e"
integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==
-postcss-merge-longhand@^5.1.6:
- version "5.1.6"
- resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.6.tgz#f378a8a7e55766b7b644f48e5d8c789ed7ed51ce"
- integrity sha512-6C/UGF/3T5OE2CEbOuX7iNO63dnvqhGZeUnKkDeifebY0XqkkvrctYSZurpNE902LDf2yKwwPFgotnfSoPhQiw==
+postcss-merge-longhand@^5.1.7:
+ version "5.1.7"
+ resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16"
+ integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==
dependencies:
postcss-value-parser "^4.2.0"
- stylehacks "^5.1.0"
+ stylehacks "^5.1.1"
-postcss-merge-rules@^5.1.2:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.2.tgz#7049a14d4211045412116d79b751def4484473a5"
- integrity sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ==
+postcss-merge-rules@^5.1.4:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c"
+ integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
caniuse-api "^3.0.0"
cssnano-utils "^3.1.0"
postcss-selector-parser "^6.0.5"
@@ -2597,12 +2490,12 @@ postcss-minify-gradients@^5.1.1:
cssnano-utils "^3.1.0"
postcss-value-parser "^4.2.0"
-postcss-minify-params@^5.1.3:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.3.tgz#ac41a6465be2db735099bbd1798d85079a6dc1f9"
- integrity sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg==
+postcss-minify-params@^5.1.4:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352"
+ integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
cssnano-utils "^3.1.0"
postcss-value-parser "^4.2.0"
@@ -2621,15 +2514,15 @@ postcss-modules-extract-imports@^3.0.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"
- integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=
+ integrity sha512-X4cquUPIaAd86raVrBwO8fwRfkIdbwFu7CTfEOjiZQHVQwlHRSkTgH5NLDmMm5+1hQO8u6dZ+TOOJDbay1hYpA==
dependencies:
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==
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524"
+ integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser "^6.0.2"
@@ -2638,7 +2531,7 @@ postcss-modules-local-by-default@^4.0.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"
- integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A=
+ integrity sha512-LTYwnA4C1He1BKZXIx1CYiHixdSe9LWYVKadq9lK5aCCMkoOkFyZ7aigt+srfjlRplJY3gIol6KUNefdMQJdlw==
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
@@ -2653,7 +2546,7 @@ postcss-modules-scope@^3.0.0:
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"
- integrity sha1-YZpxnPeN0WpINBNRQLMkz3czS+E=
+ integrity sha512-kIDk2NYmxHshqUbjtFf1WdBij08IsvRdgDT0nOGWhvwkr8/z1piLSzxVrPt56J4DU6ON986h2H+5xcBnFhT8UQ==
dependencies:
generic-names "^1.0.2"
icss-replace-symbols "^1.0.2"
@@ -2670,11 +2563,11 @@ postcss-modules-values@^4.0.0:
icss-utils "^5.0.0"
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==
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.3.1.tgz#517c06c09eab07d133ae0effca2c510abba18048"
+ integrity sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==
dependencies:
- generic-names "^2.0.1"
+ generic-names "^4.0.0"
icss-replace-symbols "^1.1.0"
lodash.camelcase "^4.3.0"
postcss-modules-extract-imports "^3.0.0"
@@ -2723,12 +2616,12 @@ postcss-normalize-timing-functions@^5.1.0:
dependencies:
postcss-value-parser "^4.2.0"
-postcss-normalize-unicode@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75"
- integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ==
+postcss-normalize-unicode@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030"
+ integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
postcss-value-parser "^4.2.0"
postcss-normalize-url@^5.1.0:
@@ -2754,12 +2647,12 @@ postcss-ordered-values@^5.1.3:
cssnano-utils "^3.1.0"
postcss-value-parser "^4.2.0"
-postcss-reduce-initial@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6"
- integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw==
+postcss-reduce-initial@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6"
+ integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
caniuse-api "^3.0.0"
postcss-reduce-transforms@^5.1.0:
@@ -2770,9 +2663,9 @@ postcss-reduce-transforms@^5.1.0:
postcss-value-parser "^4.2.0"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
- version "6.0.10"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
- integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+ version "6.0.13"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b"
+ integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
@@ -2797,12 +2690,12 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-postcss@8:
- version "8.4.8"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.8.tgz#dad963a76e82c081a0657d3a2f3602ce10c2e032"
- integrity sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==
+postcss@8, postcss@^8.1.10, postcss@^8.3.11:
+ version "8.4.24"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
+ integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
dependencies:
- nanoid "^3.3.1"
+ nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"
@@ -2825,37 +2718,18 @@ postcss@^6.0.1:
source-map "^0.6.1"
supports-color "^5.4.0"
-postcss@^7.0.14:
- version "7.0.14"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
- integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
+postcss@^7.0.36:
+ version "7.0.39"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309"
+ integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==
dependencies:
- chalk "^2.4.2"
+ picocolors "^0.2.1"
source-map "^0.6.1"
- supports-color "^6.1.0"
-postcss@^8.1.10:
- version "8.4.17"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.17.tgz#f87863ec7cd353f81f7ab2dec5d67d861bbb1be5"
- integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==
- dependencies:
- nanoid "^3.3.4"
- picocolors "^1.0.0"
- source-map-js "^1.0.2"
-
-postcss@^8.2.4:
- version "8.3.5"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709"
- integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==
- dependencies:
- colorette "^1.2.2"
- nanoid "^3.1.23"
- source-map-js "^0.6.2"
-
-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==
+"prettier@^1.18.2 || ^2.0.0":
+ version "2.8.8"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+ integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
process-nextick-args@~2.0.0:
version "2.0.1"
@@ -2872,12 +2746,12 @@ promise@^7.0.1:
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
- integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
+ integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
- integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+ integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==
pug-attrs@^3.0.0:
version "3.0.0"
@@ -2983,9 +2857,9 @@ pug@^3.0.1:
pug-strip-comments "^2.0.0"
qs@^6.5.1:
- version "6.11.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
- integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ version "6.11.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
+ integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
dependencies:
side-channel "^1.0.4"
@@ -3054,9 +2928,9 @@ quill@^1.2.2:
quill-delta "^3.6.2"
qz-tray@^2.0.8:
- version "2.0.8"
- resolved "https://registry.yarnpkg.com/qz-tray/-/qz-tray-2.0.8.tgz#5e15d102cf3a11a31ddb332891c7f8a6af8f6ad5"
- integrity sha512-lncGYzz7/sTORZuC1S3ukNlMPCMOmsHWNvJF4FjMCZ2+0UV3txi6kgPd754B7kDFKm0J587sIODgxIlFY7qU4w==
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/qz-tray/-/qz-tray-2.2.2.tgz#1ee812502afaa5132e4ecb4bccb8c42992ac53f4"
+ integrity sha512-v3oMIIu1UIkcKbEMH6bp/Ey0Ww9YsF2Cl5aJbKNckAh6Mo69rShi1N1nF+KjB4FURNxcD+8fokfgYL++RCOdPA==
rangetouch@^2.0.1:
version "2.0.1"
@@ -3066,12 +2940,12 @@ rangetouch@^2.0.1:
raw-loader@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
- integrity sha1-DD0L6u2KAclm2Xh793goElKpeao=
+ integrity sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==
readable-stream@^2.3.5:
- version "2.3.7"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
- integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
+ integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
@@ -3081,10 +2955,10 @@ readable-stream@^2.3.5:
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==
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
@@ -3096,68 +2970,43 @@ redis-commands@^1.7.0:
redis-errors@^1.0.0, redis-errors@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
- integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=
+ integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==
redis-parser@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
- integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
+ integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==
dependencies:
redis-errors "^1.0.0"
redis@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/redis/-/redis-3.1.1.tgz#a44bee7c072dcf685e139048d6a1a4d3b00f5d01"
- integrity sha512-QhkKhOuzhogR1NDJfBD34TQJz2ZJwDhhIC6ZmvpftlmfYShHHQXjjNspAJ+Z2HH5NwSBVYBVganbiZ8bgFMHjg==
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/redis/-/redis-3.1.2.tgz#766851117e80653d23e0ed536254677ab647638c"
+ integrity sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==
dependencies:
denque "^1.5.0"
redis-commands "^1.7.0"
redis-errors "^1.2.0"
redis-parser "^3.0.0"
-regenerate@^1.2.1:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
- integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
-
-regexp.prototype.flags@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
- integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb"
+ integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==
dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.0-next.1"
-
-regexpu-core@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
- integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=
- dependencies:
- regenerate "^1.2.1"
- regjsgen "^0.2.0"
- regjsparser "^0.1.4"
-
-regjsgen@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
- integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
-
-regjsparser@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
- integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=
- dependencies:
- jsesc "~0.5.0"
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ functions-have-names "^1.2.3"
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
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=
+ integrity sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==
dependencies:
expand-tilde "^1.2.2"
global-modules "^0.2.3"
@@ -3165,7 +3014,7 @@ resolve-dir@^0.1.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=
+ integrity sha512-9RXicAgDvLD272hZ3HwJv9MJUGxCBRRwwSBRdOGWgcO03MtC9UTGC6XG1VbS4T5MvDrb+tVZx2RhZ90uk3uczg==
dependencies:
cwd "^0.10.0"
expand-tilde "^2.0.2"
@@ -3178,25 +3027,17 @@ resolve-file@^0.3.0:
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
- integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+ integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
-resolve@^1.15.1:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+resolve@^1.15.1, resolve@^1.2.0:
+ version "1.22.2"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
+ integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
- is-core-module "^2.9.0"
+ is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-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"
-
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
@@ -3210,14 +3051,13 @@ rimraf@^3.0.0:
glob "^7.1.3"
rtlcss@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.2.1.tgz#654e55ea2f46991f9738d952ba77ba0aa94a670d"
- integrity sha512-S9bh35JXwPIhfun7nFu/HjlNrwELL5nvTJqA1suLfbnqY/mauIL5sBkrJNHziVppX9PA2rJ7NV82+RtzB71mJA==
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3"
+ integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==
dependencies:
- chalk "^4.1.0"
find-up "^5.0.0"
- mkdirp "^1.0.4"
- postcss "^8.2.4"
+ picocolors "^1.0.0"
+ postcss "^8.3.11"
strip-json-comments "^3.1.1"
run-parallel@^1.1.9:
@@ -3232,22 +3072,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.2:
+"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-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"
-
-sass@^1.53.0:
- version "1.53.0"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.53.0.tgz#eab73a7baac045cc57ddc1d1ff501ad2659952eb"
- integrity sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==
+sass@^1.18.0, sass@^1.53.0, sass@^1.x:
+ version "1.63.3"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.63.3.tgz#527746aa43bf2e4eac1ab424f67f6f18a081061a"
+ integrity sha512-ySdXN+DVpfwq49jG1+hmtDslYqpS7SkOR5GpF6o2bmb1RL/xS+wvPmegMvMywyfsmAV6p7TgwXYGrCZIFFbAHg==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
@@ -3275,10 +3108,10 @@ set-getter@^0.1.0:
dependencies:
to-object-path "^0.3.0"
-shell-quote@^1.6.1:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
- integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==
+shell-quote@^1.7.3:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
+ integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
showdown@^2.1.0:
version "2.1.0"
@@ -3287,7 +3120,7 @@ showdown@^2.1.0:
dependencies:
commander "^9.0.0"
-side-channel@^1.0.2, side-channel@^1.0.4:
+side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
@@ -3296,49 +3129,42 @@ side-channel@^1.0.2, side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
-socket.io-adapter@~2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6"
- integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==
+socket.io-adapter@~2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12"
+ integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==
+ dependencies:
+ ws "~8.11.0"
socket.io-client@^4.5.1:
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.5.1.tgz#cab8da71976a300d3090414e28c2203a47884d84"
- integrity sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.2.tgz#2bfde952e74625d54e622718a7cb1d591ee62fd6"
+ integrity sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
- engine.io-client "~6.2.1"
- socket.io-parser "~4.2.0"
+ engine.io-client "~6.4.0"
+ socket.io-parser "~4.2.4"
-socket.io-parser@~4.0.4:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.5.tgz#cb404382c32324cc962f27f3a44058cf6e0552df"
- integrity sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==
- dependencies:
- "@types/component-emitter" "^1.2.10"
- component-emitter "~1.3.0"
- debug "~4.3.1"
-
-socket.io-parser@~4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.0.tgz#3f01e5bc525d94aa52a97ed5cbc12e229bbc4d6b"
- integrity sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==
+socket.io-parser@~4.2.4:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83"
+ integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
socket.io@^4.5.1:
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.1.tgz#aa7e73f8a6ce20ee3c54b2446d321bbb6b1a9029"
- integrity sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.6.2.tgz#d597db077d4df9cbbdfaa7a9ed8ccc3d49439786"
+ integrity sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==
dependencies:
accepts "~1.3.4"
base64id "~2.0.0"
debug "~4.3.2"
- engine.io "~6.2.0"
- socket.io-adapter "~2.4.0"
- socket.io-parser "~4.0.4"
+ engine.io "~6.4.2"
+ socket.io-adapter "~2.5.2"
+ socket.io-parser "~4.2.4"
sortablejs@1.14.0:
version "1.14.0"
@@ -3351,20 +3177,15 @@ sortablejs@1.9.0:
integrity sha512-Ot6bYJ6PoqPmpsqQYXjn1+RKrY2NWQvQt/o4jfd/UYwVWndyO5EPO8YHbnm5HIykf8ENsm4JUrdAvolPT86yYA==
sortablejs@^1.7.0:
- version "1.8.3"
- resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.8.3.tgz#5ae908ef96300966e95440a143340f5dd565a0df"
- integrity sha512-AftvD4hdKcR5QlGi7L/JST506zGNGrysE8/QohDpwKXJarHWqCt+TUlrtoMk/wkECB607Q019/OZlJViyWiD6A==
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.0.tgz#53230b8aa3502bb77a29e2005808ffdb4a5f7e2a"
+ integrity sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-source-map-js@^0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
- integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
-
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"
@@ -3377,9 +3198,9 @@ source-map-resolve@^0.5.2:
urix "^0.1.0"
source-map-url@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
- integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
source-map@0.6.*, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
@@ -3389,12 +3210,12 @@ source-map@0.6.*, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
source-map@^0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
- integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
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==
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
sourcemap-codec@^1.4.8:
version "1.4.8"
@@ -3406,30 +3227,19 @@ stable@^0.1.8:
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+stop-iteration-iterator@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4"
+ integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==
+ dependencies:
+ internal-slot "^1.0.4"
+
string-hash@^1.1.0, string-hash@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
- integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=
+ integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
-string-width@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
- integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-string-width@^4.2.0:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
- integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-string-width@^4.2.3:
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -3438,40 +3248,6 @@ string-width@^4.2.3:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
-string.prototype.trimend@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
- integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
-
-string.prototype.trimleft@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc"
- integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
- string.prototype.trimstart "^1.0.0"
-
-string.prototype.trimright@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3"
- integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
- string.prototype.trimend "^1.0.0"
-
-string.prototype.trimstart@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
- integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
- dependencies:
- define-properties "^1.1.3"
- es-abstract "^1.17.5"
-
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -3482,18 +3258,11 @@ string_decoder@~1.1.1:
strip-ansi@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==
dependencies:
ansi-regex "^2.0.0"
-strip-ansi@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
- integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
- dependencies:
- ansi-regex "^5.0.0"
-
-strip-ansi@^6.0.1:
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -3505,15 +3274,15 @@ strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-stylehacks@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520"
- integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q==
+stylehacks@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9"
+ integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==
dependencies:
- browserslist "^4.16.6"
+ browserslist "^4.21.4"
postcss-selector-parser "^6.0.4"
-stylus@^0.54.5, stylus@^0.x:
+stylus@^0.54.5:
version "0.54.8"
resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147"
integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==
@@ -3527,6 +3296,17 @@ stylus@^0.54.5, stylus@^0.x:
semver "^6.3.0"
source-map "^0.7.3"
+stylus@^0.x:
+ version "0.59.0"
+ resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.59.0.tgz#a344d5932787142a141946536d6e24e6a6be7aa6"
+ integrity sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==
+ dependencies:
+ "@adobe/css-tools" "^4.0.1"
+ debug "^4.3.2"
+ glob "^7.1.6"
+ sax "~1.2.4"
+ 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"
@@ -3546,12 +3326,12 @@ superagent@^3.8.2:
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
- integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+ integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==
supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
- integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
+ integrity sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==
dependencies:
has-flag "^1.0.0"
@@ -3562,20 +3342,6 @@ supports-color@^5.3.0, supports-color@^5.4.0:
dependencies:
has-flag "^3.0.0"
-supports-color@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
- integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.1.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
- integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
- dependencies:
- has-flag "^4.0.0"
-
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
@@ -3609,7 +3375,7 @@ to-fast-properties@^2.0.0:
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"
- integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+ integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==
dependencies:
kind-of "^3.0.2"
@@ -3633,19 +3399,29 @@ touch@^3.1.0:
nopt "~1.0.10"
tslib@^1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
- integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.3.0:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
+ integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==
+
+typescript@^4.7.4:
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+ integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-update-browserslist-db@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz#dbfc5a789caa26b1db8990796c2c8ebbce304824"
- integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==
+update-browserslist-db@^1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
+ integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
@@ -3653,7 +3429,7 @@ update-browserslist-db@^1.0.0:
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
- integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+ integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==
url-polyfill@^1.1.12:
version "1.1.12"
@@ -3663,7 +3439,7 @@ url-polyfill@^1.1.12:
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=
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
vary@^1:
version "1.1.2"
@@ -3675,17 +3451,17 @@ void-elements@^3.1.0:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
-vue-demi@*:
- version "0.13.11"
- resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
- integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
+vue-demi@*, vue-demi@>=0.14.0, vue-demi@>=0.14.5:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"
+ integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
vue-router@^4.1.5:
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.5.tgz#256f597e3f5a281a23352a6193aa6e342c8d9f9a"
- integrity sha512-IsvoF5D2GQ/EGTs/Th4NQms9gd2NSqV+yylxIyp/OYp8xOwxmU8Kj/74E9DTSYAyH5LX7idVUngN3JSj1X4xcQ==
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.2.2.tgz#b0097b66d89ca81c0986be03da244c7b32a4fd81"
+ integrity sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==
dependencies:
- "@vue/devtools-api" "^6.1.4"
+ "@vue/devtools-api" "^6.5.0"
vue-template-es2015-compiler@^1.9.0:
version "1.9.1"
@@ -3717,16 +3493,16 @@ vuex@4.0.2:
dependencies:
"@vue/devtools-api" "^6.0.0-beta.11"
-which-boxed-primitive@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1"
- integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==
+which-boxed-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
+ integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
dependencies:
- is-bigint "^1.0.0"
- is-boolean-object "^1.0.0"
- is-number-object "^1.0.3"
- is-string "^1.0.4"
- is-symbol "^1.0.2"
+ is-bigint "^1.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ is-symbol "^1.0.3"
which-collection@^1.0.1:
version "1.0.1"
@@ -3738,17 +3514,17 @@ which-collection@^1.0.1:
is-weakmap "^2.0.1"
is-weakset "^2.0.1"
-which-typed-array@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2"
- integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==
+which-typed-array@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6"
+ integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==
dependencies:
- available-typed-arrays "^1.0.2"
- es-abstract "^1.17.5"
- foreach "^2.0.5"
- function-bind "^1.1.1"
- has-symbols "^1.0.1"
- is-typed-array "^1.1.3"
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.2"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.0"
+ is-typed-array "^1.1.10"
which@^1.2.12:
version "1.3.1"
@@ -3779,12 +3555,12 @@ wrap-ansi@^7.0.0:
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-ws@~8.2.3:
- version "8.2.3"
- resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
- integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
+ws@~8.11.0:
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
+ integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
@@ -3799,30 +3575,30 @@ y18n@^5.0.5:
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
- integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+ integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==
yaml@^1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-yargs-parser@^21.0.0:
- version "21.0.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35"
- integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
yargs@^17.5.1:
- version "17.5.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
- integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
- cliui "^7.0.2"
+ cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
- yargs-parser "^21.0.0"
+ yargs-parser "^21.1.1"
yocto-queue@^0.1.0:
version "0.1.0"
From 171b616e571cfa3579b3118ec31cea1a94ee99ef Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Tue, 13 Jun 2023 15:42:40 +0530
Subject: [PATCH 13/97] fix: Props should be constant as it is a read-only
variable
---
frappe/public/js/form_builder/components/Column.vue | 2 +-
frappe/public/js/form_builder/components/EditableInput.vue | 4 ++--
frappe/public/js/form_builder/components/Field.vue | 2 +-
frappe/public/js/form_builder/components/Section.vue | 2 +-
.../js/form_builder/components/controls/AttachControl.vue | 2 +-
.../js/form_builder/components/controls/ButtonControl.vue | 2 +-
.../js/form_builder/components/controls/CheckControl.vue | 2 +-
.../js/form_builder/components/controls/CodeControl.vue | 2 +-
.../js/form_builder/components/controls/DataControl.vue | 2 +-
.../form_builder/components/controls/GeolocationControl.vue | 2 +-
.../js/form_builder/components/controls/ImageControl.vue | 2 +-
.../js/form_builder/components/controls/LinkControl.vue | 2 +-
.../js/form_builder/components/controls/RatingControl.vue | 2 +-
.../js/form_builder/components/controls/SelectControl.vue | 2 +-
.../js/form_builder/components/controls/SignatureControl.vue | 2 +-
.../js/form_builder/components/controls/TableControl.vue | 2 +-
.../js/form_builder/components/controls/TextControl.vue | 2 +-
.../js/form_builder/components/controls/TextEditorControl.vue | 2 +-
frappe/public/js/frappe/file_uploader/FilePreview.vue | 2 +-
frappe/public/js/frappe/file_uploader/ImageCropper.vue | 2 +-
frappe/public/js/frappe/file_uploader/ProgressRing.vue | 2 +-
frappe/public/js/frappe/file_uploader/TreeNode.vue | 2 +-
frappe/public/js/print_format_builder/ConfigureColumns.vue | 2 +-
frappe/public/js/print_format_builder/Field.vue | 2 +-
frappe/public/js/print_format_builder/HTMLEditor.vue | 2 +-
frappe/public/js/print_format_builder/PrintFormatBuilder.vue | 2 +-
frappe/public/js/print_format_builder/PrintFormatSection.vue | 2 +-
27 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/frappe/public/js/form_builder/components/Column.vue b/frappe/public/js/form_builder/components/Column.vue
index 1563d1033e..54dd49d5bf 100644
--- a/frappe/public/js/form_builder/components/Column.vue
+++ b/frappe/public/js/form_builder/components/Column.vue
@@ -6,7 +6,7 @@ import { ref } from "vue";
import { useStore } from "../store";
import { move_children_to_parent, confirm_dialog } from "../utils";
-let props = defineProps(["section", "column"]);
+const props = defineProps(["section", "column"]);
let store = useStore();
let hovered = ref(false);
diff --git a/frappe/public/js/form_builder/components/EditableInput.vue b/frappe/public/js/form_builder/components/EditableInput.vue
index 8964838f4a..21b517af3b 100644
--- a/frappe/public/js/form_builder/components/EditableInput.vue
+++ b/frappe/public/js/form_builder/components/EditableInput.vue
@@ -3,7 +3,7 @@ import { ref, nextTick, computed } from "vue";
import { useStore } from "../store";
let store = useStore();
-let props = defineProps({
+const props = defineProps({
text: {
type: String
},
@@ -46,7 +46,7 @@ function focus_on_label() {
:disabled="store.read_only"
type="text"
:placeholder="placeholder"
- v-model="text"
+ :value="text"
:style="{ width: hidden_span_width }"
@input="event => $emit('update:modelValue', event.target.value)"
@keydown.enter="editing = false"
diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue
index e0230765b5..b67d6db0c9 100644
--- a/frappe/public/js/form_builder/components/Field.vue
+++ b/frappe/public/js/form_builder/components/Field.vue
@@ -4,7 +4,7 @@ import { ref, computed } from "vue";
import { useStore } from "../store";
import { move_children_to_parent, clone_field } from "../utils";
-let props = defineProps(["column", "field"]);
+const props = defineProps(["column", "field"]);
let store = useStore();
let hovered = ref(false);
diff --git a/frappe/public/js/form_builder/components/Section.vue b/frappe/public/js/form_builder/components/Section.vue
index 5131ff25d3..cd675e5958 100644
--- a/frappe/public/js/form_builder/components/Section.vue
+++ b/frappe/public/js/form_builder/components/Section.vue
@@ -6,7 +6,7 @@ import { ref } from "vue";
import { useStore } from "../store";
import { section_boilerplate, move_children_to_parent, confirm_dialog } from "../utils";
-let props = defineProps(["tab", "section"]);
+const props = defineProps(["tab", "section"]);
let store = useStore();
let hovered = ref(false);
diff --git a/frappe/public/js/form_builder/components/controls/AttachControl.vue b/frappe/public/js/form_builder/components/controls/AttachControl.vue
index 86cdf7c5ac..6d8718d5dc 100644
--- a/frappe/public/js/form_builder/components/controls/AttachControl.vue
+++ b/frappe/public/js/form_builder/components/controls/AttachControl.vue
@@ -1,6 +1,6 @@
diff --git a/frappe/public/js/form_builder/components/controls/ButtonControl.vue b/frappe/public/js/form_builder/components/controls/ButtonControl.vue
index bb6d4b8388..46fc97052c 100644
--- a/frappe/public/js/form_builder/components/controls/ButtonControl.vue
+++ b/frappe/public/js/form_builder/components/controls/ButtonControl.vue
@@ -1,6 +1,6 @@
diff --git a/frappe/public/js/form_builder/components/controls/CheckControl.vue b/frappe/public/js/form_builder/components/controls/CheckControl.vue
index 0d786de0b4..8052e979ba 100644
--- a/frappe/public/js/form_builder/components/controls/CheckControl.vue
+++ b/frappe/public/js/form_builder/components/controls/CheckControl.vue
@@ -3,7 +3,7 @@ import { useStore } from "../../store";
import { useSlots } from "vue";
let store = useStore();
-let props = defineProps(["df", "value"]);
+const props = defineProps(["df", "value"]);
let slots = useSlots();
diff --git a/frappe/public/js/form_builder/components/controls/CodeControl.vue b/frappe/public/js/form_builder/components/controls/CodeControl.vue
index d42bc43f81..b8051a8f48 100644
--- a/frappe/public/js/form_builder/components/controls/CodeControl.vue
+++ b/frappe/public/js/form_builder/components/controls/CodeControl.vue
@@ -4,7 +4,7 @@ import { computed, onMounted, ref, useSlots, watch } from "vue";
import { useStore } from "../../store";
let store = useStore();
-let props = defineProps(["df", "modelValue"]);
+const props = defineProps(["df", "modelValue"]);
let emit = defineEmits(["update:modelValue"]);
let slots = useSlots();
diff --git a/frappe/public/js/form_builder/components/controls/DataControl.vue b/frappe/public/js/form_builder/components/controls/DataControl.vue
index 2052912130..fcbc5d9c77 100644
--- a/frappe/public/js/form_builder/components/controls/DataControl.vue
+++ b/frappe/public/js/form_builder/components/controls/DataControl.vue
@@ -4,7 +4,7 @@ import { useStore } from "../../store";
import { ref, useSlots } from "vue";
let store = useStore();
-let props = defineProps(["df", "value"]);
+const props = defineProps(["df", "value"]);
let slots = useSlots();
let time_zone = ref("");
let placeholder = ref("");
diff --git a/frappe/public/js/form_builder/components/controls/GeolocationControl.vue b/frappe/public/js/form_builder/components/controls/GeolocationControl.vue
index b46f6aed33..8acc005fad 100644
--- a/frappe/public/js/form_builder/components/controls/GeolocationControl.vue
+++ b/frappe/public/js/form_builder/components/controls/GeolocationControl.vue
@@ -1,7 +1,7 @@
diff --git a/frappe/public/js/form_builder/components/controls/LinkControl.vue b/frappe/public/js/form_builder/components/controls/LinkControl.vue
index ce58c9a81e..8c1f73f255 100644
--- a/frappe/public/js/form_builder/components/controls/LinkControl.vue
+++ b/frappe/public/js/form_builder/components/controls/LinkControl.vue
@@ -4,7 +4,7 @@ import { onMounted, ref, useSlots, computed, watch } from "vue";
import { useStore } from "../../store";
let store = useStore();
-let props = defineProps(["args", "df", "modelValue"]);
+const props = defineProps(["args", "df", "modelValue"]);
let emit = defineEmits(["update:modelValue"]);
let slots = useSlots();
diff --git a/frappe/public/js/form_builder/components/controls/RatingControl.vue b/frappe/public/js/form_builder/components/controls/RatingControl.vue
index 9247f3e925..4356dc0b2d 100644
--- a/frappe/public/js/form_builder/components/controls/RatingControl.vue
+++ b/frappe/public/js/form_builder/components/controls/RatingControl.vue
@@ -1,7 +1,7 @@
diff --git a/frappe/public/js/form_builder/components/controls/TableControl.vue b/frappe/public/js/form_builder/components/controls/TableControl.vue
index 425997e7ea..78518f6fd6 100644
--- a/frappe/public/js/form_builder/components/controls/TableControl.vue
+++ b/frappe/public/js/form_builder/components/controls/TableControl.vue
@@ -2,7 +2,7 @@
import { get_table_columns } from "../../utils";
import { computedAsync } from "@vueuse/core";
-let props = defineProps(["df"]);
+const props = defineProps(["df"]);
let table_columns = computedAsync(async () => {
let doctype = props.df.options;
diff --git a/frappe/public/js/form_builder/components/controls/TextControl.vue b/frappe/public/js/form_builder/components/controls/TextControl.vue
index 8a5dbdf947..91fe920bdb 100644
--- a/frappe/public/js/form_builder/components/controls/TextControl.vue
+++ b/frappe/public/js/form_builder/components/controls/TextControl.vue
@@ -5,7 +5,7 @@ import { useSlots, ref, computed, watch } from "vue";
import { computedAsync } from "@vueuse/core";
let store = useStore();
-let props = defineProps(["df", "value", "modelValue"]);
+const props = defineProps(["df", "value", "modelValue"]);
let emit = defineEmits(["update:modelValue"]);
let slots = useSlots();
diff --git a/frappe/public/js/form_builder/components/controls/TextEditorControl.vue b/frappe/public/js/form_builder/components/controls/TextEditorControl.vue
index a47a444836..6a3aa21046 100644
--- a/frappe/public/js/form_builder/components/controls/TextEditorControl.vue
+++ b/frappe/public/js/form_builder/components/controls/TextEditorControl.vue
@@ -1,7 +1,7 @@
diff --git a/frappe/public/js/frappe/file_uploader/file_uploader.bundle.js b/frappe/public/js/frappe/file_uploader/file_uploader.bundle.js
index 7834c8adb1..f9134f10fa 100644
--- a/frappe/public/js/frappe/file_uploader/file_uploader.bundle.js
+++ b/frappe/public/js/frappe/file_uploader/file_uploader.bundle.js
@@ -1,5 +1,6 @@
import { createApp } from "vue";
import FileUploaderComponent from "./FileUploader.vue";
+import { watch } from "vue";
class FileUploader {
constructor({
@@ -52,8 +53,8 @@ class FileUploader {
this.uploader.wrapper_ready = true;
}
- this.uploader.$watch(
- "files",
+ watch(
+ () => this.uploader.files,
(files) => {
let all_private = files.every((file) => file.private);
if (this.dialog) {
@@ -65,27 +66,36 @@ class FileUploader {
{ deep: true }
);
- this.uploader.$watch("trigger_upload", (trigger_upload) => {
- if (trigger_upload) {
- this.upload_files();
+ watch(
+ () => this.uploader.trigger_upload,
+ (trigger_upload) => {
+ if (trigger_upload) {
+ this.upload_files();
+ }
}
- });
+ );
- this.uploader.$watch("close_dialog", (close_dialog) => {
- if (close_dialog) {
- this.dialog && this.dialog.hide();
+ watch(
+ () => this.uploader.close_dialog,
+ (close_dialog) => {
+ if (close_dialog) {
+ this.dialog && this.dialog.hide();
+ }
}
- });
+ );
- this.uploader.$watch("hide_dialog_footer", (hide_dialog_footer) => {
- if (hide_dialog_footer) {
- this.dialog && this.dialog.footer.addClass("hide");
- this.dialog.$wrapper.data("bs.modal")._config.backdrop = "static";
- } else {
- this.dialog && this.dialog.footer.removeClass("hide");
- this.dialog.$wrapper.data("bs.modal")._config.backdrop = true;
+ watch(
+ () => this.uploader.hide_dialog_footer,
+ (hide_dialog_footer) => {
+ if (hide_dialog_footer) {
+ this.dialog && this.dialog.footer.addClass("hide");
+ this.dialog.$wrapper.data("bs.modal")._config.backdrop = "static";
+ } else {
+ this.dialog && this.dialog.footer.removeClass("hide");
+ this.dialog.$wrapper.data("bs.modal")._config.backdrop = true;
+ }
}
- });
+ );
if (files && files.length) {
this.uploader.add_files(files);
diff --git a/frappe/public/js/print_format_builder/print_format_builder.bundle.js b/frappe/public/js/print_format_builder/print_format_builder.bundle.js
index 62535fd1cf..45a6dd91cc 100644
--- a/frappe/public/js/print_format_builder/print_format_builder.bundle.js
+++ b/frappe/public/js/print_format_builder/print_format_builder.bundle.js
@@ -1,4 +1,4 @@
-import { createApp } from "vue";
+import { createApp, watch } from "vue";
import PrintFormatBuilderComponent from "./PrintFormatBuilder.vue";
class PrintFormatBuilder {
@@ -32,8 +32,8 @@ class PrintFormatBuilder {
SetVueGlobals(app);
this.$component = app.mount(this.$wrapper.get(0));
- this.$component.$watch(
- "$store.dirty",
+ watch(
+ () => this.$component.$store.dirty,
(dirty) => {
if (dirty.value) {
this.page.set_indicator("Not Saved", "orange");
@@ -48,9 +48,12 @@ class PrintFormatBuilder {
{ deep: true }
);
- this.$component.$watch("show_preview", (value) => {
- $toggle_preview_btn.text(value ? __("Hide Preview") : __("Show Preview"));
- });
+ watch(
+ () => this.$component.show_preview,
+ (value) => {
+ $toggle_preview_btn.text(value ? __("Hide Preview") : __("Show Preview"));
+ }
+ );
}
}
From 3667d1ae04378e9ffe822bab1e7e7d53f7f9fb50 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Sat, 24 Jun 2023 19:20:11 +0530
Subject: [PATCH 23/97] test: Simplify list_view test
---
cypress/integration/list_view.js | 21 +++++----------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/cypress/integration/list_view.js b/cypress/integration/list_view.js
index 3fa0758f0c..b07f18edc2 100644
--- a/cypress/integration/list_view.js
+++ b/cypress/integration/list_view.js
@@ -13,15 +13,8 @@ context("List View", () => {
it("Keep checkbox checked after Refresh", { scrollBehavior: false }, () => {
cy.go_to_list("ToDo");
cy.clear_filters();
- cy.get(".list-row-container .list-row-checkbox").click({
- multiple: true,
- force: true,
- });
- cy.get(".actions-btn-group button").contains("Actions").should("be.visible");
- cy.intercept("/api/method/frappe.desk.reportview.get").as("list-refresh");
- cy.wait(3000); // wait before you hit another refresh
- cy.get('button[data-original-title="Refresh"]').click();
- cy.wait("@list-refresh");
+ cy.get(".list-header-subject > .list-subject > .list-check-all").click();
+ cy.get("button[data-original-title='Refresh']").click();
cy.get(".list-row-container .list-row-checkbox:checked").should("be.visible");
});
@@ -39,11 +32,8 @@ context("List View", () => {
];
cy.go_to_list("ToDo");
cy.clear_filters();
- cy.get('.list-row-container:contains("Pending") .list-row-checkbox').click({
- multiple: true,
- force: true,
- });
- cy.get(".actions-btn-group button").contains("Actions").should("be.visible").click();
+ cy.get(".list-header-subject > .list-subject > .list-check-all").click();
+ cy.findByRole("button", { name: "Actions" }).click();
cy.get(".dropdown-menu li:visible .dropdown-item")
.should("have.length", 9)
.each((el, index) => {
@@ -56,8 +46,7 @@ context("List View", () => {
}).as("bulk-approval");
cy.wrap(elements).contains("Approve").click();
cy.wait("@bulk-approval");
- cy.wait(300);
- cy.get_open_dialog().find(".btn-modal-close").click();
+ cy.hide_dialog();
cy.reload();
cy.clear_filters();
cy.get(".list-row-container:visible").should("contain", "Approved");
From 84ac0243962fe6bef2d133d1b40d9e214c703341 Mon Sep 17 00:00:00 2001
From: Ernesto Ruiz
Date: Sun, 25 Jun 2023 23:05:49 -0600
Subject: [PATCH 24/97] chore: Add translation to text in Update
kanban_settings.js (#21452)
[skip ci]
---
frappe/public/js/frappe/views/kanban/kanban_settings.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/frappe/views/kanban/kanban_settings.js b/frappe/public/js/frappe/views/kanban/kanban_settings.js
index fb294be30c..076ab77547 100644
--- a/frappe/public/js/frappe/views/kanban/kanban_settings.js
+++ b/frappe/public/js/frappe/views/kanban/kanban_settings.js
@@ -111,14 +111,14 @@ export default class KanbanSettings {
fields_html.html(`
From e26152f0dc3fed4ca797a12c7086b61a3dc82207 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 13:28:57 +0530
Subject: [PATCH 25/97] chore: use node18 for github workflow
[skip ci]
---
frappe/utils/boilerplate.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py
index 0e646f9992..e2aaa26f22 100644
--- a/frappe/utils/boilerplate.py
+++ b/frappe/utils/boilerplate.py
@@ -593,7 +593,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
- node-version: 16
+ node-version: 18
check-latest: true
- name: Cache pip
From ee74830460a13e1042a9f587de423d61b0b3594b Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 17:32:02 +0530
Subject: [PATCH 26/97] chore: add github star CTA on server script sidebar
[skip ci]
---
.../server_script/server_script_list.js | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 frappe/core/doctype/server_script/server_script_list.js
diff --git a/frappe/core/doctype/server_script/server_script_list.js b/frappe/core/doctype/server_script/server_script_list.js
new file mode 100644
index 0000000000..0df447a0eb
--- /dev/null
+++ b/frappe/core/doctype/server_script/server_script_list.js
@@ -0,0 +1,38 @@
+frappe.listview_settings["Server Script"] = {
+ onload: function (listview) {
+ add_github_star_cta(listview);
+ },
+};
+
+function add_github_star_cta(listview) {
+ try {
+ const key = "show_github_star_banner";
+ if (localStorage.getItem(key) == "false") {
+ return;
+ }
+
+ if (listview.github_star_banner) {
+ listview.github_star_banner.remove();
+ }
+
+ const message = "Loving Frappe Framework?";
+ const link = "https://github.com/frappe/frappe";
+ const cta = "Star us on GitHub";
+
+ listview.github_star_banner = $(`
+
+ `).appendTo(listview.page.sidebar);
+ } catch (error) {
+ console.error(error);
+ }
+}
From ca95b591ae8581a48dfc28f3560670da36f8da0e Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 17:36:53 +0530
Subject: [PATCH 27/97] refactor: Pass redis connection directly
---
frappe/utils/background_jobs.py | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index 6b0249e720..b2a3fbab24 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -9,7 +9,7 @@ from uuid import uuid4
import redis
from redis.exceptions import BusyLoadingError, ConnectionError
-from rq import Connection, Queue, Worker
+from rq import Queue, Worker
from rq.exceptions import NoSuchJobError
from rq.job import Job, JobStatus
from rq.logutils import setup_loghandlers
@@ -253,17 +253,16 @@ def start_worker(
WorkerKlass = DEQUEUE_STRATEGIES.get(strategy, Worker)
- with Connection(redis_connection):
- logging_level = "INFO"
- if quiet:
- logging_level = "WARNING"
- worker = WorkerKlass(queues, name=get_worker_name(queue_name))
- worker.work(
- logging_level=logging_level,
- burst=burst,
- date_format="%Y-%m-%d %H:%M:%S",
- log_format="%(asctime)s,%(msecs)03d %(message)s",
- )
+ logging_level = "INFO"
+ if quiet:
+ logging_level = "WARNING"
+ worker = WorkerKlass(queues, name=get_worker_name(queue_name), connection=redis_connection)
+ worker.work(
+ logging_level=logging_level,
+ burst=burst,
+ date_format="%Y-%m-%d %H:%M:%S",
+ log_format="%(asctime)s,%(msecs)03d %(message)s",
+ )
def get_worker_name(queue):
From 7fbc6e8175da239a230428d936b2af7f58ceeff9 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 17:42:18 +0530
Subject: [PATCH 28/97] refactor: Simplify dequeue_strategy selection
Classes arent required anymore, it can just be a parm to worker class
isntead.
---
frappe/utils/background_jobs.py | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index b2a3fbab24..a713163a7b 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -4,7 +4,7 @@ import socket
import time
from collections import defaultdict
from functools import lru_cache
-from typing import Any, Callable, Literal, NoReturn
+from typing import Any, Callable, NoReturn
from uuid import uuid4
import redis
@@ -13,7 +13,7 @@ from rq import Queue, Worker
from rq.exceptions import NoSuchJobError
from rq.job import Job, JobStatus
from rq.logutils import setup_loghandlers
-from rq.worker import RandomWorker, RoundRobinWorker
+from rq.worker import DequeueStrategy
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
import frappe
@@ -230,10 +230,12 @@ def start_worker(
rq_username: str | None = None,
rq_password: str | None = None,
burst: bool = False,
- strategy: Literal["round_robin", "random"] | None = None,
+ strategy: DequeueStrategy | None = DequeueStrategy.DEFAULT,
) -> NoReturn | None: # pragma: no cover
"""Wrapper to start rq worker. Connects to redis and monitors these queues."""
- DEQUEUE_STRATEGIES = {"round_robin": RoundRobinWorker, "random": RandomWorker}
+
+ if not strategy:
+ strategy = DequeueStrategy.DEFAULT
if frappe._tune_gc:
gc.collect()
@@ -251,17 +253,17 @@ def start_worker(
if os.environ.get("CI"):
setup_loghandlers("ERROR")
- WorkerKlass = DEQUEUE_STRATEGIES.get(strategy, Worker)
-
logging_level = "INFO"
if quiet:
logging_level = "WARNING"
- worker = WorkerKlass(queues, name=get_worker_name(queue_name), connection=redis_connection)
+
+ worker = Worker(queues, name=get_worker_name(queue_name), connection=redis_connection)
worker.work(
logging_level=logging_level,
burst=burst,
date_format="%Y-%m-%d %H:%M:%S",
log_format="%(asctime)s,%(msecs)03d %(message)s",
+ dequeue_strategy=strategy,
)
From 73bca16d77acbdf9c78eb38f0e4132a0518094ff Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 17:59:28 +0530
Subject: [PATCH 29/97] feat: RQ `WorkerPool`
RQ now has experimental support for workerpools.
When to use this?
Roughly when you have more than 2 workers a workerpool might make
sense, below 2 it's overhead as master "pool" process will need to run
to manager workerpool itself.
Why is it any better?
Currently we just let supervisor duplicate the worker process N number
of times. This is inefficient from shared memory POV. Forking the
original process to create workers enables sharing of more memory thus
leading upwards of 60-70% reduction in memory usage with pool size of 8
workers.
---
frappe/commands/scheduler.py | 22 +++++++++++
frappe/core/doctype/rq_job/test_rq_job.py | 11 ++++++
frappe/utils/background_jobs.py | 46 +++++++++++++++++++++--
3 files changed, 76 insertions(+), 3 deletions(-)
diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py
index 36fa81f8a5..6af3a2403e 100755
--- a/frappe/commands/scheduler.py
+++ b/frappe/commands/scheduler.py
@@ -215,6 +215,27 @@ def start_worker(
)
+@click.command("worker-pool")
+@click.option(
+ "--queue",
+ type=str,
+ help="Queue to consume from. Multiple queues can be specified using comma-separated string. If not specified all queues are consumed.",
+)
+@click.option("--num-workers", type=int, default=2, help="Number of workers to spawn in pool.")
+@click.option("--quiet", is_flag=True, default=False, help="Hide Log Outputs")
+@click.option("--burst", is_flag=True, default=False, help="Run Worker in Burst mode.")
+def start_worker_pool(queue, quiet=False, num_workers=2, burst=False):
+ """Start a backgrond worker"""
+ from frappe.utils.background_jobs import start_worker_pool
+
+ start_worker_pool(
+ queue=queue,
+ quiet=quiet,
+ burst=burst,
+ num_workers=num_workers,
+ )
+
+
@click.command("ready-for-migration")
@click.option("--site", help="site name")
@pass_context
@@ -251,5 +272,6 @@ commands = [
show_pending_jobs,
start_scheduler,
start_worker,
+ start_worker_pool,
trigger_scheduler_event,
]
diff --git a/frappe/core/doctype/rq_job/test_rq_job.py b/frappe/core/doctype/rq_job/test_rq_job.py
index c39717cfd8..6512902fb3 100644
--- a/frappe/core/doctype/rq_job/test_rq_job.py
+++ b/frappe/core/doctype/rq_job/test_rq_job.py
@@ -96,6 +96,17 @@ class TestRQJob(FrappeTestCase):
_, stderr = execute_in_shell("bench worker --queue short,default --burst", check_exit_code=True)
self.assertIn("quitting", cstr(stderr))
+ @timeout(20)
+ def test_multi_queue_burst_consumption_worker_pool(self):
+ for _ in range(3):
+ for q in ["default", "short"]:
+ frappe.enqueue(self.BG_JOB, sleep=1, queue=q)
+
+ _, stderr = execute_in_shell(
+ "bench worker-pool --queue short,default --burst --num-workers=4", check_exit_code=True
+ )
+ self.assertIn("quitting", cstr(stderr))
+
@timeout(20)
def test_job_id_dedup(self):
job_id = "test_dedup"
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index a713163a7b..9008ba00ee 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -14,6 +14,7 @@ from rq.exceptions import NoSuchJobError
from rq.job import Job, JobStatus
from rq.logutils import setup_loghandlers
from rq.worker import DequeueStrategy
+from rq.worker_pool import WorkerPool
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
import frappe
@@ -237,9 +238,7 @@ def start_worker(
if not strategy:
strategy = DequeueStrategy.DEFAULT
- if frappe._tune_gc:
- gc.collect()
- gc.freeze()
+ _freeze_gc()
with frappe.init_site():
# empty init is required to get redis_queue from common_site_config.json
@@ -267,6 +266,47 @@ def start_worker(
)
+def start_worker_pool(
+ queue: str | None = None,
+ num_workers: int = 1,
+ quiet: bool = False,
+ burst: bool = False,
+) -> NoReturn:
+ """Start worker pool with specified number of workers.
+
+ WARNING: This feature is considered "EXPERIMENTAL".
+ """
+
+ _freeze_gc()
+
+ with frappe.init_site():
+ redis_connection = get_redis_conn()
+
+ if queue:
+ queue = [q.strip() for q in queue.split(",")]
+ queues = get_queue_list(queue, build_queue_name=True)
+
+ if os.environ.get("CI"):
+ setup_loghandlers("ERROR")
+
+ logging_level = "INFO"
+ if quiet:
+ logging_level = "WARNING"
+
+ pool = WorkerPool(
+ queues=queues,
+ connection=redis_connection,
+ num_workers=num_workers,
+ )
+ pool.start(logging_level=logging_level, burst=burst)
+
+
+def _freeze_gc():
+ if frappe._tune_gc:
+ gc.collect()
+ gc.freeze()
+
+
def get_worker_name(queue):
"""When limiting worker to a specific queue, also append queue name to default worker name"""
name = None
From 4b046f0b1116830ba2326ba36fea06465782c6fb Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Mon, 26 Jun 2023 15:53:15 +0200
Subject: [PATCH 30/97] refactor: use new_doc instead of get_doc
---
frappe/core/doctype/file/test_file.py | 84 ++++++++++++---------------
1 file changed, 36 insertions(+), 48 deletions(-)
diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py
index b07e344dc0..1e7e698062 100644
--- a/frappe/core/doctype/file/test_file.py
+++ b/frappe/core/doctype/file/test_file.py
@@ -615,46 +615,38 @@ class TestAttachmentsAccess(FrappeTestCase):
frappe.set_user("test4@example.com")
self.attached_to_doctype, self.attached_to_docname = make_test_doc()
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_user_attachment.txt",
- "attached_to_doctype": self.attached_to_doctype,
- "attached_to_name": self.attached_to_docname,
- "content": "Testing User",
- "is_private": 1,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_user_attachment.txt",
+ attached_to_doctype=self.attached_to_doctype,
+ attached_to_name=self.attached_to_docname,
+ content="Testing User",
+ is_private=1,
).insert()
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_user_standalone.txt",
- "content": "User Home",
- "is_private": 1,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_user_standalone.txt",
+ content="User Home",
+ is_private=1,
).insert()
frappe.set_user("test@example.com")
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_sm_attachment.txt",
- "attached_to_doctype": self.attached_to_doctype,
- "attached_to_name": self.attached_to_docname,
- "content": "Testing System Manager",
- "is_private": 1,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_sm_attachment.txt",
+ attached_to_doctype=self.attached_to_doctype,
+ attached_to_name=self.attached_to_docname,
+ content="Testing System Manager",
+ is_private=1,
).insert()
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_sm_standalone.txt",
- "content": "System Manager Home",
- "is_private": 1,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_sm_standalone.txt",
+ content="System Manager Home",
+ is_private=1,
).insert()
system_manager_files = [file.file_name for file in get_files_in_folder("Home")["files"]]
@@ -682,13 +674,11 @@ class TestAttachmentsAccess(FrappeTestCase):
def test_list_public_single_file(self):
"""Ensure that users are able to list public standalone files."""
frappe.set_user("test@example.com")
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_public_single.txt",
- "content": "Public single File",
- "is_private": 0,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_public_single.txt",
+ content="Public single File",
+ is_private=0,
).insert()
frappe.set_user("test4@example.com")
@@ -699,15 +689,13 @@ class TestAttachmentsAccess(FrappeTestCase):
"""Ensure that users are able to list public attachments."""
frappe.set_user("test@example.com")
self.attached_to_doctype, self.attached_to_docname = make_test_doc()
- frappe.get_doc(
- {
- "doctype": "File",
- "file_name": "test_public_attachment.txt",
- "attached_to_doctype": self.attached_to_doctype,
- "attached_to_name": self.attached_to_docname,
- "content": "Public Attachment",
- "is_private": 0,
- }
+ frappe.new_doc(
+ "File",
+ file_name="test_public_attachment.txt",
+ attached_to_doctype=self.attached_to_doctype,
+ attached_to_name=self.attached_to_docname,
+ content="Public Attachment",
+ is_private=0,
).insert()
frappe.set_user("test4@example.com")
From e2c468df6026992a706116c35074c3bcd6153a2f Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Mon, 26 Jun 2023 19:56:04 +0530
Subject: [PATCH 31/97] fix: set prepared report in background (#21485)
---
frappe/core/doctype/report/report.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 8cdbc24074..dba82bada5 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -135,7 +135,7 @@ class Report(Document):
# automatically set as prepared
execution_time = (datetime.datetime.now() - start_time).total_seconds()
if execution_time > threshold and not self.prepared_report:
- self.db_set("prepared_report", 1)
+ frappe.enqueue(enable_prepared_report, report=self.name)
frappe.cache.hset("report_execution_time", self.name, execution_time)
@@ -382,3 +382,7 @@ def get_group_by_column_label(args, meta):
function=sql_fn_map[args.aggregate_function], fieldlabel=aggregate_on_label
)
return label
+
+
+def enable_prepared_report(report: str):
+ frappe.db.set_value("Report", report, "prepared_report", 1)
From b9bd05581323085d44b365b2027ad011e180bc04 Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Tue, 27 Jun 2023 17:10:46 +0530
Subject: [PATCH 32/97] fix(WebForm): auto-increment link field
---
frappe/public/js/frappe/form/controls/autocomplete.js | 9 +++++++++
frappe/website/doctype/web_form/web_form.py | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/controls/autocomplete.js b/frappe/public/js/frappe/form/controls/autocomplete.js
index 27bf75e807..c0674956e9 100644
--- a/frappe/public/js/frappe/form/controls/autocomplete.js
+++ b/frappe/public/js/frappe/form/controls/autocomplete.js
@@ -174,6 +174,15 @@ frappe.ui.form.ControlAutocomplete = class ControlAutoComplete extends frappe.ui
if (typeof options[0] === "string") {
options = options.map((o) => ({ label: o, value: o }));
}
+
+ options = options.map((o) => {
+ if (typeof o !== "string") {
+ o.label = o.label.toString();
+ o.value = o.value.toString();
+ }
+ return o;
+ });
+
return options;
}
diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py
index fd9949c45f..75f8793b4a 100644
--- a/frappe/website/doctype/web_form/web_form.py
+++ b/frappe/website/doctype/web_form/web_form.py
@@ -631,7 +631,7 @@ def get_link_options(web_form_name, doctype, allow_read_on_all_link_options=Fals
if title_field and show_title_field_in_link:
return json.dumps(link_options, default=str)
else:
- return "\n".join([doc.value for doc in link_options])
+ return "\n".join([str(doc.value) for doc in link_options])
else:
raise frappe.PermissionError(
From b9f000e1f9f460e1e800a6bef381883c3694d9e4 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 10:07:14 +0530
Subject: [PATCH 33/97] refactor!: Log 5xx error to error log instead of error
snapshot
Also move log_error function to right location
---
frappe/__init__.py | 37 +-----
frappe/app.py | 4 +-
frappe/hooks.py | 1 -
frappe/utils/error.py | 275 ++++++------------------------------------
4 files changed, 43 insertions(+), 274 deletions(-)
diff --git a/frappe/__init__.py b/frappe/__init__.py
index 998d881a13..13e9448109 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -2213,41 +2213,6 @@ def logger(
)
-def log_error(title=None, message=None, reference_doctype=None, reference_name=None):
- """Log error to Error Log"""
- # Parameter ALERT:
- # the title and message may be swapped
- # the better API for this is log_error(title, message), and used in many cases this way
- # this hack tries to be smart about whats a title (single line ;-)) and fixes it
-
- traceback = None
- if message:
- if "\n" in title: # traceback sent as title
- traceback, title = title, message
- else:
- traceback = message
-
- title = title or "Error"
- traceback = as_unicode(traceback or get_traceback(with_context=True))
-
- if not db:
- print(f"Failed to log error in db: {title}")
- return
-
- error_log = get_doc(
- doctype="Error Log",
- error=traceback,
- method=title,
- reference_doctype=reference_doctype,
- reference_name=reference_name,
- )
-
- if flags.read_only:
- error_log.deferred_insert()
- else:
- return error_log.insert(ignore_permissions=True)
-
-
def get_desk_link(doctype, name):
html = (
'{doctype_local} {name}'
@@ -2439,6 +2404,8 @@ def validate_and_sanitize_search_inputs(fn):
return wrapper
+from frappe.utils.error import log_error # noqa: backward compatibility
+
if _tune_gc:
# generational GC gets triggered after certain allocs (g0) which is 700 by default.
# This number is quite small for frappe where a single query can potentially create 700+
diff --git a/frappe/app.py b/frappe/app.py
index 5113c858a5..1cbdca1361 100644
--- a/frappe/app.py
+++ b/frappe/app.py
@@ -22,7 +22,7 @@ from frappe import _
from frappe.auth import SAFE_HTTP_METHODS, UNSAFE_HTTP_METHODS, HTTPRequest
from frappe.middlewares import StaticDataMiddleware
from frappe.utils import cint, get_site_name, sanitize_html
-from frappe.utils.error import make_error_snapshot
+from frappe.utils.error import log_error_snapshot
from frappe.website.serve import get_response
local_manager = LocalManager(frappe.local)
@@ -346,7 +346,7 @@ def handle_exception(e):
frappe.local.login_manager.clear_cookies()
if http_status_code >= 500:
- make_error_snapshot(e)
+ log_error_snapshot(e)
if return_as_message:
response = get_response("message", http_status_code=http_status_code)
diff --git a/frappe/hooks.py b/frappe/hooks.py
index f160d93ecc..85a28feb39 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -214,7 +214,6 @@ scheduler_events = {
"hourly": [
"frappe.model.utils.link_count.update_link_count",
"frappe.model.utils.user_settings.sync_user_settings",
- "frappe.utils.error.collect_error_snapshots",
"frappe.desk.page.backups.backups.delete_downloadable_backups",
"frappe.deferred_insert.save_to_db",
"frappe.desk.form.document_follow.send_hourly_updates",
diff --git a/frappe/utils/error.py b/frappe/utils/error.py
index a9891cb532..d44bdef47f 100644
--- a/frappe/utils/error.py
+++ b/frappe/utils/error.py
@@ -1,17 +1,10 @@
# Copyright (c) 2015, Maxwell Morais and contributors
# License: MIT. See LICENSE
-import datetime
import functools
import inspect
-import json
-import linecache
-import os
-import sys
-import traceback
import frappe
-from frappe.utils import cstr, encode
EXCLUDE_EXCEPTIONS = (
frappe.AuthenticationError,
@@ -37,194 +30,57 @@ def _is_ldap_exception(e):
return False
-def make_error_snapshot(exception):
- if frappe.conf.disable_error_snapshot:
+def log_error(
+ title=None, message=None, reference_doctype=None, reference_name=None, *, defer_insert=False
+):
+ """Log error to Error Log"""
+ # Parameter ALERT:
+ # the title and message may be swapped
+ # the better API for this is log_error(title, message), and used in many cases this way
+ # this hack tries to be smart about whats a title (single line ;-)) and fixes it
+
+ traceback = None
+ if message:
+ if "\n" in title: # traceback sent as title
+ traceback, title = title, message
+ else:
+ traceback = message
+
+ title = title or "Error"
+ traceback = frappe.as_unicode(traceback or frappe.get_traceback(with_context=True))
+
+ if not frappe.db:
+ print(f"Failed to log error in db: {title}")
return
+ error_log = frappe.get_doc(
+ doctype="Error Log",
+ error=traceback,
+ method=title,
+ reference_doctype=reference_doctype,
+ reference_name=reference_name,
+ )
+
+ if frappe.flags.read_only or defer_insert:
+ error_log.deferred_insert()
+ else:
+ return error_log.insert(ignore_permissions=True)
+
+
+def log_error_snapshot(exception: Exception):
+
if isinstance(exception, EXCLUDE_EXCEPTIONS) or _is_ldap_exception(exception):
return
logger = frappe.logger(with_more_info=True)
try:
- error_id = "{timestamp:s}-{ip:s}-{hash:s}".format(
- timestamp=cstr(datetime.datetime.now()),
- ip=frappe.local.request_ip or "127.0.0.1",
- hash=frappe.generate_hash(length=3),
- )
- snapshot_folder = get_error_snapshot_path()
- frappe.create_folder(snapshot_folder)
-
- snapshot_file_path = os.path.join(snapshot_folder, f"{error_id}.json")
- snapshot = get_snapshot(exception)
-
- with open(encode(snapshot_file_path), "wb") as error_file:
- error_file.write(encode(frappe.as_json(snapshot)))
-
- logger.error(f"New Exception collected with id: {error_id}")
-
+ log_error(title=str(exception), defer_insert=True)
+ logger.error("New Exception collected in error log")
except Exception as e:
logger.error(f"Could not take error snapshot: {e}", exc_info=True)
-def get_snapshot(exception, context=10):
- import pydoc
-
- """
- Return a dict describing a given traceback (based on cgitb.text)
- """
-
- etype, evalue, etb = sys.exc_info()
- if isinstance(etype, type):
- etype = etype.__name__
-
- # creates a snapshot dict with some basic information
-
- s = {
- "pyver": "Python {version:s}: {executable:s} (prefix: {prefix:s})".format(
- version=sys.version.split(maxsplit=1)[0], executable=sys.executable, prefix=sys.prefix
- ),
- "timestamp": cstr(datetime.datetime.now()),
- "traceback": traceback.format_exc(),
- "frames": [],
- "etype": cstr(etype),
- "evalue": cstr(repr(evalue)),
- "exception": {},
- "locals": {},
- }
-
- # start to process frames
- records = inspect.getinnerframes(etb, 5)
-
- for frame, file, lnum, func, lines, index in records:
- file = file and os.path.abspath(file) or "?"
- args, varargs, varkw, locals = inspect.getargvalues(frame)
- call = ""
-
- if func != "?":
- call = inspect.formatargvalues(
- args, varargs, varkw, locals, formatvalue=lambda value: f"={pydoc.text.repr(value)}"
- )
-
- # basic frame information
- f = {"file": file, "func": func, "call": call, "lines": {}, "lnum": lnum}
-
- def reader(lnum=[lnum]): # noqa
- try:
- # B023: function is evaluated immediately, binding not necessary
- return linecache.getline(file, lnum[0]) # noqa: B023
- finally:
- lnum[0] += 1
-
- vars = _scanvars(reader, frame, locals)
-
- # if it is a view, replace with generated code
- # if file.endswith('html'):
- # lmin = lnum > context and (lnum - context) or 0
- # lmax = lnum + context
- # lines = code.split("\n")[lmin:lmax]
- # index = min(context, lnum) - 1
-
- if index is not None:
- i = lnum - index
- for line in lines:
- f["lines"][i] = line.rstrip()
- i += 1
-
- # dump local variable (referenced in current line only)
- f["dump"] = {}
- for name, where, value in vars:
- if name in f["dump"]:
- continue
- if value is not __UNDEF__:
- if where == "global":
- name = f"global {name:s}"
- elif where != "local":
- name = where + " " + name.split(".")[-1]
- f["dump"][name] = pydoc.text.repr(value)
- else:
- f["dump"][name] = "undefined"
-
- s["frames"].append(f)
-
- # add exception type, value and attributes
- if isinstance(evalue, BaseException):
- for name in dir(evalue):
- if name != "messages" and not name.startswith("__"):
- value = pydoc.text.repr(getattr(evalue, name))
- s["exception"][name] = encode(value)
-
- # add all local values (of last frame) to the snapshot
- for name, value in locals.items():
- s["locals"][name] = value if isinstance(value, str) else pydoc.text.repr(value)
-
- return s
-
-
-def collect_error_snapshots():
- """Scheduled task to collect error snapshots from files and push into Error Snapshot table"""
- if frappe.conf.disable_error_snapshot:
- return
-
- try:
- path = get_error_snapshot_path()
- if not os.path.exists(path):
- return
-
- for fname in os.listdir(path):
- fullpath = os.path.join(path, fname)
-
- try:
- with open(fullpath) as filedata:
- data = json.load(filedata)
-
- except ValueError:
- # empty file
- os.remove(fullpath)
- continue
-
- for field in ["locals", "exception", "frames"]:
- data[field] = frappe.as_json(data[field])
-
- doc = frappe.new_doc("Error Snapshot")
- doc.update(data)
- doc.save()
-
- frappe.db.commit()
-
- os.remove(fullpath)
-
- clear_old_snapshots()
-
- except Exception as e:
- make_error_snapshot(e)
-
- # prevent creation of unlimited error snapshots
- raise
-
-
-def clear_old_snapshots():
- """Clear snapshots that are older than a month"""
- from frappe.query_builder import DocType, Interval
- from frappe.query_builder.functions import Now
-
- ErrorSnapshot = DocType("Error Snapshot")
- frappe.db.delete(ErrorSnapshot, filters=(ErrorSnapshot.creation < (Now() - Interval(months=1))))
-
- path = get_error_snapshot_path()
- today = datetime.datetime.now()
-
- for file in os.listdir(path):
- p = os.path.join(path, file)
- ctime = datetime.datetime.fromtimestamp(os.path.getctime(p))
- if (today - ctime).days > 31:
- os.remove(os.path.join(path, p))
-
-
-def get_error_snapshot_path():
- return frappe.get_site_path("error-snapshots")
-
-
def get_default_args(func):
"""Get default arguments of a function from its signature."""
signature = inspect.signature(func)
@@ -270,56 +126,3 @@ def raise_error_on_no_output(error_message, error_type=None, keep_quiet=None):
return wrapper_raise_error_on_no_output
return decorator_raise_error_on_no_output
-
-
-# Vendored from cgitb standard library reused under PSF License:
-# https://github.com/python/cpython/blob/main/LICENSE
-
-
-import keyword
-import tokenize
-
-__UNDEF__ = [] # a special sentinel object
-
-
-def _scanvars(reader, frame, locals):
- """Scan one logical line of Python and look up values of variables used."""
- vars, lasttoken, parent, prefix, value = [], None, None, "", __UNDEF__
- for ttype, token, start, end, line in tokenize.generate_tokens(reader):
- if ttype == tokenize.NEWLINE:
- break
- if ttype == tokenize.NAME and token not in keyword.kwlist:
- if lasttoken == ".":
- if parent is not __UNDEF__:
- value = getattr(parent, token, __UNDEF__)
- vars.append((prefix + token, prefix, value))
- else:
- where, value = _lookup(token, frame, locals)
- vars.append((token, where, value))
- elif token == ".":
- prefix += lasttoken + "."
- parent = value
- else:
- parent, prefix = None, ""
- lasttoken = token
- return vars
-
-
-def _lookup(name, frame, locals):
- """Find the value for a given name in the given environment."""
- if name in locals:
- return "local", locals[name]
- if name in frame.f_globals:
- return "global", frame.f_globals[name]
- if "__builtins__" in frame.f_globals:
- builtins = frame.f_globals["__builtins__"]
- if type(builtins) is type({}): # noqa
- if name in builtins:
- return "builtin", builtins[name]
- else:
- if hasattr(builtins, name):
- return "builtin", getattr(builtins, name)
- return None, __UNDEF__
-
-
-# end: vendored code
From ae8ee5064c972f66411030bcf7e9d6f9a4236743 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 10:25:26 +0530
Subject: [PATCH 34/97] refactor!: Remove error snapshot
---
.../core/doctype/error_snapshot/__init__.py | 0
.../doctype/error_snapshot/error_object.html | 12 --
.../error_snapshot/error_snapshot.html | 77 -----------
.../doctype/error_snapshot/error_snapshot.js | 20 ---
.../error_snapshot/error_snapshot.json | 130 ------------------
.../doctype/error_snapshot/error_snapshot.py | 40 ------
.../error_snapshot/error_snapshot_list.js | 19 ---
.../error_snapshot/test_error_snapshot.py | 11 --
.../core/doctype/log_settings/log_settings.py | 2 -
.../doctype/log_settings/test_log_settings.py | 1 -
frappe/core/notifications.py | 1 -
frappe/core/workspace/build/build.json | 128 ++++++++---------
frappe/installer.py | 1 -
frappe/patches.txt | 3 +-
.../v14_0/clear_long_pending_stale_logs.py | 1 -
15 files changed, 60 insertions(+), 386 deletions(-)
delete mode 100644 frappe/core/doctype/error_snapshot/__init__.py
delete mode 100644 frappe/core/doctype/error_snapshot/error_object.html
delete mode 100644 frappe/core/doctype/error_snapshot/error_snapshot.html
delete mode 100644 frappe/core/doctype/error_snapshot/error_snapshot.js
delete mode 100644 frappe/core/doctype/error_snapshot/error_snapshot.json
delete mode 100644 frappe/core/doctype/error_snapshot/error_snapshot.py
delete mode 100644 frappe/core/doctype/error_snapshot/error_snapshot_list.js
delete mode 100644 frappe/core/doctype/error_snapshot/test_error_snapshot.py
diff --git a/frappe/core/doctype/error_snapshot/__init__.py b/frappe/core/doctype/error_snapshot/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/core/doctype/error_snapshot/error_object.html b/frappe/core/doctype/error_snapshot/error_object.html
deleted file mode 100644
index 450bfacfc6..0000000000
--- a/frappe/core/doctype/error_snapshot/error_object.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% if (Object.prototype.toString.call(x) === "[object Object]") { %}
-
- {% for (var key in x) { %}
-
- {{ key }} |
- {{ x[key] }} |
-
- {% } %}
-
-{% } else { %}
- {{ x }}
-{% } %}
diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.html b/frappe/core/doctype/error_snapshot/error_snapshot.html
deleted file mode 100644
index 6f449e0fe9..0000000000
--- a/frappe/core/doctype/error_snapshot/error_snapshot.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-{% function id(){ return id._old_id++; }; id._old_id = 0; %}
-{{ __("Error Report") }}
-{{ doc.pyver }}
-
- - {{ __("Timestamp") }}:
- - {{ doc.timestamp }}
- - {{ __("Relapsed") }}
- {{ doc.relapses }}
-
-
-{{ __("Exception") }}
-{{ frappe.render_template("error_object", {x: JSON.parse(doc.exception)}) }}
-
-{{ __("Locals") }}
-{{ frappe.render_template("error_object", {x: JSON.parse(doc.locals)} )}}
-
-{{ __("Traceback") }}
-{% var frames = JSON.parse(doc.frames); %}
-{% for (var i in frames) { %}
- {% var frameid = id(), frame = frames[i] %}
- {{ frame.file }}: {{ frame.lnum }}
-
-
-
- {% for (var index in frame.lines) { %}
- {% var line = frame.lines[index] %}
-
- {{ index }}
- {{ line }}
-
- {% } %}
-
-
-
- {{ __("Locals") }}
-
-
-
-
-
-
-
{{ __("Locals") }}
- {{ frappe.render_template("error_object", {x: frame.dump }) }}
-
-
-
-{% } %}
diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.js b/frappe/core/doctype/error_snapshot/error_snapshot.js
deleted file mode 100644
index f8a7e3ded5..0000000000
--- a/frappe/core/doctype/error_snapshot/error_snapshot.js
+++ /dev/null
@@ -1,20 +0,0 @@
-frappe.ui.form.on("Error Snapshot", "load", function (frm) {
- frm.set_read_only(true);
-});
-
-frappe.ui.form.on("Error Snapshot", "refresh", function (frm) {
- frm.set_df_property(
- "view",
- "options",
- frappe.render_template("error_snapshot", { doc: frm.doc })
- );
-
- if (frm.doc.relapses) {
- frm.add_custom_button(__("Show Relapses"), function () {
- frappe.route_options = {
- parent_error_snapshot: frm.doc.name,
- };
- frappe.set_route("List", "Error Snapshot");
- });
- }
-});
diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.json b/frappe/core/doctype/error_snapshot/error_snapshot.json
deleted file mode 100644
index b92db8f99a..0000000000
--- a/frappe/core/doctype/error_snapshot/error_snapshot.json
+++ /dev/null
@@ -1,130 +0,0 @@
-{
- "actions": [],
- "creation": "2015-11-28 00:57:39.766888",
- "doctype": "DocType",
- "document_type": "System",
- "engine": "InnoDB",
- "field_order": [
- "view",
- "seen",
- "evalue",
- "timestamp",
- "relapses",
- "etype",
- "traceback",
- "parent_error_snapshot",
- "pyver",
- "exception",
- "locals",
- "frames"
- ],
- "fields": [
- {
- "fieldname": "view",
- "fieldtype": "HTML",
- "label": "Snapshot View"
- },
- {
- "default": "0",
- "fieldname": "seen",
- "fieldtype": "Check",
- "hidden": 1,
- "in_filter": 1,
- "label": "Seen"
- },
- {
- "fieldname": "evalue",
- "fieldtype": "Code",
- "hidden": 1,
- "in_list_view": 1,
- "label": "Friendly Title",
- "read_only": 1
- },
- {
- "fieldname": "timestamp",
- "fieldtype": "Datetime",
- "hidden": 1,
- "label": "Timestamp",
- "read_only": 1
- },
- {
- "default": "1",
- "fieldname": "relapses",
- "fieldtype": "Int",
- "hidden": 1,
- "in_list_view": 1,
- "label": "Relapses",
- "read_only": 1
- },
- {
- "fieldname": "etype",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Exception Type",
- "read_only": 1
- },
- {
- "fieldname": "traceback",
- "fieldtype": "Code",
- "hidden": 1,
- "label": "Traceback",
- "read_only": 1
- },
- {
- "fieldname": "parent_error_snapshot",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Parent Error Snapshot"
- },
- {
- "fieldname": "pyver",
- "fieldtype": "Code",
- "hidden": 1,
- "label": "Pyver",
- "read_only": 1
- },
- {
- "fieldname": "exception",
- "fieldtype": "Code",
- "hidden": 1,
- "label": "Exception"
- },
- {
- "fieldname": "locals",
- "fieldtype": "Code",
- "hidden": 1,
- "label": "Locals"
- },
- {
- "fieldname": "frames",
- "fieldtype": "Code",
- "hidden": 1,
- "label": "Frames"
- }
- ],
- "in_create": 1,
- "links": [],
- "modified": "2022-08-03 12:20:53.504160",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Error Snapshot",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Administrator",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "timestamp",
- "sort_order": "DESC",
- "states": [],
- "title_field": "evalue"
-}
\ No newline at end of file
diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.py b/frappe/core/doctype/error_snapshot/error_snapshot.py
deleted file mode 100644
index acc49c78cd..0000000000
--- a/frappe/core/doctype/error_snapshot/error_snapshot.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
-# License: MIT. See LICENSE
-
-import frappe
-from frappe.model.document import Document
-from frappe.query_builder import Interval
-from frappe.query_builder.functions import Now
-
-
-class ErrorSnapshot(Document):
- no_feed_on_delete = True
-
- def onload(self):
- if not self.parent_error_snapshot:
- self.db_set("seen", 1, update_modified=False)
-
- for relapsed in frappe.get_all("Error Snapshot", filters={"parent_error_snapshot": self.name}):
- frappe.db.set_value("Error Snapshot", relapsed.name, "seen", 1, update_modified=False)
-
- frappe.local.flags.commit = True
-
- def validate(self):
- parent = frappe.get_all(
- "Error Snapshot",
- filters={"evalue": self.evalue, "parent_error_snapshot": ""},
- fields=["name", "relapses", "seen"],
- limit_page_length=1,
- )
-
- if parent:
- parent = parent[0]
- self.update({"parent_error_snapshot": parent["name"]})
- frappe.db.set_value("Error Snapshot", parent["name"], "relapses", parent["relapses"] + 1)
- if parent["seen"]:
- frappe.db.set_value("Error Snapshot", parent["name"], "seen", 0)
-
- @staticmethod
- def clear_old_logs(days=30):
- table = frappe.qb.DocType("Error Snapshot")
- frappe.db.delete(table, filters=(table.modified < (Now() - Interval(days=days))))
diff --git a/frappe/core/doctype/error_snapshot/error_snapshot_list.js b/frappe/core/doctype/error_snapshot/error_snapshot_list.js
deleted file mode 100644
index b331788852..0000000000
--- a/frappe/core/doctype/error_snapshot/error_snapshot_list.js
+++ /dev/null
@@ -1,19 +0,0 @@
-frappe.listview_settings["Error Snapshot"] = {
- add_fields: ["parent_error_snapshot", "relapses", "seen"],
- filters: [
- ["parent_error_snapshot", "=", null],
- ["seen", "=", false],
- ],
- get_indicator: function (doc) {
- if (doc.parent_error_snapshot && doc.parent_error_snapshot.length) {
- return [__("Relapsed"), !doc.seen ? "orange" : "blue", "parent_error_snapshot,!=,"];
- } else {
- return [__("First Level"), !doc.seen ? "red" : "green", "parent_error_snapshot,=,"];
- }
- },
- onload: function (listview) {
- frappe.require("logtypes.bundle.js", () => {
- frappe.utils.logtypes.show_log_retention_message(cur_list.doctype);
- });
- },
-};
diff --git a/frappe/core/doctype/error_snapshot/test_error_snapshot.py b/frappe/core/doctype/error_snapshot/test_error_snapshot.py
deleted file mode 100644
index 4779d56c7b..0000000000
--- a/frappe/core/doctype/error_snapshot/test_error_snapshot.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-from frappe.tests.utils import FrappeTestCase
-from frappe.utils.logger import sanitized_dict
-
-# test_records = frappe.get_test_records('Error Snapshot')
-
-
-class TestErrorSnapshot(FrappeTestCase):
- def test_form_dict_sanitization(self):
- self.assertNotEqual(sanitized_dict({"pwd": "SECRET", "usr": "WHAT"}).get("pwd"), "SECRET")
diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py
index 832be49f3c..c4d311cb3d 100644
--- a/frappe/core/doctype/log_settings/log_settings.py
+++ b/frappe/core/doctype/log_settings/log_settings.py
@@ -14,7 +14,6 @@ DEFAULT_LOGTYPES_RETENTION = {
"Error Log": 30,
"Activity Log": 90,
"Email Queue": 30,
- "Error Snapshot": 30,
"Scheduled Job Log": 90,
"Route History": 90,
"Submission Queue": 30,
@@ -156,7 +155,6 @@ LOG_DOCTYPES = [
"Route History",
"Email Queue",
"Email Queue Recipient",
- "Error Snapshot",
"Error Log",
]
diff --git a/frappe/core/doctype/log_settings/test_log_settings.py b/frappe/core/doctype/log_settings/test_log_settings.py
index d7f43a181d..edee098553 100644
--- a/frappe/core/doctype/log_settings/test_log_settings.py
+++ b/frappe/core/doctype/log_settings/test_log_settings.py
@@ -62,7 +62,6 @@ class TestLogSettings(FrappeTestCase):
"Activity Log",
"Email Queue",
"Route History",
- "Error Snapshot",
"Scheduled Job Log",
]
diff --git a/frappe/core/notifications.py b/frappe/core/notifications.py
index 093418e345..26e920bca9 100644
--- a/frappe/core/notifications.py
+++ b/frappe/core/notifications.py
@@ -11,7 +11,6 @@ def get_notification_config():
"Communication": {"status": "Open", "communication_type": "Communication"},
"ToDo": "frappe.core.notifications.get_things_todo",
"Event": "frappe.core.notifications.get_todays_events",
- "Error Snapshot": {"seen": 0, "parent_error_snapshot": None},
"Workflow Action": {"status": "Open"},
},
}
diff --git a/frappe/core/workspace/build/build.json b/frappe/core/workspace/build/build.json
index b917f88e27..12bef0ed89 100644
--- a/frappe/core/workspace/build/build.json
+++ b/frappe/core/workspace/build/build.json
@@ -155,74 +155,6 @@
"onboard": 0,
"type": "Link"
},
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "System Logs",
- "link_count": 6,
- "onboard": 0,
- "type": "Card Break"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Background Jobs",
- "link_count": 0,
- "link_to": "RQ Job",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Scheduled Jobs Logs",
- "link_count": 0,
- "link_to": "Scheduled Job Log",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Error Logs",
- "link_count": 0,
- "link_to": "Error Log",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Error Snapshot",
- "link_count": 0,
- "link_to": "Error Snapshot",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Communication Logs",
- "link_count": 0,
- "link_to": "Communication",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Activity Log",
- "link_count": 0,
- "link_to": "Activity Log",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
{
"hidden": 0,
"is_query_report": 0,
@@ -331,9 +263,67 @@
"link_type": "DocType",
"onboard": 0,
"type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "System Logs",
+ "link_count": 5,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Background Jobs",
+ "link_count": 0,
+ "link_to": "RQ Job",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Scheduled Jobs Logs",
+ "link_count": 0,
+ "link_to": "Scheduled Job Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Error Logs",
+ "link_count": 0,
+ "link_to": "Error Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Communication Logs",
+ "link_count": 0,
+ "link_to": "Communication",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Activity Log",
+ "link_count": 0,
+ "link_to": "Activity Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
}
],
- "modified": "2023-05-24 14:47:24.395259",
+ "modified": "2023-06-28 10:30:17.228167",
"modified_by": "Administrator",
"module": "Core",
"name": "Build",
diff --git a/frappe/installer.py b/frappe/installer.py
index 4f02e207bd..775e5b9b02 100644
--- a/frappe/installer.py
+++ b/frappe/installer.py
@@ -617,7 +617,6 @@ def make_site_dirs():
os.path.join("public", "files"),
os.path.join("private", "backups"),
os.path.join("private", "files"),
- "error-snapshots",
"locks",
"logs",
]:
diff --git a/frappe/patches.txt b/frappe/patches.txt
index c26b1a74d7..ebdda9b220 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -31,7 +31,6 @@ execute:frappe.reload_doc('core', 'doctype', 'user') #2017-10-27
execute:frappe.reload_doc('core', 'doctype', 'report_column')
execute:frappe.reload_doc('core', 'doctype', 'report_filter')
execute:frappe.reload_doc('core', 'doctype', 'report') #2020-08-25
-execute:frappe.reload_doc('core', 'doctype', 'error_snapshot')
execute:frappe.get_doc("User", "Guest").save()
execute:frappe.delete_doc("DocType", "Control Panel", force=1)
execute:frappe.delete_doc("DocType", "Tag")
@@ -42,7 +41,6 @@ execute:frappe.db.sql("delete from `tabProperty Setter` where `property` = 'idx'
execute:frappe.db.sql("delete from tabSessions where user is null")
execute:frappe.delete_doc("DocType", "Backup Manager")
execute:frappe.permissions.reset_perms("Web Page")
-execute:frappe.permissions.reset_perms("Error Snapshot")
execute:frappe.db.sql("delete from `tabWeb Page` where ifnull(template_path, '')!=''")
execute:frappe.core.doctype.language.language.update_language_names() # 2017-04-12
execute:frappe.db.set_value("Print Settings", "Print Settings", "add_draft_heading", 1)
@@ -227,3 +225,4 @@ frappe.patches.v15_0.remove_background_jobs_from_dropdown
frappe.desk.doctype.form_tour.patches.introduce_ui_tours
execute:frappe.delete_doc_if_exists("Workspace", "Customization")
execute:frappe.db.set_single_value("Document Naming Settings", "default_amend_naming", "Amend Counter")
+execute:frappe.delete_doc_if_exists("DocType", "Error Snapshot")
diff --git a/frappe/patches/v14_0/clear_long_pending_stale_logs.py b/frappe/patches/v14_0/clear_long_pending_stale_logs.py
index 53127cb197..e419b1e562 100644
--- a/frappe/patches/v14_0/clear_long_pending_stale_logs.py
+++ b/frappe/patches/v14_0/clear_long_pending_stale_logs.py
@@ -15,7 +15,6 @@ def execute():
"Email Queue": get_current_setting("clear_email_queue_after") or 30,
# child table on email queue
"Email Queue Recipient": get_current_setting("clear_email_queue_after") or 30,
- "Error Snapshot": get_current_setting("clear_error_log_after") or 90,
# newly added
"Scheduled Job Log": 90,
}
From 37577b752ef025f9815e0996ca88417ca608d7a1 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 10:57:54 +0530
Subject: [PATCH 35/97] fix: log settings should delete delted doctypes
[skip ci]
---
frappe/core/doctype/log_settings/log_settings.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/frappe/core/doctype/log_settings/log_settings.py b/frappe/core/doctype/log_settings/log_settings.py
index c4d311cb3d..623e358b6c 100644
--- a/frappe/core/doctype/log_settings/log_settings.py
+++ b/frappe/core/doctype/log_settings/log_settings.py
@@ -44,11 +44,11 @@ def _supports_log_clearing(doctype: str) -> bool:
class LogSettings(Document):
def validate(self):
- self._remove_unsupported_doctypes()
+ self.remove_unsupported_doctypes()
self._deduplicate_entries()
self.add_default_logtypes()
- def _remove_unsupported_doctypes(self):
+ def remove_unsupported_doctypes(self):
for entry in list(self.logs_to_clear):
if _supports_log_clearing(entry.ref_doctype):
continue
@@ -113,6 +113,7 @@ class LogSettings(Document):
def run_log_clean_up():
doc = frappe.get_doc("Log Settings")
+ doc.remove_unsupported_doctypes()
doc.add_default_logtypes()
doc.save()
doc.clear_logs()
From 537d5511127235b41b44f7c4fc15df340f89d5de Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 28 Jun 2023 11:17:17 +0530
Subject: [PATCH 36/97] refactor: Deprecate broken-img mixin
---
frappe/public/scss/common/mixins.scss | 41 ++-----------------------
frappe/public/scss/desk/file_view.scss | 5 ---
frappe/public/scss/desk/image_view.scss | 5 ---
frappe/public/scss/desk/kanban.scss | 5 ---
4 files changed, 2 insertions(+), 54 deletions(-)
diff --git a/frappe/public/scss/common/mixins.scss b/frappe/public/scss/common/mixins.scss
index 6d71ea9d6f..55b54d9de3 100644
--- a/frappe/public/scss/common/mixins.scss
+++ b/frappe/public/scss/common/mixins.scss
@@ -45,42 +45,5 @@
$background-color: var(--bg-color),
$border-radius: var(--border-radius),
) {
-
- @if $content {
- img:after {
- content: url($content);
- }
- } @else {
- img:after {
- content: url("data:image/svg+xml;utf8,");
- }
- }
-
- img[alt]:after {
- height: $height;
- top: $top;
- left: $left;
- background-color: $background-color;
- border-radius: $border-radius;
- width: 100%;
- position: absolute;
- @include flex();
- z-index: 1;
- }
-}
-
-// @mixin img-foreground() {
-// content: "\f1c5";
-// display: block;
-// font-style: normal;
-// font-family: FontAwesome;
-// font-size: 32px;
-// color: var(--text-muted);
-
-// position: absolute;
-// top: 50%;
-// transform: translateY(-50%);
-// left: 0;
-// width: 100%;
-// text-align: center;
-// }
\ No newline at end of file
+ // Deprecated: Does not work as expected anymore. Also, this never worked in Safari.
+}
\ No newline at end of file
diff --git a/frappe/public/scss/desk/file_view.scss b/frappe/public/scss/desk/file_view.scss
index d074a7efdd..29e49ab65e 100644
--- a/frappe/public/scss/desk/file_view.scss
+++ b/frappe/public/scss/desk/file_view.scss
@@ -97,11 +97,6 @@
color: transparent;
position: relative;
}
-
- @include broken-img(
- $height: 70px,
- $top: -15px,
- );
}
}
diff --git a/frappe/public/scss/desk/image_view.scss b/frappe/public/scss/desk/image_view.scss
index 3b9d033406..063af27923 100644
--- a/frappe/public/scss/desk/image_view.scss
+++ b/frappe/public/scss/desk/image_view.scss
@@ -153,11 +153,6 @@
position: relative;
width: 100%;
}
-
- @include broken-img(
- $height: 175px,
- $border-radius: 0
- );
}
.image-title {
diff --git a/frappe/public/scss/desk/kanban.scss b/frappe/public/scss/desk/kanban.scss
index 8f286b7b35..5a748c581c 100644
--- a/frappe/public/scss/desk/kanban.scss
+++ b/frappe/public/scss/desk/kanban.scss
@@ -181,11 +181,6 @@
color: transparent;
position: relative;
}
-
- @include broken-img(
- $height: 125px,
- $top: -4px,
- )
}
.kanban-card-body {
From f3c876e43e0c8182220e6d5a0e6365efcfa4fd97 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 11:43:23 +0530
Subject: [PATCH 37/97] chore: ignore pyo files too
---
frappe/website/page_renderers/static_page.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/website/page_renderers/static_page.py b/frappe/website/page_renderers/static_page.py
index d6de2f2991..f992743c6a 100644
--- a/frappe/website/page_renderers/static_page.py
+++ b/frappe/website/page_renderers/static_page.py
@@ -8,7 +8,7 @@ import frappe
from frappe.website.page_renderers.base_renderer import BaseRenderer
from frappe.website.utils import is_binary_file
-UNSUPPORTED_STATIC_PAGE_TYPES = ("html", "md", "js", "xml", "css", "txt", "py", "pyc", "json")
+UNSUPPORTED_STATIC_PAGE_TYPES = ("html", "md", "js", "xml", "css", "txt", "py", "pyc", "json", "pyo")
class StaticPage(BaseRenderer):
From aaf1bd7f4bcd21db2e36888ac48d91d2260f772f Mon Sep 17 00:00:00 2001
From: Hussain Nagaria
Date: Wed, 28 Jun 2023 11:46:17 +0530
Subject: [PATCH 38/97] style: fix linter whitespace issue
---
frappe/public/js/frappe/form/controls/autocomplete.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/controls/autocomplete.js b/frappe/public/js/frappe/form/controls/autocomplete.js
index c0674956e9..7b91a2031c 100644
--- a/frappe/public/js/frappe/form/controls/autocomplete.js
+++ b/frappe/public/js/frappe/form/controls/autocomplete.js
@@ -182,7 +182,7 @@ frappe.ui.form.ControlAutocomplete = class ControlAutoComplete extends frappe.ui
}
return o;
});
-
+
return options;
}
From 814265d24581ca6024ebdf8c4e53df95ac060726 Mon Sep 17 00:00:00 2001
From: Maharshi Patel <39730881+maharshivpatel@users.noreply.github.com>
Date: Wed, 28 Jun 2023 13:34:36 +0530
Subject: [PATCH 39/97] fix(minor): workflow state indicator (#21508)
In List view only `Status` type was considered for indicator. Added fields with `Workflow State` as options
---
frappe/public/js/frappe/list/list_view.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js
index c0eef27b9d..1ca72a4e45 100644
--- a/frappe/public/js/frappe/list/list_view.js
+++ b/frappe/public/js/frappe/list/list_view.js
@@ -711,7 +711,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
get_column_html(col, doc) {
- if (col.type === "Status") {
+ if (col.type === "Status" || col.df?.options == "Workflow State") {
return `
${this.get_indicator_html(doc)}
From 95e49193c838564de080379eab804b586a85277f Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 15:21:04 +0530
Subject: [PATCH 40/97] fix: dont retry if redis not available for realtime
(#21517)
* fix: reduce retries for rq connection
10 seconds of retries when connection isn't available is too much, just
failing might be beneficial.
- BusyLoadingError only occurs when redis is restarting
- ConnectionError mostly means redis is dead, no amount of retries will
bring it back.
* fix: dont retry if redis is down for realtime
---
frappe/realtime.py | 4 ++--
frappe/utils/background_jobs.py | 16 +++++++++++-----
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/frappe/realtime.py b/frappe/realtime.py
index 410112b164..47b3d8a95c 100644
--- a/frappe/realtime.py
+++ b/frappe/realtime.py
@@ -100,10 +100,10 @@ def emit_via_redis(event, message, room):
:param event: Event name, like `task_progress` etc.
:param message: JSON message object. For async must contain `task_id`
:param room: name of the room"""
- from frappe.utils.background_jobs import get_redis_conn
+ from frappe.utils.background_jobs import get_redis_connection_without_auth
with suppress(redis.exceptions.ConnectionError):
- r = get_redis_conn()
+ r = get_redis_connection_without_auth()
r.publish("events", frappe.as_json({"event": event, "message": message, "room": room}))
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index 9008ba00ee..7de7ef6692 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -394,8 +394,8 @@ def validate_queue(queue, default_queue_list=None):
@retry(
- retry=retry_if_exception_type(BusyLoadingError) | retry_if_exception_type(ConnectionError),
- stop=stop_after_attempt(10),
+ retry=retry_if_exception_type((BusyLoadingError, ConnectionError)),
+ stop=stop_after_attempt(5),
wait=wait_fixed(1),
reraise=True,
)
@@ -423,9 +423,7 @@ def get_redis_conn(username=None, password=None):
try:
if not cred:
- if not _redis_queue_conn:
- _redis_queue_conn = RedisQueue.get_connection()
- return _redis_queue_conn
+ return get_redis_connection_without_auth()
else:
return RedisQueue.get_connection(**cred)
except (redis.exceptions.AuthenticationError, redis.exceptions.ResponseError):
@@ -440,6 +438,14 @@ def get_redis_conn(username=None, password=None):
raise
+def get_redis_connection_without_auth():
+ global _redis_queue_conn
+
+ if not _redis_queue_conn:
+ _redis_queue_conn = RedisQueue.get_connection()
+ return _redis_queue_conn
+
+
def get_queues() -> list[Queue]:
"""Get all the queues linked to the current bench."""
queues = Queue.all(connection=get_redis_conn())
From 564b960678d7ff31da1cb527f689a39a935a4016 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 13:20:49 +0530
Subject: [PATCH 41/97] fix: correct last update value
`NOW()` evalautes to server's time we should use system time instead.
---
frappe/sessions.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 64a1a6b663..8682300845 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -386,8 +386,8 @@ class Session:
# update sessions table
frappe.db.sql(
"""update `tabSessions` set sessiondata=%s,
- lastupdate=NOW() where sid=%s""",
- (str(self.data["data"]), self.data["sid"]),
+ lastupdate=%s where sid=%s""",
+ (str(self.data["data"]), now, self.data["sid"]),
)
# update last active in user table
From 7c4009fde98244459be25e1f6d15699f87f5f02c Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 13:26:39 +0530
Subject: [PATCH 42/97] refactor: use QB
---
frappe/sessions.py | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 8682300845..bcacc79ce7 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -373,6 +373,8 @@ class Session:
now = frappe.utils.now()
+ Sessions = frappe.qb.DocType("Sessions")
+
self.data["data"]["last_updated"] = now
self.data["data"]["lang"] = str(frappe.lang)
@@ -384,17 +386,14 @@ class Session:
updated_in_db = False
if (force or (time_diff is None) or (time_diff > 600)) and not frappe.flags.read_only:
# update sessions table
- frappe.db.sql(
- """update `tabSessions` set sessiondata=%s,
- lastupdate=%s where sid=%s""",
- (str(self.data["data"]), now, self.data["sid"]),
- )
+ (
+ frappe.qb.update(Sessions)
+ .where(Sessions.sid == self.data["sid"])
+ .set(Sessions.sessiondata, str(self.data["data"]))
+ .set(Sessions.lastupdate, now)
+ ).run()
- # update last active in user table
- frappe.db.sql(
- """update `tabUser` set last_active=%(now)s where name=%(name)s""",
- {"now": now, "name": frappe.session.user},
- )
+ frappe.db.set_value("User", frappe.session.user, "last_active", now, update_modified=False)
frappe.db.commit()
frappe.cache.hset("last_db_session_update", self.sid, now)
From 60efb7c2ff7350f52a9da1f878ba14ae76d2230e Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 15:58:41 +0530
Subject: [PATCH 43/97] fix: incorrect session expiry datediff
Datediff doesn't work like this in MYSQL, mysql just treats the
timestamp as flat timestamp.
---
frappe/sessions.py | 45 +++++++++++++++++++++------------------------
1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index bcacc79ce7..94ad991c3a 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -19,8 +19,7 @@ import frappe.utils
from frappe import _
from frappe.cache_manager import clear_user_cache
from frappe.query_builder import DocType, Order
-from frappe.query_builder.functions import Now
-from frappe.query_builder.utils import PseudoColumn
+from frappe.query_builder.functions import UnixTimestamp
from frappe.utils import cint, cstr, get_assets_json
@@ -112,17 +111,14 @@ def clear_all_sessions(reason=None):
def get_expired_sessions():
"""Returns list of expired sessions"""
- sessions = DocType("Sessions")
+ sessions = frappe.qb.DocType("Sessions")
+ now = frappe.utils.now()
- return frappe.db.get_values(
- sessions,
- filters=(
- PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})") > get_expiry_period_for_query()
- ),
- fieldname="sid",
- order_by=None,
- pluck=True,
- )
+ return (
+ frappe.qb.from_(sessions)
+ .select(sessions.sid)
+ .where((UnixTimestamp(now) - UnixTimestamp(sessions.lastupdate)) > get_expiry_period_for_query())
+ ).run(pluck=True)
def clear_expired_sessions():
@@ -339,19 +335,20 @@ class Session:
def get_session_data_from_db(self):
sessions = DocType("Sessions")
- rec = frappe.db.get_values(
- sessions,
- filters=(sessions.sid == self.sid)
- & (
- PseudoColumn(f"({Now()} - {sessions.lastupdate.get_sql()})") < get_expiry_period_for_query()
- ),
- fieldname=["user", "sessiondata"],
- order_by=None,
- )
+ now = frappe.utils.now()
- if rec:
- data = frappe._dict(frappe.safe_eval(rec and rec[0][1] or "{}"))
- data.user = rec[0][0]
+ record = (
+ frappe.qb.from_(sessions)
+ .select(sessions.user, sessions.sessiondata)
+ .where(sessions.sid == self.sid)
+ .where(
+ (UnixTimestamp(now) - UnixTimestamp(sessions.lastupdate)) < get_expiry_period_for_query()
+ )
+ ).run()
+
+ if record:
+ data = frappe._dict(frappe.safe_eval(record and record[0][1] or "{}"))
+ data.user = record[0][0]
else:
self._delete_session()
data = None
From d353662b53aea7e4232de456bbcdf2de83f0fc99 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 16:21:00 +0530
Subject: [PATCH 44/97] fix: Session insert using system time
NOW() is server time not system time.
---
frappe/sessions.py | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 94ad991c3a..d14a4211af 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -18,7 +18,7 @@ import frappe.translate
import frappe.utils
from frappe import _
from frappe.cache_manager import clear_user_cache
-from frappe.query_builder import DocType, Order
+from frappe.query_builder import Order
from frappe.query_builder.functions import UnixTimestamp
from frappe.utils import cint, cstr, get_assets_json
@@ -61,7 +61,7 @@ def get_sessions_to_clear(user=None, keep_current=False):
simultaneous_sessions = frappe.db.get_value("User", user, "simultaneous_sessions") or 1
offset = simultaneous_sessions - 1
- session = DocType("Sessions")
+ session = frappe.qb.DocType("Sessions")
session_id = frappe.qb.from_(session).where(session.user == user)
if keep_current:
session_id = session_id.where(session.sid != frappe.session.sid)
@@ -87,7 +87,7 @@ def delete_session(sid=None, user=None, reason="Session Expired"):
frappe.cache.hdel("session", sid)
frappe.cache.hdel("last_db_session_update", sid)
if sid and not user:
- table = DocType("Sessions")
+ table = frappe.qb.DocType("Sessions")
user_details = (
frappe.qb.from_(table).where(table.sid == sid).select(table.user).run(as_dict=True)
)
@@ -264,14 +264,17 @@ class Session:
frappe.db.commit()
def insert_session_record(self):
- frappe.db.sql(
- """insert into `tabSessions`
- (`sessiondata`, `user`, `lastupdate`, `sid`, `status`)
- values (%s , %s, NOW(), %s, 'Active')""",
- (str(self.data["data"]), self.data["user"], self.data["sid"]),
- )
- # also add to memcache
+ Sessions = frappe.qb.DocType("Sessions")
+ now = frappe.utils.now()
+
+ (
+ frappe.qb.into(Sessions)
+ .columns(
+ Sessions.sessiondata, Sessions.user, Sessions.lastupdate, Sessions.sid, Sessions.status
+ )
+ .insert((str(self.data["data"]), self.data["user"], now, self.data["sid"], "Active"))
+ ).run()
frappe.cache.hset("session", self.data.sid, self.data)
def resume(self):
@@ -334,7 +337,7 @@ class Session:
return data and data.data
def get_session_data_from_db(self):
- sessions = DocType("Sessions")
+ sessions = frappe.qb.DocType("Sessions")
now = frappe.utils.now()
record = (
From 0e1236b6bef8109c561e524d73b51c3be92c9048 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 17:23:27 +0530
Subject: [PATCH 45/97] refactor: Simplify expiry queries.
Dont rely on mysql dateutils, simply compare dates with a cutoff.
---
frappe/sessions.py | 22 +++++++++++++---------
frappe/tests/test_auth.py | 34 ++++++++++++++++++++++++++++++----
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/frappe/sessions.py b/frappe/sessions.py
index d14a4211af..2709de8fab 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -19,8 +19,8 @@ import frappe.utils
from frappe import _
from frappe.cache_manager import clear_user_cache
from frappe.query_builder import Order
-from frappe.query_builder.functions import UnixTimestamp
from frappe.utils import cint, cstr, get_assets_json
+from frappe.utils.data import add_to_date
@frappe.whitelist()
@@ -112,12 +112,10 @@ def get_expired_sessions():
"""Returns list of expired sessions"""
sessions = frappe.qb.DocType("Sessions")
- now = frappe.utils.now()
-
return (
frappe.qb.from_(sessions)
.select(sessions.sid)
- .where((UnixTimestamp(now) - UnixTimestamp(sessions.lastupdate)) > get_expiry_period_for_query())
+ .where(sessions.lastupdate < get_expired_threshold())
).run(pluck=True)
@@ -228,7 +226,7 @@ class Session:
sid = frappe.generate_hash()
self.data.user = self.user
- self.data.sid = sid
+ self.sid = self.data.sid = sid
self.data.data.user = self.user
self.data.data.session_ip = frappe.local.request_ip
if self.user != "Guest":
@@ -338,15 +336,12 @@ class Session:
def get_session_data_from_db(self):
sessions = frappe.qb.DocType("Sessions")
- now = frappe.utils.now()
record = (
frappe.qb.from_(sessions)
.select(sessions.user, sessions.sessiondata)
.where(sessions.sid == self.sid)
- .where(
- (UnixTimestamp(now) - UnixTimestamp(sessions.lastupdate)) < get_expiry_period_for_query()
- )
+ .where(sessions.lastupdate > get_expired_threshold())
).run()
if record:
@@ -420,6 +415,15 @@ def get_expiry_in_seconds(expiry=None):
return (cint(parts[0]) * 3600) + (cint(parts[1]) * 60) + cint(parts[2])
+def get_expired_threshold():
+ """Get cutoff time before which all sessions are considered expired."""
+
+ now = frappe.utils.now()
+ expiry_in_seconds = get_expiry_in_seconds()
+
+ return add_to_date(now, seconds=-expiry_in_seconds, as_string=True)
+
+
def get_expiry_period():
exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00"
diff --git a/frappe/tests/test_auth.py b/frappe/tests/test_auth.py
index d4cfe4451e..6aa8d2cc2f 100644
--- a/frappe/tests/test_auth.py
+++ b/frappe/tests/test_auth.py
@@ -1,14 +1,18 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
import time
+from unittest.mock import patch
import requests
import frappe
-import frappe.utils
from frappe.auth import LoginAttemptTracker
from frappe.frappeclient import AuthError, FrappeClient
+from frappe.sessions import Session, get_expired_sessions, get_expiry_in_seconds
+from frappe.tests.test_api import FrappeAPITestCase
from frappe.tests.utils import FrappeTestCase
+from frappe.utils import get_site_url, now
+from frappe.utils.data import add_to_date
from frappe.www.login import _generate_temporary_login_link
@@ -26,9 +30,7 @@ class TestAuth(FrappeTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
- cls.HOST_NAME = frappe.get_site_config().host_name or frappe.utils.get_site_url(
- frappe.local.site
- )
+ cls.HOST_NAME = frappe.get_site_config().host_name or get_site_url(frappe.local.site)
cls.test_user_email = "test_auth@test.com"
cls.test_user_name = "test_auth_user"
cls.test_user_mobile = "+911234567890"
@@ -197,3 +199,27 @@ class TestLoginAttemptTracker(FrappeTestCase):
tracker.add_failure_attempt()
self.assertTrue(tracker.is_user_allowed())
+
+
+class TestSessionExpirty(FrappeAPITestCase):
+ def test_session_expires(self):
+ sid = self.sid # triggers login for test case login
+ s: Session = frappe.local.session_obj
+
+ expiry_in = get_expiry_in_seconds()
+ session_created = now()
+
+ # Try with 1% increments of times, it should always work
+ for step in range(0, 100, 1):
+ seconds_elapsed = expiry_in * step / 100
+
+ time_now = add_to_date(session_created, seconds=seconds_elapsed, as_string=True)
+ with patch("frappe.utils.now", return_value=time_now):
+ data = s.get_session_data_from_db()
+ self.assertEqual(data.user, "Administrator")
+
+ # 1% higher should immediately expire
+ time_now = add_to_date(session_created, seconds=expiry_in * 1.01, as_string=True)
+ with patch("frappe.utils.now", return_value=time_now):
+ self.assertIn(sid, get_expired_sessions())
+ self.assertFalse(s.get_session_data_from_db())
From c73d9fb7838178bb3d01db61ef3c76c38157b0dd Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 19:47:04 +0530
Subject: [PATCH 46/97] test: add perf test helper for counting rows read
---
frappe/tests/test_db.py | 21 ---------------------
frappe/tests/test_perf.py | 20 ++++++++++++++++++++
frappe/tests/utils.py | 20 ++++++++++++++++++++
3 files changed, 40 insertions(+), 21 deletions(-)
diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py
index f026726cfa..e8afba5d96 100644
--- a/frappe/tests/test_db.py
+++ b/frappe/tests/test_db.py
@@ -140,27 +140,6 @@ class TestDB(FrappeTestCase):
frappe.db.get_value("DocType", "DocField", order_by="creation desc, modified asc, name", run=0),
)
- def test_get_value_limits(self):
- # check both dict and list style filters
- filters = [{"enabled": 1}, [["enabled", "=", 1]]]
- for filter in filters:
- self.assertEqual(1, len(frappe.db.get_values("User", filters=filter, limit=1)))
- # count of last touched rows as per DB-API 2.0 https://peps.python.org/pep-0249/#rowcount
- self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount))
- self.assertEqual(2, len(frappe.db.get_values("User", filters=filter, limit=2)))
- self.assertGreaterEqual(2, cint(frappe.db._cursor.rowcount))
-
- # without limits length == count
- self.assertEqual(
- len(frappe.db.get_values("User", filters=filter)), frappe.db.count("User", filter)
- )
-
- frappe.db.get_value("User", filters=filter)
- self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount))
-
- frappe.db.exists("User", filter)
- self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount))
-
def test_escape(self):
frappe.db.escape("香港濟生堂製藥有限公司 - IT".encode())
diff --git a/frappe/tests/test_perf.py b/frappe/tests/test_perf.py
index 65f03c2f13..cc7d0b031d 100644
--- a/frappe/tests/test_perf.py
+++ b/frappe/tests/test_perf.py
@@ -27,6 +27,7 @@ from frappe.model.base_document import get_controller
from frappe.query_builder.utils import db_type_is
from frappe.tests.test_query_builder import run_only_if
from frappe.tests.utils import FrappeTestCase
+from frappe.utils import cint
from frappe.website.path_resolver import PathResolver
@@ -70,6 +71,25 @@ class TestPerformance(FrappeTestCase):
with self.assertQueryCount(0):
get_controller("User")
+ def test_get_value_limits(self):
+ # check both dict and list style filters
+ filters = [{"enabled": 1}, [["enabled", "=", 1]]]
+ for filter in filters:
+ with self.assertRowsRead(1):
+ self.assertEqual(1, len(frappe.db.get_values("User", filters=filter, limit=1)))
+ with self.assertRowsRead(2):
+ self.assertEqual(2, len(frappe.db.get_values("User", filters=filter, limit=2)))
+
+ self.assertEqual(
+ len(frappe.db.get_values("User", filters=filter)), frappe.db.count("User", filter)
+ )
+
+ with self.assertRowsRead(1):
+ frappe.db.get_value("User", filters=filter)
+
+ with self.assertRowsRead(1):
+ frappe.db.exists("User", filter)
+
def test_db_value_cache(self):
"""Link validation if repeated should just use db.value_cache, hence no extra queries"""
doc = frappe.get_last_doc("User")
diff --git a/frappe/tests/utils.py b/frappe/tests/utils.py
index 6e6c72052a..762cd885b0 100644
--- a/frappe/tests/utils.py
+++ b/frappe/tests/utils.py
@@ -92,6 +92,26 @@ class FrappeTestCase(unittest.TestCase):
finally:
frappe.db.sql = orig_sql
+ @contextmanager
+ def assertRowsRead(self, count):
+ rows_read = 0
+
+ def _sql_with_count(*args, **kwargs):
+ nonlocal rows_read
+
+ ret = orig_sql(*args, **kwargs)
+ # count of last touched rows as per DB-API 2.0 https://peps.python.org/pep-0249/#rowcount
+ rows_read += cint(frappe.db._cursor.rowcount)
+ return ret
+
+ try:
+ orig_sql = frappe.db.sql
+ frappe.db.sql = _sql_with_count
+ yield
+ self.assertLessEqual(rows_read, count, msg="Queries read more rows than expected")
+ finally:
+ frappe.db.sql = orig_sql
+
class MockedRequestTestCase(FrappeTestCase):
def setUp(self):
From e4bae5c8315c25da3402739dfa2c615ba68667f1 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 28 Jun 2023 19:39:37 +0530
Subject: [PATCH 47/97] perf: faster doc shared checks
- If document, explicitly query document
- If checking doctype then put limit and only see if 1 record is
returned.
---
frappe/core/doctype/docshare/test_docshare.py | 17 ++++++++++++++++-
frappe/permissions.py | 17 ++++++++++++-----
frappe/share.py | 16 ++++++++++++----
3 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/frappe/core/doctype/docshare/test_docshare.py b/frappe/core/doctype/docshare/test_docshare.py
index e080b0d4ff..125e829d9b 100644
--- a/frappe/core/doctype/docshare/test_docshare.py
+++ b/frappe/core/doctype/docshare/test_docshare.py
@@ -33,13 +33,28 @@ class TestDocShare(FrappeTestCase):
def test_doc_permission(self):
frappe.set_user(self.user)
+
self.assertFalse(self.event.has_permission())
frappe.set_user("Administrator")
frappe.share.add("Event", self.event.name, self.user)
frappe.set_user(self.user)
- self.assertTrue(self.event.has_permission())
+ # PERF: All share permission check should happen with maximum 1 query.
+ with self.assertRowsRead(1):
+ self.assertTrue(self.event.has_permission())
+
+ second_event = frappe.get_doc(
+ {
+ "doctype": "Event",
+ "subject": "test share event 2",
+ "starts_on": "2015-01-01 10:00:00",
+ "event_type": "Private",
+ }
+ ).insert()
+ frappe.share.add("Event", second_event.name, self.user)
+ with self.assertRowsRead(1):
+ self.assertTrue(self.event.has_permission())
def test_share_permission(self):
frappe.share.add("Event", self.event.name, self.user, write=1, share=1)
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 633d0e278d..e8ca0ecb3c 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -118,17 +118,24 @@ def has_permission(
def false_if_not_shared():
if ptype in ("read", "write", "share", "submit", "email", "print"):
- shared = frappe.share.get_shared(
- doctype, user, ["read" if ptype in ("email", "print") else ptype]
- )
+
+ rights = ["read" if ptype in ("email", "print") else ptype]
if doc:
doc_name = get_doc_name(doc)
- if doc_name in shared:
+ shared = frappe.share.get_shared(
+ doctype,
+ user,
+ rights=rights,
+ filters=[["share_name", "=", doc_name]],
+ limit=1,
+ )
+
+ if shared:
if ptype in ("read", "write", "share", "submit") or meta.permissions[0].get(ptype):
return True
- elif shared:
+ elif frappe.share.get_shared(doctype, user, rights=rights, limit=1):
# if atleast one shared doc of that type, then return True
# this is used in db_query to check if permission on DocType
return True
diff --git a/frappe/share.py b/frappe/share.py
index 6c2fb356a6..c068e063b2 100644
--- a/frappe/share.py
+++ b/frappe/share.py
@@ -141,7 +141,7 @@ def get_users(doctype, name):
)
-def get_shared(doctype, user=None, rights=None):
+def get_shared(doctype, user=None, rights=None, *, filters=None, limit=None):
"""Get list of shared document names for given user and DocType.
:param doctype: DocType of which shared names are queried.
@@ -154,14 +154,22 @@ def get_shared(doctype, user=None, rights=None):
if not rights:
rights = ["read"]
- filters = [[right, "=", 1] for right in rights]
- filters += [["share_doctype", "=", doctype]]
+ share_filters = [[right, "=", 1] for right in rights]
+ share_filters += [["share_doctype", "=", doctype]]
+ if filters:
+ share_filters += filters
+
or_filters = [["user", "=", user]]
if user != "Guest":
or_filters += [["everyone", "=", 1]]
shared_docs = frappe.get_all(
- "DocShare", fields=["share_name"], filters=filters, or_filters=or_filters, order_by=None
+ "DocShare",
+ fields=["share_name"],
+ filters=share_filters,
+ or_filters=or_filters,
+ order_by=None,
+ limit_page_length=limit,
)
return [doc.share_name for doc in shared_docs]
From 85145c2c1189a538280c9cc4d4cf78acece2e629 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Wed, 28 Jun 2023 17:22:40 +0200
Subject: [PATCH 48/97] fix: styling of group by button
---
frappe/public/scss/desk/report.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/scss/desk/report.scss b/frappe/public/scss/desk/report.scss
index 03e2763cd7..1db38529ed 100644
--- a/frappe/public/scss/desk/report.scss
+++ b/frappe/public/scss/desk/report.scss
@@ -100,11 +100,11 @@
.group-by-button {
margin: 5px;
- max-width: 125px;
}
.group-by-button.btn-primary-light {
color: var(--text-on-blue);
+ outline: 1px solid var(--bg-dark-blue);
}
.group-by-icon.active {
From 1668ba7d9eb7aa4dcff3233e95195a8720cec162 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 16:35:10 +0530
Subject: [PATCH 49/97] feat: Namespace all RQ jobs to site
---
frappe/utils/background_jobs.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index 7de7ef6692..8254a6fb87 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -84,9 +84,8 @@ def enqueue(
# To handle older implementations
is_async = kwargs.pop("async", is_async)
- if job_id:
- # namespace job ids to sites
- job_id = create_job_id(job_id)
+ # namespace job ids to sites
+ job_id = create_job_id(job_id)
if job_name:
deprecation_warning("Using enqueue with `job_name` is deprecated, use `job_id` instead.")
@@ -481,6 +480,9 @@ def test_job(s):
def create_job_id(job_id: str) -> str:
"""Generate unique job id for deduplication"""
+
+ if not job_id:
+ job_id = str(uuid4())
return f"{frappe.local.site}::{job_id}"
From 1092eef7bd8b71e741109db6f835af30af22a6c0 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 16:42:37 +0530
Subject: [PATCH 50/97] perf: faster pending jobs check
---
frappe/commands/scheduler.py | 4 ++--
frappe/tests/test_commands.py | 15 +++++++++++++++
frappe/utils/doctor.py | 9 +++++++++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/frappe/commands/scheduler.py b/frappe/commands/scheduler.py
index 6af3a2403e..5d453e3568 100755
--- a/frappe/commands/scheduler.py
+++ b/frappe/commands/scheduler.py
@@ -240,14 +240,14 @@ def start_worker_pool(queue, quiet=False, num_workers=2, burst=False):
@click.option("--site", help="site name")
@pass_context
def ready_for_migration(context, site=None):
- from frappe.utils.doctor import get_pending_jobs
+ from frappe.utils.doctor import any_job_pending
if not site:
site = get_site(context)
try:
frappe.init(site=site)
- pending_jobs = get_pending_jobs(site=site)
+ pending_jobs = any_job_pending(site=site)
if pending_jobs:
print(f"NOT READY for migration: site {site} has pending background jobs")
diff --git a/frappe/tests/test_commands.py b/frappe/tests/test_commands.py
index 7bda577bb6..cdf93a1870 100644
--- a/frappe/tests/test_commands.py
+++ b/frappe/tests/test_commands.py
@@ -20,9 +20,11 @@ from unittest.mock import patch
import click
from click import Command
from click.testing import CliRunner, Result
+from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
# imports - module imports
import frappe
+import frappe.commands.scheduler
import frappe.commands.site
import frappe.commands.utils
import frappe.recorder
@@ -760,6 +762,19 @@ class TestBenchBuild(BaseTestCommands):
)
+class TestSchedulerUtils(BaseTestCommands):
+ # Retry just in case there are stuck queued jobs
+ @retry(
+ retry=retry_if_exception_type(AssertionError),
+ stop=stop_after_attempt(3),
+ wait=wait_fixed(3),
+ reraise=True,
+ )
+ def test_ready_for_migrate(self):
+ with cli(frappe.commands.scheduler.ready_for_migration) as result:
+ self.assertEqual(result.exit_code, 0)
+
+
class TestCommandUtils(FrappeTestCase):
def test_bench_helper(self):
from frappe.utils.bench_helper import get_app_groups
diff --git a/frappe/utils/doctor.py b/frappe/utils/doctor.py
index 5b12a01990..002fd8b154 100644
--- a/frappe/utils/doctor.py
+++ b/frappe/utils/doctor.py
@@ -79,6 +79,15 @@ def get_pending_jobs(site=None):
return jobs_per_queue
+def any_job_pending(site: str) -> bool:
+ for queue in get_queue_list():
+ q = get_queue(queue)
+ for job_id in q.get_job_ids():
+ if job_id.startswith(site):
+ return True
+ return False
+
+
def check_number_of_workers():
return len(get_workers())
From 3ae2d19073598afad874344d35813b9937916889 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 16:56:59 +0530
Subject: [PATCH 51/97] perf: efficient RQ jobs filters
Assuming site's job start with site prefix it's much easier to filter
jobs by looking at job IDs instead of fetching entire job in memory.
---
frappe/core/doctype/rq_job/rq_job.py | 37 ++++++++++++++--------------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/frappe/core/doctype/rq_job/rq_job.py b/frappe/core/doctype/rq_job/rq_job.py
index 391ccd8dfd..9a67fae586 100644
--- a/frappe/core/doctype/rq_job/rq_job.py
+++ b/frappe/core/doctype/rq_job/rq_job.py
@@ -63,23 +63,15 @@ class RQJob(Document):
order_desc = "desc" in args.get("order_by", "")
- matched_job_ids = RQJob.get_matching_job_ids(args)
+ matched_job_ids = RQJob.get_matching_job_ids(args)[start : start + page_length]
- jobs = []
- for job_ids in create_batch(matched_job_ids, 100):
- jobs.extend(
- serialize_job(job)
- for job in Job.fetch_many(job_ids=job_ids, connection=get_redis_conn())
- if job and for_current_site(job)
- )
- if len(jobs) > start + page_length:
- # we have fetched enough. This is inefficient but because of site filtering TINA
- break
+ conn = get_redis_conn()
+ jobs = [serialize_job(job) for job in Job.fetch_many(job_ids=matched_job_ids, connection=conn)]
- return sorted(jobs, key=lambda j: j.modified, reverse=order_desc)[start : start + page_length]
+ return sorted(jobs, key=lambda j: j.modified, reverse=order_desc)
@staticmethod
- def get_matching_job_ids(args):
+ def get_matching_job_ids(args) -> list[str]:
filters = make_filter_dict(args.get("filters"))
queues = _eval_filters(filters.get("queue"), QUEUES)
@@ -92,7 +84,7 @@ class RQJob(Document):
for status in statuses:
matched_job_ids.extend(fetch_job_ids(queue, status))
- return matched_job_ids
+ return filter_current_site_jobs(matched_job_ids)
@check_permissions
def delete(self):
@@ -155,6 +147,12 @@ def for_current_site(job: Job) -> bool:
return job.kwargs.get("site") == frappe.local.site
+def filter_current_site_jobs(job_ids: list[str]) -> list[str]:
+ site = frappe.local.site
+
+ return [j for j in job_ids if j.startswith(site)]
+
+
def _eval_filters(filter, values: list[str]) -> list[str]:
if filter:
operator, operand = filter
@@ -186,10 +184,13 @@ def remove_failed_jobs():
frappe.only_for("System Manager")
for queue in get_queues():
fail_registry = queue.failed_job_registry
- for job_ids in create_batch(fail_registry.get_job_ids(), 100):
- for job in Job.fetch_many(job_ids=job_ids, connection=get_redis_conn()):
- if job and for_current_site(job):
- fail_registry.remove(job, delete_job=True)
+ failed_jobs = filter_current_site_jobs(fail_registry.get_job_ids())
+
+ # Delete in batches to avoid loading too many things in memory
+ conn = get_redis_conn()
+ for job_ids in create_batch(failed_jobs, 100):
+ for job in Job.fetch_many(job_ids=job_ids, connection=conn):
+ job and fail_registry.remove(job, delete_job=True)
def get_all_queued_jobs():
From d57c552e26aba55e26701b20e52677e757e33811 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 17:20:48 +0530
Subject: [PATCH 52/97] feat: frappe.enqueue with deduplication
use deduplicate=True and set job_id for automatic and mostly sane job deduplication.
---
frappe/core/doctype/rq_job/test_rq_job.py | 16 +++++++++++++-
frappe/utils/background_jobs.py | 26 ++++++++++++++++++++---
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/frappe/core/doctype/rq_job/test_rq_job.py b/frappe/core/doctype/rq_job/test_rq_job.py
index 6512902fb3..f5d5f89ed4 100644
--- a/frappe/core/doctype/rq_job/test_rq_job.py
+++ b/frappe/core/doctype/rq_job/test_rq_job.py
@@ -108,13 +108,27 @@ class TestRQJob(FrappeTestCase):
self.assertIn("quitting", cstr(stderr))
@timeout(20)
- def test_job_id_dedup(self):
+ def test_job_id_manual_dedup(self):
job_id = "test_dedup"
job = frappe.enqueue(self.BG_JOB, sleep=5, job_id=job_id)
self.assertTrue(is_job_enqueued(job_id))
self.check_status(job, "finished")
self.assertFalse(is_job_enqueued(job_id))
+ @timeout(20)
+ def test_auto_job_dedup(self):
+ job_id = "test_dedup"
+ job1 = frappe.enqueue(self.BG_JOB, sleep=2, job_id=job_id, deduplicate=True)
+ job2 = frappe.enqueue(self.BG_JOB, sleep=5, job_id=job_id, deduplicate=True)
+ self.assertIsNone(job2)
+ self.check_status(job1, "finished") # wait
+
+ # Failed jobs last longer, subsequent job should still pass with same ID.
+ job3 = frappe.enqueue(self.BG_JOB, fail=True, job_id=job_id, deduplicate=True)
+ self.check_status(job3, "failed")
+ job4 = frappe.enqueue(self.BG_JOB, sleep=1, job_id=job_id, deduplicate=True)
+ self.check_status(job4, "finished")
+
@timeout(20)
def test_enqueue_after_commit(self):
job_id = frappe.generate_hash()
diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py
index 8254a6fb87..be5291b771 100755
--- a/frappe/utils/background_jobs.py
+++ b/frappe/utils/background_jobs.py
@@ -66,6 +66,7 @@ def enqueue(
on_failure: Callable = None,
at_front: bool = False,
job_id: str = None,
+ deduplicate=False,
**kwargs,
) -> Job | Any:
"""
@@ -79,11 +80,26 @@ def enqueue(
:param job_name: [DEPRECATED] can be used to name an enqueue call, which can be used to prevent duplicate calls
:param now: if now=True, the method is executed via frappe.call
:param kwargs: keyword arguments to be passed to the method
+ :param deduplicate: do not re-queue job if it's already queued, requires job_id.
:param job_id: Assigning unique job id, which can be checked using `is_job_enqueued`
"""
# To handle older implementations
is_async = kwargs.pop("async", is_async)
+ if deduplicate:
+ if not job_id:
+ frappe.throw(_("`job_id` paramater is required for deduplication."))
+ job = get_job(job_id)
+ if job and job.get_status() in (JobStatus.QUEUED, JobStatus.STARTED):
+ frappe.logger().debug(f"Not queueing job {job.id} because it is in queue already")
+ return
+ elif job:
+ # delete job to avoid argument issues related to job args
+ # https://github.com/rq/rq/issues/793
+ job.delete()
+
+ # If job exists and is completed then delete it before re-queue
+
# namespace job ids to sites
job_id = create_job_id(job_id)
@@ -492,9 +508,13 @@ def is_job_enqueued(job_id: str) -> bool:
def get_job_status(job_id: str) -> JobStatus | None:
"""Get RQ job status, returns None if job is not found."""
+ job = get_job(job_id)
+ if job:
+ return job.get_status()
+
+
+def get_job(job_id: str) -> Job:
try:
- job = Job.fetch(create_job_id(job_id), connection=get_redis_conn())
+ return Job.fetch(create_job_id(job_id), connection=get_redis_conn())
except NoSuchJobError:
return None
-
- return job.get_status()
From 31d05b466a0b0cf0ae0b0bc4a107c1ca97e84395 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 17:14:53 +0530
Subject: [PATCH 53/97] perf: Email queue dedup using job id instead of name
---
frappe/email/queue.py | 25 ++++++++-----------------
1 file changed, 8 insertions(+), 17 deletions(-)
diff --git a/frappe/email/queue.py b/frappe/email/queue.py
index 0df88ebd5c..500a126f72 100755
--- a/frappe/email/queue.py
+++ b/frappe/email/queue.py
@@ -132,7 +132,6 @@ def return_unsubscribed_page(email, doctype, name):
def flush(from_test=False):
"""flush email queue, every time: called from scheduler"""
from frappe.email.doctype.email_queue.email_queue import send_mail
- from frappe.utils.background_jobs import get_jobs
# To avoid running jobs inside unit tests
if frappe.are_emails_muted():
@@ -142,24 +141,16 @@ def flush(from_test=False):
if cint(frappe.db.get_default("suspend_email_queue")) == 1:
return
- try:
- queued_jobs = set(get_jobs(site=frappe.local.site, key="job_name")[frappe.local.site])
- except Exception:
- queued_jobs = set()
-
for row in get_queue():
try:
- job_name = f"email_queue_sendmail_{row.name}"
- if job_name not in queued_jobs:
- frappe.enqueue(
- method=send_mail,
- email_queue_name=row.name,
- now=from_test,
- job_name=job_name,
- queue="short",
- )
- else:
- frappe.logger().debug(f"Not queueing job {job_name} because it is in queue already")
+ frappe.enqueue(
+ method=send_mail,
+ email_queue_name=row.name,
+ now=from_test,
+ job_id=f"email_queue_sendmail_{row.name}",
+ queue="short",
+ dedupicate=True,
+ )
except Exception:
frappe.get_doc("Email Queue", row.name).log_error()
From a52485cc53269e0c5d73b1c3d174e6dad4fcb6fe Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 17:34:29 +0530
Subject: [PATCH 54/97] feat: RQ jobs can show count
---
frappe/core/doctype/rq_job/rq_job.py | 3 +--
frappe/core/doctype/rq_job/rq_job_list.js | 3 +--
frappe/tests/test_background_jobs.py | 6 ++++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/frappe/core/doctype/rq_job/rq_job.py b/frappe/core/doctype/rq_job/rq_job.py
index 9a67fae586..659c81e5c4 100644
--- a/frappe/core/doctype/rq_job/rq_job.py
+++ b/frappe/core/doctype/rq_job/rq_job.py
@@ -99,8 +99,7 @@ class RQJob(Document):
@staticmethod
def get_count(args) -> int:
- # Can not be implemented efficiently due to site filtering hence ignored.
- return 0
+ return len(RQJob.get_matching_job_ids(args))
# None of these methods apply to virtual job doctype, overriden for sanity.
@staticmethod
diff --git a/frappe/core/doctype/rq_job/rq_job_list.js b/frappe/core/doctype/rq_job/rq_job_list.js
index aa05b411ba..7d140d668f 100644
--- a/frappe/core/doctype/rq_job/rq_job_list.js
+++ b/frappe/core/doctype/rq_job/rq_job_list.js
@@ -15,7 +15,6 @@ frappe.listview_settings["RQ Job"] = {
);
if (listview.list_view_settings) {
- listview.list_view_settings.disable_count = 1;
listview.list_view_settings.disable_sidebar_stats = 1;
}
@@ -57,6 +56,6 @@ frappe.listview_settings["RQ Job"] = {
}
listview.refresh();
- }, 5000);
+ }, 15000);
},
};
diff --git a/frappe/tests/test_background_jobs.py b/frappe/tests/test_background_jobs.py
index b6c1a0d694..99373a84a6 100644
--- a/frappe/tests/test_background_jobs.py
+++ b/frappe/tests/test_background_jobs.py
@@ -10,6 +10,7 @@ from frappe.tests.utils import FrappeTestCase
from frappe.utils.background_jobs import (
RQ_JOB_FAILURE_TTL,
RQ_RESULTS_TTL,
+ create_job_id,
execute_job,
generate_qname,
get_redis_conn,
@@ -54,11 +55,12 @@ class TestBackgroundJobs(FrappeTestCase):
def test_enqueue_call(self):
with patch.object(Queue, "enqueue_call") as mock_enqueue_call:
- frappe.enqueue(
+ job = frappe.enqueue(
"frappe.handler.ping",
queue="short",
timeout=300,
kwargs={"site": frappe.local.site},
+ job_id="test",
)
mock_enqueue_call.assert_called_once_with(
@@ -78,7 +80,7 @@ class TestBackgroundJobs(FrappeTestCase):
at_front=False,
failure_ttl=RQ_JOB_FAILURE_TTL,
result_ttl=RQ_RESULTS_TTL,
- job_id=None,
+ job_id=create_job_id("test"),
)
def test_job_hooks(self):
From c6a46e68122a9f0bc7309f6c76082e3ba6f424fd Mon Sep 17 00:00:00 2001
From: Smit Vora
Date: Fri, 30 Jun 2023 13:35:01 +0530
Subject: [PATCH 55/97] fix: correct condition check for dynamic filters
(#21530)
Co-authored-by: Sagar Vora
---
frappe/public/js/frappe/utils/dashboard_utils.js | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/frappe/public/js/frappe/utils/dashboard_utils.js b/frappe/public/js/frappe/utils/dashboard_utils.js
index 488aa20742..1058101fff 100644
--- a/frappe/public/js/frappe/utils/dashboard_utils.js
+++ b/frappe/public/js/frappe/utils/dashboard_utils.js
@@ -202,14 +202,16 @@ frappe.dashboard_utils = {
},
get_all_filters(doc) {
- let filters = JSON.parse(doc.filters_json || "null");
- let dynamic_filters = JSON.parse(doc.dynamic_filters_json || "null");
+ let filters = doc.filters_json ? JSON.parse(doc.filters_json) : null;
+ let dynamic_filters = doc.dynamic_filters_json
+ ? JSON.parse(doc.dynamic_filters_json)
+ : null;
- if (!dynamic_filters) {
+ if (!dynamic_filters || !Object.keys(dynamic_filters).length) {
return filters;
}
- if ($.isArray(dynamic_filters)) {
+ if (Array.isArray(dynamic_filters)) {
dynamic_filters.forEach((f) => {
try {
f[3] = eval(f[3]);
From 69d0060bdf631ed9888eed17eeb372636f566f4f Mon Sep 17 00:00:00 2001
From: Corentin Flr <10946971+cogk@users.noreply.github.com>
Date: Fri, 30 Jun 2023 11:52:29 +0200
Subject: [PATCH 56/97] chore: format code
---
frappe/website/page_renderers/static_page.py | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/frappe/website/page_renderers/static_page.py b/frappe/website/page_renderers/static_page.py
index f992743c6a..00162c0772 100644
--- a/frappe/website/page_renderers/static_page.py
+++ b/frappe/website/page_renderers/static_page.py
@@ -8,7 +8,18 @@ import frappe
from frappe.website.page_renderers.base_renderer import BaseRenderer
from frappe.website.utils import is_binary_file
-UNSUPPORTED_STATIC_PAGE_TYPES = ("html", "md", "js", "xml", "css", "txt", "py", "pyc", "json", "pyo")
+UNSUPPORTED_STATIC_PAGE_TYPES = (
+ "css",
+ "html",
+ "js",
+ "json",
+ "md",
+ "py",
+ "pyc",
+ "pyo",
+ "txt",
+ "xml",
+)
class StaticPage(BaseRenderer):
From 441495b561ed6df9a05ce6716c6439d58654ac6d Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 30 Jun 2023 17:57:40 +0530
Subject: [PATCH 57/97] refactor!: Drop support for currentsite.txt (#21536)
* refactor!: Drop currentsite.txt
- `bench use` will continue to work.
- Instead of txt file use common_site_config to set default site using `default_site` key.
- `FRAPPE_SITE` environment variable also works
* fix(DX): warn if non-empty currentsite.txt is present
---
frappe/commands/site.py | 7 +++++--
frappe/utils/bench_helper.py | 18 ++++++++++++++----
node_utils.js | 4 ----
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index d606bb78cf..01b3be9590 100644
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -700,9 +700,12 @@ def _use(site, sites_path="."):
def use(site, sites_path="."):
+ from frappe.installer import update_site_config
+
if os.path.exists(os.path.join(sites_path, site)):
- with open(os.path.join(sites_path, "currentsite.txt"), "w") as sitefile:
- sitefile.write(site)
+ sites_path = os.getcwd()
+ conifg = os.path.join(sites_path, "common_site_config.json")
+ update_site_config("default_site", site, validate=False, site_config_path=conifg)
print(f"Current Site set to {site}")
else:
print(f"Site {site} does not exist")
diff --git a/frappe/utils/bench_helper.py b/frappe/utils/bench_helper.py
index 01e611f021..14db5c8449 100644
--- a/frappe/utils/bench_helper.py
+++ b/frappe/utils/bench_helper.py
@@ -4,6 +4,7 @@ import os
import traceback
import warnings
from pathlib import Path
+from textwrap import dedent
import click
@@ -52,10 +53,19 @@ def get_sites(site_arg: str) -> list[str]:
return [site_arg]
elif os.environ.get("FRAPPE_SITE"):
return [os.environ.get("FRAPPE_SITE")]
- elif os.path.exists("currentsite.txt"):
- with open("currentsite.txt") as f:
- if site := f.read().strip():
- return [site]
+ elif default_site := frappe.get_conf().default_site:
+ return [default_site]
+ # This is not supported, just added here for warning.
+ elif (site := frappe.read_file("currentsite.txt")) and site.strip():
+ click.secho(
+ dedent(
+ f"""
+ WARNING: currentsite.txt is not supported anymore for setting default site. Use following command to set it as default site.
+ $ bench use {site}"""
+ ),
+ fg="red",
+ )
+
return []
diff --git a/node_utils.js b/node_utils.js
index 0b8c455875..4835a84433 100644
--- a/node_utils.js
+++ b/node_utils.js
@@ -31,10 +31,6 @@ function get_conf() {
if (process.env.FRAPPE_SITE) {
conf.default_site = process.env.FRAPPE_SITE;
}
- if (fs.existsSync("sites/currentsite.txt")) {
- conf.default_site = fs.readFileSync("sites/currentsite.txt").toString().trim();
- }
-
return conf;
}
From 97c1106acaede659fe30c1f7f95dc2217df972b9 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 12:19:28 +0530
Subject: [PATCH 58/97] refactor!: Remove doc typer code
- This hasn't worked since v13 refactor and no one has noticed.
- Needs better implementation.
---
frappe/public/js/frappe/views/formview.js | 5 --
socketio.js | 70 +++--------------------
2 files changed, 8 insertions(+), 67 deletions(-)
diff --git a/frappe/public/js/frappe/views/formview.js b/frappe/public/js/frappe/views/formview.js
index ec9db0e982..99bfe1fa01 100644
--- a/frappe/public/js/frappe/views/formview.js
+++ b/frappe/public/js/frappe/views/formview.js
@@ -52,11 +52,6 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
// set users that currently viewing the form
frappe.ui.form.FormViewers.set_users(data, "viewers");
});
-
- frappe.realtime.on("doc_typers", function (data) {
- // set users that currently typing on the form
- frappe.ui.form.FormViewers.set_users(data, "typers");
- });
}
this.initialized = true;
}
diff --git a/socketio.js b/socketio.js
index 31be39c847..4980e2aac3 100644
--- a/socketio.js
+++ b/socketio.js
@@ -114,24 +114,11 @@ io.on("connection", function (socket) {
socket.join(room);
// show who is currently viewing the form
- send_users(
- {
- socket: socket,
- doctype: doctype,
- docname: docname,
- },
- "view"
- );
-
- // show who is currently typing on the form
- send_users(
- {
- socket: socket,
- doctype: doctype,
- docname: docname,
- },
- "type"
- );
+ send_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
},
});
});
@@ -150,36 +137,6 @@ io.on("connection", function (socket) {
);
});
- socket.on("doc_typing", function (doctype, docname) {
- // show users that are currently typing on the form
- const room = get_typing_room(socket, doctype, docname);
- socket.join(room);
-
- send_users(
- {
- socket: socket,
- doctype: doctype,
- docname: docname,
- },
- "type"
- );
- });
-
- socket.on("doc_typing_stopped", function (doctype, docname) {
- // remove this user from the list of users currently typing on the form'
- const room = get_typing_room(socket, doctype, docname);
- socket.leave(room);
-
- send_users(
- {
- socket: socket,
- doctype: doctype,
- docname: docname,
- },
- "type"
- );
- });
-
socket.on("open_in_editor", (data) => {
let s = get_redis_subscriber("redis_queue");
s.publish("open_in_editor", JSON.stringify(data));
@@ -206,10 +163,6 @@ function get_open_doc_room(socket, doctype, docname) {
return get_site_name(socket) + ":open_doc:" + doctype + "/" + docname;
}
-function get_typing_room(socket, doctype, docname) {
- return get_site_name(socket) + ":typing:" + doctype + "/" + docname;
-}
-
function get_user_room(socket, user) {
return get_site_name(socket) + ":user:" + user || socket.user;
}
@@ -314,19 +267,14 @@ function can_subscribe_doctype(args) {
});
}
-function send_users(args, action) {
+function send_users(args) {
if (!(args && args.doctype && args.docname)) {
return;
}
const open_doc_room = get_open_doc_room(args.socket, args.doctype, args.docname);
- const room =
- action == "view"
- ? open_doc_room
- : get_typing_room(args.socket, args.doctype, args.docname);
-
- const clients = Array.from(io.sockets.adapter.rooms.get(room) || []);
+ const clients = Array.from(io.sockets.adapter.rooms.get(open_doc_room) || []);
let users = [];
io.sockets.sockets.forEach((sock) => {
@@ -335,10 +283,8 @@ function send_users(args, action) {
}
});
- const emit_event = action == "view" ? "doc_viewers" : "doc_typers";
-
// notify
- io.to(open_doc_room).emit(emit_event, {
+ io.to(open_doc_room).emit("doc_viewers", {
doctype: args.doctype,
docname: args.docname,
users: Array.from(new Set(users)),
From de5d1e0fe1a2d0e502c2a9da0be5e9436a5ad326 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 12:29:33 +0530
Subject: [PATCH 59/97] refactor: Consolidate doc viewer code
It's spread accross 3 different JS files.
It should be responsibility of 1 class.
---
frappe/public/js/frappe/form/form_viewers.js | 60 +++++++++++---------
frappe/public/js/frappe/views/formview.js | 5 --
2 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index 9d722403ca..a037392ae3 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -3,6 +3,7 @@ frappe.ui.form.FormViewers = class FormViewers {
this.frm = frm;
this.parent = parent;
this.parent.tooltip({ title: __("Currently Viewing") });
+ this.setup_events();
}
refresh() {
@@ -19,27 +20,36 @@ frappe.ui.form.FormViewers = class FormViewers {
});
this.parent.empty().append(avatar_group);
}
-};
-frappe.ui.form.FormViewers.set_users = function (data, type) {
- const doctype = data.doctype;
- const docname = data.docname;
- const docinfo = frappe.model.get_docinfo(doctype, docname);
+ setup_events() {
+ if (!this.initialized) {
+ let me = this;
+ frappe.realtime.on("doc_viewers", function (data) {
+ me.update_users(data);
+ });
+ }
+ this.initialized = true;
+ }
- const past_users = ((docinfo && docinfo[type]) || {}).past || [];
- const users = data.users || [];
- const new_users = users.filter((user) => !past_users.includes(user));
+ async update_users({ doctype, docname, users }) {
+ const docinfo = frappe.model.get_docinfo(doctype, docname);
+ const docinfo_key = "viewers";
- if (new_users.length === 0) return;
+ const past_users = ((docinfo && docinfo[docinfo_key]) || {}).past || [];
+ users = users || [];
+ const new_users = users.filter((user) => !past_users.includes(user));
+
+ if (new_users.length === 0) return;
+
+ await this.fetch_user_info(users);
- const set_and_refresh = () => {
const info = {
past: past_users.concat(new_users),
new: new_users,
current: users,
};
- frappe.model.set_docinfo(doctype, docname, type, info);
+ frappe.model.set_docinfo(doctype, docname, docinfo_key, info);
if (
cur_frm &&
@@ -48,24 +58,20 @@ frappe.ui.form.FormViewers.set_users = function (data, type) {
cur_frm.doc.name == docname &&
cur_frm.viewers
) {
- cur_frm.viewers.refresh(true, type);
+ cur_frm.viewers.refresh(true);
}
- };
-
- let unknown_users = [];
- for (let user of users) {
- if (!frappe.boot.user_info[user]) unknown_users.push(user);
}
- if (unknown_users.length === 0) {
- set_and_refresh();
- } else {
- // load additional user info
- frappe
- .xcall("frappe.desk.form.load.get_user_info_for_viewers", { users: unknown_users })
- .then((data) => {
- Object.assign(frappe.boot.user_info, data);
- set_and_refresh();
- });
+ async fetch_user_info(users) {
+ let unknown_users = [];
+ for (let user of users) {
+ if (!frappe.boot.user_info[user]) unknown_users.push(user);
+ }
+ if (!unknown_users) return;
+
+ const data = await frappe.xcall("frappe.desk.form.load.get_user_info_for_viewers", {
+ users: unknown_users,
+ });
+ Object.assign(frappe.boot.user_info, data);
}
};
diff --git a/frappe/public/js/frappe/views/formview.js b/frappe/public/js/frappe/views/formview.js
index 99bfe1fa01..4f58f92d0c 100644
--- a/frappe/public/js/frappe/views/formview.js
+++ b/frappe/public/js/frappe/views/formview.js
@@ -47,11 +47,6 @@ frappe.views.FormFactory = class FormFactory extends frappe.views.Factory {
$(document).on("page-change", function () {
frappe.ui.form.close_grid_form();
});
-
- frappe.realtime.on("doc_viewers", function (data) {
- // set users that currently viewing the form
- frappe.ui.form.FormViewers.set_users(data, "viewers");
- });
}
this.initialized = true;
}
From 94f182384c7abee14d08068199dfa7284cd3303c Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 12:57:17 +0530
Subject: [PATCH 60/97] refactor: move viewers to form
it's attached to form but managed by toolbar, needlessly convoluted
code.
---
frappe/public/js/frappe/form/form.js | 6 ++++++
frappe/public/js/frappe/form/form_viewers.js | 13 +++++++------
frappe/public/js/frappe/form/toolbar.js | 13 -------------
3 files changed, 13 insertions(+), 19 deletions(-)
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index 0a60b00af2..876be1867a 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -93,6 +93,11 @@ frappe.ui.form.Form = class FrappeForm {
page: this.page,
});
+ this.viewers = new frappe.ui.form.FormViewers({
+ frm: this,
+ parent: $('').prependTo(this.page.page_actions),
+ });
+
// navigate records keyboard shortcuts
this.add_form_keyboard_shortcuts();
@@ -709,6 +714,7 @@ frappe.ui.form.Form = class FrappeForm {
}
this.toolbar.refresh();
}
+ this.viewers.refresh();
this.dashboard.refresh();
frappe.breadcrumbs.update();
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index a037392ae3..b14939cb93 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -24,6 +24,7 @@ frappe.ui.form.FormViewers = class FormViewers {
setup_events() {
if (!this.initialized) {
let me = this;
+ frappe.realtime.off("doc_viewers");
frappe.realtime.on("doc_viewers", function (data) {
me.update_users(data);
});
@@ -52,13 +53,13 @@ frappe.ui.form.FormViewers = class FormViewers {
frappe.model.set_docinfo(doctype, docname, docinfo_key, info);
if (
- cur_frm &&
- cur_frm.doc &&
- cur_frm.doc.doctype === doctype &&
- cur_frm.doc.name == docname &&
- cur_frm.viewers
+ this.frm &&
+ this.frm.doc &&
+ this.frm.doc.doctype === doctype &&
+ this.frm.doc.name == docname &&
+ this.frm.viewers
) {
- cur_frm.viewers.refresh(true);
+ this.frm.viewers.refresh(true);
}
}
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index 6d9a3365c4..fa1d7330cf 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -13,7 +13,6 @@ frappe.ui.form.Toolbar = class Toolbar {
}
refresh() {
this.make_menu();
- this.make_viewers();
this.set_title();
this.page.clear_user_actions();
this.show_title_as_dirty();
@@ -272,18 +271,6 @@ frappe.ui.form.Toolbar = class Toolbar {
}
}
- make_viewers() {
- if (this.frm.viewers) {
- return;
- }
- this.frm.viewers = new frappe.ui.form.FormViewers({
- frm: this.frm,
- parent: $('').prependTo(
- this.frm.page.page_actions
- ),
- });
- }
-
make_navigation() {
// Navigate
if (!this.frm.is_new() && !this.frm.meta.issingle) {
From 3511f82dc220b09fca5a21d414693afe3189159d Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 13:07:59 +0530
Subject: [PATCH 61/97] refactor: dont rely on docinfo for form viewers
---
frappe/public/js/frappe/form/form_viewers.js | 52 +++++++-------------
1 file changed, 17 insertions(+), 35 deletions(-)
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index b14939cb93..15a6dc4968 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -3,17 +3,18 @@ frappe.ui.form.FormViewers = class FormViewers {
this.frm = frm;
this.parent = parent;
this.parent.tooltip({ title: __("Currently Viewing") });
+
+ this.past_users = []; // Remember last users to compute changes
+ this.active_users = []; // current users viewing this form
this.setup_events();
}
refresh() {
- let users = this.frm.get_docinfo()["viewers"];
- if (!users || !users.current || !users.current.length) {
+ if (!this.active_users.length) {
this.parent.empty();
return;
}
-
- let currently_viewing = users.current.filter((user) => user != frappe.session.user);
+ let currently_viewing = this.active_users.filter((user) => user != frappe.session.user);
let avatar_group = frappe.avatar_group(currently_viewing, 5, {
align: "left",
overlap: true,
@@ -22,44 +23,25 @@ frappe.ui.form.FormViewers = class FormViewers {
}
setup_events() {
- if (!this.initialized) {
- let me = this;
- frappe.realtime.off("doc_viewers");
- frappe.realtime.on("doc_viewers", function (data) {
- me.update_users(data);
- });
- }
- this.initialized = true;
+ let me = this;
+ frappe.realtime.off("doc_viewers");
+ frappe.realtime.on("doc_viewers", function (data) {
+ me.update_users(data);
+ });
}
- async update_users({ doctype, docname, users }) {
- const docinfo = frappe.model.get_docinfo(doctype, docname);
- const docinfo_key = "viewers";
-
- const past_users = ((docinfo && docinfo[docinfo_key]) || {}).past || [];
- users = users || [];
- const new_users = users.filter((user) => !past_users.includes(user));
-
+ async update_users({ doctype, docname, users = [] }) {
+ // TODO: Do symmetric differenc here, user can be removed or added
+ const new_users = users.filter((user) => !this.past_users.includes(user));
if (new_users.length === 0) return;
await this.fetch_user_info(users);
- const info = {
- past: past_users.concat(new_users),
- new: new_users,
- current: users,
- };
+ this.active_users = users;
+ this.past_users = users;
- frappe.model.set_docinfo(doctype, docname, docinfo_key, info);
-
- if (
- this.frm &&
- this.frm.doc &&
- this.frm.doc.doctype === doctype &&
- this.frm.doc.name == docname &&
- this.frm.viewers
- ) {
- this.frm.viewers.refresh(true);
+ if (this.frm?.doc?.doctype === doctype && this.frm?.doc?.name == docname) {
+ this.refresh();
}
}
From fbcc594986e328cfc95d14add4668853f482dce6 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 13:12:36 +0530
Subject: [PATCH 62/97] fix: Correctly update form viewers
People who stopped viewing forms weren't removed, even though event was
sent.
---
frappe/public/js/frappe/form/form_viewers.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index 15a6dc4968..db43f86a62 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -14,8 +14,7 @@ frappe.ui.form.FormViewers = class FormViewers {
this.parent.empty();
return;
}
- let currently_viewing = this.active_users.filter((user) => user != frappe.session.user);
- let avatar_group = frappe.avatar_group(currently_viewing, 5, {
+ let avatar_group = frappe.avatar_group(this.active_users, 5, {
align: "left",
overlap: true,
});
@@ -31,9 +30,13 @@ frappe.ui.form.FormViewers = class FormViewers {
}
async update_users({ doctype, docname, users = [] }) {
- // TODO: Do symmetric differenc here, user can be removed or added
- const new_users = users.filter((user) => !this.past_users.includes(user));
- if (new_users.length === 0) return;
+ users = users.filter((u) => u != frappe.session.user);
+
+ const added_users = users.filter((user) => !this.past_users.includes(user));
+ const removed_users = this.past_users.filter((user) => !users.includes(user));
+ const changed_users = [...added_users, ...removed_users];
+
+ if (changed_users.length === 0) return;
await this.fetch_user_info(users);
From 38f04be747a461813bde8e5278e8077fd0d6901a Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 13:22:23 +0530
Subject: [PATCH 63/97] fix: remove hacky logic for doc open and doc close
How and why is this so complicated?
- If doc is opned - send doc open event
- If doc gets closed - send doc close event.
No need to rememeber last doc and do weird logic on top of it.
---
frappe/public/js/frappe/socketio_client.js | 28 +---------------------
1 file changed, 1 insertion(+), 27 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index f67da84ef4..a709261f08 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -162,36 +162,10 @@ frappe.socketio = {
});
},
doc_open: function (doctype, docname) {
- // notify that the user has opened this doc, if not already notified
- if (
- !frappe.socketio.last_doc ||
- frappe.socketio.last_doc[0] != doctype ||
- frappe.socketio.last_doc[1] != docname
- ) {
- frappe.socketio.socket.emit("doc_open", doctype, docname);
-
- frappe.socketio.last_doc &&
- frappe.socketio.doc_close(
- frappe.socketio.last_doc[0],
- frappe.socketio.last_doc[1]
- );
- }
- frappe.socketio.last_doc = [doctype, docname];
+ frappe.socketio.socket.emit("doc_open", doctype, docname);
},
doc_close: function (doctype, docname) {
- // notify that the user has closed this doc
frappe.socketio.socket.emit("doc_close", doctype, docname);
-
- // if the doc is closed the user has also stopped typing
- frappe.socketio.socket.emit("doc_typing_stopped", doctype, docname);
- },
- form_typing: function (doctype, docname) {
- // notifiy that the user is typing on the doc
- frappe.socketio.socket.emit("doc_typing", doctype, docname);
- },
- form_stopped_typing: function (doctype, docname) {
- // notifiy that the user has stopped typing
- frappe.socketio.socket.emit("doc_typing_stopped", doctype, docname);
},
setup_listeners: function () {
frappe.socketio.socket.on("task_status_change", function (data) {
From d772365d5d6bdc938f1923448b393584650e9201 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 13:24:16 +0530
Subject: [PATCH 64/97] fix: dont query if unknown_users are empty
---
frappe/public/js/frappe/form/form_viewers.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/public/js/frappe/form/form_viewers.js b/frappe/public/js/frappe/form/form_viewers.js
index db43f86a62..bc03687b45 100644
--- a/frappe/public/js/frappe/form/form_viewers.js
+++ b/frappe/public/js/frappe/form/form_viewers.js
@@ -53,7 +53,7 @@ frappe.ui.form.FormViewers = class FormViewers {
for (let user of users) {
if (!frappe.boot.user_info[user]) unknown_users.push(user);
}
- if (!unknown_users) return;
+ if (!unknown_users.length) return;
const data = await frappe.xcall("frappe.desk.form.load.get_user_info_for_viewers", {
users: unknown_users,
From 0ea7f77dd13471da03f8b5e6e4feaaf28c3e6051 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 14:09:40 +0530
Subject: [PATCH 65/97] perf: Remove socketio reconnect attempts
It works just fine without it. This sends duplicate events.
---
frappe/public/js/frappe/socketio_client.js | 25 ----------------------
1 file changed, 25 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index a709261f08..20e95dff56 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -52,7 +52,6 @@ frappe.socketio = {
});
frappe.socketio.setup_listeners();
- frappe.socketio.setup_reconnect();
$(document).on("form-load form-rename", function (e, frm) {
if (!frm.doc || frm.is_new()) {
@@ -175,30 +174,6 @@ frappe.socketio = {
frappe.socketio.process_response(data, "progress");
});
},
- setup_reconnect: function () {
- // subscribe again to open_tasks
- frappe.socketio.socket.on("connect", function () {
- // wait for 5 seconds before subscribing again
- // because it takes more time to start python server than nodejs server
- // and we use validation requests to python server for subscribing
- setTimeout(function () {
- $.each(frappe.socketio.open_tasks, function (task_id, opts) {
- frappe.socketio.subscribe(task_id, opts);
- });
-
- // re-connect open docs
- $.each(frappe.socketio.open_docs, function (d) {
- if (locals[d.doctype] && locals[d.doctype][d.name]) {
- frappe.socketio.doc_subscribe(d.doctype, d.name);
- }
- });
-
- if (cur_frm && cur_frm.doc && !cur_frm.is_new()) {
- frappe.socketio.doc_open(cur_frm.doc.doctype, cur_frm.doc.name);
- }
- }, 5000);
- });
- },
process_response: function (data, method) {
if (!data) {
return;
From 73f388628f34493687dda0b80d9bb269be02ca82 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 14:20:01 +0530
Subject: [PATCH 66/97] refactor: Convert socketio client to class
---
frappe/public/js/frappe/socketio_client.js | 69 ++++++++++++----------
1 file changed, 38 insertions(+), 31 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 20e95dff56..eeb21fc609 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -1,10 +1,13 @@
import { io } from "socket.io-client";
-frappe.socketio = {
- open_tasks: {},
- open_docs: [],
- emit_queue: [],
- init: function (port = 3000) {
+class SocketIOCient {
+ constructor() {
+ this.open_tasks = {};
+ this.open_docs = [];
+ this.emit_queue = [];
+ }
+
+ init(port = 3000) {
if (frappe.boot.disable_async) {
return;
}
@@ -101,8 +104,9 @@ frappe.socketio = {
frappe.socketio.doc_close(cur_frm.doctype, cur_frm.docname);
});
- },
- get_host: function (port = 3000) {
+ }
+
+ get_host(port = 3000) {
var host = window.location.origin;
if (window.dev_server) {
var parts = host.split(":");
@@ -113,28 +117,29 @@ frappe.socketio = {
host = host + ":" + port;
}
return host;
- },
- subscribe: function (task_id, opts) {
+ }
+
+ subscribe(task_id, opts) {
// TODO DEPRECATE
frappe.socketio.socket.emit("task_subscribe", task_id);
frappe.socketio.socket.emit("progress_subscribe", task_id);
frappe.socketio.open_tasks[task_id] = opts;
- },
- task_subscribe: function (task_id) {
+ }
+ task_subscribe(task_id) {
frappe.socketio.socket.emit("task_subscribe", task_id);
- },
- task_unsubscribe: function (task_id) {
+ }
+ task_unsubscribe(task_id) {
frappe.socketio.socket.emit("task_unsubscribe", task_id);
- },
- doctype_subscribe: function (doctype) {
+ }
+ doctype_subscribe(doctype) {
frappe.socketio.socket.emit("doctype_subscribe", doctype);
- },
- doctype_unsubscribe: function (doctype) {
+ }
+ doctype_unsubscribe(doctype) {
frappe.socketio.socket.emit("doctype_unsubscribe", doctype);
- },
- doc_subscribe: function (doctype, docname) {
+ }
+ doc_subscribe(doctype, docname) {
if (frappe.flags.doc_subscribe) {
console.log("throttled");
return;
@@ -149,8 +154,8 @@ frappe.socketio = {
frappe.socketio.socket.emit("doc_subscribe", doctype, docname);
frappe.socketio.open_docs.push({ doctype: doctype, docname: docname });
- },
- doc_unsubscribe: function (doctype, docname) {
+ }
+ doc_unsubscribe(doctype, docname) {
frappe.socketio.socket.emit("doc_unsubscribe", doctype, docname);
frappe.socketio.open_docs = $.filter(frappe.socketio.open_docs, function (d) {
if (d.doctype === doctype && d.name === docname) {
@@ -159,22 +164,22 @@ frappe.socketio = {
return d;
}
});
- },
- doc_open: function (doctype, docname) {
+ }
+ doc_open(doctype, docname) {
frappe.socketio.socket.emit("doc_open", doctype, docname);
- },
- doc_close: function (doctype, docname) {
+ }
+ doc_close(doctype, docname) {
frappe.socketio.socket.emit("doc_close", doctype, docname);
- },
- setup_listeners: function () {
+ }
+ setup_listeners() {
frappe.socketio.socket.on("task_status_change", function (data) {
frappe.socketio.process_response(data, data.status.toLowerCase());
});
frappe.socketio.socket.on("task_progress", function (data) {
frappe.socketio.process_response(data, "progress");
});
- },
- process_response: function (data, method) {
+ }
+ process_response(data, method) {
if (!data) {
return;
}
@@ -200,8 +205,10 @@ frappe.socketio = {
if (data.status_code && data.status_code > 400 && opts.error) {
opts.error(data);
}
- },
-};
+ }
+}
+
+frappe.socketio = new SocketIOCient();
frappe.provide("frappe.realtime");
frappe.realtime.on = function (event, callback) {
From 7591f3fd62aaa8c1a31310f610e2556d024c0dfd Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 14:29:23 +0530
Subject: [PATCH 67/97] refactor: merge frappe.realtime and frappe.socketio
frappe.realtime should be the api which encapsulates socketio.
---
frappe/public/js/frappe/socketio_client.js | 115 +++++++++++----------
1 file changed, 62 insertions(+), 53 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index eeb21fc609..0e9831e7a4 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -1,45 +1,61 @@
import { io } from "socket.io-client";
-class SocketIOCient {
+frappe.provide("frappe.realtime");
+
+class RealTimeClient {
constructor() {
this.open_tasks = {};
this.open_docs = [];
this.emit_queue = [];
}
- init(port = 3000) {
+ on(event, callback) {
+ if (this.socket) {
+ this.socket.on(event, callback);
+ }
+ }
+
+ off(event, callback) {
+ if (this.socket) {
+ this.socket.off(event, callback);
+ }
+ }
+
+ init(port = 9000) {
if (frappe.boot.disable_async) {
return;
}
- if (frappe.socketio.socket) {
+ if (this.socket) {
return;
}
+ let me = this;
+
// Enable secure option when using HTTPS
if (window.location.protocol == "https:") {
- frappe.socketio.socket = io.connect(frappe.socketio.get_host(port), {
+ this.socket = io.connect(this.get_host(port), {
secure: true,
withCredentials: true,
reconnectionAttempts: 3,
});
} else if (window.location.protocol == "http:") {
- frappe.socketio.socket = io.connect(frappe.socketio.get_host(port), {
+ this.socket = io.connect(this.get_host(port), {
withCredentials: true,
reconnectionAttempts: 3,
});
}
- if (!frappe.socketio.socket) {
- console.log("Unable to connect to " + frappe.socketio.get_host(port));
+ if (!this.socket) {
+ console.log("Unable to connect to " + this.get_host(port));
return;
}
- frappe.socketio.socket.on("msgprint", function (message) {
+ this.socket.on("msgprint", function (message) {
frappe.msgprint(message);
});
- frappe.socketio.socket.on("progress", function (data) {
+ this.socket.on("progress", function (data) {
if (data.progress) {
data.percent = (flt(data.progress[0]) / data.progress[1]) * 100;
}
@@ -54,30 +70,29 @@ class SocketIOCient {
}
});
- frappe.socketio.setup_listeners();
+ this.setup_listeners();
$(document).on("form-load form-rename", function (e, frm) {
if (!frm.doc || frm.is_new()) {
return;
}
- for (var i = 0, l = frappe.socketio.open_docs.length; i < l; i++) {
- var d = frappe.socketio.open_docs[i];
+ for (var i = 0, l = me.open_docs.length; i < l; i++) {
+ var d = me.open_docs[i];
if (frm.doctype == d.doctype && frm.docname == d.name) {
// already subscribed
return false;
}
}
- frappe.socketio.doc_subscribe(frm.doctype, frm.docname);
+ me.doc_subscribe(frm.doctype, frm.docname);
});
$(document).on("form-refresh", function (e, frm) {
if (!frm.doc || frm.is_new()) {
return;
}
-
- frappe.socketio.doc_open(frm.doctype, frm.docname);
+ me.doc_open(frm.doctype, frm.docname);
});
$(document).on("form-unload", function (e, frm) {
@@ -85,16 +100,16 @@ class SocketIOCient {
return;
}
- // frappe.socketio.doc_unsubscribe(frm.doctype, frm.docname);
- frappe.socketio.doc_close(frm.doctype, frm.docname);
+ // me.doc_unsubscribe(frm.doctype, frm.docname);
+ me.doc_close(frm.doctype, frm.docname);
});
$(document).on("form-typing", function (e, frm) {
- frappe.socketio.form_typing(frm.doctype, frm.docname);
+ me.form_typing(frm.doctype, frm.docname);
});
$(document).on("form-stopped-typing", function (e, frm) {
- frappe.socketio.form_stopped_typing(frm.doctype, frm.docname);
+ me.form_stopped_typing(frm.doctype, frm.docname);
});
window.addEventListener("beforeunload", () => {
@@ -102,7 +117,7 @@ class SocketIOCient {
return;
}
- frappe.socketio.doc_close(cur_frm.doctype, cur_frm.docname);
+ me.doc_close(cur_frm.doctype, cur_frm.docname);
});
}
@@ -122,22 +137,22 @@ class SocketIOCient {
subscribe(task_id, opts) {
// TODO DEPRECATE
- frappe.socketio.socket.emit("task_subscribe", task_id);
- frappe.socketio.socket.emit("progress_subscribe", task_id);
+ this.socket.emit("task_subscribe", task_id);
+ this.socket.emit("progress_subscribe", task_id);
- frappe.socketio.open_tasks[task_id] = opts;
+ this.open_tasks[task_id] = opts;
}
task_subscribe(task_id) {
- frappe.socketio.socket.emit("task_subscribe", task_id);
+ this.socket.emit("task_subscribe", task_id);
}
task_unsubscribe(task_id) {
- frappe.socketio.socket.emit("task_unsubscribe", task_id);
+ this.socket.emit("task_unsubscribe", task_id);
}
doctype_subscribe(doctype) {
- frappe.socketio.socket.emit("doctype_subscribe", doctype);
+ this.socket.emit("doctype_subscribe", doctype);
}
doctype_unsubscribe(doctype) {
- frappe.socketio.socket.emit("doctype_unsubscribe", doctype);
+ this.socket.emit("doctype_unsubscribe", doctype);
}
doc_subscribe(doctype, docname) {
if (frappe.flags.doc_subscribe) {
@@ -152,12 +167,12 @@ class SocketIOCient {
frappe.flags.doc_subscribe = false;
}, 1000);
- frappe.socketio.socket.emit("doc_subscribe", doctype, docname);
- frappe.socketio.open_docs.push({ doctype: doctype, docname: docname });
+ this.socket.emit("doc_subscribe", doctype, docname);
+ this.open_docs.push({ doctype: doctype, docname: docname });
}
doc_unsubscribe(doctype, docname) {
- frappe.socketio.socket.emit("doc_unsubscribe", doctype, docname);
- frappe.socketio.open_docs = $.filter(frappe.socketio.open_docs, function (d) {
+ this.socket.emit("doc_unsubscribe", doctype, docname);
+ this.open_docs = $.filter(frappe.socketio.open_docs, function (d) {
if (d.doctype === doctype && d.name === docname) {
return null;
} else {
@@ -166,17 +181,17 @@ class SocketIOCient {
});
}
doc_open(doctype, docname) {
- frappe.socketio.socket.emit("doc_open", doctype, docname);
+ this.socket.emit("doc_open", doctype, docname);
}
doc_close(doctype, docname) {
- frappe.socketio.socket.emit("doc_close", doctype, docname);
+ this.socket.emit("doc_close", doctype, docname);
}
setup_listeners() {
- frappe.socketio.socket.on("task_status_change", function (data) {
- frappe.socketio.process_response(data, data.status.toLowerCase());
+ this.socket.on("task_status_change", function (data) {
+ this.process_response(data, data.status.toLowerCase());
});
- frappe.socketio.socket.on("task_progress", function (data) {
- frappe.socketio.process_response(data, "progress");
+ this.socket.on("task_progress", function (data) {
+ this.process_response(data, "progress");
});
}
process_response(data, method) {
@@ -185,7 +200,7 @@ class SocketIOCient {
}
// success
- var opts = frappe.socketio.open_tasks[data.task_id];
+ var opts = this.open_tasks[data.task_id];
if (opts[method]) {
opts[method](data);
}
@@ -206,21 +221,15 @@ class SocketIOCient {
opts.error(data);
}
}
+
+ publish(event, message) {
+ if (this.socket) {
+ this.socket.emit(event, message);
+ }
+ }
}
-frappe.socketio = new SocketIOCient();
+frappe.realtime = new RealTimeClient();
-frappe.provide("frappe.realtime");
-frappe.realtime.on = function (event, callback) {
- frappe.socketio.socket && frappe.socketio.socket.on(event, callback);
-};
-
-frappe.realtime.off = function (event, callback) {
- frappe.socketio.socket && frappe.socketio.socket.off(event, callback);
-};
-
-frappe.realtime.publish = function (event, message) {
- if (frappe.socketio.socket) {
- frappe.socketio.socket.emit(event, message);
- }
-};
+// backward compatbility
+frappe.socketio = frappe.realtime;
From 43ec9fe2cc2d4cd84f9d3f26d53eb345dc4cf2a4 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 14:43:27 +0530
Subject: [PATCH 68/97] refactor: simplify open doc checks
---
frappe/public/js/frappe/socketio_client.js | 24 ++++++----------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 0e9831e7a4..c21733130e 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -5,7 +5,7 @@ frappe.provide("frappe.realtime");
class RealTimeClient {
constructor() {
this.open_tasks = {};
- this.open_docs = [];
+ this.open_docs = new Set();
this.emit_queue = [];
}
@@ -76,15 +76,6 @@ class RealTimeClient {
if (!frm.doc || frm.is_new()) {
return;
}
-
- for (var i = 0, l = me.open_docs.length; i < l; i++) {
- var d = me.open_docs[i];
- if (frm.doctype == d.doctype && frm.docname == d.name) {
- // already subscribed
- return false;
- }
- }
-
me.doc_subscribe(frm.doctype, frm.docname);
});
@@ -159,6 +150,9 @@ class RealTimeClient {
console.log("throttled");
return;
}
+ if (this.open_docs.has(`${doctype}:${docname}`)) {
+ return;
+ }
frappe.flags.doc_subscribe = true;
@@ -168,17 +162,11 @@ class RealTimeClient {
}, 1000);
this.socket.emit("doc_subscribe", doctype, docname);
- this.open_docs.push({ doctype: doctype, docname: docname });
+ this.open_docs.add(`${doctype}:${docname}`);
}
doc_unsubscribe(doctype, docname) {
this.socket.emit("doc_unsubscribe", doctype, docname);
- this.open_docs = $.filter(frappe.socketio.open_docs, function (d) {
- if (d.doctype === doctype && d.name === docname) {
- return null;
- } else {
- return d;
- }
- });
+ return this.open_docs.delete(`${doctype}:${docname}`);
}
doc_open(doctype, docname) {
this.socket.emit("doc_open", doctype, docname);
From c3a37421d6b405c58b0eba6d2e30d3fdd244a38a Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 14:46:25 +0530
Subject: [PATCH 69/97] chore: remove typing code
---
frappe/public/js/frappe/socketio_client.js | 8 --------
1 file changed, 8 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index c21733130e..5c625a9346 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -95,14 +95,6 @@ class RealTimeClient {
me.doc_close(frm.doctype, frm.docname);
});
- $(document).on("form-typing", function (e, frm) {
- me.form_typing(frm.doctype, frm.docname);
- });
-
- $(document).on("form-stopped-typing", function (e, frm) {
- me.form_stopped_typing(frm.doctype, frm.docname);
- });
-
window.addEventListener("beforeunload", () => {
if (!cur_frm || !cur_frm.doc || cur_frm.is_new()) {
return;
From 4ea6f3d6726e62a2b28cfb4e4999d9cd0b58ebd9 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 15:01:19 +0530
Subject: [PATCH 70/97] perf: dont send doc view updates to self
---
socketio.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/socketio.js b/socketio.js
index 4980e2aac3..285ccfd96a 100644
--- a/socketio.js
+++ b/socketio.js
@@ -271,7 +271,6 @@ function send_users(args) {
if (!(args && args.doctype && args.docname)) {
return;
}
-
const open_doc_room = get_open_doc_room(args.socket, args.doctype, args.docname);
const clients = Array.from(io.sockets.adapter.rooms.get(open_doc_room) || []);
@@ -283,6 +282,9 @@ function send_users(args) {
}
});
+ // dont send update to self. meaningless.
+ if (users.length == 1 && users[0] == args.socket.user) return;
+
// notify
io.to(open_doc_room).emit("doc_viewers", {
doctype: args.doctype,
From b2366bf8a620286bfeb2a3e999198fd2f75371f1 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 15:03:57 +0530
Subject: [PATCH 71/97] fix: accurately handle socket close/loss event
---
frappe/public/js/frappe/socketio_client.js | 9 -----
socketio.js | 41 ++++++++++++++--------
2 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 5c625a9346..9e70e6a835 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -91,17 +91,8 @@ class RealTimeClient {
return;
}
- // me.doc_unsubscribe(frm.doctype, frm.docname);
me.doc_close(frm.doctype, frm.docname);
});
-
- window.addEventListener("beforeunload", () => {
- if (!cur_frm || !cur_frm.doc || cur_frm.is_new()) {
- return;
- }
-
- me.doc_close(cur_frm.doctype, cur_frm.docname);
- });
}
get_host(port = 3000) {
diff --git a/socketio.js b/socketio.js
index 285ccfd96a..e4570bcfce 100644
--- a/socketio.js
+++ b/socketio.js
@@ -42,6 +42,7 @@ io.use((socket, next) => {
socket.user = res.body.message.user;
socket.user_type = res.body.message.user_type;
socket.sid = cookies.sid;
+ socket.subscribed_documents = [];
next();
})
.catch((e) => {
@@ -93,14 +94,14 @@ io.on("connection", function (socket) {
doctype,
docname,
callback: () => {
- var room = get_doc_room(socket, doctype, docname);
+ let room = get_doc_room(socket, doctype, docname);
socket.join(room);
},
});
});
socket.on("doc_unsubscribe", function (doctype, docname) {
- var room = get_doc_room(socket, doctype, docname);
+ let room = get_doc_room(socket, doctype, docname);
socket.leave(room);
});
@@ -110,11 +111,12 @@ io.on("connection", function (socket) {
doctype,
docname,
callback: () => {
- var room = get_open_doc_room(socket, doctype, docname);
+ let room = get_open_doc_room(socket, doctype, docname);
socket.join(room);
+ socket.subscribed_documents.push([doctype, docname]);
// show who is currently viewing the form
- send_users({
+ notify_subscribed_doc_users({
socket: socket,
doctype: doctype,
docname: docname,
@@ -125,16 +127,17 @@ io.on("connection", function (socket) {
socket.on("doc_close", function (doctype, docname) {
// remove this user from the list of 'who is currently viewing the form'
- var room = get_open_doc_room(socket, doctype, docname);
+ let room = get_open_doc_room(socket, doctype, docname);
socket.leave(room);
- send_users(
- {
- socket: socket,
- doctype: doctype,
- docname: docname,
- },
- "view"
- );
+ socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
+ !(dt == doctype && dn == docname);
+ });
+
+ notify_subscribed_doc_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
});
socket.on("open_in_editor", (data) => {
@@ -267,7 +270,7 @@ function can_subscribe_doctype(args) {
});
}
-function send_users(args) {
+function notify_subscribed_doc_users(args) {
if (!(args && args.doctype && args.docname)) {
return;
}
@@ -292,3 +295,13 @@ function send_users(args) {
users: Array.from(new Set(users)),
});
}
+
+io.sockets.on("connection", function (socket) {
+ socket.on("disconnect", () => user_disconnected(socket));
+});
+
+function user_disconnected(socket) {
+ socket.subscribed_documents.forEach(([doctype, docname]) => {
+ notify_subscribed_doc_users({ socket, doctype, docname });
+ });
+}
From 5e4e60b5090d275fc997dce3080f71760068a216 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 15:53:59 +0530
Subject: [PATCH 72/97] refactor: Split socketio in multiple logical files
---
realtime/index.js | 307 +++++++++++++++++++++++++++++++++++++++++++++
socketio.js | 308 +---------------------------------------------
2 files changed, 308 insertions(+), 307 deletions(-)
create mode 100644 realtime/index.js
diff --git a/realtime/index.js b/realtime/index.js
new file mode 100644
index 0000000000..88a621c983
--- /dev/null
+++ b/realtime/index.js
@@ -0,0 +1,307 @@
+const cookie = require("cookie");
+const request = require("superagent");
+
+const { get_conf, get_redis_subscriber } = require("../node_utils");
+const conf = get_conf();
+const log = console.log; // eslint-disable-line
+const subscriber = get_redis_subscriber();
+
+const io = require("socket.io")(conf.socketio_port, {
+ cors: {
+ // Should be fine since we are ensuring whether hostname and origin are same before adding setting listeners for s socket
+ origin: true,
+ credentials: true,
+ },
+});
+
+io.use((socket, next) => {
+ if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
+ next(new Error("Invalid origin"));
+ return;
+ }
+
+ if (!socket.request.headers.cookie) {
+ next(new Error("No cookie transmitted."));
+ return;
+ }
+
+ let cookies = cookie.parse(socket.request.headers.cookie);
+
+ if (!cookies.sid) {
+ next(new Error("No sid transmitted."));
+ return;
+ }
+
+ request
+ .get(get_url(socket, "/api/method/frappe.realtime.get_user_info"))
+ .type("form")
+ .query({
+ sid: cookies.sid,
+ })
+ .then((res) => {
+ socket.user = res.body.message.user;
+ socket.user_type = res.body.message.user_type;
+ socket.sid = cookies.sid;
+ socket.subscribed_documents = [];
+ next();
+ })
+ .catch((e) => {
+ next(new Error(`Unauthorized: ${e}`));
+ });
+});
+
+// on socket connection
+io.on("connection", function (socket) {
+ socket.join(get_user_room(socket, socket.user));
+ socket.join(get_website_room(socket));
+
+ if (socket.user_type == "System User") {
+ socket.join(get_site_room(socket));
+ }
+
+ socket.on("doctype_subscribe", function (doctype) {
+ can_subscribe_doctype({
+ socket,
+ doctype,
+ callback: () => {
+ socket.join(get_doctype_room(socket, doctype));
+ },
+ });
+ });
+
+ socket.on("doctype_unsubscribe", function (doctype) {
+ socket.leave(get_doctype_room(socket, doctype));
+ });
+
+ socket.on("task_subscribe", function (task_id) {
+ var room = get_task_room(socket, task_id);
+ socket.join(room);
+ });
+
+ socket.on("task_unsubscribe", function (task_id) {
+ var room = get_task_room(socket, task_id);
+ socket.leave(room);
+ });
+
+ socket.on("progress_subscribe", function (task_id) {
+ var room = get_task_room(socket, task_id);
+ socket.join(room);
+ });
+
+ socket.on("doc_subscribe", function (doctype, docname) {
+ can_subscribe_doc({
+ socket,
+ doctype,
+ docname,
+ callback: () => {
+ let room = get_doc_room(socket, doctype, docname);
+ socket.join(room);
+ },
+ });
+ });
+
+ socket.on("doc_unsubscribe", function (doctype, docname) {
+ let room = get_doc_room(socket, doctype, docname);
+ socket.leave(room);
+ });
+
+ socket.on("doc_open", function (doctype, docname) {
+ can_subscribe_doc({
+ socket,
+ doctype,
+ docname,
+ callback: () => {
+ let room = get_open_doc_room(socket, doctype, docname);
+ socket.join(room);
+ socket.subscribed_documents.push([doctype, docname]);
+
+ // show who is currently viewing the form
+ notify_subscribed_doc_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
+ },
+ });
+ });
+
+ socket.on("doc_close", function (doctype, docname) {
+ // remove this user from the list of 'who is currently viewing the form'
+ let room = get_open_doc_room(socket, doctype, docname);
+ socket.leave(room);
+ socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
+ !(dt == doctype && dn == docname);
+ });
+
+ notify_subscribed_doc_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
+ });
+
+ socket.on("open_in_editor", (data) => {
+ let s = get_redis_subscriber("redis_queue");
+ s.publish("open_in_editor", JSON.stringify(data));
+ });
+});
+
+subscriber.on("message", function (_channel, message) {
+ message = JSON.parse(message);
+
+ if (message.room) {
+ io.to(message.room).emit(message.event, message.message);
+ } else {
+ io.emit(message.event, message.message);
+ }
+});
+
+subscriber.subscribe("events");
+
+function get_doc_room(socket, doctype, docname) {
+ return get_site_name(socket) + ":doc:" + doctype + "/" + docname;
+}
+
+function get_open_doc_room(socket, doctype, docname) {
+ return get_site_name(socket) + ":open_doc:" + doctype + "/" + docname;
+}
+
+function get_user_room(socket, user) {
+ return get_site_name(socket) + ":user:" + user || socket.user;
+}
+
+function get_site_room(socket) {
+ return get_site_name(socket) + ":all";
+}
+
+function get_website_room(socket) {
+ return get_site_name(socket) + ":website";
+}
+
+function get_doctype_room(socket, doctype) {
+ return get_site_name(socket) + ":doctype:" + doctype;
+}
+
+function get_task_room(socket, task_id) {
+ return get_site_name(socket) + ":task_progress:" + task_id;
+}
+
+function get_site_name(socket) {
+ if (socket.site_name) {
+ return socket.site_name;
+ } else if (socket.request.headers["x-frappe-site-name"]) {
+ socket.site_name = get_hostname(socket.request.headers["x-frappe-site-name"]);
+ } else if (
+ conf.default_site &&
+ ["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
+ ) {
+ // from currentsite.txt since host is localhost
+ socket.site_name = conf.default_site;
+ } else if (socket.request.headers.origin) {
+ socket.site_name = get_hostname(socket.request.headers.origin);
+ } else {
+ socket.site_name = get_hostname(socket.request.headers.host);
+ }
+ return socket.site_name;
+}
+
+function get_hostname(url) {
+ if (!url) return undefined;
+ if (url.indexOf("://") > -1) {
+ url = url.split("/")[2];
+ }
+ return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
+}
+
+function get_url(socket, path) {
+ if (!path) {
+ path = "";
+ }
+ return socket.request.headers.origin + path;
+}
+
+function can_subscribe_doc(args) {
+ if (!args) return;
+ if (!args.doctype || !args.docname) return;
+ request
+ .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doc"))
+ .type("form")
+ .query({
+ sid: args.socket.sid,
+ doctype: args.doctype,
+ docname: args.docname,
+ })
+ .end(function (err, res) {
+ if (!res) {
+ log("No response for doc_subscribe");
+ } else if (res.status == 403) {
+ return;
+ } else if (err) {
+ log(err);
+ } else if (res.status == 200) {
+ args.callback(err, res);
+ } else {
+ log("Something went wrong", err, res);
+ }
+ });
+}
+
+function can_subscribe_doctype(args) {
+ if (!args) return;
+ if (!args.doctype) return;
+ request
+ .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doctype"))
+ .type("form")
+ .query({
+ sid: args.socket.sid,
+ doctype: args.doctype,
+ })
+ .end(function (err, res) {
+ if (!res || res.status == 403 || err) {
+ if (err) {
+ log(err);
+ }
+ return false;
+ } else if (res.status == 200) {
+ args.callback && args.callback(err, res);
+ return true;
+ }
+ log("ERROR (can_subscribe_doctype): ", err, res);
+ });
+}
+
+function notify_subscribed_doc_users(args) {
+ if (!(args && args.doctype && args.docname)) {
+ return;
+ }
+ const open_doc_room = get_open_doc_room(args.socket, args.doctype, args.docname);
+
+ const clients = Array.from(io.sockets.adapter.rooms.get(open_doc_room) || []);
+
+ let users = [];
+ io.sockets.sockets.forEach((sock) => {
+ if (clients.includes(sock.id)) {
+ users.push(sock.user);
+ }
+ });
+
+ // dont send update to self. meaningless.
+ if (users.length == 1 && users[0] == args.socket.user) return;
+
+ // notify
+ io.to(open_doc_room).emit("doc_viewers", {
+ doctype: args.doctype,
+ docname: args.docname,
+ users: Array.from(new Set(users)),
+ });
+}
+
+io.sockets.on("connection", function (socket) {
+ socket.on("disconnect", () => user_disconnected(socket));
+});
+
+function user_disconnected(socket) {
+ socket.subscribed_documents.forEach(([doctype, docname]) => {
+ notify_subscribed_doc_users({ socket, doctype, docname });
+ });
+}
diff --git a/socketio.js b/socketio.js
index e4570bcfce..14360d995c 100644
--- a/socketio.js
+++ b/socketio.js
@@ -1,307 +1 @@
-const cookie = require("cookie");
-const request = require("superagent");
-
-const { get_conf, get_redis_subscriber } = require("./node_utils");
-const conf = get_conf();
-const log = console.log; // eslint-disable-line
-const subscriber = get_redis_subscriber();
-
-const io = require("socket.io")(conf.socketio_port, {
- cors: {
- // Should be fine since we are ensuring whether hostname and origin are same before adding setting listeners for s socket
- origin: true,
- credentials: true,
- },
-});
-
-io.use((socket, next) => {
- if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
- next(new Error("Invalid origin"));
- return;
- }
-
- if (!socket.request.headers.cookie) {
- next(new Error("No cookie transmitted."));
- return;
- }
-
- let cookies = cookie.parse(socket.request.headers.cookie);
-
- if (!cookies.sid) {
- next(new Error("No sid transmitted."));
- return;
- }
-
- request
- .get(get_url(socket, "/api/method/frappe.realtime.get_user_info"))
- .type("form")
- .query({
- sid: cookies.sid,
- })
- .then((res) => {
- socket.user = res.body.message.user;
- socket.user_type = res.body.message.user_type;
- socket.sid = cookies.sid;
- socket.subscribed_documents = [];
- next();
- })
- .catch((e) => {
- next(new Error(`Unauthorized: ${e}`));
- });
-});
-
-// on socket connection
-io.on("connection", function (socket) {
- socket.join(get_user_room(socket, socket.user));
- socket.join(get_website_room(socket));
-
- if (socket.user_type == "System User") {
- socket.join(get_site_room(socket));
- }
-
- socket.on("doctype_subscribe", function (doctype) {
- can_subscribe_doctype({
- socket,
- doctype,
- callback: () => {
- socket.join(get_doctype_room(socket, doctype));
- },
- });
- });
-
- socket.on("doctype_unsubscribe", function (doctype) {
- socket.leave(get_doctype_room(socket, doctype));
- });
-
- socket.on("task_subscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
- socket.join(room);
- });
-
- socket.on("task_unsubscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
- socket.leave(room);
- });
-
- socket.on("progress_subscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
- socket.join(room);
- });
-
- socket.on("doc_subscribe", function (doctype, docname) {
- can_subscribe_doc({
- socket,
- doctype,
- docname,
- callback: () => {
- let room = get_doc_room(socket, doctype, docname);
- socket.join(room);
- },
- });
- });
-
- socket.on("doc_unsubscribe", function (doctype, docname) {
- let room = get_doc_room(socket, doctype, docname);
- socket.leave(room);
- });
-
- socket.on("doc_open", function (doctype, docname) {
- can_subscribe_doc({
- socket,
- doctype,
- docname,
- callback: () => {
- let room = get_open_doc_room(socket, doctype, docname);
- socket.join(room);
- socket.subscribed_documents.push([doctype, docname]);
-
- // show who is currently viewing the form
- notify_subscribed_doc_users({
- socket: socket,
- doctype: doctype,
- docname: docname,
- });
- },
- });
- });
-
- socket.on("doc_close", function (doctype, docname) {
- // remove this user from the list of 'who is currently viewing the form'
- let room = get_open_doc_room(socket, doctype, docname);
- socket.leave(room);
- socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
- !(dt == doctype && dn == docname);
- });
-
- notify_subscribed_doc_users({
- socket: socket,
- doctype: doctype,
- docname: docname,
- });
- });
-
- socket.on("open_in_editor", (data) => {
- let s = get_redis_subscriber("redis_queue");
- s.publish("open_in_editor", JSON.stringify(data));
- });
-});
-
-subscriber.on("message", function (_channel, message) {
- message = JSON.parse(message);
-
- if (message.room) {
- io.to(message.room).emit(message.event, message.message);
- } else {
- io.emit(message.event, message.message);
- }
-});
-
-subscriber.subscribe("events");
-
-function get_doc_room(socket, doctype, docname) {
- return get_site_name(socket) + ":doc:" + doctype + "/" + docname;
-}
-
-function get_open_doc_room(socket, doctype, docname) {
- return get_site_name(socket) + ":open_doc:" + doctype + "/" + docname;
-}
-
-function get_user_room(socket, user) {
- return get_site_name(socket) + ":user:" + user || socket.user;
-}
-
-function get_site_room(socket) {
- return get_site_name(socket) + ":all";
-}
-
-function get_website_room(socket) {
- return get_site_name(socket) + ":website";
-}
-
-function get_doctype_room(socket, doctype) {
- return get_site_name(socket) + ":doctype:" + doctype;
-}
-
-function get_task_room(socket, task_id) {
- return get_site_name(socket) + ":task_progress:" + task_id;
-}
-
-function get_site_name(socket) {
- if (socket.site_name) {
- return socket.site_name;
- } else if (socket.request.headers["x-frappe-site-name"]) {
- socket.site_name = get_hostname(socket.request.headers["x-frappe-site-name"]);
- } else if (
- conf.default_site &&
- ["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
- ) {
- // from currentsite.txt since host is localhost
- socket.site_name = conf.default_site;
- } else if (socket.request.headers.origin) {
- socket.site_name = get_hostname(socket.request.headers.origin);
- } else {
- socket.site_name = get_hostname(socket.request.headers.host);
- }
- return socket.site_name;
-}
-
-function get_hostname(url) {
- if (!url) return undefined;
- if (url.indexOf("://") > -1) {
- url = url.split("/")[2];
- }
- return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
-}
-
-function get_url(socket, path) {
- if (!path) {
- path = "";
- }
- return socket.request.headers.origin + path;
-}
-
-function can_subscribe_doc(args) {
- if (!args) return;
- if (!args.doctype || !args.docname) return;
- request
- .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doc"))
- .type("form")
- .query({
- sid: args.socket.sid,
- doctype: args.doctype,
- docname: args.docname,
- })
- .end(function (err, res) {
- if (!res) {
- log("No response for doc_subscribe");
- } else if (res.status == 403) {
- return;
- } else if (err) {
- log(err);
- } else if (res.status == 200) {
- args.callback(err, res);
- } else {
- log("Something went wrong", err, res);
- }
- });
-}
-
-function can_subscribe_doctype(args) {
- if (!args) return;
- if (!args.doctype) return;
- request
- .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doctype"))
- .type("form")
- .query({
- sid: args.socket.sid,
- doctype: args.doctype,
- })
- .end(function (err, res) {
- if (!res || res.status == 403 || err) {
- if (err) {
- log(err);
- }
- return false;
- } else if (res.status == 200) {
- args.callback && args.callback(err, res);
- return true;
- }
- log("ERROR (can_subscribe_doctype): ", err, res);
- });
-}
-
-function notify_subscribed_doc_users(args) {
- if (!(args && args.doctype && args.docname)) {
- return;
- }
- const open_doc_room = get_open_doc_room(args.socket, args.doctype, args.docname);
-
- const clients = Array.from(io.sockets.adapter.rooms.get(open_doc_room) || []);
-
- let users = [];
- io.sockets.sockets.forEach((sock) => {
- if (clients.includes(sock.id)) {
- users.push(sock.user);
- }
- });
-
- // dont send update to self. meaningless.
- if (users.length == 1 && users[0] == args.socket.user) return;
-
- // notify
- io.to(open_doc_room).emit("doc_viewers", {
- doctype: args.doctype,
- docname: args.docname,
- users: Array.from(new Set(users)),
- });
-}
-
-io.sockets.on("connection", function (socket) {
- socket.on("disconnect", () => user_disconnected(socket));
-});
-
-function user_disconnected(socket) {
- socket.subscribed_documents.forEach(([doctype, docname]) => {
- notify_subscribed_doc_users({ socket, doctype, docname });
- });
-}
+require("./realtime");
From 164840c32e86742bb7ddf9658b23f3f67dc4554e Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 16:21:03 +0530
Subject: [PATCH 73/97] refactor: explicitly import socketio
---
realtime/index.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/realtime/index.js b/realtime/index.js
index 88a621c983..a0990f7094 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -1,12 +1,13 @@
const cookie = require("cookie");
const request = require("superagent");
+const { Server } = require("socket.io");
const { get_conf, get_redis_subscriber } = require("../node_utils");
const conf = get_conf();
const log = console.log; // eslint-disable-line
const subscriber = get_redis_subscriber();
-const io = require("socket.io")(conf.socketio_port, {
+const io = new Server(conf.socketio_port, {
cors: {
// Should be fine since we are ensuring whether hostname and origin are same before adding setting listeners for s socket
origin: true,
From 7320d2d0204872f47babdab024f54dca1e79e480 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 18:26:21 +0530
Subject: [PATCH 74/97] refactor: move middleware out
---
realtime/index.js | 58 +++-------------------------
realtime/middlewares/authenticate.js | 41 ++++++++++++++++++++
realtime/utils.js | 19 +++++++++
3 files changed, 66 insertions(+), 52 deletions(-)
create mode 100644 realtime/middlewares/authenticate.js
create mode 100644 realtime/utils.js
diff --git a/realtime/index.js b/realtime/index.js
index a0990f7094..bebf3cba1c 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -1,4 +1,3 @@
-const cookie = require("cookie");
const request = require("superagent");
const { Server } = require("socket.io");
@@ -7,6 +6,8 @@ const conf = get_conf();
const log = console.log; // eslint-disable-line
const subscriber = get_redis_subscriber();
+const { get_hostname, get_url } = require("./utils");
+
const io = new Server(conf.socketio_port, {
cors: {
// Should be fine since we are ensuring whether hostname and origin are same before adding setting listeners for s socket
@@ -15,43 +16,11 @@ const io = new Server(conf.socketio_port, {
},
});
-io.use((socket, next) => {
- if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
- next(new Error("Invalid origin"));
- return;
- }
+// load and register middlewares
+const authenticate = require("./middlewares/authenticate");
+io.use(authenticate);
- if (!socket.request.headers.cookie) {
- next(new Error("No cookie transmitted."));
- return;
- }
-
- let cookies = cookie.parse(socket.request.headers.cookie);
-
- if (!cookies.sid) {
- next(new Error("No sid transmitted."));
- return;
- }
-
- request
- .get(get_url(socket, "/api/method/frappe.realtime.get_user_info"))
- .type("form")
- .query({
- sid: cookies.sid,
- })
- .then((res) => {
- socket.user = res.body.message.user;
- socket.user_type = res.body.message.user_type;
- socket.sid = cookies.sid;
- socket.subscribed_documents = [];
- next();
- })
- .catch((e) => {
- next(new Error(`Unauthorized: ${e}`));
- });
-});
-
-// on socket connection
+// load and register handler
io.on("connection", function (socket) {
socket.join(get_user_room(socket, socket.user));
socket.join(get_website_room(socket));
@@ -206,21 +175,6 @@ function get_site_name(socket) {
return socket.site_name;
}
-function get_hostname(url) {
- if (!url) return undefined;
- if (url.indexOf("://") > -1) {
- url = url.split("/")[2];
- }
- return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
-}
-
-function get_url(socket, path) {
- if (!path) {
- path = "";
- }
- return socket.request.headers.origin + path;
-}
-
function can_subscribe_doc(args) {
if (!args) return;
if (!args.doctype || !args.docname) return;
diff --git a/realtime/middlewares/authenticate.js b/realtime/middlewares/authenticate.js
new file mode 100644
index 0000000000..b18af4fecf
--- /dev/null
+++ b/realtime/middlewares/authenticate.js
@@ -0,0 +1,41 @@
+const cookie = require("cookie");
+const request = require("superagent");
+const { get_hostname, get_url } = require("../utils");
+
+function authenticate_with_frappe(socket, next) {
+ if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
+ next(new Error("Invalid origin"));
+ return;
+ }
+
+ if (!socket.request.headers.cookie) {
+ next(new Error("No cookie transmitted."));
+ return;
+ }
+
+ let cookies = cookie.parse(socket.request.headers.cookie);
+
+ if (!cookies.sid) {
+ next(new Error("No sid transmitted."));
+ return;
+ }
+
+ request
+ .get(get_url(socket, "/api/method/frappe.realtime.get_user_info"))
+ .type("form")
+ .query({
+ sid: cookies.sid,
+ })
+ .then((res) => {
+ socket.user = res.body.message.user;
+ socket.user_type = res.body.message.user_type;
+ socket.sid = cookies.sid;
+ socket.subscribed_documents = [];
+ next();
+ })
+ .catch((e) => {
+ next(new Error(`Unauthorized: ${e}`));
+ });
+}
+
+module.exports = authenticate_with_frappe;
diff --git a/realtime/utils.js b/realtime/utils.js
new file mode 100644
index 0000000000..74620f3bd1
--- /dev/null
+++ b/realtime/utils.js
@@ -0,0 +1,19 @@
+function get_hostname(url) {
+ if (!url) return undefined;
+ if (url.indexOf("://") > -1) {
+ url = url.split("/")[2];
+ }
+ return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
+}
+
+function get_url(socket, path) {
+ if (!path) {
+ path = "";
+ }
+ return socket.request.headers.origin + path;
+}
+
+module.exports = {
+ get_url,
+ get_hostname,
+};
From d13cb116bc7e2df589ae52efc9c516782bc2a9e9 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 18:58:18 +0530
Subject: [PATCH 75/97] refactor: use existing redis client
---
realtime/index.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/realtime/index.js b/realtime/index.js
index bebf3cba1c..f745dedf43 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -111,8 +111,7 @@ io.on("connection", function (socket) {
});
socket.on("open_in_editor", (data) => {
- let s = get_redis_subscriber("redis_queue");
- s.publish("open_in_editor", JSON.stringify(data));
+ subscriber.publish("open_in_editor", JSON.stringify(data));
});
});
From dad1d57b90e4768f6841d3d7d5f395a1fc0098f2 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 19:51:25 +0530
Subject: [PATCH 76/97] chore: move redis sub setup
---
realtime/index.js | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/realtime/index.js b/realtime/index.js
index f745dedf43..c625608a2f 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -4,7 +4,6 @@ const { Server } = require("socket.io");
const { get_conf, get_redis_subscriber } = require("../node_utils");
const conf = get_conf();
const log = console.log; // eslint-disable-line
-const subscriber = get_redis_subscriber();
const { get_hostname, get_url } = require("./utils");
@@ -115,18 +114,6 @@ io.on("connection", function (socket) {
});
});
-subscriber.on("message", function (_channel, message) {
- message = JSON.parse(message);
-
- if (message.room) {
- io.to(message.room).emit(message.event, message.message);
- } else {
- io.emit(message.event, message.message);
- }
-});
-
-subscriber.subscribe("events");
-
function get_doc_room(socket, doctype, docname) {
return get_site_name(socket) + ":doc:" + doctype + "/" + docname;
}
@@ -259,3 +246,17 @@ function user_disconnected(socket) {
notify_subscribed_doc_users({ socket, doctype, docname });
});
}
+
+const subscriber = get_redis_subscriber();
+
+subscriber.on("message", function (_channel, message) {
+ message = JSON.parse(message);
+
+ if (message.room) {
+ io.to(message.room).emit(message.event, message.message);
+ } else {
+ io.emit(message.event, message.message);
+ }
+});
+
+subscriber.subscribe("events");
From d59e499418b26501cf9775ebec95b1c12860c358 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 22:06:01 +0530
Subject: [PATCH 77/97] refactor!: Use SocketIO namespaces for multitenancy
---
frappe/public/js/frappe/socketio_client.js | 6 +-
frappe/realtime.py | 19 +++--
realtime/index.js | 99 ++++++++++------------
realtime/middlewares/authenticate.js | 29 +++++++
4 files changed, 88 insertions(+), 65 deletions(-)
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 9e70e6a835..bfcf0b1a6c 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -34,13 +34,13 @@ class RealTimeClient {
// Enable secure option when using HTTPS
if (window.location.protocol == "https:") {
- this.socket = io.connect(this.get_host(port), {
+ this.socket = io(this.get_host(port), {
secure: true,
withCredentials: true,
reconnectionAttempts: 3,
});
} else if (window.location.protocol == "http:") {
- this.socket = io.connect(this.get_host(port), {
+ this.socket = io(this.get_host(port), {
withCredentials: true,
reconnectionAttempts: 3,
});
@@ -105,7 +105,7 @@ class RealTimeClient {
}
host = host + ":" + port;
}
- return host;
+ return host + `/${frappe.boot.sitename}`;
}
subscribe(task_id, opts) {
diff --git a/frappe/realtime.py b/frappe/realtime.py
index 47b3d8a95c..eb5d4a7541 100644
--- a/frappe/realtime.py
+++ b/frappe/realtime.py
@@ -104,7 +104,12 @@ def emit_via_redis(event, message, room):
with suppress(redis.exceptions.ConnectionError):
r = get_redis_connection_without_auth()
- r.publish("events", frappe.as_json({"event": event, "message": message, "room": room}))
+ r.publish(
+ "events",
+ frappe.as_json(
+ {"event": event, "message": message, "room": room, "namespace": frappe.local.site}
+ ),
+ )
@frappe.whitelist(allow_guest=True)
@@ -136,24 +141,24 @@ def get_user_info():
def get_doctype_room(doctype):
- return f"{frappe.local.site}:doctype:{doctype}"
+ return f"doctype:{doctype}"
def get_doc_room(doctype, docname):
- return f"{frappe.local.site}:doc:{doctype}/{cstr(docname)}"
+ return f"doc:{doctype}/{cstr(docname)}"
def get_user_room(user):
- return f"{frappe.local.site}:user:{user}"
+ return f"user:{user}"
def get_site_room():
- return f"{frappe.local.site}:all"
+ return "all"
def get_task_progress_room(task_id):
- return f"{frappe.local.site}:task_progress:{task_id}"
+ return f"task_progress:{task_id}"
def get_website_room():
- return f"{frappe.local.site}:website"
+ return "website"
diff --git a/realtime/index.js b/realtime/index.js
index c625608a2f..3c01db7246 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -5,9 +5,9 @@ const { get_conf, get_redis_subscriber } = require("../node_utils");
const conf = get_conf();
const log = console.log; // eslint-disable-line
-const { get_hostname, get_url } = require("./utils");
+const { get_url } = require("./utils");
-const io = new Server(conf.socketio_port, {
+let io = new Server(conf.socketio_port, {
cors: {
// Should be fine since we are ensuring whether hostname and origin are same before adding setting listeners for s socket
origin: true,
@@ -15,17 +15,22 @@ const io = new Server(conf.socketio_port, {
},
});
+// Multitenancy implementation
+// allow arbitrary sitename as namespaces
+// namespaces get validated during authentication.
+const realtime = io.of(/^\/.*$/);
+
// load and register middlewares
const authenticate = require("./middlewares/authenticate");
-io.use(authenticate);
+realtime.use(authenticate);
// load and register handler
-io.on("connection", function (socket) {
- socket.join(get_user_room(socket, socket.user));
- socket.join(get_website_room(socket));
+realtime.on("connection", function (socket) {
+ socket.join(get_user_room(socket.user));
+ socket.join(get_website_room());
if (socket.user_type == "System User") {
- socket.join(get_site_room(socket));
+ socket.join(get_site_room());
}
socket.on("doctype_subscribe", function (doctype) {
@@ -33,27 +38,27 @@ io.on("connection", function (socket) {
socket,
doctype,
callback: () => {
- socket.join(get_doctype_room(socket, doctype));
+ socket.join(get_doctype_room(doctype));
},
});
});
socket.on("doctype_unsubscribe", function (doctype) {
- socket.leave(get_doctype_room(socket, doctype));
+ socket.leave(get_doctype_room(doctype));
});
socket.on("task_subscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
+ var room = get_task_room(task_id);
socket.join(room);
});
socket.on("task_unsubscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
+ var room = get_task_room(task_id);
socket.leave(room);
});
socket.on("progress_subscribe", function (task_id) {
- var room = get_task_room(socket, task_id);
+ var room = get_task_room(task_id);
socket.join(room);
});
@@ -63,14 +68,14 @@ io.on("connection", function (socket) {
doctype,
docname,
callback: () => {
- let room = get_doc_room(socket, doctype, docname);
+ let room = get_doc_room(doctype, docname);
socket.join(room);
},
});
});
socket.on("doc_unsubscribe", function (doctype, docname) {
- let room = get_doc_room(socket, doctype, docname);
+ let room = get_doc_room(doctype, docname);
socket.leave(room);
});
@@ -80,7 +85,7 @@ io.on("connection", function (socket) {
doctype,
docname,
callback: () => {
- let room = get_open_doc_room(socket, doctype, docname);
+ let room = get_open_doc_room(doctype, docname);
socket.join(room);
socket.subscribed_documents.push([doctype, docname]);
@@ -96,7 +101,7 @@ io.on("connection", function (socket) {
socket.on("doc_close", function (doctype, docname) {
// remove this user from the list of 'who is currently viewing the form'
- let room = get_open_doc_room(socket, doctype, docname);
+ let room = get_open_doc_room(doctype, docname);
socket.leave(room);
socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
!(dt == doctype && dn == docname);
@@ -114,51 +119,32 @@ io.on("connection", function (socket) {
});
});
-function get_doc_room(socket, doctype, docname) {
- return get_site_name(socket) + ":doc:" + doctype + "/" + docname;
+function get_doc_room(doctype, docname) {
+ return "doc:" + doctype + "/" + docname;
}
-function get_open_doc_room(socket, doctype, docname) {
- return get_site_name(socket) + ":open_doc:" + doctype + "/" + docname;
+function get_open_doc_room(doctype, docname) {
+ return "open_doc:" + doctype + "/" + docname;
}
-function get_user_room(socket, user) {
- return get_site_name(socket) + ":user:" + user || socket.user;
+function get_user_room(user) {
+ return "user:" + user;
}
-function get_site_room(socket) {
- return get_site_name(socket) + ":all";
+function get_site_room() {
+ return "all";
}
-function get_website_room(socket) {
- return get_site_name(socket) + ":website";
+function get_website_room() {
+ return "website";
}
-function get_doctype_room(socket, doctype) {
- return get_site_name(socket) + ":doctype:" + doctype;
+function get_doctype_room(doctype) {
+ return "doctype:" + doctype;
}
-function get_task_room(socket, task_id) {
- return get_site_name(socket) + ":task_progress:" + task_id;
-}
-
-function get_site_name(socket) {
- if (socket.site_name) {
- return socket.site_name;
- } else if (socket.request.headers["x-frappe-site-name"]) {
- socket.site_name = get_hostname(socket.request.headers["x-frappe-site-name"]);
- } else if (
- conf.default_site &&
- ["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
- ) {
- // from currentsite.txt since host is localhost
- socket.site_name = conf.default_site;
- } else if (socket.request.headers.origin) {
- socket.site_name = get_hostname(socket.request.headers.origin);
- } else {
- socket.site_name = get_hostname(socket.request.headers.host);
- }
- return socket.site_name;
+function get_task_room(task_id) {
+ return "task_progress:" + task_id;
}
function can_subscribe_doc(args) {
@@ -215,12 +201,14 @@ function notify_subscribed_doc_users(args) {
if (!(args && args.doctype && args.docname)) {
return;
}
- const open_doc_room = get_open_doc_room(args.socket, args.doctype, args.docname);
+ const socket = args.socket;
+ const open_doc_room = get_open_doc_room(args.doctype, args.docname);
- const clients = Array.from(io.sockets.adapter.rooms.get(open_doc_room) || []);
+ const clients = Array.from(socket.nsp.adapter.rooms.get(open_doc_room) || []);
let users = [];
- io.sockets.sockets.forEach((sock) => {
+
+ socket.nsp.sockets.forEach((sock) => {
if (clients.includes(sock.id)) {
users.push(sock.user);
}
@@ -230,14 +218,14 @@ function notify_subscribed_doc_users(args) {
if (users.length == 1 && users[0] == args.socket.user) return;
// notify
- io.to(open_doc_room).emit("doc_viewers", {
+ socket.nsp.to(open_doc_room).emit("doc_viewers", {
doctype: args.doctype,
docname: args.docname,
users: Array.from(new Set(users)),
});
}
-io.sockets.on("connection", function (socket) {
+realtime.on("connection", function (socket) {
socket.on("disconnect", () => user_disconnected(socket));
});
@@ -252,8 +240,9 @@ const subscriber = get_redis_subscriber();
subscriber.on("message", function (_channel, message) {
message = JSON.parse(message);
+ let namespace = "/" + message.namespace;
if (message.room) {
- io.to(message.room).emit(message.event, message.message);
+ io.of(namespace).to(message.room).emit(message.event, message.message);
} else {
io.emit(message.event, message.message);
}
diff --git a/realtime/middlewares/authenticate.js b/realtime/middlewares/authenticate.js
index b18af4fecf..9bd2ed592e 100644
--- a/realtime/middlewares/authenticate.js
+++ b/realtime/middlewares/authenticate.js
@@ -2,7 +2,17 @@ const cookie = require("cookie");
const request = require("superagent");
const { get_hostname, get_url } = require("../utils");
+const { get_conf } = require("../../node_utils");
+const conf = get_conf();
+
function authenticate_with_frappe(socket, next) {
+ let namespace = socket.nsp.name;
+ namespace = namespace.slice(1, namespace.length); // remove leading `/`
+
+ if (namespace != get_site_name(socket)) {
+ next(new Error("Invalid namespace"));
+ }
+
if (get_hostname(socket.request.headers.host) != get_hostname(socket.request.headers.origin)) {
next(new Error("Invalid origin"));
return;
@@ -38,4 +48,23 @@ function authenticate_with_frappe(socket, next) {
});
}
+function get_site_name(socket) {
+ if (socket.site_name) {
+ return socket.site_name;
+ } else if (socket.request.headers["x-frappe-site-name"]) {
+ socket.site_name = get_hostname(socket.request.headers["x-frappe-site-name"]);
+ } else if (
+ conf.default_site &&
+ ["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
+ ) {
+ // from currentsite.txt since host is localhost
+ socket.site_name = conf.default_site;
+ } else if (socket.request.headers.origin) {
+ socket.site_name = get_hostname(socket.request.headers.origin);
+ } else {
+ socket.site_name = get_hostname(socket.request.headers.host);
+ }
+ return socket.site_name;
+}
+
module.exports = authenticate_with_frappe;
From bdaed29ef253ba6ef149af7eeff24179c1a736e3 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 23:11:28 +0530
Subject: [PATCH 78/97] refactor: move handlers to separate file
---
frappe/public/js/frappe/socketio_client.js | 7 +-
realtime/handlers/frappe_handlers.js | 198 ++++++++++++++++++
realtime/index.js | 223 ++-------------------
realtime/middlewares/authenticate.js | 11 +-
realtime/utils.js | 9 -
5 files changed, 223 insertions(+), 225 deletions(-)
create mode 100644 realtime/handlers/frappe_handlers.js
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index bfcf0b1a6c..7084e9e2df 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -6,7 +6,6 @@ class RealTimeClient {
constructor() {
this.open_tasks = {};
this.open_docs = new Set();
- this.emit_queue = [];
}
on(event, callback) {
@@ -96,9 +95,9 @@ class RealTimeClient {
}
get_host(port = 3000) {
- var host = window.location.origin;
+ let host = window.location.origin;
if (window.dev_server) {
- var parts = host.split(":");
+ let parts = host.split(":");
port = frappe.boot.socketio_port || port.toString() || "3000";
if (parts.length > 2) {
host = parts[0] + ":" + parts[1];
@@ -171,7 +170,7 @@ class RealTimeClient {
}
// success
- var opts = this.open_tasks[data.task_id];
+ let opts = this.open_tasks[data.task_id];
if (opts[method]) {
opts[method](data);
}
diff --git a/realtime/handlers/frappe_handlers.js b/realtime/handlers/frappe_handlers.js
new file mode 100644
index 0000000000..eb7344388c
--- /dev/null
+++ b/realtime/handlers/frappe_handlers.js
@@ -0,0 +1,198 @@
+const request = require("superagent");
+const { get_url } = require("../utils");
+const log = console.log; // eslint-disable-line
+
+const WEBSITE_ROOM = "website";
+const SITE_ROOM = "all";
+
+function frappe_handlers(realtime, socket) {
+ socket.join(user_room(socket.user));
+ socket.join(WEBSITE_ROOM);
+
+ if (socket.user_type == "System User") {
+ socket.join(SITE_ROOM);
+ }
+
+ socket.on("doctype_subscribe", function (doctype) {
+ can_subscribe_doctype({
+ socket,
+ doctype,
+ callback: () => {
+ socket.join(doctype_room(doctype));
+ },
+ });
+ });
+
+ socket.on("doctype_unsubscribe", function (doctype) {
+ socket.leave(doctype_room(doctype));
+ });
+
+ socket.on("task_subscribe", function (task_id) {
+ const room = task_room(task_id);
+ socket.join(room);
+ });
+
+ socket.on("task_unsubscribe", function (task_id) {
+ const room = task_room(task_id);
+ socket.leave(room);
+ });
+
+ socket.on("progress_subscribe", function (task_id) {
+ const room = task_room(task_id);
+ socket.join(room);
+ });
+
+ socket.on("doc_subscribe", function (doctype, docname) {
+ can_subscribe_doc({
+ socket,
+ doctype,
+ docname,
+ callback: () => {
+ let room = doc_room(doctype, docname);
+ socket.join(room);
+ },
+ });
+ });
+
+ socket.on("doc_unsubscribe", function (doctype, docname) {
+ let room = doc_room(doctype, docname);
+ socket.leave(room);
+ });
+
+ socket.on("doc_open", function (doctype, docname) {
+ can_subscribe_doc({
+ socket,
+ doctype,
+ docname,
+ callback: () => {
+ let room = open_doc_room(doctype, docname);
+ socket.join(room);
+ if (!socket.subscribed_documents) socket.subscribed_documents = [];
+ socket.subscribed_documents.push([doctype, docname]);
+
+ // show who is currently viewing the form
+ notify_subscribed_doc_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
+ },
+ });
+ });
+
+ socket.on("doc_close", function (doctype, docname) {
+ // remove this user from the list of 'who is currently viewing the form'
+ let room = open_doc_room(doctype, docname);
+ socket.leave(room);
+
+ if (socket.subscribed_documents) {
+ socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
+ !(dt == doctype && dn == docname);
+ });
+ }
+
+ notify_subscribed_doc_users({
+ socket: socket,
+ doctype: doctype,
+ docname: docname,
+ });
+ });
+
+ socket.on("disconnect", () => {
+ notify_disconnected_documents(socket);
+ });
+}
+
+function notify_disconnected_documents(socket) {
+ if (socket.subscribed_documents) {
+ socket.subscribed_documents.forEach(([doctype, docname]) => {
+ notify_subscribed_doc_users({ socket, doctype, docname });
+ });
+ }
+}
+
+function can_subscribe_doctype(args) {
+ if (!args) return;
+ if (!args.doctype) return;
+ request
+ .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doctype"))
+ .type("form")
+ .query({
+ sid: args.socket.sid,
+ doctype: args.doctype,
+ })
+ .end(function (err, res) {
+ if (!res || res.status == 403 || err) {
+ if (err) {
+ log(err);
+ }
+ return false;
+ } else if (res.status == 200) {
+ args.callback && args.callback(err, res);
+ return true;
+ }
+ log("ERROR (can_subscribe_doctype): ", err, res);
+ });
+}
+
+function notify_subscribed_doc_users(args) {
+ if (!(args && args.doctype && args.docname)) {
+ return;
+ }
+ const socket = args.socket;
+ const room = open_doc_room(args.doctype, args.docname);
+
+ const clients = Array.from(socket.nsp.adapter.rooms.get(room) || []);
+
+ let users = [];
+
+ socket.nsp.sockets.forEach((sock) => {
+ if (clients.includes(sock.id)) {
+ users.push(sock.user);
+ }
+ });
+
+ // dont send update to self. meaningless.
+ if (users.length == 1 && users[0] == args.socket.user) return;
+
+ // notify
+ socket.nsp.to(room).emit("doc_viewers", {
+ doctype: args.doctype,
+ docname: args.docname,
+ users: Array.from(new Set(users)),
+ });
+}
+
+function can_subscribe_doc(args) {
+ if (!args) return;
+ if (!args.doctype || !args.docname) return;
+ request
+ .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doc"))
+ .type("form")
+ .query({
+ sid: args.socket.sid,
+ doctype: args.doctype,
+ docname: args.docname,
+ })
+ .end(function (err, res) {
+ if (!res) {
+ log("No response for doc_subscribe");
+ } else if (res.status == 403) {
+ return;
+ } else if (err) {
+ log(err);
+ } else if (res.status == 200) {
+ args.callback(err, res);
+ } else {
+ log("Something went wrong", err, res);
+ }
+ });
+}
+
+const doc_room = (doctype, docname) => "doc:" + doctype + "/" + docname;
+const open_doc_room = (doctype, docname) => "open_doc:" + doctype + "/" + docname;
+const user_room = (user) => "user:" + user;
+const doctype_room = (doctype) => "doctype:" + doctype;
+const task_room = (task_id) => "task_progress:" + task_id;
+
+module.exports = frappe_handlers;
diff --git a/realtime/index.js b/realtime/index.js
index 3c01db7246..cf6549d521 100644
--- a/realtime/index.js
+++ b/realtime/index.js
@@ -1,11 +1,7 @@
-const request = require("superagent");
const { Server } = require("socket.io");
const { get_conf, get_redis_subscriber } = require("../node_utils");
const conf = get_conf();
-const log = console.log; // eslint-disable-line
-
-const { get_url } = require("./utils");
let io = new Server(conf.socketio_port, {
cors: {
@@ -15,7 +11,7 @@ let io = new Server(conf.socketio_port, {
},
});
-// Multitenancy implementation
+// Multitenancy implementation.
// allow arbitrary sitename as namespaces
// namespaces get validated during authentication.
const realtime = io.of(/^\/.*$/);
@@ -23,218 +19,23 @@ const realtime = io.of(/^\/.*$/);
// load and register middlewares
const authenticate = require("./middlewares/authenticate");
realtime.use(authenticate);
+// =======================
-// load and register handler
-realtime.on("connection", function (socket) {
- socket.join(get_user_room(socket.user));
- socket.join(get_website_room());
-
- if (socket.user_type == "System User") {
- socket.join(get_site_room());
- }
-
- socket.on("doctype_subscribe", function (doctype) {
- can_subscribe_doctype({
- socket,
- doctype,
- callback: () => {
- socket.join(get_doctype_room(doctype));
- },
- });
- });
-
- socket.on("doctype_unsubscribe", function (doctype) {
- socket.leave(get_doctype_room(doctype));
- });
-
- socket.on("task_subscribe", function (task_id) {
- var room = get_task_room(task_id);
- socket.join(room);
- });
-
- socket.on("task_unsubscribe", function (task_id) {
- var room = get_task_room(task_id);
- socket.leave(room);
- });
-
- socket.on("progress_subscribe", function (task_id) {
- var room = get_task_room(task_id);
- socket.join(room);
- });
-
- socket.on("doc_subscribe", function (doctype, docname) {
- can_subscribe_doc({
- socket,
- doctype,
- docname,
- callback: () => {
- let room = get_doc_room(doctype, docname);
- socket.join(room);
- },
- });
- });
-
- socket.on("doc_unsubscribe", function (doctype, docname) {
- let room = get_doc_room(doctype, docname);
- socket.leave(room);
- });
-
- socket.on("doc_open", function (doctype, docname) {
- can_subscribe_doc({
- socket,
- doctype,
- docname,
- callback: () => {
- let room = get_open_doc_room(doctype, docname);
- socket.join(room);
- socket.subscribed_documents.push([doctype, docname]);
-
- // show who is currently viewing the form
- notify_subscribed_doc_users({
- socket: socket,
- doctype: doctype,
- docname: docname,
- });
- },
- });
- });
-
- socket.on("doc_close", function (doctype, docname) {
- // remove this user from the list of 'who is currently viewing the form'
- let room = get_open_doc_room(doctype, docname);
- socket.leave(room);
- socket.subscribed_documents = socket.subscribed_documents.filter(([dt, dn]) => {
- !(dt == doctype && dn == docname);
- });
-
- notify_subscribed_doc_users({
- socket: socket,
- doctype: doctype,
- docname: docname,
- });
- });
+// load and register handlers
+const frappe_handlers = require("./handlers/frappe_handlers");
+function on_connection(socket) {
+ frappe_handlers(realtime, socket);
+ // ESBUild "open in editor" on error
socket.on("open_in_editor", (data) => {
subscriber.publish("open_in_editor", JSON.stringify(data));
});
-});
-
-function get_doc_room(doctype, docname) {
- return "doc:" + doctype + "/" + docname;
}
-function get_open_doc_room(doctype, docname) {
- return "open_doc:" + doctype + "/" + docname;
-}
-
-function get_user_room(user) {
- return "user:" + user;
-}
-
-function get_site_room() {
- return "all";
-}
-
-function get_website_room() {
- return "website";
-}
-
-function get_doctype_room(doctype) {
- return "doctype:" + doctype;
-}
-
-function get_task_room(task_id) {
- return "task_progress:" + task_id;
-}
-
-function can_subscribe_doc(args) {
- if (!args) return;
- if (!args.doctype || !args.docname) return;
- request
- .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doc"))
- .type("form")
- .query({
- sid: args.socket.sid,
- doctype: args.doctype,
- docname: args.docname,
- })
- .end(function (err, res) {
- if (!res) {
- log("No response for doc_subscribe");
- } else if (res.status == 403) {
- return;
- } else if (err) {
- log(err);
- } else if (res.status == 200) {
- args.callback(err, res);
- } else {
- log("Something went wrong", err, res);
- }
- });
-}
-
-function can_subscribe_doctype(args) {
- if (!args) return;
- if (!args.doctype) return;
- request
- .get(get_url(args.socket, "/api/method/frappe.realtime.can_subscribe_doctype"))
- .type("form")
- .query({
- sid: args.socket.sid,
- doctype: args.doctype,
- })
- .end(function (err, res) {
- if (!res || res.status == 403 || err) {
- if (err) {
- log(err);
- }
- return false;
- } else if (res.status == 200) {
- args.callback && args.callback(err, res);
- return true;
- }
- log("ERROR (can_subscribe_doctype): ", err, res);
- });
-}
-
-function notify_subscribed_doc_users(args) {
- if (!(args && args.doctype && args.docname)) {
- return;
- }
- const socket = args.socket;
- const open_doc_room = get_open_doc_room(args.doctype, args.docname);
-
- const clients = Array.from(socket.nsp.adapter.rooms.get(open_doc_room) || []);
-
- let users = [];
-
- socket.nsp.sockets.forEach((sock) => {
- if (clients.includes(sock.id)) {
- users.push(sock.user);
- }
- });
-
- // dont send update to self. meaningless.
- if (users.length == 1 && users[0] == args.socket.user) return;
-
- // notify
- socket.nsp.to(open_doc_room).emit("doc_viewers", {
- doctype: args.doctype,
- docname: args.docname,
- users: Array.from(new Set(users)),
- });
-}
-
-realtime.on("connection", function (socket) {
- socket.on("disconnect", () => user_disconnected(socket));
-});
-
-function user_disconnected(socket) {
- socket.subscribed_documents.forEach(([doctype, docname]) => {
- notify_subscribed_doc_users({ socket, doctype, docname });
- });
-}
+realtime.on("connection", on_connection);
+// =======================
+// Consume events sent from python via redis pub-sub channel.
const subscriber = get_redis_subscriber();
subscriber.on("message", function (_channel, message) {
@@ -244,8 +45,10 @@ subscriber.on("message", function (_channel, message) {
if (message.room) {
io.of(namespace).to(message.room).emit(message.event, message.message);
} else {
- io.emit(message.event, message.message);
+ // publish to ALL sites only used for things like build event.
+ realtime.emit(message.event, message.message);
}
});
subscriber.subscribe("events");
+// =======================
diff --git a/realtime/middlewares/authenticate.js b/realtime/middlewares/authenticate.js
index 9bd2ed592e..1f8876a1da 100644
--- a/realtime/middlewares/authenticate.js
+++ b/realtime/middlewares/authenticate.js
@@ -1,6 +1,6 @@
const cookie = require("cookie");
const request = require("superagent");
-const { get_hostname, get_url } = require("../utils");
+const { get_url } = require("../utils");
const { get_conf } = require("../../node_utils");
const conf = get_conf();
@@ -40,7 +40,6 @@ function authenticate_with_frappe(socket, next) {
socket.user = res.body.message.user;
socket.user_type = res.body.message.user_type;
socket.sid = cookies.sid;
- socket.subscribed_documents = [];
next();
})
.catch((e) => {
@@ -67,4 +66,12 @@ function get_site_name(socket) {
return socket.site_name;
}
+function get_hostname(url) {
+ if (!url) return undefined;
+ if (url.indexOf("://") > -1) {
+ url = url.split("/")[2];
+ }
+ return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
+}
+
module.exports = authenticate_with_frappe;
diff --git a/realtime/utils.js b/realtime/utils.js
index 74620f3bd1..0ff3be0a49 100644
--- a/realtime/utils.js
+++ b/realtime/utils.js
@@ -1,11 +1,3 @@
-function get_hostname(url) {
- if (!url) return undefined;
- if (url.indexOf("://") > -1) {
- url = url.split("/")[2];
- }
- return url.match(/:/g) ? url.slice(0, url.indexOf(":")) : url;
-}
-
function get_url(socket, path) {
if (!path) {
path = "";
@@ -15,5 +7,4 @@ function get_url(socket, path) {
module.exports = {
get_url,
- get_hostname,
};
From e4ec6e65ee5567a92416e2108d821123c7be5683 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 29 Jun 2023 23:56:05 +0530
Subject: [PATCH 79/97] fix: socketio namespace on website
---
frappe/website/utils.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/frappe/website/utils.py b/frappe/website/utils.py
index f5215e9440..cab98eee15 100644
--- a/frappe/website/utils.py
+++ b/frappe/website/utils.py
@@ -170,6 +170,7 @@ def get_boot_data():
"user": frappe.db.get_value("User", frappe.session.user, "time_zone") or get_system_timezone(),
},
"assets_json": get_assets_json(),
+ "sitename": frappe.local.site,
}
From be8d2b9de0427688bb8902eed0ed3ff58619b8d7 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 30 Jun 2023 00:40:55 +0530
Subject: [PATCH 80/97] perf: lazy websocket connection on website
Establishing 1 connection for every website visit is too much.
Only after calling frappe.realtime.on(...) for ANY event, we will
establish a websocket connection.
This is used for handful of things:
- Discussion component
- File upload
Socketio was initially added here: https://github.com/frappe/frappe/pull/6866 this use case no longer exists.
Rarely anywhere website uses realtime.
---
.../js/frappe/build_events/BuildError.vue | 4 +-
frappe/public/js/frappe/desk.js | 2 +-
frappe/public/js/frappe/form/form.js | 2 +-
frappe/public/js/frappe/form/toolbar.js | 2 +-
frappe/public/js/frappe/list/list_view.js | 4 +-
frappe/public/js/frappe/request.js | 2 +-
frappe/public/js/frappe/socketio_client.js | 43 ++++++++++++-------
.../js/frappe/views/reports/report_view.js | 2 +-
frappe/templates/discussions/discussions.js | 8 ++--
frappe/website/js/website.js | 2 +-
realtime/middlewares/authenticate.js | 1 -
11 files changed, 42 insertions(+), 30 deletions(-)
diff --git a/frappe/public/js/frappe/build_events/BuildError.vue b/frappe/public/js/frappe/build_events/BuildError.vue
index 13c0ce39a2..4cdbbd85c0 100644
--- a/frappe/public/js/frappe/build_events/BuildError.vue
+++ b/frappe/public/js/frappe/build_events/BuildError.vue
@@ -24,7 +24,7 @@ function hide() {
data.value = null;
}
function open_in_editor(location) {
- frappe.socketio.socket.emit("open_in_editor", location);
+ frappe.realtime.emit("open_in_editor", location);
}
function error_component(error, i) {
let location = data.value.error.errors[i].location;
@@ -40,7 +40,7 @@ function error_component(error, i) {
template: `${template}
`,
methods: {
open() {
- frappe.socketio.socket.emit("open_in_editor", location);
+ frappe.realtime.emit("open_in_editor", location);
}
}
};
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index a797c6302f..5476dc9dbf 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -31,7 +31,7 @@ frappe.Application = class Application {
}
startup() {
- frappe.socketio.init();
+ frappe.realtime.init();
frappe.model.init();
this.load_bootinfo();
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index 876be1867a..e8fa017cf0 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -1950,7 +1950,7 @@ frappe.ui.form.Form = class FrappeForm {
let docname = this.docname;
if (this.doc && !this.is_new()) {
- frappe.socketio.doc_subscribe(doctype, docname);
+ frappe.realtime.doc_subscribe(doctype, docname);
}
frappe.realtime.off("docinfo_update");
frappe.realtime.on("docinfo_update", ({ doc, key, action = "update" }) => {
diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js
index fa1d7330cf..60b90fe9db 100644
--- a/frappe/public/js/frappe/form/toolbar.js
+++ b/frappe/public/js/frappe/form/toolbar.js
@@ -108,7 +108,7 @@ frappe.ui.form.Toolbar = class Toolbar {
}
let rename_document = () => {
- if (input_name != docname) frappe.socketio.doctype_subscribe(doctype, input_name);
+ if (input_name != docname) frappe.realtime.doctype_subscribe(doctype, input_name);
return frappe
.xcall("frappe.model.rename_doc.update_document_title", {
doctype,
diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js
index 1ca72a4e45..10f933aecd 100644
--- a/frappe/public/js/frappe/list/list_view.js
+++ b/frappe/public/js/frappe/list/list_view.js
@@ -1362,7 +1362,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
if (this.list_view_settings?.disable_auto_refresh || this.realtime_events_setup) {
return;
}
- frappe.socketio.doctype_subscribe(this.doctype);
+ frappe.realtime.doctype_subscribe(this.doctype);
frappe.realtime.off("list_update");
frappe.realtime.on("list_update", (data) => {
if (data?.doctype !== this.doctype) {
@@ -1385,7 +1385,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
disable_realtime_updates() {
- frappe.socketio.doctype_unsubscribe(this.doctype);
+ frappe.realtime.doctype_unsubscribe(this.doctype);
this.realtime_events_setup = false;
}
diff --git a/frappe/public/js/frappe/request.js b/frappe/public/js/frappe/request.js
index 47ca1f7548..69867a6b14 100644
--- a/frappe/public/js/frappe/request.js
+++ b/frappe/public/js/frappe/request.js
@@ -75,7 +75,7 @@ frappe.call = function (opts) {
var callback = function (data, response_text) {
if (data.task_id) {
// async call, subscribe
- frappe.socketio.subscribe(data.task_id, opts);
+ frappe.realtime.subscribe(data.task_id, opts);
if (opts.queued) {
opts.queued(data);
diff --git a/frappe/public/js/frappe/socketio_client.js b/frappe/public/js/frappe/socketio_client.js
index 7084e9e2df..4797756baa 100644
--- a/frappe/public/js/frappe/socketio_client.js
+++ b/frappe/public/js/frappe/socketio_client.js
@@ -10,6 +10,7 @@ class RealTimeClient {
on(event, callback) {
if (this.socket) {
+ this.connect();
this.socket.on(event, callback);
}
}
@@ -20,7 +21,19 @@ class RealTimeClient {
}
}
- init(port = 9000) {
+ connect() {
+ if (this.lazy_connect) {
+ this.socket.connect();
+ this.lazy_connect = false;
+ }
+ }
+
+ emit(event, ...args) {
+ this.connect();
+ this.socket.emit(event, ...args);
+ }
+
+ init(port = 9000, lazy_connect = false) {
if (frappe.boot.disable_async) {
return;
}
@@ -28,7 +41,7 @@ class RealTimeClient {
if (this.socket) {
return;
}
-
+ this.lazy_connect = lazy_connect;
let me = this;
// Enable secure option when using HTTPS
@@ -37,11 +50,13 @@ class RealTimeClient {
secure: true,
withCredentials: true,
reconnectionAttempts: 3,
+ autoConnect: !lazy_connect,
});
} else if (window.location.protocol == "http:") {
this.socket = io(this.get_host(port), {
withCredentials: true,
reconnectionAttempts: 3,
+ autoConnect: !lazy_connect,
});
}
@@ -108,24 +123,22 @@ class RealTimeClient {
}
subscribe(task_id, opts) {
- // TODO DEPRECATE
-
- this.socket.emit("task_subscribe", task_id);
- this.socket.emit("progress_subscribe", task_id);
+ this.emit("task_subscribe", task_id);
+ this.emit("progress_subscribe", task_id);
this.open_tasks[task_id] = opts;
}
task_subscribe(task_id) {
- this.socket.emit("task_subscribe", task_id);
+ this.emit("task_subscribe", task_id);
}
task_unsubscribe(task_id) {
- this.socket.emit("task_unsubscribe", task_id);
+ this.emit("task_unsubscribe", task_id);
}
doctype_subscribe(doctype) {
- this.socket.emit("doctype_subscribe", doctype);
+ this.emit("doctype_subscribe", doctype);
}
doctype_unsubscribe(doctype) {
- this.socket.emit("doctype_unsubscribe", doctype);
+ this.emit("doctype_unsubscribe", doctype);
}
doc_subscribe(doctype, docname) {
if (frappe.flags.doc_subscribe) {
@@ -143,18 +156,18 @@ class RealTimeClient {
frappe.flags.doc_subscribe = false;
}, 1000);
- this.socket.emit("doc_subscribe", doctype, docname);
+ this.emit("doc_subscribe", doctype, docname);
this.open_docs.add(`${doctype}:${docname}`);
}
doc_unsubscribe(doctype, docname) {
- this.socket.emit("doc_unsubscribe", doctype, docname);
+ this.emit("doc_unsubscribe", doctype, docname);
return this.open_docs.delete(`${doctype}:${docname}`);
}
doc_open(doctype, docname) {
- this.socket.emit("doc_open", doctype, docname);
+ this.emit("doc_open", doctype, docname);
}
doc_close(doctype, docname) {
- this.socket.emit("doc_close", doctype, docname);
+ this.emit("doc_close", doctype, docname);
}
setup_listeners() {
this.socket.on("task_status_change", function (data) {
@@ -194,7 +207,7 @@ class RealTimeClient {
publish(event, message) {
if (this.socket) {
- this.socket.emit(event, message);
+ this.emit(event, message);
}
}
}
diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js
index b45f2346f1..2efe2314f5 100644
--- a/frappe/public/js/frappe/views/reports/report_view.js
+++ b/frappe/public/js/frappe/views/reports/report_view.js
@@ -56,7 +56,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
if (this.list_view_settings?.disable_auto_refresh) {
return;
}
- frappe.socketio.doctype_subscribe(this.doctype);
+ frappe.realtime.doctype_subscribe(this.doctype);
frappe.realtime.on("list_update", (data) => this.on_update(data));
}
diff --git a/frappe/templates/discussions/discussions.js b/frappe/templates/discussions/discussions.js
index ad6d13e834..56ab3e1ed2 100644
--- a/frappe/templates/discussions/discussions.js
+++ b/frappe/templates/discussions/discussions.js
@@ -69,14 +69,14 @@ const show_new_topic_modal = (e) => {
};
const setup_socket_io = () => {
- frappe.socketio.init(window.socketio_port || "9000");
- frappe.socketio.socket.on("publish_message", (data) => {
+ frappe.realtime.init(window.socketio_port || "9000");
+ frappe.realtime.on("publish_message", (data) => {
publish_message(data);
});
- frappe.socketio.socket.on("update_message", (data) => {
+ frappe.realtime.on("update_message", (data) => {
update_message(data);
});
- frappe.socketio.socket.on("delete_message", (data) => {
+ frappe.realtime.socket.on("delete_message", (data) => {
delete_message(data);
});
};
diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js
index a93c4d88cf..13f6390e97 100644
--- a/frappe/website/js/website.js
+++ b/frappe/website/js/website.js
@@ -653,5 +653,5 @@ $(document).on("page-change", function () {
frappe.ready(function () {
frappe.show_language_picker();
frappe.setup_videos();
- frappe.socketio.init(window.socketio_port);
+ frappe.realtime.init(window.socketio_port, true); // lazy connection
});
diff --git a/realtime/middlewares/authenticate.js b/realtime/middlewares/authenticate.js
index 1f8876a1da..6d81cd2e15 100644
--- a/realtime/middlewares/authenticate.js
+++ b/realtime/middlewares/authenticate.js
@@ -56,7 +56,6 @@ function get_site_name(socket) {
conf.default_site &&
["localhost", "127.0.0.1"].indexOf(get_hostname(socket.request.headers.host)) !== -1
) {
- // from currentsite.txt since host is localhost
socket.site_name = conf.default_site;
} else if (socket.request.headers.origin) {
socket.site_name = get_hostname(socket.request.headers.origin);
From ab44a9cca80c04b3090e8a9d44eca20b1e4f2fd7 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 11:27:25 +0530
Subject: [PATCH 81/97] test: socketio tests
- conflict check (moved from form)
- list view updates
- custom event subscribe and recieve
---
cypress/integration/form.js | 16 ------
cypress/integration/socket_updates.js | 72 +++++++++++++++++++++++++++
frappe/tests/ui_test_helpers.py | 21 ++++++++
3 files changed, 93 insertions(+), 16 deletions(-)
create mode 100644 cypress/integration/socket_updates.js
diff --git a/cypress/integration/form.js b/cypress/integration/form.js
index cdd6d7e9bd..bbd89ddb7a 100644
--- a/cypress/integration/form.js
+++ b/cypress/integration/form.js
@@ -111,22 +111,6 @@ context("Form", () => {
cy.get("@email_input2").should("not.have.class", "invalid");
});
- it("Shows version conflict warning", { scrollBehavior: false }, () => {
- cy.visit("/app/todo");
-
- cy.insert_doc("ToDo", { description: "old" }).then((doc) => {
- cy.visit(`/app/todo/${doc.name}`);
- // make form dirty
- cy.fill_field("status", "Cancelled", "Select");
-
- // update doc using api - simulating parallel change by another user
- cy.update_doc("ToDo", doc.name, { status: "Closed" }).then(() => {
- cy.findByRole("button", { name: "Refresh" }).click();
- cy.get_field("status", "Select").should("have.value", "Closed");
- });
- });
- });
-
it("Jump to field in collapsed section", { scrollBehavior: false }, () => {
cy.new_form("User");
diff --git a/cypress/integration/socket_updates.js b/cypress/integration/socket_updates.js
new file mode 100644
index 0000000000..38d13a500e
--- /dev/null
+++ b/cypress/integration/socket_updates.js
@@ -0,0 +1,72 @@
+context("Realtime updates", () => {
+ before(() => {
+ cy.login();
+ });
+
+ beforeEach(() => {
+ cy.visit("/app/todo");
+ // required because immediately after load socket is still connecting.
+ // Not a huge deal breaker in prod.
+ cy.wait(500);
+ });
+
+ it("Shows version conflict warning", { scrollBehavior: false }, () => {
+ cy.insert_doc("ToDo", { description: "old" }).then((doc) => {
+ cy.visit(`/app/todo/${doc.name}`);
+ // make form dirty
+ cy.fill_field("status", "Cancelled", "Select");
+
+ // update doc using api - simulating parallel change by another user
+ cy.update_doc("ToDo", doc.name, { status: "Closed" }).then(() => {
+ cy.findByRole("button", { name: "Refresh" }).click();
+ cy.get_field("status", "Select").should("have.value", "Closed");
+ });
+ });
+ });
+
+ it("List view updates in realtime on insert", { scrollBehavior: false }, () => {
+ const original = "Added for realtime update";
+ const updated = "Updated for realtime update";
+ cy.insert_doc("ToDo", { description: original }).then((doc) => {
+ cy.contains(original).should("be.visible");
+
+ // update doc using api - simulating parallel change by another user
+ cy.update_doc("ToDo", doc.name, { description: updated }).then(() => {
+ cy.contains(updated).should("be.visible");
+ });
+ });
+ });
+
+ it("Recieves msgprint from server", { scrollBehavior: false }, () => {
+ // required because immediately after load socket is still connecting.
+ // Not a deal breaker in prod
+ const msg = "msgprint sent via realtime";
+ publish_realtime({ event: "msgprint", message: msg }).then(() => {
+ cy.contains(msg).should("be.visible");
+ });
+ });
+
+ it("Recieves custom messages from server", { scrollBehavior: false }, () => {
+ const event = "cypress_event";
+ let handler = {
+ handle() {
+ console.log("clear");
+ },
+ };
+ cy.spy(handler, "handle").as("callback");
+
+ cy.window()
+ .its("frappe")
+ .then((frappe) => {
+ frappe.realtime.on(event, () => handler.handle());
+ });
+
+ publish_realtime({ event }).then(() => {
+ cy.get("@callback").should("be.called");
+ });
+ });
+});
+
+function publish_realtime(args) {
+ return cy.call("frappe.tests.ui_test_helpers.publish_realtime", args);
+}
diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py
index 0ffc120907..fd0fdbdc5b 100644
--- a/frappe/tests/ui_test_helpers.py
+++ b/frappe/tests/ui_test_helpers.py
@@ -621,3 +621,24 @@ def add_remove_role(action, user, role):
user_doc.remove_roles(role)
else:
user_doc.add_roles(role)
+
+
+@whitelist_for_tests
+def publish_realtime(
+ event=None,
+ message=None,
+ room=None,
+ user=None,
+ doctype=None,
+ docname=None,
+ task_id=None,
+):
+ frappe.publish_realtime(
+ event=event,
+ message=message,
+ room=room,
+ user=user,
+ doctype=doctype,
+ docname=docname,
+ task_id=task_id,
+ )
From 91377658039880e1090c9d968e9fe6a154f7c3e6 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 16:58:18 +0530
Subject: [PATCH 82/97] fix: halve prepared report threshold
Users can still enable/disable on their own after last refactor.
---
frappe/core/doctype/report/report.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index dba82bada5..89cbc1b2f5 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -121,7 +121,7 @@ class Report(Document):
def execute_script_report(self, filters):
# save the timestamp to automatically set to prepared
- threshold = 30
+ threshold = 15
res = []
start_time = datetime.datetime.now()
From b81aff3237152a5319c9d95e90d0b788af33b8af Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 17:09:15 +0530
Subject: [PATCH 83/97] test: simplify prepared report tests
---
.../prepared_report/test_prepared_report.py | 37 ++++++++++++-------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/frappe/core/doctype/prepared_report/test_prepared_report.py b/frappe/core/doctype/prepared_report/test_prepared_report.py
index a864ea73f8..6c2458d8a1 100644
--- a/frappe/core/doctype/prepared_report/test_prepared_report.py
+++ b/frappe/core/doctype/prepared_report/test_prepared_report.py
@@ -5,7 +5,7 @@ import time
import frappe
from frappe.desk.query_report import generate_report_result, get_report_doc
-from frappe.tests.utils import FrappeTestCase
+from frappe.tests.utils import FrappeTestCase, timeout
class TestPreparedReport(FrappeTestCase):
@@ -16,7 +16,18 @@ class TestPreparedReport(FrappeTestCase):
frappe.db.commit()
- def create_prepared_report(self, commit=False):
+ @timeout(seconds=20)
+ def wait_for_completion(self, report, status="Completed"):
+ frappe.db.commit() # Flush changes first
+ while True:
+ frappe.db.rollback() # read new data
+ report.reload()
+ if report.status == status:
+ break
+ # Cheap blocking behaviour
+ time.sleep(0.5)
+
+ def create_prepared_report(self, commit=True):
doc = frappe.get_doc(
{
"doctype": "Prepared Report",
@@ -30,23 +41,21 @@ class TestPreparedReport(FrappeTestCase):
return doc
def test_queueing(self):
- doc_ = self.create_prepared_report()
- self.assertEqual("Queued", doc_.status)
- self.assertTrue(doc_.queued_at)
+ doc = self.create_prepared_report()
+ self.assertEqual("Queued", doc.status)
+ self.assertTrue(doc.queued_at)
- frappe.db.commit()
- time.sleep(5)
+ self.wait_for_completion(doc)
- doc_ = frappe.get_last_doc("Prepared Report")
- self.assertEqual("Completed", doc_.status)
- self.assertTrue(doc_.job_id)
- self.assertTrue(doc_.report_end_time)
+ doc = frappe.get_last_doc("Prepared Report")
+ self.assertTrue(doc.job_id)
+ self.assertTrue(doc.report_end_time)
def test_prepared_data(self):
- doc_ = self.create_prepared_report(commit=True)
- time.sleep(5)
+ doc = self.create_prepared_report()
+ self.wait_for_completion(doc)
- prepared_data = json.loads(doc_.get_prepared_data().decode("utf-8"))
+ prepared_data = json.loads(doc.get_prepared_data().decode("utf-8"))
generated_data = generate_report_result(get_report_doc("Database Storage Usage By Tables"))
self.assertEqual(len(prepared_data["columns"]), len(generated_data["columns"]))
self.assertEqual(len(prepared_data["result"]), len(generated_data["result"]))
From 869f2194185bdac416726a8c2d522556d46b0454 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 17:17:10 +0530
Subject: [PATCH 84/97] fix: dont export prepared_report and letterhead
---
frappe/core/doctype/report/report.py | 4 ++++
.../database_storage_usage_by_tables.json | 3 +--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 89cbc1b2f5..8bd22b173e 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -49,6 +49,10 @@ class Report(Document):
def on_update(self):
self.export_doc()
+ def before_export(self):
+ self.letterhead = None
+ self.prepared_report = 0
+
def on_trash(self):
if (
self.is_standard == "Yes"
diff --git a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.json b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.json
index 20deb78ad6..773cb7771f 100644
--- a/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.json
+++ b/frappe/core/report/database_storage_usage_by_tables/database_storage_usage_by_tables.json
@@ -9,7 +9,6 @@
"filters": [],
"idx": 0,
"is_standard": "Yes",
- "letter_head": "abc",
"modified": "2022-10-19 02:59:00.365307",
"modified_by": "Administrator",
"module": "Core",
@@ -25,4 +24,4 @@
"role": "System Manager"
}
]
-}
\ No newline at end of file
+}
From f72643781d3c21723dba56210de55c6dbd594e78 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 17:22:43 +0530
Subject: [PATCH 85/97] feat: "Started" status in prepared reports
---
.../prepared_report/prepared_report.json | 4 +--
.../prepared_report/prepared_report.py | 18 +++++++---
.../prepared_report/test_prepared_report.py | 34 ++++++++++++++++---
3 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/frappe/core/doctype/prepared_report/prepared_report.json b/frappe/core/doctype/prepared_report/prepared_report.json
index fb3809e481..135b6a996c 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.json
+++ b/frappe/core/doctype/prepared_report/prepared_report.json
@@ -35,7 +35,7 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
- "options": "Error\nQueued\nCompleted",
+ "options": "Error\nQueued\nCompleted\nStarted",
"read_only": 1
},
{
@@ -104,7 +104,7 @@
],
"in_create": 1,
"links": [],
- "modified": "2023-05-19 15:41:03.428589",
+ "modified": "2023-07-01 17:18:40.183106",
"modified_by": "Administrator",
"module": "Core",
"name": "Prepared Report",
diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py
index ed7f4711aa..7182fa4920 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.py
+++ b/frappe/core/doctype/prepared_report/prepared_report.py
@@ -58,7 +58,7 @@ class PreparedReport(Document):
def generate_report(prepared_report):
- update_job_id(prepared_report, get_current_job().id)
+ update_job_id(prepared_report)
instance = frappe.get_doc("Prepared Report", prepared_report)
report = frappe.get_doc("Report", instance.report_name)
@@ -95,8 +95,18 @@ def generate_report(prepared_report):
)
-def update_job_id(prepared_report, job_id):
- frappe.db.set_value("Prepared Report", prepared_report, "job_id", job_id, update_modified=False)
+def update_job_id(prepared_report):
+ job = get_current_job()
+
+ frappe.db.set_value(
+ "Prepared Report",
+ prepared_report,
+ {
+ "job_id": job and job.id,
+ "status": "Started",
+ },
+ )
+
frappe.db.commit()
@@ -132,7 +142,7 @@ def get_reports_in_queued_state(report_name, filters):
filters={
"report_name": report_name,
"filters": process_filters_for_prepared_report(filters),
- "status": "Queued",
+ "status": ("in", ("Queued", "Started")),
"owner": frappe.session.user,
},
)
diff --git a/frappe/core/doctype/prepared_report/test_prepared_report.py b/frappe/core/doctype/prepared_report/test_prepared_report.py
index 6c2458d8a1..b8dd3d67d0 100644
--- a/frappe/core/doctype/prepared_report/test_prepared_report.py
+++ b/frappe/core/doctype/prepared_report/test_prepared_report.py
@@ -2,6 +2,7 @@
# License: MIT. See LICENSE
import json
import time
+from contextlib import contextmanager
import frappe
from frappe.desk.query_report import generate_report_result, get_report_doc
@@ -17,7 +18,7 @@ class TestPreparedReport(FrappeTestCase):
frappe.db.commit()
@timeout(seconds=20)
- def wait_for_completion(self, report, status="Completed"):
+ def wait_for_status(self, report, status):
frappe.db.commit() # Flush changes first
while True:
frappe.db.rollback() # read new data
@@ -27,11 +28,11 @@ class TestPreparedReport(FrappeTestCase):
# Cheap blocking behaviour
time.sleep(0.5)
- def create_prepared_report(self, commit=True):
+ def create_prepared_report(self, report=None, commit=True):
doc = frappe.get_doc(
{
"doctype": "Prepared Report",
- "report_name": "Database Storage Usage By Tables",
+ "report_name": report or "Database Storage Usage By Tables",
}
).insert()
@@ -45,7 +46,7 @@ class TestPreparedReport(FrappeTestCase):
self.assertEqual("Queued", doc.status)
self.assertTrue(doc.queued_at)
- self.wait_for_completion(doc)
+ self.wait_for_status(doc, "Completed")
doc = frappe.get_last_doc("Prepared Report")
self.assertTrue(doc.job_id)
@@ -53,10 +54,33 @@ class TestPreparedReport(FrappeTestCase):
def test_prepared_data(self):
doc = self.create_prepared_report()
- self.wait_for_completion(doc)
+ self.wait_for_status(doc, "Completed")
prepared_data = json.loads(doc.get_prepared_data().decode("utf-8"))
generated_data = generate_report_result(get_report_doc("Database Storage Usage By Tables"))
self.assertEqual(len(prepared_data["columns"]), len(generated_data["columns"]))
self.assertEqual(len(prepared_data["result"]), len(generated_data["result"]))
self.assertEqual(len(prepared_data), len(generated_data))
+
+ def test_start_status(self):
+ if frappe.db.db_type == "postgres":
+ return
+
+ with test_report(report_type="Query Report", query="select sleep(5)") as report:
+ doc = self.create_prepared_report(report.name)
+ self.wait_for_status(doc, "Started")
+
+
+@contextmanager
+def test_report(**args):
+ try:
+ report = frappe.new_doc("Report")
+ report.update(args)
+ if not report.report_name:
+ report.report_name = frappe.generate_hash()
+ if not report.ref_doctype:
+ report.ref_doctype = "ToDo"
+ report.insert()
+ yield report
+ finally:
+ report.delete()
From 58501760666bdce4348eaa72df51eef6ec834698 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 18:05:30 +0530
Subject: [PATCH 86/97] fix: Stop running prepared reports when report is
deleted
---
.../doctype/prepared_report/prepared_report.py | 10 ++++++++++
.../prepared_report/test_prepared_report.py | 18 ++++++++++++------
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py
index 7182fa4920..1d768cb6a1 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.py
+++ b/frappe/core/doctype/prepared_report/prepared_report.py
@@ -3,6 +3,7 @@
import json
+from contextlib import suppress
from typing import Any
from rq import get_current_job
@@ -38,6 +39,15 @@ class PreparedReport(Document):
def before_insert(self):
self.status = "Queued"
+ def on_trash(self):
+ # If job is running then send stop signal.
+ if self.status != "Started":
+ return
+
+ with suppress(Exception):
+ job = frappe.get_doc("RQ Job", self.job_id)
+ job.stop_job()
+
def after_insert(self):
enqueue(
generate_report,
diff --git a/frappe/core/doctype/prepared_report/test_prepared_report.py b/frappe/core/doctype/prepared_report/test_prepared_report.py
index b8dd3d67d0..dbd1294cbb 100644
--- a/frappe/core/doctype/prepared_report/test_prepared_report.py
+++ b/frappe/core/doctype/prepared_report/test_prepared_report.py
@@ -6,6 +6,8 @@ from contextlib import contextmanager
import frappe
from frappe.desk.query_report import generate_report_result, get_report_doc
+from frappe.query_builder.utils import db_type_is
+from frappe.tests.test_query_builder import run_only_if
from frappe.tests.utils import FrappeTestCase, timeout
@@ -25,7 +27,6 @@ class TestPreparedReport(FrappeTestCase):
report.reload()
if report.status == status:
break
- # Cheap blocking behaviour
time.sleep(0.5)
def create_prepared_report(self, report=None, commit=True):
@@ -62,13 +63,17 @@ class TestPreparedReport(FrappeTestCase):
self.assertEqual(len(prepared_data["result"]), len(generated_data["result"]))
self.assertEqual(len(prepared_data), len(generated_data))
- def test_start_status(self):
- if frappe.db.db_type == "postgres":
- return
-
- with test_report(report_type="Query Report", query="select sleep(5)") as report:
+ @run_only_if(db_type_is.MARIADB)
+ def test_start_status_and_kill_jobs(self):
+ with test_report(report_type="Query Report", query="select sleep(10)") as report:
doc = self.create_prepared_report(report.name)
self.wait_for_status(doc, "Started")
+ job_id = doc.job_id
+
+ doc.delete()
+ time.sleep(1)
+ job = frappe.get_doc("RQ Job", job_id)
+ self.assertEqual(job.status, "stopped")
@contextmanager
@@ -81,6 +86,7 @@ def test_report(**args):
if not report.ref_doctype:
report.ref_doctype = "ToDo"
report.insert()
+ frappe.db.commit()
yield report
finally:
report.delete()
From 4ece3da47d7a664de56b2e48dfdea2fd6003a1a3 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 13:14:00 +0530
Subject: [PATCH 87/97] test: publish_progress ui test
---
cypress/integration/socket_updates.js | 7 +++++++
frappe/tests/ui_test_helpers.py | 16 ++++++++++++++++
2 files changed, 23 insertions(+)
diff --git a/cypress/integration/socket_updates.js b/cypress/integration/socket_updates.js
index 38d13a500e..9f8c55b938 100644
--- a/cypress/integration/socket_updates.js
+++ b/cypress/integration/socket_updates.js
@@ -65,6 +65,13 @@ context("Realtime updates", () => {
cy.get("@callback").should("be.called");
});
});
+
+ it("Progress bar", { scrollBehavior: false }, () => {
+ const title = "RealTime Progress";
+ cy.call("frappe.tests.ui_test_helpers.publish_progress", { title }).then(() => {
+ cy.contains(title).should("be.visible");
+ });
+ });
});
function publish_realtime(args) {
diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py
index fd0fdbdc5b..8920872069 100644
--- a/frappe/tests/ui_test_helpers.py
+++ b/frappe/tests/ui_test_helpers.py
@@ -642,3 +642,19 @@ def publish_realtime(
docname=docname,
task_id=task_id,
)
+
+
+@whitelist_for_tests
+def publish_progress(duration=3, title=None, doctype=None, docname=None):
+ # This should consider session user and only show it to current user.
+ frappe.enqueue(slow_task, duration=duration, title=title, doctype=doctype, docname=docname)
+
+
+def slow_task(duration, title, doctype, docname):
+ import time
+
+ steps = 10
+
+ for i in range(steps + 1):
+ frappe.publish_progress(i * 10, title=title, doctype=doctype, docname=docname)
+ time.sleep(int(duration) / steps)
From 2e8ea0202810c3a68b4946cccb2ef9e9b6875509 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 18:24:57 +0530
Subject: [PATCH 88/97] fix: Expire stalled reports
Mark any report that take more than 60 minutes as failed
---
.../prepared_report/prepared_report.py | 23 +++++++++++++++++--
frappe/hooks.py | 6 ++---
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py
index 1d768cb6a1..30efa8eb91 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.py
+++ b/frappe/core/doctype/prepared_report/prepared_report.py
@@ -13,9 +13,13 @@ from frappe.desk.form.load import get_attachments
from frappe.desk.query_report import generate_report_result
from frappe.model.document import Document
from frappe.monitor import add_data_to_monitor
-from frappe.utils import gzip_compress, gzip_decompress
+from frappe.utils import add_to_date, gzip_compress, gzip_decompress, now
from frappe.utils.background_jobs import enqueue
+# If prepared report runs for longer than this time it's automatically considered as failed
+FAILURE_THRESHOLD = 60 * 60
+REPORT_TIMEOUT = 25 * 60
+
class PreparedReport(Document):
@property
@@ -53,7 +57,7 @@ class PreparedReport(Document):
generate_report,
queue="long",
prepared_report=self.name,
- timeout=1500,
+ timeout=REPORT_TIMEOUT,
enqueue_after_commit=True,
)
@@ -171,6 +175,21 @@ def get_completed_prepared_report(filters, user, report_name):
)
+def expire_stalled_report():
+ frappe.db.set_value(
+ "Prepared Report",
+ {
+ "status": "Started",
+ "modified": ("<", add_to_date(now(), seconds=-FAILURE_THRESHOLD, as_datetime=True)),
+ },
+ {
+ "status": "Failed",
+ "error_message": frappe._("Report timed out."),
+ },
+ update_modified=False,
+ )
+
+
@frappe.whitelist()
def delete_prepared_reports(reports):
reports = frappe.parse_json(reports)
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 85a28feb39..fe430918d0 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -196,9 +196,9 @@ scheduler_events = {
"frappe.email.doctype.email_account.email_account.pull",
],
# Hourly but offset by 30 minutes
- # "30 * * * *": [
- #
- # ],
+ "30 * * * *": [
+ "frappe.core.doctype.prepared_report.prepared_report.expire_stalled_report",
+ ],
# Daily but offset by 45 minutes
"45 0 * * *": [
"frappe.core.doctype.log_settings.log_settings.run_log_clean_up",
From e342f7bd9cd14a951d2a7b0b0795fc079eca07a2 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 18:29:38 +0530
Subject: [PATCH 89/97] perf: index status and report names
Two commonly used fields to filter by
---
frappe/core/doctype/prepared_report/prepared_report.json | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/frappe/core/doctype/prepared_report/prepared_report.json b/frappe/core/doctype/prepared_report/prepared_report.json
index 135b6a996c..b64b91c4ef 100644
--- a/frappe/core/doctype/prepared_report/prepared_report.json
+++ b/frappe/core/doctype/prepared_report/prepared_report.json
@@ -25,7 +25,8 @@
"fieldtype": "Data",
"label": "Report Name",
"read_only": 1,
- "reqd": 1
+ "reqd": 1,
+ "search_index": 1
},
{
"default": "Queued",
@@ -36,7 +37,8 @@
"in_standard_filter": 1,
"label": "Status",
"options": "Error\nQueued\nCompleted\nStarted",
- "read_only": 1
+ "read_only": 1,
+ "search_index": 1
},
{
"fieldname": "column_break_4",
@@ -104,7 +106,7 @@
],
"in_create": 1,
"links": [],
- "modified": "2023-07-01 17:18:40.183106",
+ "modified": "2023-07-01 18:29:12.700239",
"modified_by": "Administrator",
"module": "Core",
"name": "Prepared Report",
From ab42e58dcfa39a32ac5718189a13169f511f1f9a Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 19:34:08 +0530
Subject: [PATCH 90/97] test: flaky test due to list view filters
---
cypress/integration/socket_updates.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/cypress/integration/socket_updates.js b/cypress/integration/socket_updates.js
index 9f8c55b938..d0642e1b03 100644
--- a/cypress/integration/socket_updates.js
+++ b/cypress/integration/socket_updates.js
@@ -8,6 +8,7 @@ context("Realtime updates", () => {
// required because immediately after load socket is still connecting.
// Not a huge deal breaker in prod.
cy.wait(500);
+ cy.clear_filters();
});
it("Shows version conflict warning", { scrollBehavior: false }, () => {
From ad79c9d18062b544e06a607a68c31d7b8c7f4774 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 20:06:00 +0530
Subject: [PATCH 91/97] chore: remove broken call to geoip
This has never worked afaik
---
frappe/auth.py | 2 --
frappe/sessions.py | 3 ---
2 files changed, 5 deletions(-)
diff --git a/frappe/auth.py b/frappe/auth.py
index 29c3e41694..d1259e1aaf 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -349,8 +349,6 @@ class CookieManager:
expires = datetime.datetime.now() + datetime.timedelta(days=3)
if frappe.session.sid:
self.set_cookie("sid", frappe.session.sid, expires=expires, httponly=True)
- if frappe.session.session_country:
- self.set_cookie("country", frappe.session.session_country)
def set_cookie(self, key, value, expires=None, secure=False, httponly=False, samesite="Lax"):
if not secure and hasattr(frappe.local, "request"):
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 2709de8fab..b0eb7e7353 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -236,9 +236,6 @@ class Session:
"session_expiry": get_expiry_period(),
"full_name": self.full_name,
"user_type": self.user_type,
- "session_country": get_geo_ip_country(frappe.local.request_ip)
- if frappe.local.request_ip
- else None,
}
)
From 70da4ba51ddc08bb1f03fc56ceff79f6b10d4a4a Mon Sep 17 00:00:00 2001
From: Kevin Shenk
Date: Sat, 1 Jul 2023 13:56:50 -0400
Subject: [PATCH 92/97] fix: typo on enqueue args
The deduplicate argument was missing the 'l'.
---
frappe/email/queue.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/email/queue.py b/frappe/email/queue.py
index 500a126f72..cae5f76b3d 100755
--- a/frappe/email/queue.py
+++ b/frappe/email/queue.py
@@ -149,7 +149,7 @@ def flush(from_test=False):
now=from_test,
job_id=f"email_queue_sendmail_{row.name}",
queue="short",
- dedupicate=True,
+ deduplicate=True,
)
except Exception:
frappe.get_doc("Email Queue", row.name).log_error()
From e0f35fb85f1550086a4f37306d3700261a8f9121 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 2 Jul 2023 11:25:43 +0530
Subject: [PATCH 93/97] fix: Update country names (#21545)
* fix: Update country names
* fix: revert name back
---
frappe/geo/country_info.json | 6 +++---
frappe/patches.txt | 1 +
frappe/patches/v14_0/update_country_names.py | 12 ++++++++++++
3 files changed, 16 insertions(+), 3 deletions(-)
create mode 100644 frappe/patches/v14_0/update_country_names.py
diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json
index f308dc63e3..858b43b883 100644
--- a/frappe/geo/country_info.json
+++ b/frappe/geo/country_info.json
@@ -669,7 +669,7 @@
"currency_fraction_units": 100,
"isd": "+242"
},
- "Congo, The Democratic Republic of the": {
+ "Congo, Democratic Republic of the": {
"code": "cd",
"number_format": "#,###.##",
"currency": "CDF",
@@ -2632,7 +2632,7 @@
],
"isd": "+992"
},
- "Tanzania": {
+ "Tanzania, United Republic of": {
"code": "tz",
"currency": "TZS",
"currency_name": "Tanzanian Shilling",
@@ -2913,7 +2913,7 @@
"currency_fraction_units": 100,
"isd": "+58"
},
- "Vietnam": {
+ "Viet Nam": {
"code": "vn",
"currency": "VND",
"currency_name": "Dong",
diff --git a/frappe/patches.txt b/frappe/patches.txt
index ebdda9b220..9ce2d0896d 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -226,3 +226,4 @@ frappe.desk.doctype.form_tour.patches.introduce_ui_tours
execute:frappe.delete_doc_if_exists("Workspace", "Customization")
execute:frappe.db.set_single_value("Document Naming Settings", "default_amend_naming", "Amend Counter")
execute:frappe.delete_doc_if_exists("DocType", "Error Snapshot")
+frappe.patches.v14_0.update_country_names
diff --git a/frappe/patches/v14_0/update_country_names.py b/frappe/patches/v14_0/update_country_names.py
new file mode 100644
index 0000000000..272c4ed896
--- /dev/null
+++ b/frappe/patches/v14_0/update_country_names.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+ country_info_map = {
+ "Tanzania": "Tanzania, United Republic of",
+ "Vietnam": "Viet Nam",
+ "Congo, The Democratic Republic of the": "Congo, Democratic Republic of the",
+ }
+
+ for old, new in country_info_map.items():
+ frappe.rename_doc("Country", old, new, force=True)
From 3a74b38e8c94d4b26267c650a9c9c112941f85e8 Mon Sep 17 00:00:00 2001
From: Deepesh Garg
Date: Sun, 2 Jul 2023 12:08:43 +0530
Subject: [PATCH 94/97] Revert "fix: Update country names (#21545)"
This reverts commit e0f35fb85f1550086a4f37306d3700261a8f9121.
---
frappe/geo/country_info.json | 6 +++---
frappe/patches.txt | 1 -
frappe/patches/v14_0/update_country_names.py | 12 ------------
3 files changed, 3 insertions(+), 16 deletions(-)
delete mode 100644 frappe/patches/v14_0/update_country_names.py
diff --git a/frappe/geo/country_info.json b/frappe/geo/country_info.json
index 858b43b883..f308dc63e3 100644
--- a/frappe/geo/country_info.json
+++ b/frappe/geo/country_info.json
@@ -669,7 +669,7 @@
"currency_fraction_units": 100,
"isd": "+242"
},
- "Congo, Democratic Republic of the": {
+ "Congo, The Democratic Republic of the": {
"code": "cd",
"number_format": "#,###.##",
"currency": "CDF",
@@ -2632,7 +2632,7 @@
],
"isd": "+992"
},
- "Tanzania, United Republic of": {
+ "Tanzania": {
"code": "tz",
"currency": "TZS",
"currency_name": "Tanzanian Shilling",
@@ -2913,7 +2913,7 @@
"currency_fraction_units": 100,
"isd": "+58"
},
- "Viet Nam": {
+ "Vietnam": {
"code": "vn",
"currency": "VND",
"currency_name": "Dong",
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 9ce2d0896d..ebdda9b220 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -226,4 +226,3 @@ frappe.desk.doctype.form_tour.patches.introduce_ui_tours
execute:frappe.delete_doc_if_exists("Workspace", "Customization")
execute:frappe.db.set_single_value("Document Naming Settings", "default_amend_naming", "Amend Counter")
execute:frappe.delete_doc_if_exists("DocType", "Error Snapshot")
-frappe.patches.v14_0.update_country_names
diff --git a/frappe/patches/v14_0/update_country_names.py b/frappe/patches/v14_0/update_country_names.py
deleted file mode 100644
index 272c4ed896..0000000000
--- a/frappe/patches/v14_0/update_country_names.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import frappe
-
-
-def execute():
- country_info_map = {
- "Tanzania": "Tanzania, United Republic of",
- "Vietnam": "Viet Nam",
- "Congo, The Democratic Republic of the": "Congo, Democratic Republic of the",
- }
-
- for old, new in country_info_map.items():
- frappe.rename_doc("Country", old, new, force=True)
From ee4c66ecf152d82b33308ed5fb49370940a0eb34 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sat, 1 Jul 2023 20:47:22 +0530
Subject: [PATCH 95/97] feat(UX): Guess country from system_timezone
This is accurate enough for vast majority of countries.
Alternate is using GeoIP and making network calls.
---
frappe/desk/page/setup_wizard/setup_wizard.js | 31 ++++++++++++++-----
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js
index 7d68fd683c..c19a336c3b 100644
--- a/frappe/desk/page/setup_wizard/setup_wizard.js
+++ b/frappe/desk/page/setup_wizard/setup_wizard.js
@@ -545,15 +545,19 @@ frappe.setup.utils = {
slide.get_input("timezone").empty().add_options(data.all_timezones);
- // set values if present
- if (frappe.wizard.values.country) {
- country_field.set_input(frappe.wizard.values.country);
- } else if (data.default_country) {
- country_field.set_input(data.default_country);
- }
-
slide.get_field("currency").set_input(frappe.wizard.values.currency);
slide.get_field("timezone").set_input(frappe.wizard.values.timezone);
+
+ // set values if present
+ let country =
+ frappe.wizard.values.country ||
+ data.default_country ||
+ guess_country(frappe.setup.data.regional_data.country_info);
+
+ if (country) {
+ country_field.set_input(country);
+ $(country_field.input).change();
+ }
},
bind_language_events: function (slide) {
@@ -630,3 +634,16 @@ frappe.setup.utils = {
});
},
};
+
+function guess_country(country_info) {
+ try {
+ const system_timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
+
+ for ([country, info] of Object.entries(country_info)) {
+ let possible_timezones = (info.timezones || []).filter((t) => t == system_timezone);
+ if (possible_timezones.length) return country;
+ }
+ } catch (e) {
+ console.log("Could not guess country", e);
+ }
+}
From 1a7cb47826e11d840e63b4c8aea1c2203795f61e Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sun, 2 Jul 2023 12:50:43 +0530
Subject: [PATCH 96/97] fix: setup wizard auto completes when clickin on
autocomplete fields
closes https://github.com/frappe/frappe/issues/15693
---
frappe/desk/page/setup_wizard/setup_wizard.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js
index c19a336c3b..e5c268b24c 100644
--- a/frappe/desk/page/setup_wizard/setup_wizard.js
+++ b/frappe/desk/page/setup_wizard/setup_wizard.js
@@ -97,10 +97,13 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {
handle_enter_press(e) {
if (e.which === frappe.ui.keyCode.ENTER) {
- var $target = $(e.target);
- if ($target.hasClass("prev-btn")) {
+ let $target = $(e.target);
+ if ($target.hasClass("prev-btn") || $target.hasClass("next-btn")) {
$target.trigger("click");
} else {
+ // hitting enter on autocomplete field shouldn't trigger next slide.
+ if ($target.data().fieldtype == "Autocomplete") return;
+
this.container.find(".next-btn").trigger("click");
e.preventDefault();
}
From a63398778eb88c43a26f5985f40adbbcdd59e712 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Sun, 2 Jul 2023 16:22:14 +0530
Subject: [PATCH 97/97] perf: tune gc by default
This is running on several prod site without any noticable problems, so
making it default behaviour.
Opt out by setting env variable `FRAPPE_TUNE_GC=False`
---
.github/helper/install.sh | 2 --
frappe/__init__.py | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index 5a4d341a9b..5cdcbebe1a 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -54,8 +54,6 @@ fi
echo "Starting Bench..."
-export FRAPPE_TUNE_GC=True
-
bench start &> ~/frappe-bench/bench_start.log &
if [ "$TYPE" == "server" ]
diff --git a/frappe/__init__.py b/frappe/__init__.py
index 13e9448109..88b995d17b 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -58,7 +58,7 @@ re._MAXCACHE = (
50 # reduced from default 512 given we are already maintaining this on parent worker
)
-_tune_gc = bool(os.environ.get("FRAPPE_TUNE_GC", False))
+_tune_gc = bool(sbool(os.environ.get("FRAPPE_TUNE_GC", True)))
if _dev_server:
warnings.simplefilter("always", DeprecationWarning)