diff --git a/cypress/integration/recorder.js b/cypress/integration/recorder.js index 878d8af848..ed2a9c86ba 100644 --- a/cypress/integration/recorder.js +++ b/cypress/integration/recorder.js @@ -61,7 +61,7 @@ context('Recorder', () => { cy.visit('/desk#recorder'); - cy.contains('.list-row-container span', 'frappe.desk.reportview.get').click(); + cy.get('.list-row-container span').contains('frappe.desk.reportview.get').click(); cy.location('hash').should('contain', '#recorder/request/'); cy.get('form').should('contain', 'frappe.desk.reportview.get'); diff --git a/frappe/client.py b/frappe/client.py index a813e3ec55..0db18421ef 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -73,6 +73,8 @@ def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False, paren frappe.throw(_("No permission for {0}").format(doctype), frappe.PermissionError) filters = get_safe_filters(filters) + if isinstance(filters, string_types): + filters = {"name": filters} try: fields = json.loads(fieldname) @@ -85,7 +87,12 @@ def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False, paren if not filters: filters = None - value = frappe.get_list(doctype, filters=filters, fields=fields, debug=debug, limit=1) + + if frappe.get_meta(doctype).issingle: + value = frappe.db.get_values_from_single(fields, filters, doctype, as_dict=as_dict, debug=debug) + else: + value = frappe.get_list(doctype, filters=filters, fields=fields, debug=debug, limit=1) + if as_dict: value = value[0] if value else {} else: diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index ae9d070976..148ae87249 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -47,11 +47,11 @@ class Workspace: self.allowed_pages = get_allowed_pages(cache=True) self.allowed_reports = get_allowed_reports(cache=True) - + if not minimal: self.onboarding_doc = self.get_onboarding_doc() self.onboarding = None - + self.table_counts = get_table_with_counts() self.restricted_doctypes = frappe.cache().get_value("domain_restricted_doctypes") or build_domain_restriced_doctype_cache() self.restricted_pages = frappe.cache().get_value("domain_restricted_pages") or build_domain_restriced_page_cache() @@ -59,7 +59,7 @@ class Workspace: def is_page_allowed(self): cards = self.doc.cards + get_custom_reports_and_doctypes(self.doc.module) + self.extended_cards shortcuts = self.doc.shortcuts + self.extended_shortcuts - + for section in cards: links = loads(section.links) if isinstance(section.links, string_types) else section.links for item in links: @@ -195,7 +195,7 @@ class Workspace: 'docs_url': self.onboarding_doc.documentation_url, 'items': self.get_onboarding_steps() } - + @handle_not_exist def get_cards(self): cards = self.doc.cards @@ -303,7 +303,7 @@ class Workspace: if self.is_item_allowed(item.link_to, item.type) and _in_active_domains(item): if item.type == "Report": report = self.allowed_reports.get(item.link_to, {}) - if report.get("report_type") in ["Query Report", "Script Report"]: + if report.get("report_type") in ["Query Report", "Script Report", "Custom Report"]: new_item['is_query_report'] = 1 else: new_item['ref_doctype'] = report.get('ref_doctype') @@ -358,7 +358,7 @@ def get_desk_sidebar_items(flatten=False, cache=True): _cache = frappe.cache() if cache: pages = _cache.get_value("desk_sidebar_items", user=frappe.session.user) - + if not pages or not cache: # don't get domain restricted pages blocked_modules = frappe.get_doc('User', frappe.session.user).get_blocked_modules() @@ -377,7 +377,7 @@ def get_desk_sidebar_items(flatten=False, cache=True): order_by = "pin_to_top desc, pin_to_bottom asc, name asc" all_pages = frappe.get_all("Desk Page", fields=["name", "category"], filters=filters, order_by=order_by, ignore_permissions=True) pages = [] - + # Filter Page based on Permission for page in all_pages: try: diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 29cd890bf1..14a3cfd9f1 100755 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -700,8 +700,10 @@ class EmailAccount(Document): email_server.connect() if email_server.imap: - email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message) - + try: + email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message.encode()) + except Exception: + frappe.log_error() @frappe.whitelist() def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len=None, filters=None): diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 8bffc108b9..25b6f93f83 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -460,7 +460,7 @@ def send_one(email, smtpserver=None, auto_commit=True, now=False): frappe.get_doc('Communication', email.communication).set_delivery_status(commit=auto_commit) if smtpserver.append_emails_to_sent_folder and email_sent_to_any_recipient: - smtpserver.email_account.append_email_to_sent_folder(encode(message)) + smtpserver.email_account.append_email_to_sent_folder(message) except (smtplib.SMTPServerDisconnected, smtplib.SMTPConnectError, diff --git a/frappe/integrations/desk_page/integrations/integrations.json b/frappe/integrations/desk_page/integrations/integrations.json index 9201e223f8..cbf7c9c085 100644 --- a/frappe/integrations/desk_page/integrations/integrations.json +++ b/frappe/integrations/desk_page/integrations/integrations.json @@ -10,11 +10,6 @@ "label": "Google Services", "links": "[\n {\n \"description\": \"Google API Settings.\",\n \"label\": \"Google Settings\",\n \"name\": \"Google Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Contacts Integration.\",\n \"label\": \"Google Contacts\",\n \"name\": \"Google Contacts\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Calendar Integration.\",\n \"label\": \"Google Calendar\",\n \"name\": \"Google Calendar\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Google Drive Integration.\",\n \"label\": \"Google Drive\",\n \"name\": \"Google Drive\",\n \"type\": \"doctype\"\n }\n]" }, - { - "hidden": 0, - "label": "Webhook", - "links": "[\n {\n \"description\": \"Webhooks calling API requests into web apps\",\n \"label\": \"Webhook\",\n \"name\": \"Webhook\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Slack Webhooks for internal integration\",\n \"label\": \"Slack Webhook URL\",\n \"name\": \"Slack Webhook URL\",\n \"type\": \"doctype\"\n }\n]" - }, { "hidden": 0, "label": "Authentication", @@ -23,7 +18,12 @@ { "hidden": 0, "label": "Payments", - "links": "[\n {\n \"description\": \"Braintree payment gateway settings\",\n \"label\": \"Braintree Settings\",\n \"name\": \"Braintree Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"PayPal payment gateway settings\",\n \"label\": \"PayPal Settings\",\n \"name\": \"PayPal Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Razorpay Payment gateway settings\",\n \"label\": \"Razorpay Settings\",\n \"name\": \"Razorpay Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stripe payment gateway settings\",\n \"label\": \"Stripe Settings\",\n \"name\": \"Stripe Settings\",\n \"type\": \"doctype\"\n }\n]" + "links": "[\n {\n \"description\": \"Braintree payment gateway settings\",\n \"label\": \"Braintree Settings\",\n \"name\": \"Braintree Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"PayPal payment gateway settings\",\n \"label\": \"PayPal Settings\",\n \"name\": \"PayPal Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Razorpay Payment gateway settings\",\n \"label\": \"Razorpay Settings\",\n \"name\": \"Razorpay Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Stripe payment gateway settings\",\n \"label\": \"Stripe Settings\",\n \"name\": \"Stripe Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Paytm payment gateway settings\",\n \"label\": \"Paytm Settings\",\n \"name\": \"Paytm Settings\",\n \"type\": \"doctype\"\n }\n]" + }, + { + "hidden": 0, + "label": "Settings", + "links": "[\n {\n \"description\": \"Webhooks calling API requests into web apps\",\n \"label\": \"Webhook\",\n \"name\": \"Webhook\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Slack Webhooks for internal integration\",\n \"label\": \"Slack Webhook URL\",\n \"name\": \"Slack Webhook URL\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Twilio Settings for WhatsApp integration\",\n \"label\": \"Twilio Settings\",\n \"name\": \"Twilio Settings\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"SMS Settings for sending sms\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n }\n]" } ], "category": "Administration", @@ -34,11 +34,11 @@ "docstatus": 0, "doctype": "Desk Page", "extends_another_page": 0, - "icon": "frapicon-dashboard", + "hide_custom": 0, "idx": 0, "is_standard": 1, "label": "Integrations", - "modified": "2020-04-01 11:24:40.751651", + "modified": "2020-08-20 23:04:04.528572", "modified_by": "Administrator", "module": "Integrations", "name": "Integrations", diff --git a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py index c8b007ba7b..470b301204 100755 --- a/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py +++ b/frappe/integrations/doctype/s3_backup_settings/s3_backup_settings.py @@ -8,7 +8,7 @@ import os.path import frappe import boto3 from frappe import _ -from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size +from frappe.integrations.offsite_backup_utils import get_latest_backup_file, send_email, validate_file_size, generate_files_backup from frappe.model.document import Document from frappe.utils import cint from frappe.utils.background_jobs import enqueue @@ -125,6 +125,11 @@ def backup_to_s3(): else: if backup_files: db_filename, site_config, files_filename, private_files = get_latest_backup_file(with_files=backup_files) + + if not files_filename or not private_files: + generate_files_backup() + db_filename, site_config, files_filename, private_files = get_latest_backup_file(with_files=backup_files) + else: db_filename, site_config = get_latest_backup_file() diff --git a/frappe/integrations/doctype/twilio_number_group/twilio_number_group.json b/frappe/integrations/doctype/twilio_number_group/twilio_number_group.json index 1790581ca7..9d51e4b452 100644 --- a/frappe/integrations/doctype/twilio_number_group/twilio_number_group.json +++ b/frappe/integrations/doctype/twilio_number_group/twilio_number_group.json @@ -14,12 +14,16 @@ "fieldtype": "Data", "in_list_view": 1, "label": "Phone Number", + "options": "Phone", + "show_days": 1, + "show_seconds": 1, "unique": 1 } ], + "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-03-02 14:54:34.396254", + "modified": "2020-08-20 22:48:57.166791", "modified_by": "Administrator", "module": "Integrations", "name": "Twilio Number Group", diff --git a/frappe/integrations/doctype/twilio_settings/twilio_settings.py b/frappe/integrations/doctype/twilio_settings/twilio_settings.py index ba0565b3af..6c698d719a 100644 --- a/frappe/integrations/doctype/twilio_settings/twilio_settings.py +++ b/frappe/integrations/doctype/twilio_settings/twilio_settings.py @@ -11,7 +11,16 @@ from frappe.utils.password import get_decrypted_password from six import string_types class TwilioSettings(Document): - pass + def validate(self): + self.validate_twilio_credentials() + + def validate_twilio_credentials(self): + try: + auth_token = get_decrypted_password("Twilio Settings", "Twilio Settings", 'auth_token') + client = Client(self.account_sid, auth_token) + client.api.accounts(self.account_sid).fetch() + except Exception: + frappe.throw(_("Invalid Account SID or Auth Token.")) def send_whatsapp_message(sender, receiver_list, message): import json diff --git a/frappe/integrations/offsite_backup_utils.py b/frappe/integrations/offsite_backup_utils.py index a551d8edf1..7d33dd14bc 100644 --- a/frappe/integrations/offsite_backup_utils.py +++ b/frappe/integrations/offsite_backup_utils.py @@ -90,3 +90,13 @@ def validate_file_size(): if file_size > 1: frappe.flags.create_new_backup = False + +def generate_files_backup(): + from frappe.utils.backups import BackupGenerator + + backup = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name, + frappe.conf.db_password, db_host = frappe.db.host, + db_type=frappe.conf.db_type, db_port=frappe.conf.db_port) + + backup.set_backup_file_name() + backup.zip_files() \ No newline at end of file diff --git a/frappe/patches.txt b/frappe/patches.txt index 8657be1fc5..afbd007abc 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -205,7 +205,7 @@ frappe.patches.v9_1.resave_domain_settings frappe.patches.v9_1.revert_domain_settings frappe.patches.v9_1.move_feed_to_activity_log execute:frappe.delete_doc('Page', 'data-import-tool', ignore_missing=True) -frappe.patches.v10_0.reload_countries_and_currencies +frappe.patches.v10_0.reload_countries_and_currencies # 20-10-2020 frappe.patches.v10_0.refactor_social_login_keys frappe.patches.v10_0.enable_chat_by_default_within_system_settings frappe.patches.v10_0.remove_custom_field_for_disabled_domain @@ -301,3 +301,4 @@ frappe.patches.v13_0.generate_theme_files_in_public_folder frappe.patches.v13_0.increase_password_length frappe.patches.v13_0.add_toggle_width_in_navbar_settings frappe.patches.v13_0.rename_notification_fields +frappe.patches.v13_0.remove_duplicate_navbar_items diff --git a/frappe/patches/v13_0/add_toggle_width_in_navbar_settings.py b/frappe/patches/v13_0/add_toggle_width_in_navbar_settings.py index 4d241cd8c7..59acb77480 100644 --- a/frappe/patches/v13_0/add_toggle_width_in_navbar_settings.py +++ b/frappe/patches/v13_0/add_toggle_width_in_navbar_settings.py @@ -4,6 +4,9 @@ import frappe def execute(): navbar_settings = frappe.get_single("Navbar Settings") + if frappe.db.exists('Navbar Item', {'item_label': 'Toggle Full Width'}): + return + for navbar_item in navbar_settings.settings_dropdown[5:]: navbar_item.idx = navbar_item.idx + 1 diff --git a/frappe/patches/v13_0/remove_duplicate_navbar_items.py b/frappe/patches/v13_0/remove_duplicate_navbar_items.py new file mode 100644 index 0000000000..cb4de4ca07 --- /dev/null +++ b/frappe/patches/v13_0/remove_duplicate_navbar_items.py @@ -0,0 +1,14 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + navbar_settings = frappe.get_single("Navbar Settings") + duplicate_items = [] + + for navbar_item in navbar_settings.settings_dropdown: + if navbar_item.item_label == 'Toggle Full Width': + duplicate_items.append(navbar_item) + + if len(duplicate_items) > 1: + navbar_settings.remove(duplicate_items[0]) + navbar_settings.save() diff --git a/frappe/public/js/frappe/form/controls/text_editor.js b/frappe/public/js/frappe/form/controls/text_editor.js index 5881e52d74..875893ae6e 100644 --- a/frappe/public/js/frappe/form/controls/text_editor.js +++ b/frappe/public/js/frappe/form/controls/text_editor.js @@ -1,5 +1,7 @@ import Quill from 'quill'; +import ImageResize from 'quill-image-resize'; +Quill.register('modules/imageResize', ImageResize); const CodeBlockContainer = Quill.import('formats/code-block-container'); CodeBlockContainer.tagName = 'PRE'; Quill.register(CodeBlockContainer, true); @@ -145,7 +147,8 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({ return { modules: { toolbar: this.get_toolbar_options(), - table: true + table: true, + imageResize: {} }, theme: 'snow' }; diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index 855e1b4b51..9a255d0776 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -151,7 +151,7 @@ function shorten_number(number, country) { for (const map of number_system) { const condition = map.condition ? map.condition(x) : x >= map.divisor; if (condition) { - return Math.round(number/map.divisor) + ' ' + map.symbol; + return (number/map.divisor).toFixed(2) + ' ' + map.symbol; } } return number.toFixed(); diff --git a/frappe/tests/test_api.py b/frappe/tests/test_api.py index 3e559ac0f3..01ad11dde3 100644 --- a/frappe/tests/test_api.py +++ b/frappe/tests/test_api.py @@ -67,9 +67,19 @@ class TestAPI(unittest.TestCase): {"doctype": "Note", "public": True, "title": "get_value", "content": test_content}, ]) self.assertEqual(server.get_value("Note", "content", {"title": "get_value"}).get('content'), test_content) + name = server.get_value("Note", "name", {"title": "get_value"}).get('name') + + # test by name + self.assertEqual(server.get_value("Note", "content", name).get('content'), test_content) self.assertRaises(FrappeException, server.get_value, "Note", "(select (password) from(__Auth) order by name desc limit 1)", {"title": "get_value"}) + def test_get_single(self): + server = FrappeClient(get_url(), "Administrator", "admin", verify=False) + server.set_value('Website Settings', 'Website Settings', 'title_prefix', 'test-prefix') + self.assertEqual(server.get_value('Website Settings', 'title_prefix', 'Website Settings').get('title_prefix'), 'test-prefix') + self.assertEqual(server.get_value('Website Settings', 'title_prefix').get('title_prefix'), 'test-prefix') + frappe.db.set_value('Website Settings', None, 'title_prefix', '') def test_update_doc(self): server = FrappeClient(get_url(), "Administrator", "admin", verify=False) diff --git a/package.json b/package.json index d6bb3ccda4..d48d2a3f65 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "moment-timezone": "^0.5.28", "quagga": "^0.12.1", "quill": "2.0.0-dev.4", + "quill-image-resize": "^3.0.9", "qz-tray": "^2.0.8", "redis": "^2.8.0", "showdown": "^1.9.1", diff --git a/requirements.txt b/requirements.txt index a88d0e3c1d..af3104cce7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ oauthlib==3.1.0 openpyxl==2.6.4 passlib==1.7.2 pdfkit==0.6.1 -Pillow==6.2.2 +Pillow==7.1.0 premailer==3.6.1 psycopg2-binary==2.8.4 pyasn1==0.4.8 diff --git a/yarn.lock b/yarn.lock index 96edef8766..93ce879ebb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1052,7 +1052,7 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" -clone@^2.1.2: +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= @@ -2015,6 +2015,11 @@ eventemitter2@4.1.2: resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15" integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU= +eventemitter3@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= + eventemitter3@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" @@ -2200,6 +2205,11 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== +fast-diff@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig== + fast-diff@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" @@ -4433,6 +4443,11 @@ parchment@2.0.0-dev.2: resolved "https://registry.yarnpkg.com/parchment/-/parchment-2.0.0-dev.2.tgz#9d6fe57b3721317bd1c481ea38ffa9b287d496b8" integrity sha512-4fgRny4pPISoML08Zp7poi52Dff3E2G1ORTi2D/acJ/RiROdDAMDB6VcQNfBcmehrX5Wixp6dxh6JjLyE5yUNQ== +parchment@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5" + integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg== + parse-data-uri@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/parse-data-uri/-/parse-data-uri-0.2.0.tgz#bf04d851dd5c87b0ab238e5d01ace494b604b4c9" @@ -5124,6 +5139,24 @@ quill-delta@4.2.1: extend "^3.0.2" fast-diff "1.2.0" +quill-delta@^3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032" + integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg== + dependencies: + deep-equal "^1.0.1" + extend "^3.0.2" + fast-diff "1.1.2" + +quill-image-resize@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/quill-image-resize/-/quill-image-resize-3.0.9.tgz#5677fb6257560bff951153ddbdb836758e49f804" + integrity sha512-5Dk0nixhbFsCwSWtPU9qqqtfM2gURfaP+pbBhQvAoMJoF4p99xbAibfAI3gsZJkbWUodoK2iAPf1V5oTSpv9ww== + dependencies: + lodash "^4.17.4" + quill "^1.2.2" + raw-loader "^0.5.1" + quill@2.0.0-dev.4: version "2.0.0-dev.4" resolved "https://registry.yarnpkg.com/quill/-/quill-2.0.0-dev.4.tgz#130e38efe7a16b3766d767d750c8aacc038945e7" @@ -5136,6 +5169,18 @@ quill@2.0.0-dev.4: parchment "2.0.0-dev.2" quill-delta "4.2.1" +quill@^1.2.2: + version "1.3.7" + resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8" + integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g== + dependencies: + clone "^2.1.1" + deep-equal "^1.0.1" + eventemitter3 "^2.0.3" + extend "^3.0.2" + parchment "^1.1.4" + 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" @@ -5171,6 +5216,11 @@ raw-body@^2.2.0: iconv-lite "0.4.24" unpipe "1.0.0" +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= + rc@^1.0.1, rc@^1.1.6: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"