From 9e139171f41405d677d62361fb2ef2190d475d5e Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 8 Apr 2020 18:35:49 +0530 Subject: [PATCH 001/145] feat: custom form dashboards --- frappe/custom/doctype/custom_link/__init__.py | 0 .../custom/doctype/custom_link/custom_link.js | 16 ++++++ .../doctype/custom_link/custom_link.json | 52 +++++++++++++++++++ .../custom/doctype/custom_link/custom_link.py | 43 +++++++++++++++ .../doctype/custom_link/test_custom_link.py | 10 ++++ frappe/desk/form/meta.py | 2 - frappe/desk/notifications.py | 7 +-- frappe/model/meta.py | 4 +- 8 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 frappe/custom/doctype/custom_link/__init__.py create mode 100644 frappe/custom/doctype/custom_link/custom_link.js create mode 100644 frappe/custom/doctype/custom_link/custom_link.json create mode 100644 frappe/custom/doctype/custom_link/custom_link.py create mode 100644 frappe/custom/doctype/custom_link/test_custom_link.py diff --git a/frappe/custom/doctype/custom_link/__init__.py b/frappe/custom/doctype/custom_link/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/custom/doctype/custom_link/custom_link.js b/frappe/custom/doctype/custom_link/custom_link.js new file mode 100644 index 0000000000..f1c06daeeb --- /dev/null +++ b/frappe/custom/doctype/custom_link/custom_link.js @@ -0,0 +1,16 @@ +// Copyright (c) 2020, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Custom Link', { + refresh: function(frm) { + frm.set_query("document_type", function () { + return { + filters: { + custom: 0, + istable: 0, + module: ['not in', ["Email", "Core", "Custom", "Event Streaming", "Social", "Data Migration", "Geo", "Desk"]] + } + } + }); + } +}); diff --git a/frappe/custom/doctype/custom_link/custom_link.json b/frappe/custom/doctype/custom_link/custom_link.json new file mode 100644 index 0000000000..350e6b1c2d --- /dev/null +++ b/frappe/custom/doctype/custom_link/custom_link.json @@ -0,0 +1,52 @@ +{ + "actions": [], + "autoname": "field:document_type", + "creation": "2020-04-08 15:16:44.342509", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "document_type", + "links" + ], + "fields": [ + { + "fieldname": "document_type", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Document Type", + "options": "DocType", + "reqd": 1, + "unique": 1 + }, + { + "fieldname": "links", + "fieldtype": "Table", + "label": "Links", + "options": "DocType Link" + } + ], + "links": [], + "modified": "2020-04-08 16:42:59.402671", + "modified_by": "Administrator", + "module": "Custom", + "name": "Custom Link", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/custom/doctype/custom_link/custom_link.py b/frappe/custom/doctype/custom_link/custom_link.py new file mode 100644 index 0000000000..b9a88b58f2 --- /dev/null +++ b/frappe/custom/doctype/custom_link/custom_link.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class CustomLink(Document): + pass + +def get_custom_doctype_links(doctype, data): + if frappe.get_all("Custom Link", {"document_type": doctype}): + doc = frappe.get_doc("Custom Link", doctype) + + if not data.transactions: + # init groups + data.transactions = [] + data.non_standard_fieldnames = {} + + for link in doc.links: + link.added = False + for group in data.transactions: + # group found + if group.get("label") == link.group: + if not link.link_doctype in group.get("items"): + group.get("items").append(link.link_doctype) + link.added = True + + if not link.added: + # group not found, make a new group + data.transactions.append({ + "label": link.group, + "items": [link.link_doctype] + }) + + if link.link_fieldname != data.fieldname: + if data.fieldname: + data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname + else: + data.fieldname = link.link_fieldname + + return data \ No newline at end of file diff --git a/frappe/custom/doctype/custom_link/test_custom_link.py b/frappe/custom/doctype/custom_link/test_custom_link.py new file mode 100644 index 0000000000..a292f73ad0 --- /dev/null +++ b/frappe/custom/doctype/custom_link/test_custom_link.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and Contributors +# See license.txt +from __future__ import unicode_literals + +# import frappe +import unittest + +class TestCustomLink(unittest.TestCase): + pass diff --git a/frappe/desk/form/meta.py b/frappe/desk/form/meta.py index 26fc6037fd..ba0e5c2216 100644 --- a/frappe/desk/form/meta.py +++ b/frappe/desk/form/meta.py @@ -196,8 +196,6 @@ class FormMeta(Meta): self.get("__messages").update(messages, as_value=True) def load_dashboard(self): - if self.custom: - return self.set('__dashboard', self.get_dashboard_data()) def load_kanban_meta(self): diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 3a8815ca71..109dd25f4f 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -268,8 +268,9 @@ def get_open_count(doctype, name, items=[]): "count": out, } - module = frappe.get_meta_module(doctype) - if hasattr(module, "get_timeline_data"): - out["timeline_data"] = module.get_timeline_data(doctype, name) + if not meta.custom: + module = frappe.get_meta_module(doctype) + if hasattr(module, "get_timeline_data"): + out["timeline_data"] = module.get_timeline_data(doctype, name) return out diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 5065684311..e6a89be108 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -26,6 +26,7 @@ from frappe.model.base_document import BaseDocument from frappe.modules import load_doctype_module from frappe.model.workflow import get_workflow_name from frappe import _ +from frappe.custom.doctype.custom_link.custom_link import get_custom_doctype_links def get_meta(doctype, cached=True): if cached: @@ -429,6 +430,7 @@ class Meta(Document): pass self.add_doctype_links(data) + get_custom_doctype_links(self.name, data) for hook in frappe.get_hooks("override_doctype_dashboards", {}).get(self.name, []): data = frappe.get_attr(hook)(data=data) @@ -447,7 +449,7 @@ class Meta(Document): link.added = False for group in data.transactions: # group found - if group.label == link.label: + if group.label == link.group: if not link.link_doctype in group.items: group.items.append(link.link_doctype) link.added = True From a25088a606dd50a293d1f6b542af9b8c75e8cd5e Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Mon, 13 Apr 2020 19:10:19 +0530 Subject: [PATCH 002/145] chore: show message on migrate when services are not running shows message before migrate if the database or redis service is not running instead of trying to migrate and then failing. Signed-off-by: Chinmay D. Pai --- frappe/migrate.py | 16 +++++++++++++ frappe/utils/connections.py | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 frappe/utils/connections.py diff --git a/frappe/migrate.py b/frappe/migrate.py index 043b6817d7..711f51c57a 100644 --- a/frappe/migrate.py +++ b/frappe/migrate.py @@ -5,11 +5,13 @@ from __future__ import unicode_literals import json import os +import sys import frappe import frappe.translate import frappe.modules.patch_handler import frappe.model.sync from frappe.utils.fixtures import sync_fixtures +from frappe.utils.connections import check_connection from frappe.cache_manager import clear_global_cache from frappe.desk.notifications import clear_notifications from frappe.website import render @@ -18,6 +20,7 @@ from frappe.modules.utils import sync_customizations from frappe.core.doctype.scheduled_job_type.scheduled_job_type import sync_jobs from frappe.utils import global_search + def migrate(verbose=True, rebuild_website=False, skip_failing=False): '''Migrate all apps to the latest version, will: - run before migrate hooks @@ -30,6 +33,19 @@ def migrate(verbose=True, rebuild_website=False, skip_failing=False): - run after migrate hooks ''' + service_status = check_connection(redis_services=["redis_cache"]) + if False in service_status.values(): + for service in service_status: + if not service_status.get(service, True): + print("{} service is not running.".format(service)) + print("""Cannot run bench migrate without the services running. +If you are running bench in development mode, make sure that bench is running: + +$ bench start + +Otherwise, check the server logs and ensure that all the required services are running.""") + sys.exit(1) + touched_tables_file = frappe.get_site_path('touched_tables.json') if os.path.exists(touched_tables_file): os.remove(touched_tables_file) diff --git a/frappe/utils/connections.py b/frappe/utils/connections.py new file mode 100644 index 0000000000..57b9399986 --- /dev/null +++ b/frappe/utils/connections.py @@ -0,0 +1,48 @@ +import socket + +from six.moves.urllib.parse import urlparse +from frappe import get_conf + +config = get_conf() +REDIS_KEYS = ('redis_cache', 'redis_queue', 'redis_socketio') + + +def is_open(ip, port, timeout=10): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(timeout) + try: + s.connect((ip, int(port))) + s.shutdown(socket.SHUT_RDWR) + return True + except socket.error: + return False + finally: + s.close() + + +def check_database(): + db_type = config.get("db_type", "mariadb") + if db_type == "mariadb": + db_host = config.get("db_host", "localhost") + db_port = config.get("db_port", 3306) + else: + db_host = "localhost" + db_port = 5342 + return {"db_type": is_open(db_host, db_port)} + + +def check_redis(redis_services=None): + services = redis_services or REDIS_KEYS + status = {} + for conn in services: + redis_url = urlparse(config.get(conn)).netloc + redis_host, redis_port = redis_url.split(":") + status[conn] = is_open(redis_host, redis_port) + return status + + +def check_connection(redis_services=None): + service_status = {} + service_status.update(check_database()) + service_status.update(check_redis(redis_services)) + return service_status From 318e397ab35cb0508ea8697b0088f23c37e67df2 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Mon, 13 Apr 2020 19:13:43 +0530 Subject: [PATCH 003/145] chore: unquote db_type Signed-off-by: Chinmay D. Pai --- frappe/utils/connections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/connections.py b/frappe/utils/connections.py index 57b9399986..bffbd98134 100644 --- a/frappe/utils/connections.py +++ b/frappe/utils/connections.py @@ -28,7 +28,7 @@ def check_database(): else: db_host = "localhost" db_port = 5342 - return {"db_type": is_open(db_host, db_port)} + return {db_type: is_open(db_host, db_port)} def check_redis(redis_services=None): From c0d0fcfd69227562069933449881d27470bb904b Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Mon, 13 Apr 2020 19:24:51 +0530 Subject: [PATCH 004/145] chore: do not hardcode anything for postgres Signed-off-by: Chinmay D. Pai --- frappe/utils/connections.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/frappe/utils/connections.py b/frappe/utils/connections.py index bffbd98134..6bd24d57ec 100644 --- a/frappe/utils/connections.py +++ b/frappe/utils/connections.py @@ -22,12 +22,8 @@ def is_open(ip, port, timeout=10): def check_database(): db_type = config.get("db_type", "mariadb") - if db_type == "mariadb": - db_host = config.get("db_host", "localhost") - db_port = config.get("db_port", 3306) - else: - db_host = "localhost" - db_port = 5342 + db_host = config.get("db_host", "localhost") + db_port = config.get("db_port", 3306 if db_type == "mariadb" else 5342) return {db_type: is_open(db_host, db_port)} From 2ed2e9f98b6e226f770794b18657b7456d9ed6c9 Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Fri, 1 May 2020 04:32:34 +0530 Subject: [PATCH 005/145] fix: .snyk & package.json to reduce vulnerabilities The following vulnerabilities are fixed with a Snyk patch: - https://snyk.io/vuln/SNYK-JS-LODASH-567746 --- .snyk | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/.snyk b/.snyk index b39169dcee..0dfecc6136 100644 --- a/.snyk +++ b/.snyk @@ -1,5 +1,5 @@ # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. -version: v1.13.5 +version: v1.14.1 # ignores vulnerabilities until expiry date; change duration by modifying expiry date ignore: SNYK-JS-AWESOMPLETE-174474: @@ -22,3 +22,44 @@ patch: SNYK-JS-LODASH-450202: - frappe-datatable > lodash: patched: '2020-01-31T01:33:09.889Z' + SNYK-JS-LODASH-567746: + - frappe-datatable > lodash: + patched: '2020-04-30T23:02:32.330Z' + - quagga > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > lodash: + patched: '2020-04-30T23:02:32.330Z' + - tailwindcss > lodash: + patched: '2020-04-30T23:02:32.330Z' + - '@tailwindcss/ui > @tailwindcss/custom-forms > lodash': + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/dep-graph > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > inquirer > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-config > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-mvn-plugin > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-nodejs-lockfile-parser > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-nuget-plugin > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/dep-graph > graphlib > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-go-plugin > graphlib > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-nodejs-lockfile-parser > graphlib > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-nuget-plugin > dotnet-deps-parser > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > snyk-php-plugin > @snyk/composer-lockfile-parser > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > graphlib > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/ruby-semver > lodash: + patched: '2020-04-30T23:02:32.330Z' + - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/dep-graph > graphlib > lodash: + patched: '2020-04-30T23:02:32.330Z' From d11463dfd65b26f6198ade410224e6f970d5e5ef Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Fri, 1 May 2020 04:32:35 +0530 Subject: [PATCH 006/145] fix: .snyk & package.json to reduce vulnerabilities The following vulnerabilities are fixed with a Snyk patch: - https://snyk.io/vuln/SNYK-JS-LODASH-567746 --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e735beee9b..583a9a00d3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "production": "FRAPPE_ENV=production node rollup/build.js", "watch": "node rollup/watch.js", "cypress:open": "cypress open", - "snyk-protect": "snyk protect" + "snyk-protect": "snyk protect", + "prepare": "yarn run snyk-protect" }, "repository": { "type": "git", @@ -42,7 +43,7 @@ "qz-tray": "^2.0.8", "redis": "^2.8.0", "showdown": "^1.9.1", - "snyk": "^1.297.4", + "snyk": "^1.316.1", "socket.io": "^2.3.0", "superagent": "^3.8.2", "tailwindcss": "^1.3.3", From 6ea8881b29106edf45155b9ac565d95f9672ded2 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 May 2020 12:48:15 +0530 Subject: [PATCH 007/145] fix: remove exact phrase search --- frappe/utils/global_search.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/frappe/utils/global_search.py b/frappe/utils/global_search.py index 3c4b9583f8..0272ae16f4 100644 --- a/frappe/utils/global_search.py +++ b/frappe/utils/global_search.py @@ -81,10 +81,10 @@ def rebuild_for_doctype(doctype): return filters meta = frappe.get_meta(doctype) - + if cint(meta.issingle) == 1: return - + if cint(meta.istable) == 1: parent_doctypes = frappe.get_all("DocField", fields="parent", filters={ "fieldtype": ["in", frappe.model.table_fields], @@ -506,15 +506,13 @@ def web_search(text, scope=None, start=0, limit=20): mariadb_conditions = postgres_conditions = ' '.join([published_condition, scope_condition]) # https://mariadb.com/kb/en/library/full-text-index-overview/#in-boolean-mode - text = '"{}"'.format(text) - mariadb_conditions += 'MATCH(`content`) AGAINST (%(text)s IN BOOLEAN MODE)' - postgres_conditions += 'TO_TSVECTOR("content") @@ PLAINTO_TSQUERY(%(text)s)' + mariadb_conditions += 'MATCH(`content`) AGAINST ({} IN BOOLEAN MODE)'.format(frappe.db.escape('+' + text + '*')) + postgres_conditions += 'TO_TSVECTOR("content") @@ PLAINTO_TSQUERY({})'.format(frappe.db.escape(text)) values = { "scope": "".join([scope, "%"]) if scope else '', "limit": limit, - "start": start, - "text": text + "start": start } result = frappe.db.multisql({ From e91050b0e496d872d08a7898fb2124b3a64424ef Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 May 2020 13:14:22 +0530 Subject: [PATCH 008/145] fix: add admin to email unsubscribe --- frappe/desk/page/setup_wizard/install_fixtures.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frappe/desk/page/setup_wizard/install_fixtures.py b/frappe/desk/page/setup_wizard/install_fixtures.py index c857bd077f..b74153f1c7 100644 --- a/frappe/desk/page/setup_wizard/install_fixtures.py +++ b/frappe/desk/page/setup_wizard/install_fixtures.py @@ -12,6 +12,7 @@ def install(): update_salutations() update_global_search_doctypes() setup_email_linking() + add_unsubscribe() @frappe.whitelist() def update_genders(): @@ -35,4 +36,12 @@ def setup_email_linking(): "email_id": "email_linking@example.com", }) doc.insert(ignore_permissions=True, ignore_if_duplicate=True) - \ No newline at end of file + +def add_unsubscribe(): + email_unsubscribe = [ + {"email": "admin@example.com", "global_unsubscribe": 1}, + {"email": "guest@example.com", "global_unsubscribe": 1} + ] + + for unsubscribe in email_unsubscribe: + frappe.get_doc(unsubscribe).insert() \ No newline at end of file From 37e81e33a52da50ff16ed3e476afe97124a75000 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Wed, 6 May 2020 13:20:59 +0530 Subject: [PATCH 009/145] fix: add patch --- frappe/desk/page/setup_wizard/install_fixtures.py | 5 ++++- frappe/patches.txt | 1 + frappe/patches/v13_0/email_unsubscribe.py | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 frappe/patches/v13_0/email_unsubscribe.py diff --git a/frappe/desk/page/setup_wizard/install_fixtures.py b/frappe/desk/page/setup_wizard/install_fixtures.py index b74153f1c7..692c1a117a 100644 --- a/frappe/desk/page/setup_wizard/install_fixtures.py +++ b/frappe/desk/page/setup_wizard/install_fixtures.py @@ -44,4 +44,7 @@ def add_unsubscribe(): ] for unsubscribe in email_unsubscribe: - frappe.get_doc(unsubscribe).insert() \ No newline at end of file + if not frappe.get_all("Email Unsubscribe", filters=unsubscribe): + doc = frappe.new_doc("Email Unsubscribe") + doc.update(unsubscribe) + doc.insert(ignore_permissions=True) \ No newline at end of file diff --git a/frappe/patches.txt b/frappe/patches.txt index cbda8cf677..5d45cbec66 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -273,3 +273,4 @@ execute:frappe.delete_doc_if_exists('DocType', 'GCalendar Settings') frappe.patches.v12_0.remove_parent_and_parenttype_from_print_formats execute:from frappe.desk.page.setup_wizard.install_fixtures import update_genders;update_genders() frappe.patches.v13_0.website_theme_custom_scss +frappe.patches.v13_0.email_unsubscribe diff --git a/frappe/patches/v13_0/email_unsubscribe.py b/frappe/patches/v13_0/email_unsubscribe.py new file mode 100644 index 0000000000..69ed1be948 --- /dev/null +++ b/frappe/patches/v13_0/email_unsubscribe.py @@ -0,0 +1,13 @@ +import frappe + +def execute(): + email_unsubscribe = [ + {"email": "admin@example.com", "global_unsubscribe": 1}, + {"email": "guest@example.com", "global_unsubscribe": 1} + ] + + for unsubscribe in email_unsubscribe: + if not frappe.get_all("Email Unsubscribe", filters=unsubscribe): + doc = frappe.new_doc("Email Unsubscribe") + doc.update(unsubscribe) + doc.insert(ignore_permissions=True) \ No newline at end of file From 62c1b74932294e232dcc214b75b55006e214f386 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 29 Apr 2020 17:52:02 +0530 Subject: [PATCH 010/145] feat: add heatmap type dashboard chart --- frappe/core/page/dashboard/dashboard.js | 4 +- .../dashboard_chart/dashboard_chart.js | 6 +- .../dashboard_chart/dashboard_chart.json | 19 +-- .../dashboard_chart/dashboard_chart.py | 30 ++++- .../js/frappe/views/reports/report_utils.js | 2 +- .../public/js/frappe/widgets/chart_widget.js | 120 ++++++++++++------ frappe/public/less/desktop.less | 48 +++++++ 7 files changed, 175 insertions(+), 54 deletions(-) diff --git a/frappe/core/page/dashboard/dashboard.js b/frappe/core/page/dashboard/dashboard.js index 222a31a863..0d1337351e 100644 --- a/frappe/core/page/dashboard/dashboard.js +++ b/frappe/core/page/dashboard/dashboard.js @@ -6,7 +6,7 @@ frappe.provide('frappe.dashboards.chart_sources'); frappe.pages['dashboard'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ + frappe.ui.make_app_page({ parent: wrapper, title: __("Dashboard"), single_column: true @@ -21,7 +21,7 @@ frappe.pages['dashboard'].on_page_load = function(wrapper) { class Dashboard { constructor(wrapper) { this.wrapper = $(wrapper); - $(`
+ $(`
`).appendTo(this.wrapper.find(".page-content").empty()); this.container = this.wrapper.find(".dashboard-graph"); diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index f8d5886b26..894dcccb27 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -88,9 +88,9 @@ frappe.ui.form.on('Dashboard Chart', { } if (frm.doc.chart_type == 'Group By') { - frm.set_df_property('type', 'options', ['Line', 'Bar', 'Percentage', 'Pie']); + frm.set_df_property('type', 'options', ['Line', 'Bar', 'Percentage', 'Pie', 'Donut']); } else { - frm.set_df_property('type', 'options', ['Line', 'Bar']); + frm.set_df_property('type', 'options', ['Line', 'Bar', 'Heatmap']); } frm.set_value('document_type', ''); @@ -358,5 +358,3 @@ frappe.ui.form.on('Dashboard Chart', { }, }); - - diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index b5201a8b1f..d6f204db00 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -28,12 +28,12 @@ "to_date", "time_interval", "timeseries", + "type", "filters_section", "filters_json", "chart_options_section", - "type", - "column_break_2", "color", + "column_break_2", "custom_options", "section_break_10", "last_synced_on" @@ -85,22 +85,22 @@ "fieldtype": "Column Break" }, { - "depends_on": "timeseries", + "depends_on": "eval: doc.timeseries && doc.type !== 'Heatmap'", "fieldname": "timespan", "fieldtype": "Select", "label": "Timespan", "options": "Last Year\nLast Quarter\nLast Month\nLast Week\nSelect Date Range" }, { - "depends_on": "timeseries", + "depends_on": "eval: doc.timeseries && doc.type !== 'Heatmap'", "fieldname": "time_interval", "fieldtype": "Select", "label": "Time Interval", "options": "Yearly\nQuarterly\nMonthly\nWeekly\nDaily" }, { - "default": "0", - "depends_on": "eval: ['Count', 'Sum', 'Average'].includes(doc.chart_type)", + "default": "1", + "depends_on": "eval: doc.chart_type !== 'Group By'", "fieldname": "timeseries", "fieldtype": "Check", "label": "Time Series" @@ -123,10 +123,11 @@ "label": "Chart Options" }, { + "default": "Line", "fieldname": "type", "fieldtype": "Select", "label": "Type", - "options": "Line\nBar\nPercentage\nPie\nDonut", + "options": "Line\nBar\nHeatmap", "reqd": 1 }, { @@ -134,7 +135,7 @@ "fieldtype": "Column Break" }, { - "depends_on": "eval:doc.chart_type !== 'Report'", + "depends_on": "eval: doc.chart_type !== 'Report' && doc.type !== 'Heatmap'", "fieldname": "color", "fieldtype": "Color", "label": "Color" @@ -231,7 +232,7 @@ } ], "links": [], - "modified": "2020-05-01 15:22:59.119341", + "modified": "2020-04-29 17:50:59.867496", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 417ef2ba82..2b095b0263 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -87,7 +87,10 @@ def get(chart_name = None, chart = None, no_cache = None, filters = None, from_d if chart.chart_type == 'Group By': chart_config = get_group_by_chart_config(chart, filters) else: - chart_config = get_chart_config(chart, filters, timespan, timegrain, from_date, to_date) + if chart.type == 'Heatmap': + chart_config = get_heatmap_chart_config(chart, filters) + else: + chart_config = get_chart_config(chart, filters, timespan, timegrain, from_date, to_date) return chart_config @@ -174,6 +177,31 @@ def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date): return chart_config +def get_heatmap_chart_config(chart, filters): + aggregate_function = get_aggregate_function(chart.chart_type) + value_field = chart.value_based_on or '1' + doctype = chart.document_type + datefield = chart.based_on + filters.append([doctype, datefield, '>', 'subdate(curdate(), interval 1 year)', False]) + + data = dict(frappe.db.get_all( + doctype, + fields = [ + 'unix_timestamp(date({datefield}))'.format(datefield=datefield), + '{aggregate_function}({value_field})'.format(aggregate_function=aggregate_function, value_field=value_field), + ], + filters = filters, + group_by = 'date(creation)', + as_list = 1, + order_by = 'creation asc', + ignore_ifnull = True + )) + + chart_config = { + 'labels': '', + 'dataPoints': data, + } + return chart_config def get_group_by_chart_config(chart, filters): diff --git a/frappe/public/js/frappe/views/reports/report_utils.js b/frappe/public/js/frappe/views/reports/report_utils.js index a8149b9134..7b1205482f 100644 --- a/frappe/public/js/frappe/views/reports/report_utils.js +++ b/frappe/public/js/frappe/views/reports/report_utils.js @@ -20,7 +20,7 @@ frappe.report_utils = { return { data: { - labels: labels, + labels: labels.length? labels: null, datasets: datasets }, truncateLegends: 1, diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index a50acfcd9d..4f95649635 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -40,6 +40,10 @@ export default class ChartWidget extends Widget { setup_container() { this.body.empty(); + if (this.chart_doc.type == 'Heatmap') { + this.setup_heatmap_container(); + } + this.loading = $( `
${__( "Loading..." @@ -60,6 +64,12 @@ export default class ChartWidget extends Widget { this.set_chart_title(); } + setup_heatmap_container() { + this.widget.addClass('heatmap-chart'); + this.widget.removeClass('full-width').addClass('full-width'); + this.width = 'Full'; + } + set_summary() { if (!this.$summary) { this.$summary = $(`
`).hide(); @@ -104,6 +114,10 @@ export default class ChartWidget extends Widget { } render_time_series_filters() { + if (this.chart_doc.type == 'Heatmap') { + return; + } + let filters = [ { label: this.chart_settings.timespan || this.chart_doc.timespan, @@ -465,51 +479,17 @@ export default class ChartWidget extends Widget { } render() { - const chart_type_map = { - Line: "line", - Bar: "bar", - Percentage: "percentage", - Pie: "pie", - Donut: "donut" - }; - - let colors = []; - - if (this.chart_doc.y_axis.length) { - this.chart_doc.y_axis.map(field => { - colors.push(field.color); - }); - } else if (["Line", "Bar"].includes(this.chart_doc.type)) { - colors = [this.chart_doc.color || []]; - } - - if (!this.data || !this.data.labels.length || !Object.keys(this.data).length) { + if (!this.data || !this.data.labels || !Object.keys(this.data).length) { this.chart_wrapper.hide(); this.loading.hide(); - this.$summary.hide(); + this.$summary && this.$summary.hide(); this.empty.show(); } else { this.loading.hide(); this.empty.hide(); this.chart_wrapper.show(); - let chart_args = { - data: this.data, - type: chart_type_map[this.chart_doc.type], - colors: colors, - height: this.height, - axisOptions: { - xIsSeries: this.chart_doc.timeseries, - shortenYAxisNumbers: 1 - } - }; - - if (this.chart_doc.custom_options) { - let custom_options = JSON.parse(this.chart_doc.custom_options); - for (let key in custom_options) { - chart_args[key] = custom_options[key]; - } - } + const chart_args = this.get_chart_args(); if (!this.dashboard_chart) { this.dashboard_chart = new frappe.Chart( @@ -519,7 +499,73 @@ export default class ChartWidget extends Widget { } else { this.dashboard_chart.update(this.data); } + this.width == "Full" && this.summary && this.set_summary(); + this.chart_doc.type == 'Heatmap' && this.render_heatmap_legend(); + } + } + + + get_chart_args() { + let colors = this.get_chart_colors(); + + const chart_type_map = { + Line: "line", + Bar: "bar", + Percentage: "percentage", + Pie: "pie", + Donut: "donut", + Heatmap: "heatmap" + }; + + let chart_args = { + data: this.data, + type: chart_type_map[this.chart_doc.type], + colors: colors, + height: this.height, + axisOptions: { + xIsSeries: this.chart_doc.timeseries, + shortenYAxisNumbers: 1 + } + }; + + return chart_args; + } + + get_chart_colors() { + let colors = []; + if (this.chart_doc.y_axis.length) { + this.chart_doc.y_axis.map(field => { + colors.push(field.color); + }); + } else if (["Line", "Bar"].includes(this.chart_doc.type)) { + colors = [this.chart_doc.color || "light-blue"]; + } else if (this.chart_doc.type == "Heatmap") { + colors = []; + } + + return colors; + } + + render_heatmap_legend() { + if (!this.$heatmap_legend) { + this.$heatmap_legend = + $(` +
+
    +
  • +
  • +
  • +
  • +
  • +
+
+
${__("Less")}
+
${__("More")}
+
+
+ `); + this.body.append(this.$heatmap_legend); } } diff --git a/frappe/public/less/desktop.less b/frappe/public/less/desktop.less index 1e64533079..da59fd8c0a 100644 --- a/frappe/public/less/desktop.less +++ b/frappe/public/less/desktop.less @@ -293,6 +293,54 @@ } } + &.dashboard-widget-box.heatmap-chart { + min-height: 0px; + height: 180px; + + .widget-footer { + display: none; + } + + .frappe-chart .chart-legend { + display: none; + } + + .widget-body { + display: flex; + max-height: 100%; + + .chart-container { + margin-left: 65px; + margin-top: -15px; + } + + .heatmap-legend { + display: flex; + height: 100%; + margin-top: 30px; + + .legend-colors { + padding-left: 1; + padding-left: 15px; + list-style: none; + } + + li { + width: 10px; + height: 10px; + margin: 5px; + } + + .legend-label { + color: #555b51; + font-size: 11px; + margin-left: 15px; + line-height: 1.6em; + } + } + } + } + &.onboarding-widget-box { margin-bottom: 50px; margin-top: 10px; From 08eeb8350f6494deef8b7222dc5b9e7747452297 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 29 Apr 2020 18:01:58 +0530 Subject: [PATCH 011/145] fix: hide chart for smaller widths --- frappe/public/less/desktop.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/public/less/desktop.less b/frappe/public/less/desktop.less index da59fd8c0a..44c5636731 100644 --- a/frappe/public/less/desktop.less +++ b/frappe/public/less/desktop.less @@ -341,6 +341,12 @@ } } + @media (max-width: 768px) { + &.dashboard-widget-box.heatmap-chart { + display: none; + } + } + &.onboarding-widget-box { margin-bottom: 50px; margin-top: 10px; From d83127021023b0ec018e43d771125c52cb662038 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 29 Apr 2020 18:04:52 +0530 Subject: [PATCH 012/145] fix: set label as empty list --- frappe/desk/doctype/dashboard_chart/dashboard_chart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 2b095b0263..21af41adad 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -198,7 +198,7 @@ def get_heatmap_chart_config(chart, filters): )) chart_config = { - 'labels': '', + 'labels': [], 'dataPoints': data, } return chart_config From 302af369ac11ba3a4e72376f6ccb8f164f57a10f Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 30 Apr 2020 18:35:49 +0530 Subject: [PATCH 013/145] fix: set timeseries according to chart type --- .../doctype/dashboard_chart/dashboard_chart.js | 18 +++++++++++------- .../dashboard_chart/dashboard_chart.json | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 894dcccb27..7836a66443 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -49,6 +49,7 @@ frappe.ui.form.on('Dashboard Chart', { }); frm.set_df_property("filters_section", "hidden", 1); + frm.trigger('set_time_series') frm.set_query('document_type', function() { return { filters: { @@ -71,6 +72,7 @@ frappe.ui.form.on('Dashboard Chart', { }, chart_type: function(frm) { + frm.trigger('set_time_series') if (frm.doc.chart_type == 'Report') { frm.set_query('report_name', () => { return { @@ -80,13 +82,6 @@ frappe.ui.form.on('Dashboard Chart', { } }); } else { - // set timeseries based on chart type - if (['Count', 'Average', 'Sum'].includes(frm.doc.chart_type)) { - frm.set_value('timeseries', 1); - } else { - frm.set_value('timeseries', 0); - } - if (frm.doc.chart_type == 'Group By') { frm.set_df_property('type', 'options', ['Line', 'Bar', 'Percentage', 'Pie', 'Donut']); } else { @@ -97,6 +92,15 @@ frappe.ui.form.on('Dashboard Chart', { } }, + set_time_series: function(frm) { + // set timeseries based on chart type + if (['Count', 'Average', 'Sum'].includes(frm.doc.chart_type)) { + frm.set_value('timeseries', 1); + } else { + frm.set_value('timeseries', 0); + } + }, + document_type: function(frm) { // update `based_on` options based on date / datetime fields frm.set_value('source', ''); diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index d6f204db00..f62d032767 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -99,8 +99,8 @@ "options": "Yearly\nQuarterly\nMonthly\nWeekly\nDaily" }, { - "default": "1", - "depends_on": "eval: doc.chart_type !== 'Group By'", + "default": "0", + "depends_on": "eval: !['Group By', 'Report'].includes(doc.chart_type)\n", "fieldname": "timeseries", "fieldtype": "Check", "label": "Time Series" @@ -232,7 +232,7 @@ } ], "links": [], - "modified": "2020-04-29 17:50:59.867496", + "modified": "2020-04-30 18:30:46.242316", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", From bd3d572376b56ab6522968cca753745caf9aaca8 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 30 Apr 2020 18:51:53 +0530 Subject: [PATCH 014/145] fix: fix modified timestamp --- frappe/desk/doctype/dashboard_chart/dashboard_chart.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index f62d032767..19d358c8c5 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -232,7 +232,7 @@ } ], "links": [], - "modified": "2020-04-30 18:30:46.242316", + "modified": "2020-04-23 13:01:07.178866", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", From 98aad96ee8647b9f5078219665caf2a72c96bac2 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 30 Apr 2020 19:20:06 +0530 Subject: [PATCH 015/145] fix: missing semicolons --- frappe/desk/doctype/dashboard_chart/dashboard_chart.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 7836a66443..4c525e56b3 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -49,7 +49,7 @@ frappe.ui.form.on('Dashboard Chart', { }); frm.set_df_property("filters_section", "hidden", 1); - frm.trigger('set_time_series') + frm.trigger('set_time_series'); frm.set_query('document_type', function() { return { filters: { @@ -72,7 +72,7 @@ frappe.ui.form.on('Dashboard Chart', { }, chart_type: function(frm) { - frm.trigger('set_time_series') + frm.trigger('set_time_series'); if (frm.doc.chart_type == 'Report') { frm.set_query('report_name', () => { return { From b045840228ce0327c0e39a2c220a0a9a6ac99530 Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 1 May 2020 19:17:03 +0530 Subject: [PATCH 016/145] fix: fix heatmap chart css for smaller widths --- .../public/js/frappe/widgets/chart_widget.js | 2 +- frappe/public/less/desktop.less | 27 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 4f95649635..b160afa1fa 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -548,7 +548,7 @@ export default class ChartWidget extends Widget { } render_heatmap_legend() { - if (!this.$heatmap_legend) { + if (!this.$heatmap_legend && this.widget.width() > 991) { this.$heatmap_legend = $(`
diff --git a/frappe/public/less/desktop.less b/frappe/public/less/desktop.less index 44c5636731..fbd7f988a3 100644 --- a/frappe/public/less/desktop.less +++ b/frappe/public/less/desktop.less @@ -301,6 +301,10 @@ display: none; } + .widget-control { + z-index: 1; + } + .frappe-chart .chart-legend { display: none; } @@ -308,16 +312,19 @@ .widget-body { display: flex; max-height: 100%; + margin: auto; + margin-top: -15px; .chart-container { - margin-left: 65px; - margin-top: -15px; + height: 100%; + .frappe-chart { + height: 100%; + } } .heatmap-legend { display: flex; - height: 100%; - margin-top: 30px; + margin: 45px 20px 0 20px; .legend-colors { padding-left: 1; @@ -337,13 +344,17 @@ margin-left: 15px; line-height: 1.6em; } + + @media (max-width: 991px) { + display: none; + } } } - } - @media (max-width: 768px) { - &.dashboard-widget-box.heatmap-chart { - display: none; + @media (max-width: 768px) { + .heatmap-chart { + display: none; + } } } From fe31522cf58376b6db2f99b7d8dd0bdde9b69bd9 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 18:27:30 +0530 Subject: [PATCH 017/145] feat: add year field for heatmap charts --- .../dashboard_chart/dashboard_chart.js | 10 ++++++++++ .../dashboard_chart/dashboard_chart.json | 9 ++++++++- .../dashboard_chart/dashboard_chart.py | 20 ++++++++++++++----- frappe/desk/page/user_profile/user_profile.js | 19 ++---------------- .../public/js/frappe/utils/dashboard_utils.js | 16 +++++++++++++++ .../public/js/frappe/widgets/chart_widget.js | 9 ++++++++- 6 files changed, 59 insertions(+), 24 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index 4c525e56b3..90e8ce288a 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -58,6 +58,7 @@ frappe.ui.form.on('Dashboard Chart', { } }); frm.trigger('update_options'); + frm.trigger('set_heatmap_year_options'); if (frm.doc.report_name) { frm.trigger('set_chart_report_filters'); } @@ -71,6 +72,15 @@ frappe.ui.form.on('Dashboard Chart', { frm.trigger("show_filters"); }, + set_heatmap_year_options: function(frm) { + if (frm.doc.type == 'Heatmap') { + frappe.db.get_doc('System Settings').then(doc => { + const creation_date = doc.creation; + frm.set_df_property('heatmap_year', 'options', frappe.dashboard_utils.get_years_since_creation(creation_date)); + }); + } + }, + chart_type: function(frm) { frm.trigger('set_time_series'); if (frm.doc.chart_type == 'Report') { diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index 19d358c8c5..e377ef740e 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -23,6 +23,7 @@ "number_of_groups", "column_break_6", "is_public", + "heatmap_year", "timespan", "from_date", "to_date", @@ -229,10 +230,16 @@ "fieldname": "is_public", "fieldtype": "Check", "label": "Is Public" + }, + { + "depends_on": "eval: doc.type == 'Heatmap'", + "fieldname": "heatmap_year", + "fieldtype": "Select", + "label": "Year" } ], "links": [], - "modified": "2020-04-23 13:01:07.178866", + "modified": "2020-05-01 19:45:01.669384", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 21af41adad..529e60f3a2 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -8,7 +8,7 @@ from frappe import _ import datetime import json from frappe.utils.dashboard import cache_source, get_from_date_from_timespan -from frappe.utils import nowdate, add_to_date, getdate, get_last_day, formatdate, get_datetime +from frappe.utils import nowdate, add_to_date, getdate, get_last_day, formatdate, get_datetime, cint from frappe.model.naming import append_number_if_name_exists from frappe.boot import get_allowed_reports from frappe.model.document import Document @@ -182,18 +182,28 @@ def get_heatmap_chart_config(chart, filters): value_field = chart.value_based_on or '1' doctype = chart.document_type datefield = chart.based_on - filters.append([doctype, datefield, '>', 'subdate(curdate(), interval 1 year)', False]) + year = cint(chart.heatmap_year) if chart.heatmap_year else getdate(nowdate()).year + year_start_date = datetime.date(year, 1, 1).strftime('%Y-%m-%d') + next_year_start_date = datetime.date(year + 1, 1, 1).strftime('%Y-%m-%d') + + filters.append([doctype, datefield, '>', "{date}".format(date=year_start_date), False]) + filters.append([doctype, datefield, '<', "{date}".format(date=next_year_start_date), False]) + + if frappe.db.db_type == 'mariadb': + timestamp_field = 'unix_timestamp({datefield})'.format(datefield=datefield) + else: + timestamp_field = 'extract(epoch from timestamp {datefield})'.format(datefield=datefield) data = dict(frappe.db.get_all( doctype, fields = [ - 'unix_timestamp(date({datefield}))'.format(datefield=datefield), + timestamp_field, '{aggregate_function}({value_field})'.format(aggregate_function=aggregate_function, value_field=value_field), ], filters = filters, - group_by = 'date(creation)', + group_by = 'date({datefield})'.format(datefield=datefield), as_list = 1, - order_by = 'creation asc', + order_by = '{datefield} asc'.format(datefield=datefield), ignore_ifnull = True )) diff --git a/frappe/desk/page/user_profile/user_profile.js b/frappe/desk/page/user_profile/user_profile.js index ff1e906cff..c43ff27ba3 100644 --- a/frappe/desk/page/user_profile/user_profile.js +++ b/frappe/desk/page/user_profile/user_profile.js @@ -108,21 +108,6 @@ class UserProfile { }); } - get_years_since_creation() { - //Get years since user account created - this.user_creation = frappe.boot.user.creation; - let creation_year = this.get_year(this.user_creation); - let current_year = this.get_year(frappe.datetime.now_date()); - let years_list = []; - for (var year = current_year; year >= creation_year; year--) { - years_list.push(year); - } - return years_list; - } - - get_year(date_str) { - return date_str.substring(0, date_str.indexOf('-')); - } render_line_chart() { this.line_chart_filters = [['Energy Point Log', 'user', '=', this.user_id, false]]; @@ -246,8 +231,8 @@ class UserProfile { create_heatmap_chart_filters() { let filters = [ { - label: this.get_year(frappe.datetime.now_date()), - options: this.get_years_since_creation(), + label: frappe.dashboard_utils.get_year(frappe.datetime.now_date()), + options: frappe.dashboard_utils.get_years_since_creation(frappe.boot.user.creation), action: (selected_item) => { this.update_heatmap_data(frappe.datetime.obj_to_str(selected_item)); } diff --git a/frappe/public/js/frappe/utils/dashboard_utils.js b/frappe/public/js/frappe/utils/dashboard_utils.js index a1628be34a..d1621a3e15 100644 --- a/frappe/public/js/frappe/utils/dashboard_utils.js +++ b/frappe/public/js/frappe/utils/dashboard_utils.js @@ -82,5 +82,21 @@ frappe.dashboard_utils = { ).then(settings => { return settings; }); + }, + + get_years_since_creation(creation) { + //Get years since user account created + let creation_year = this.get_year(creation); + let current_year = this.get_year(frappe.datetime.now_date()); + let years_list = []; + for (var year = current_year; year >= creation_year; year--) { + years_list.push(year); + } + return years_list; + }, + + get_year(date_str) { + return date_str.substring(0, date_str.indexOf('-')); } + }; \ No newline at end of file diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index b160afa1fa..f2753be32e 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -61,6 +61,7 @@ export default class ChartWidget extends Widget { this.chart_wrapper = $(`
`); this.chart_wrapper.appendTo(this.body); + this.$heatmap_legend = null; this.set_chart_title(); } @@ -288,7 +289,7 @@ export default class ChartWidget extends Widget { }, { label: __("Reset Chart"), - action: "action-list", + action: "action-reset", handler: () => { this.reset_chart(); delete this.dashboard_chart; @@ -529,6 +530,12 @@ export default class ChartWidget extends Widget { } }; + if (this.chart_doc.type == "Heatmap") { + const heatmap_year = parseInt(this.chart_doc.heatmap_year || "2020"); + chart_args.data.start = new Date(`${heatmap_year}-01-01`); + chart_args.data.end = new Date(`${heatmap_year+1}-01-01`); + } + return chart_args; } From 31a523a720c88c8141eaae04094a4d408d611ca7 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 19:21:51 +0530 Subject: [PATCH 018/145] feat: add year filter to heatmap charts --- .../dashboard_chart/dashboard_chart.py | 10 +- .../public/js/frappe/widgets/chart_widget.js | 131 ++++++++++-------- frappe/utils/dashboard.py | 1 + 3 files changed, 82 insertions(+), 60 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 529e60f3a2..e7e4aefe09 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -58,13 +58,13 @@ def has_permission(doc, ptype, user): @frappe.whitelist() @cache_source def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None, - to_date = None, timespan = None, time_interval = None, refresh = None): + to_date = None, timespan = None, time_interval = None, heatmap_year=None, refresh = None): if chart_name: chart = frappe.get_doc('Dashboard Chart', chart_name) else: chart = frappe._dict(frappe.parse_json(chart)) - + heatmap_year = heatmap_year or chart.heatmap_year timespan = timespan or chart.timespan if timespan == 'Select Date Range': @@ -88,7 +88,7 @@ def get(chart_name = None, chart = None, no_cache = None, filters = None, from_d chart_config = get_group_by_chart_config(chart, filters) else: if chart.type == 'Heatmap': - chart_config = get_heatmap_chart_config(chart, filters) + chart_config = get_heatmap_chart_config(chart, filters, heatmap_year) else: chart_config = get_chart_config(chart, filters, timespan, timegrain, from_date, to_date) @@ -177,12 +177,12 @@ def get_chart_config(chart, filters, timespan, timegrain, from_date, to_date): return chart_config -def get_heatmap_chart_config(chart, filters): +def get_heatmap_chart_config(chart, filters, heatmap_year): aggregate_function = get_aggregate_function(chart.chart_type) value_field = chart.value_based_on or '1' doctype = chart.document_type datefield = chart.based_on - year = cint(chart.heatmap_year) if chart.heatmap_year else getdate(nowdate()).year + year = cint(heatmap_year) if heatmap_year else getdate(nowdate()).year year_start_date = datetime.date(year, 1, 1).strftime('%Y-%m-%d') next_year_start_date = datetime.date(year + 1, 1, 1).strftime('%Y-%m-%d') diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index f2753be32e..abd99e360d 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -115,58 +115,7 @@ export default class ChartWidget extends Widget { } render_time_series_filters() { - if (this.chart_doc.type == 'Heatmap') { - return; - } - - let filters = [ - { - label: this.chart_settings.timespan || this.chart_doc.timespan, - options: [ - "Select Date Range", - "Last Year", - "Last Quarter", - "Last Month", - "Last Week" - ], - action: selected_item => { - this.selected_timespan = selected_item; - - if (this.selected_timespan === "Select Date Range") { - this.render_date_range_fields(); - } else { - this.selected_from_date = null; - this.selected_to_date = null; - if (this.date_field_wrapper) { - this.date_field_wrapper.hide(); - - // Title maybe hidden becuase of date range fields - // in half width chart - this.title_field.show(); - this.head.css('flex-direction', "row"); - } - - this.save_chart_config_for_user({ - 'timespan': this.selected_timespan, - 'from_date': null, - 'to_date': null - - }); - this.fetch_and_update_chart(); - } - } - }, - { - label: this.chart_settings.time_interval || this.chart_doc.time_interval, - options: ["Yearly", "Quarterly", "Monthly", "Weekly", "Daily"], - action: selected_item => { - this.selected_time_interval = selected_item; - this.save_chart_config_for_user({'time_interval': this.selected_time_interval}); - this.fetch_and_update_chart(); - } - } - ]; - + let filters = this.get_time_series_filters(); frappe.dashboard_utils.render_chart_filters( filters, "chart-actions", @@ -175,12 +124,77 @@ export default class ChartWidget extends Widget { ); } + get_time_series_filters() { + let filters; + if (this.chart_doc.type == 'Heatmap') { + filters = [{ + label: this.chart_settings.heatmap_year || this.chart_doc.heatmap_year, + options: frappe.dashboard_utils.get_years_since_creation(frappe.boot.user.creation), + action: selected_item => { + this.selected_heatmap_year = selected_item; + this.save_chart_config_for_user({'heatmap_year': this.selected_heatmap_year}); + this.fetch_and_update_chart(); + } + }]; + } else { + filters = [ + { + label: this.chart_settings.timespan || this.chart_doc.timespan, + options: [ + "Select Date Range", + "Last Year", + "Last Quarter", + "Last Month", + "Last Week" + ], + action: selected_item => { + this.selected_timespan = selected_item; + + if (this.selected_timespan === "Select Date Range") { + this.render_date_range_fields(); + } else { + this.selected_from_date = null; + this.selected_to_date = null; + if (this.date_field_wrapper) { + this.date_field_wrapper.hide(); + + // Title maybe hidden becuase of date range fields + // in half width chart + this.title_field.show(); + this.head.css('flex-direction', "row"); + } + + this.save_chart_config_for_user({ + 'timespan': this.selected_timespan, + 'from_date': null, + 'to_date': null + + }); + this.fetch_and_update_chart(); + } + } + }, + { + label: this.chart_settings.time_interval || this.chart_doc.time_interval, + options: ["Yearly", "Quarterly", "Monthly", "Weekly", "Daily"], + action: selected_item => { + this.selected_time_interval = selected_item; + this.save_chart_config_for_user({'time_interval': this.selected_time_interval}); + this.fetch_and_update_chart(); + } + } + ]; + } + return filters; + } + fetch_and_update_chart() { this.args = { timespan: this.selected_timespan || this.chart_settings.timespan, time_interval: this.selected_time_interval || this.chart_settings.time_interval, from_date: this.selected_from_date || this.chart_settings.from_date, - to_date: this.selected_to_date || this.chart_settings.to_date + to_date: this.selected_to_date || this.chart_settings.to_date, + heatmap_year: this.selected_heatmap_year || this.chart_settings.heatmap_year, }; this.fetch(this.filters, true, this.args).then(data => { @@ -406,6 +420,9 @@ export default class ChartWidget extends Widget { this.save_chart_config_for_user(null, 1); this.chart_settings = {}; this.filters = null; + this.selected_time_interval = null; + this.selected_timespan = null; + this.selected_heatmap_year = null; } save_chart_config_for_user(config, reset=0) { @@ -473,7 +490,8 @@ export default class ChartWidget extends Widget { time_interval: args && args.time_interval ? args.time_interval : null, timespan: args && args.timespan ? args.timespan : null, from_date: args && args.from_date ? args.from_date : null, - to_date: args && args.to_date ? args.to_date : null + to_date: args && args.to_date ? args.to_date : null, + heatmap_year: args && args.heatmap_year ? args.heatmap_year : null, }; } return frappe.xcall(method, args); @@ -531,7 +549,10 @@ export default class ChartWidget extends Widget { }; if (this.chart_doc.type == "Heatmap") { - const heatmap_year = parseInt(this.chart_doc.heatmap_year || "2020"); + if (!this.chart_doc.heatmap_year) { + this.chart_doc.heatmap_year = frappe.dashboard_utils.get_year(frappe.datetime.now_date()); + } + const heatmap_year = parseInt(this.selected_heatmap_year || this.chart_settings.heatmap_year || this.chart_doc.heatmap_year); chart_args.data.start = new Date(`${heatmap_year}-01-01`); chart_args.data.end = new Date(`${heatmap_year+1}-01-01`); } diff --git a/frappe/utils/dashboard.py b/frappe/utils/dashboard.py index 7cc97ed3f9..8edcf085f0 100644 --- a/frappe/utils/dashboard.py +++ b/frappe/utils/dashboard.py @@ -41,6 +41,7 @@ def generate_and_cache_results(args, function, cache_key, chart): to_date = args.to_date or None, time_interval = args.time_interval or None, timespan = args.timespan or None, + heatmap_year = args.heatmap_year or None ) except TypeError as e: if str(e) == "'NoneType' object is not iterable": From a3bedcbef478dac49fe221854f2026d6415889a2 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 19:30:18 +0530 Subject: [PATCH 019/145] fix: fix media query to hide heatmap for smaller widths --- frappe/public/less/desktop.less | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/public/less/desktop.less b/frappe/public/less/desktop.less index fbd7f988a3..6d4bbca8e8 100644 --- a/frappe/public/less/desktop.less +++ b/frappe/public/less/desktop.less @@ -350,11 +350,11 @@ } } } + } - @media (max-width: 768px) { - .heatmap-chart { - display: none; - } + @media (max-width: 768px) { + &.dashboard-widget-box.heatmap-chart { + display: none; } } From f662d9011e803ece7644610a1eba1bba128f7bca Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 23:03:51 +0530 Subject: [PATCH 020/145] fix: style for heatmap chart loading state --- frappe/public/less/desktop.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/less/desktop.less b/frappe/public/less/desktop.less index 6d4bbca8e8..eef0b29875 100644 --- a/frappe/public/less/desktop.less +++ b/frappe/public/less/desktop.less @@ -309,6 +309,10 @@ display: none; } + .chart-loading-state { + height: 160px !important; + } + .widget-body { display: flex; max-height: 100%; From 9eabcce714332aeed994cd30c3307bbd86e74b8e Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 23:04:21 +0530 Subject: [PATCH 021/145] fix: undefined selected heatmap year --- frappe/public/js/frappe/widgets/chart_widget.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index abd99e360d..4be9ce1fd9 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -549,9 +549,6 @@ export default class ChartWidget extends Widget { }; if (this.chart_doc.type == "Heatmap") { - if (!this.chart_doc.heatmap_year) { - this.chart_doc.heatmap_year = frappe.dashboard_utils.get_year(frappe.datetime.now_date()); - } const heatmap_year = parseInt(this.selected_heatmap_year || this.chart_settings.heatmap_year || this.chart_doc.heatmap_year); chart_args.data.start = new Date(`${heatmap_year}-01-01`); chart_args.data.end = new Date(`${heatmap_year+1}-01-01`); @@ -616,6 +613,10 @@ export default class ChartWidget extends Widget { let saved_filters = this.chart_settings.filters || null; this.filters = saved_filters || this.filters || JSON.parse(this.chart_doc.filters_json || "[]"); + + if (this.chart_doc.type == 'Heatmap' && !this.chart_doc.heatmap_year) { + this.chart_doc.heatmap_year = frappe.dashboard_utils.get_year(frappe.datetime.now_date()); + } } get_settings() { From a2a697b4d547369ed39c5bcdfdc2ab5fec1602ae Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 9 May 2020 15:38:08 +0530 Subject: [PATCH 022/145] fix: Remove theme based_on from Website Theme --- frappe/public/scss/website.scss | 11 ---- frappe/templates/base.html | 24 ++------ .../website_settings/website_settings.json | 6 +- .../doctype/website_theme/website_theme.json | 55 +++---------------- .../doctype/website_theme/website_theme.py | 12 ++-- .../website_theme/website_theme_template.scss | 7 ++- 6 files changed, 24 insertions(+), 91 deletions(-) diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.scss index 546110bd5c..6f82e25ee0 100644 --- a/frappe/public/scss/website.scss +++ b/frappe/public/scss/website.scss @@ -23,17 +23,6 @@ footer { flex-shrink: 0; } -// make navbar padding consistent with the page -.navbar { - padding-left: 0; - padding-right: 0; - - .container { - padding-left: 15px; - padding-right: 15px; - } -} - .navbar.bg-dark { .dropdown-menu { font-size: .75rem; diff --git a/frappe/templates/base.html b/frappe/templates/base.html index dd5dd63a1f..0a81712eb9 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -25,26 +25,10 @@ {{ head_html or "" }} {%- endif %} - {%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%} - {%- if theme.theme_url -%} - - {%- else -%} - - {%- endif -%} - {% else %} - {%- if developer_mode -%} - - - {%- else -%} - - - - {% endif %} - {%- if theme.theme_css -%} - - {%- endif -%} + {%- if theme.theme_url -%} + + {%- else -%} + {%- endif -%} {%- for link in web_include_css %} diff --git a/frappe/website/doctype/website_settings/website_settings.json b/frappe/website/doctype/website_settings/website_settings.json index b2d765b81f..279b490c1a 100644 --- a/frappe/website/doctype/website_settings/website_settings.json +++ b/frappe/website/doctype/website_settings/website_settings.json @@ -161,20 +161,17 @@ "label": "Footer" }, { - "depends_on": "eval:doc.footer_type==='Standard'", "fieldname": "copyright", "fieldtype": "Data", "label": "Copyright" }, { - "depends_on": "eval:doc.footer_type==='Standard'", "description": "Address and other legal information you may want to put in the footer.", "fieldname": "address", "fieldtype": "Text Editor", "label": "Address" }, { - "depends_on": "eval:doc.footer_type==='Standard'", "fieldname": "footer_items", "fieldtype": "Table", "label": "Footer Items", @@ -182,7 +179,6 @@ }, { "default": "0", - "depends_on": "eval:doc.footer_type==='Standard'", "fieldname": "hide_footer_signup", "fieldtype": "Check", "label": "Hide Footer Signup" @@ -337,7 +333,7 @@ "issingle": 1, "links": [], "max_attachments": 10, - "modified": "2020-04-30 12:37:44.070662", + "modified": "2020-05-09 14:17:23.271806", "modified_by": "Administrator", "module": "Website", "name": "Website Settings", diff --git a/frappe/website/doctype/website_theme/website_theme.json b/frappe/website/doctype/website_theme/website_theme.json index 10d018aa05..6ec4751341 100644 --- a/frappe/website/doctype/website_theme/website_theme.json +++ b/frappe/website/doctype/website_theme/website_theme.json @@ -8,7 +8,6 @@ "engine": "InnoDB", "field_order": [ "theme", - "based_on", "module", "custom", "bootstrap_theme_section", @@ -25,16 +24,12 @@ "dark_color", "background_color", "stylesheet_section", - "theme_scss", + "custom_overrides", "custom_scss", + "theme_scss", "theme_url", - "tailwind_theme_section", "custom_css", "theme_css", - "navbar_section", - "navbar", - "footer_section", - "footer", "custom_js_section", "js" ], @@ -86,48 +81,11 @@ "label": "JavaScript", "options": "JS" }, - { - "default": "Bootstrap 4", - "fieldname": "based_on", - "fieldtype": "Select", - "label": "Theme Based On", - "options": "Bootstrap 4\nTailwind" - }, - { - "depends_on": "eval:doc.based_on == 'Tailwind'", - "fieldname": "navbar_section", - "fieldtype": "Section Break", - "label": "Navbar" - }, - { - "depends_on": "eval:doc.based_on=='Tailwind'", - "fieldname": "tailwind_theme_section", - "fieldtype": "Section Break", - "label": "Tailwind Theme" - }, { "fieldname": "bootstrap_theme_section", "fieldtype": "Section Break", "label": "Theme Configuration" }, - { - "depends_on": "eval:doc.based_on == 'Tailwind'", - "fieldname": "footer_section", - "fieldtype": "Section Break", - "label": "Footer" - }, - { - "fieldname": "navbar", - "fieldtype": "Table", - "label": "Navbar", - "options": "Web Page Block" - }, - { - "fieldname": "footer", - "fieldtype": "Table", - "label": "Footer", - "options": "Web Page Block" - }, { "fieldname": "custom_css", "fieldtype": "Code", @@ -177,7 +135,6 @@ "options": "Color" }, { - "depends_on": "eval:doc.based_on == 'Bootstrap 4'", "fieldname": "stylesheet_section", "fieldtype": "Section Break", "label": "Stylesheet" @@ -220,10 +177,16 @@ { "fieldname": "column_break_11", "fieldtype": "Column Break" + }, + { + "fieldname": "custom_overrides", + "fieldtype": "Code", + "label": "Custom Overrides", + "options": "SCSS" } ], "links": [], - "modified": "2020-04-25 00:00:23.347879", + "modified": "2020-05-09 15:03:35.001068", "modified_by": "Administrator", "module": "Website", "name": "Website Theme", diff --git a/frappe/website/doctype/website_theme/website_theme.py b/frappe/website/doctype/website_theme/website_theme.py index ac7637d6c7..da6d26c2e0 100644 --- a/frappe/website/doctype/website_theme/website_theme.py +++ b/frappe/website/doctype/website_theme/website_theme.py @@ -41,13 +41,9 @@ class WebsiteTheme(Document): def validate_theme(self): '''Generate theme css if theme_scss has changed''' - if self.based_on == 'Bootstrap 4': - doc_before_save = self.get_doc_before_save() - if doc_before_save is None or get_scss(self) != get_scss(doc_before_save): - self.generate_bootstrap_theme() - - if self.based_on == 'Tailwind': - self.theme_css = frappe.render_template('frappe/website/doctype/website_theme/custom_theme.css', self.as_dict(), is_path=True) + doc_before_save = self.get_doc_before_save() + if doc_before_save is None or get_scss(self) != get_scss(doc_before_save): + self.generate_bootstrap_theme() def export_doc(self): """Export to standard folder `[module]/website_theme/[name]/[name].json`.""" @@ -139,5 +135,5 @@ def generate_theme_files_if_not_exist(): frappe.log_error(frappe.get_traceback(), "Theme File Generation Failed") def get_scss(doc): - return (doc.theme_scss or '') + '\n' + (doc.custom_scss or '') + return frappe.render_template('frappe/website/doctype/website_theme/website_theme_template.scss', doc.as_dict()) diff --git a/frappe/website/doctype/website_theme/website_theme_template.scss b/frappe/website/doctype/website_theme/website_theme_template.scss index 1bb4685b98..275b105f92 100644 --- a/frappe/website/doctype/website_theme/website_theme_template.scss +++ b/frappe/website/doctype/website_theme/website_theme_template.scss @@ -1,6 +1,5 @@ {% if google_font %} @import url('https://fonts.googleapis.com/css?family={{ google_font.replace(' ', '+') }}:{{ font_properties }}&display=swap'); - $font-family-sans-serif: "{{ google_font }}", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; {% endif -%} @@ -14,6 +13,9 @@ $enable-shadows: {{ button_shadows and "true" or "false" }}; $enable-gradients: {{ button_gradients and "true" or "false" }}; $enable-rounded: {{ button_rounded_corners and "true" or "false" }}; +// Bootstrap Variable Overrides +{{ custom_overrides or '' }} + @import "frappe/public/scss/website"; {% if font_size -%} @@ -21,3 +23,6 @@ body { font-size: {{ font_size }}; } {%- endif %} + +// Custom Theme +{{ custom_scss or '' }} From e0510e2e06c84854430b5701361a3eeb048fc565 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 9 May 2020 15:38:27 +0530 Subject: [PATCH 023/145] fix: Navbar --- frappe/templates/includes/navbar/navbar.html | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frappe/templates/includes/navbar/navbar.html b/frappe/templates/includes/navbar/navbar.html index 379c6660fc..9d48390170 100644 --- a/frappe/templates/includes/navbar/navbar.html +++ b/frappe/templates/includes/navbar/navbar.html @@ -1,5 +1,4 @@ -{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%} -
-{%- else -%} -
-{{ c('web_blocks', web_blocks=theme.navbar, htmltag='div') }} -
-{%- endif -%} From 7c3749c2a8c1bd4eff62d5570176d0ce9b981762 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Sat, 9 May 2020 17:20:25 +0530 Subject: [PATCH 024/145] fix: scaffolding for migrate-to command added --- frappe/commands/site.py | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 52994ccec3..d5329d4cf9 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -1,6 +1,7 @@ # imports - standard imports import atexit import compileall +import getpass import hashlib import os import re @@ -9,6 +10,7 @@ import sys # imports - third party imports import click +import requests # imports - module imports import frappe @@ -256,6 +258,77 @@ def migrate(context, rebuild_website=False, skip_failing=False): print("Compiling Python Files...") compileall.compile_dir('../apps', quiet=1, rx=re.compile('.*node_modules.*')) + +@click.command('migrate-to') +@click.argument('site_url') +@pass_context +def migrate_to(context, site_url): + ''' + >>> import requests + >>> session = requests.Session() + >>> session.post("http://cloud:8002/api/method/login", {"usr":"gavin18d@gmail.com", "pwd":"bfdiljn;jnd"}) + + >>> session.headers.update({"X-Press-Team": "gavin18d@gmail.com"}) + >>> session.post("http://cloud:8002/api/method/press.api.site.options_for_new").json() + ''' + + if site_url in ("frappe.cloud", "frappecloud.com"): + site_url = "frappe.cloud" + + login_url = "https://{site_url}/api/method/login" + upload_url = "https://{site_url}/api/method/press.api.site.new_from_existing_account" + options_url = "https://{site_url}/api/method/press.api.site.options_for_new" + + else: + print(f"{site_url} is not supported yet") + sys.exit(1) + + for site in context.site: + username = input() + password = getpass.unix_getpass() + auth_credentials = {"usr": username, "pwd": password} + + # create frapp_cloud session + session = requests.Session() + login_sc = session.post(login_url, auth_credentials) + + if login_sc.ok: + print(f"Auth Successful w {site_url}") + + # get options + session.headers.update({"X-Press-Team": username}) + site_options_sc = session.post(options_url) + + if site_options_sc.ok: + site_options = site_options_sc.json() + + else: + print(f"Request failed with Status Code: {site_options_sc.status_code}") + sys.exit(1) + + # set preferences from options + + # take backup + import frappe.utils.backups + print(f"Taking backup for site {site}") + odb = frappe.utils.backups.new_backup(ignore_files=False, force=True) + + # relative paths here + odb.backup_path_db + odb.backup_path_files + odb.backup_path_private_files + + site_files = { + "files": [] + } + + # push to frappe_cloud + session.post(upload_url, files=site_files) + + else: + print(f"Request failed with Status Code: {login_sc.status_code}") + + @click.command('run-patch') @click.argument('module') @pass_context @@ -559,6 +632,7 @@ commands = [ install_app, list_apps, migrate, + migrate_to, new_site, reinstall, reload_doc, From 51289dbd008d0ada4da690669a02950f3c99b677 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Sat, 9 May 2020 17:21:29 +0530 Subject: [PATCH 025/145] fix: set totals currency for field --- frappe/public/js/frappe/views/reports/report_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 43540f449d..0c1f0f4635 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -1020,7 +1020,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { name: __('Totals Row'), content: totals[col.id], format: value => { - return frappe.format(value, col.docfield, { always_show_decimals: true }); + return frappe.format(value, col.docfield, { always_show_decimals: true }, data[0]); } } }) From be27513a56c69f6a70bcbf5b03b99847ea1415d9 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 12:09:54 +0530 Subject: [PATCH 026/145] feat: added driver.js with style overrides --- frappe/public/build.json | 5 +- frappe/public/js/frappe/ui/driver.js | 3 + frappe/public/less/driver.less | 180 +++++++++++++++++++++++++++ package.json | 1 + yarn.lock | 5 + 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 frappe/public/js/frappe/ui/driver.js create mode 100644 frappe/public/less/driver.less diff --git a/frappe/public/build.json b/frappe/public/build.json index d56907b558..e4c90cb708 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -112,7 +112,9 @@ "public/less/chat.less", "public/less/filters.less", "public/less/social.less", - "node_modules/frappe-charts/dist/frappe-charts.min.css" + "node_modules/frappe-charts/dist/frappe-charts.min.css", + "node_modules/driver.js/dist/driver.min.css", + "public/less/driver.less" ], "css/frappe-rtl.css": [ "public/css/bootstrap-rtl.css", @@ -244,6 +246,7 @@ "public/js/frappe/utils/energy_point_utils.js", "public/js/frappe/utils/dashboard_utils.js", "public/js/frappe/ui/chart.js", + "public/js/frappe/ui/driver.js", "public/js/frappe/barcode_scanner/index.js" ], "css/form.min.css": [ diff --git a/frappe/public/js/frappe/ui/driver.js b/frappe/public/js/frappe/ui/driver.js new file mode 100644 index 0000000000..98ed49ec05 --- /dev/null +++ b/frappe/public/js/frappe/ui/driver.js @@ -0,0 +1,3 @@ +import Driver from 'driver.js'; + +frappe.Driver = Driver; \ No newline at end of file diff --git a/frappe/public/less/driver.less b/frappe/public/less/driver.less new file mode 100644 index 0000000000..9dc7cde0b1 --- /dev/null +++ b/frappe/public/less/driver.less @@ -0,0 +1,180 @@ +@import "frappe/public/less/variables.less"; + +div#driver-popover-item { + .driver-popover-footer { + display: block; + margin-top: 12px; + + button { + // Edited + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + white-space: nowrap; + vertical-align: middle; + text-shadow: none !important; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + } + + button.driver-disabled { + color: grey; + cursor: default; + pointer-events: none; + } + + .driver-close-btn { + // Edited + float: left; + color: inherit; + background-color: #f0f4f7; + border-color: transparent; + } + + .driver-navigation-btns { + // Edited + .driver-prev-btn { + color: inherit; + background-color: #f0f4f7; + border-color: transparent; + } + + .driver-next-btn { + color: #fff; + background-color: #5e64ff; + border-color: #444bff; + } + } + } + .driver-popover-title { + // Edited + font: 18px/normal sans-serif; + margin: 0 0 5px; + font-weight: 500; + display: block; + position: relative; + line-height: 1.5; + zoom: 1; + } + .driver-popover-description { + // Edited + margin-bottom: 0; + font: 12px/normal sans-serif; + line-height: 1.5; + color: @text-muted; + font-weight: 400; + zoom: 1; + } +} + +.driver-clearfix { + &:after { + content: ""; + display: table; + clear: both; + } + &:before { + content: ""; + display: table; + } +} + +.driver-stage-no-animation { + -webkit-transition: none !important; + -moz-transition: none !important; + -ms-transition: none !important; + -o-transition: none !important; + transition: none !important; + background: transparent !important; + outline: 5000px solid rgba(0,0,0,.75); +} + +div#driver-page-overlay { + background: @modal-backdrop-bg; + position: fixed; + bottom: 0; + right: 0; + display: block; + width: 100%; + height: 100%; + zoom: 1; + filter: alpha(opacity=25); + opacity: .25; + z-index: 100002 !important; + top: 0; + left: 0; + -webkit-transition: all .3s; + -moz-transition: all .3s; + -ms-transition: all .3s; + -o-transition: all .3s; + transition: all .3s; +} + +div#driver-highlighted-element-stage { + top: 0; + left: 0; + -webkit-transition: all .3s; + -moz-transition: all .3s; + -ms-transition: all .3s; + -o-transition: all .3s; + transition: all .3s; + position: absolute; + height: 50px; + width: 300px; + background: #fff; + z-index: 100003 !important; + display: none; + border-radius: 2px; +} + +.driver-highlighted-element { + z-index: 100004 !important; +} + +.driver-position-relative { + position: relative !important; +} + +.driver-fix-stacking { + z-index: auto !important; + opacity: 1 !important; + -webkit-transform: none !important; + -moz-transform: none !important; + -ms-transform: none !important; + -o-transform: none !important; + transform: none !important; + -webkit-filter: none !important; + -moz-filter: none !important; + -ms-filter: none !important; + -o-filter: none !important; + filter: none !important; + -webkit-perspective: none !important; + -moz-perspective: none !important; + -ms-perspective: none !important; + -o-perspective: none !important; + perspective: none !important; + -webkit-transform-style: flat !important; + -moz-transform-style: flat !important; + -ms-transform-style: flat !important; + transform-style: flat !important; + -webkit-transform-box: border-box !important; + -moz-transform-box: border-box !important; + -ms-transform-box: border-box !important; + -o-transform-box: border-box !important; + transform-box: border-box !important; + will-change: unset !important; +} + + diff --git a/package.json b/package.json index e735beee9b..fae9798706 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "bootstrap": "^4.4.1", "cookie": "^0.4.0", "cssnano": "^4.1.10", + "driver.js": "^0.9.8", "express": "^4.17.1", "fast-deep-equal": "^2.0.1", "frappe-charts": "^1.3.2", diff --git a/yarn.lock b/yarn.lock index b189296086..73816bdece 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1770,6 +1770,11 @@ double-ended-queue@^2.1.0-0: resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= +driver.js@^0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/driver.js/-/driver.js-0.9.8.tgz#4b327f4537b1c9b9fb19419de86174be821ae32a" + integrity sha512-bczjyKdX6XmFyCDkwtRmlaORDwfBk1xXmRO0CAe5VwNQTM98aWaG2LAIiIdTe53iV/B7W5lXlIy2xYtf0JRb7Q== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" From 1ab4f21a3609296b7cd1898f6064a578920cb897 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 12:36:25 +0530 Subject: [PATCH 027/145] feat: added frappe tour API --- frappe/public/js/frappe/form/form.js | 29 ++++++++++++++++++++++++++++ frappe/public/js/frappe/provide.js | 1 + 2 files changed, 30 insertions(+) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index a5853d96f5..0368311a2d 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1556,6 +1556,35 @@ frappe.ui.form.Form = class FrappeForm { $el.find('input, select, textarea').focus(); }, 1000); } + + show_tour() { + if (!frappe.tour.hasOwnProperty(this.doctype) || !Array.isArray(frappe.tour[this.doctype])) { + return + } + + const driver = new frappe.Driver({ + overlayClickNext: true, + keyboardControl: true, + nextBtnText: 'Next', // Next button text for this step + prevBtnText: 'Previous', + }); + + let steps = frappe.tour[this.doctype].map(step => { + let field = this.get_docfield(step.fieldname); + return { + element: `.frappe-control[title='${step.fieldname}']`, + popover: { + title: step.title || field.label, + description: step.description + } + } + }); + + console.log(steps); + + driver.defineSteps(steps); + driver.start(); + } }; frappe.validated = 0; diff --git a/frappe/public/js/frappe/provide.js b/frappe/public/js/frappe/provide.js index 1dacc4dd47..d4d0fdffb8 100644 --- a/frappe/public/js/frappe/provide.js +++ b/frappe/public/js/frappe/provide.js @@ -35,6 +35,7 @@ frappe.provide('locals.DocType'); // for listviews frappe.provide("frappe.listview_settings"); +frappe.provide("frappe.tour"); frappe.provide("frappe.listview_parent_route"); // constants From b24de5b703c8ac2c7fed1afa5a84821768406c99 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 12:37:25 +0530 Subject: [PATCH 028/145] feat: setup tour for note --- frappe/desk/doctype/note/note.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/frappe/desk/doctype/note/note.js b/frappe/desk/doctype/note/note.js index c237998ccf..5718180b70 100644 --- a/frappe/desk/doctype/note/note.js +++ b/frappe/desk/doctype/note/note.js @@ -1,9 +1,9 @@ frappe.ui.form.on("Note", { refresh: function(frm) { - if(frm.doc.__islocal) { + if (frm.doc.__islocal) { frm.events.set_editable(frm, true); } else { - if(!frm.doc.content) { + if (!frm.doc.content) { frm.doc.content = ""; } @@ -18,16 +18,15 @@ frappe.ui.form.on("Note", { // hide all fields other than content // no permission - if(editable && !frm.perm[0].write) return; + if (editable && !frm.perm[0].write) return; // content read_only - frm.set_df_property("content", "read_only", editable ? 0: 1); + frm.set_df_property("content", "read_only", editable ? 0 : 1); // hide all other fields $.each(frm.fields_dict, function(fieldname) { - - if(fieldname !== "content") { - frm.set_df_property(fieldname, "hidden", editable ? 0: 1); + if (fieldname !== "content") { + frm.set_df_property(fieldname, "hidden", editable ? 0 : 1); } }); @@ -39,3 +38,16 @@ frappe.ui.form.on("Note", { frm.is_note_editable = editable; } }); + +frappe.tour['Note'] = [ + { + fieldname: "title", + title: "Title of the Note", + description: "This is the name by which the note will be saved, you can change this later", + }, + { + fieldname: "public", + title: "Sets the Note to Public", + description: "You can change the visibility of the note with this, setting it to public will allow other users to view it.", + }, +]; \ No newline at end of file From 470abc20a1463ae68cbc33f4d8d748edb2a9f47d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 12:56:40 +0530 Subject: [PATCH 029/145] feat: expand all sections before tour --- frappe/public/js/frappe/form/form.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 0368311a2d..41bde104dd 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1569,6 +1569,8 @@ frappe.ui.form.Form = class FrappeForm { prevBtnText: 'Previous', }); + this.layout.sections.forEach(section => section.collapse(false)) + let steps = frappe.tour[this.doctype].map(step => { let field = this.get_docfield(step.fieldname); return { @@ -1580,8 +1582,6 @@ frappe.ui.form.Form = class FrappeForm { } }); - console.log(steps); - driver.defineSteps(steps); driver.start(); } From bf7de110e27a50906a3d4384c9489a769af3b5a0 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 12:57:37 +0530 Subject: [PATCH 030/145] feat: added steps for website settings --- .../doctype/website_settings/website_settings.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/frappe/website/doctype/website_settings/website_settings.js b/frappe/website/doctype/website_settings/website_settings.js index be294258f4..7fbb785acf 100644 --- a/frappe/website/doctype/website_settings/website_settings.js +++ b/frappe/website/doctype/website_settings/website_settings.js @@ -95,4 +95,17 @@ frappe.ui.form.on('Top Bar Item', { label: function(frm, doctype, name) { frm.events.set_parent_options(frm, doctype, name); }, -}); \ No newline at end of file +}); + +frappe.tour['Website Settings'] = [ + { + fieldname: "enable_view_tracking", + title: __("Enable Tracking Page Views"), + description: __("Checking this will enable tracking page views for blogs, web pages, etc."), + }, + { + fieldname: "disable_signup", + title: __("Disable Signup for your site"), + description: __("Check this if you don't want users to sign up for an account on your site. Users won't get desk access unless you explicitly provide it."), + } +]; \ No newline at end of file From a358bcdc33246b81120ff8ee558e51b2cfdd5e41 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 14:07:21 +0530 Subject: [PATCH 031/145] feat: add form tour as onboarding option --- .../doctype/onboarding_step/onboarding_step.js | 18 ++++++++++++++++++ .../onboarding_step/onboarding_step.json | 15 ++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/onboarding_step/onboarding_step.js b/frappe/desk/doctype/onboarding_step/onboarding_step.js index 3e5d4d4260..793e044d98 100644 --- a/frappe/desk/doctype/onboarding_step/onboarding_step.js +++ b/frappe/desk/doctype/onboarding_step/onboarding_step.js @@ -25,6 +25,24 @@ frappe.ui.form.on("Onboarding Step", { } }, + action: function(frm) { + if (frm.doc.action == "Show Form Tour") { + frm.fields_dict.reference_document.set_description(`You need to add the steps in the contoller JS file. For example: note.js +

+frappe.tour['Note'] = [
+	{
+		fieldname: "title",
+		title: "Title of the Note",
+		description: "...",
+	}
+];
+
+ `); + } else { + frm.fields_dict.reference_document.set_description(null); + } + }, + disable_form: function(frm) { frm.set_read_only(); frm.fields diff --git a/frappe/desk/doctype/onboarding_step/onboarding_step.json b/frappe/desk/doctype/onboarding_step/onboarding_step.json index e1035a4343..3bc9d5f286 100644 --- a/frappe/desk/doctype/onboarding_step/onboarding_step.json +++ b/frappe/desk/doctype/onboarding_step/onboarding_step.json @@ -15,6 +15,7 @@ "action", "column_break_7", "reference_document", + "is_single", "reference_report", "report_reference_doctype", "report_type", @@ -57,7 +58,7 @@ "fieldname": "action", "fieldtype": "Select", "label": "Action", - "options": "Create Entry\nUpdate Settings\nView Report\nWatch Video", + "options": "Create Entry\nUpdate Settings\nShow Form Tour\nView Report\nWatch Video", "reqd": 1 }, { @@ -65,7 +66,7 @@ "fieldtype": "Column Break" }, { - "depends_on": "eval:doc.action == \"Create Entry\" || doc.action == \"Update Settings\"", + "depends_on": "eval:doc.action == \"Create Entry\" || doc.action == \"Update Settings\" || doc.action == \"Create Entry\" || doc.action == \"Show Form Tour\"", "fieldname": "reference_document", "fieldtype": "Link", "label": "Reference Document", @@ -127,10 +128,18 @@ "fieldtype": "Data", "label": "Report Reference Doctype", "read_only": 1 + }, + { + "default": "0", + "depends_on": "eval:doc.action == \"Create Entry\" || doc.action == \"Update Settings\" || doc.action == \"Create Entry\" || doc.action == \"Show Form Tour\"", + "fetch_from": "reference_document.issingle", + "fieldname": "is_single", + "fieldtype": "Check", + "label": "Is Single" } ], "links": [], - "modified": "2020-05-04 12:53:19.276952", + "modified": "2020-05-11 13:24:05.457160", "modified_by": "Administrator", "module": "Desk", "name": "Onboarding Step", From 5c241255516edfbc62e1ace935746611ab03551d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 14:07:55 +0530 Subject: [PATCH 032/145] feat: add on_finish hook for tour --- frappe/public/js/frappe/form/form.js | 8 ++++- .../js/frappe/widgets/onboarding_widget.js | 35 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 41bde104dd..3742ea36dc 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1557,7 +1557,7 @@ frappe.ui.form.Form = class FrappeForm { }, 1000); } - show_tour() { + show_tour(on_finish) { if (!frappe.tour.hasOwnProperty(this.doctype) || !Array.isArray(frappe.tour[this.doctype])) { return } @@ -1567,6 +1567,12 @@ frappe.ui.form.Form = class FrappeForm { keyboardControl: true, nextBtnText: 'Next', // Next button text for this step prevBtnText: 'Previous', + opacity: 0.25, + onNext: (el) => { + if (!driver.hasNextStep()) { + on_finish && on_finish(); + } + } }); this.layout.sections.forEach(section => section.collapse(false)) diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index 78305edd5d..f9abbaf64e 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -57,6 +57,7 @@ export default class OnboardingWidget extends Widget { let actions = { "Watch Video": () => this.show_video(step), "Create Entry": () => this.show_quick_entry(step), + "Show Form Tour": () => this.show_form_tour(step), "Update Settings": () => this.update_settings(step), "View Report": () => this.open_report(step), }; @@ -86,7 +87,9 @@ export default class OnboardingWidget extends Widget { primary_action: { action: () => { msg_dialog.hide(); - this.mark_complete(step); + frappe.set_route(current_route).then(() => { + this.mark_complete(step); + }); }, label: () => __("Continue"), }, @@ -105,6 +108,36 @@ export default class OnboardingWidget extends Widget { }); } + show_form_tour(step) { + let route; + if (step.is_single) { + route = `Form/${step.reference_document}` + } else { + route = `Form/${step.reference_document}/New ${step.reference_document}` + } + + frappe.route_options = {}; + frappe.route_options.after_load = (frm) => { + frm.show_tour(() => { + let msg_dialog = frappe.msgprint({ + message: __("Let's take you back to onboarding"), + title: __("Great Job"), + primary_action: { + action: () => { + frappe.set_route(current_route).then(() => { + this.mark_complete(step); + }); + msg_dialog.hide(); + }, + label: () => __("Continue"), + } + }); + }); + }; + + frappe.set_route(route) + } + update_settings(step) { let current_route = frappe.get_route(); From 986504d46d7960fe2cb272111e3d02fa33a23f9f Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Mon, 11 May 2020 14:19:22 +0530 Subject: [PATCH 033/145] fix: routing bug for tour --- frappe/public/js/frappe/widgets/onboarding_widget.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index f9abbaf64e..94b73d0c8b 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -78,6 +78,7 @@ export default class OnboardingWidget extends Widget { doctype: step.report_reference_doctype }); + let current_route = frappe.get_route(); frappe.set_route(route).then(() => { @@ -86,10 +87,10 @@ export default class OnboardingWidget extends Widget { title: __(step.reference_report), primary_action: { action: () => { - msg_dialog.hide(); frappe.set_route(current_route).then(() => { this.mark_complete(step); }); + msg_dialog.hide(); }, label: () => __("Continue"), }, @@ -116,6 +117,8 @@ export default class OnboardingWidget extends Widget { route = `Form/${step.reference_document}/New ${step.reference_document}` } + let current_route = frappe.get_route(); + frappe.route_options = {}; frappe.route_options.after_load = (frm) => { frm.show_tour(() => { From 451772dfab13abfb440c199c34d67887cf1921d9 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 11 May 2020 15:47:19 +0530 Subject: [PATCH 034/145] refactor(commands): migrate-to frappecloud connector --- frappe/commands/site.py | 67 +------------ frappe/utils/remote_migrations.py | 151 ++++++++++++++++++++++++++++++ requirements.txt | 1 + 3 files changed, 155 insertions(+), 64 deletions(-) create mode 100644 frappe/utils/remote_migrations.py diff --git a/frappe/commands/site.py b/frappe/commands/site.py index d5329d4cf9..058554cff6 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -263,70 +263,9 @@ def migrate(context, rebuild_website=False, skip_failing=False): @click.argument('site_url') @pass_context def migrate_to(context, site_url): - ''' - >>> import requests - >>> session = requests.Session() - >>> session.post("http://cloud:8002/api/method/login", {"usr":"gavin18d@gmail.com", "pwd":"bfdiljn;jnd"}) - - >>> session.headers.update({"X-Press-Team": "gavin18d@gmail.com"}) - >>> session.post("http://cloud:8002/api/method/press.api.site.options_for_new").json() - ''' - - if site_url in ("frappe.cloud", "frappecloud.com"): - site_url = "frappe.cloud" - - login_url = "https://{site_url}/api/method/login" - upload_url = "https://{site_url}/api/method/press.api.site.new_from_existing_account" - options_url = "https://{site_url}/api/method/press.api.site.options_for_new" - - else: - print(f"{site_url} is not supported yet") - sys.exit(1) - - for site in context.site: - username = input() - password = getpass.unix_getpass() - auth_credentials = {"usr": username, "pwd": password} - - # create frapp_cloud session - session = requests.Session() - login_sc = session.post(login_url, auth_credentials) - - if login_sc.ok: - print(f"Auth Successful w {site_url}") - - # get options - session.headers.update({"X-Press-Team": username}) - site_options_sc = session.post(options_url) - - if site_options_sc.ok: - site_options = site_options_sc.json() - - else: - print(f"Request failed with Status Code: {site_options_sc.status_code}") - sys.exit(1) - - # set preferences from options - - # take backup - import frappe.utils.backups - print(f"Taking backup for site {site}") - odb = frappe.utils.backups.new_backup(ignore_files=False, force=True) - - # relative paths here - odb.backup_path_db - odb.backup_path_files - odb.backup_path_private_files - - site_files = { - "files": [] - } - - # push to frappe_cloud - session.post(upload_url, files=site_files) - - else: - print(f"Request failed with Status Code: {login_sc.status_code}") + from frappe.utils.remote_migrations import migrate_to + for site in context.sites: + migrate_to(site, site_url) @click.command('run-patch') diff --git a/frappe/utils/remote_migrations.py b/frappe/utils/remote_migrations.py new file mode 100644 index 0000000000..7664411474 --- /dev/null +++ b/frappe/utils/remote_migrations.py @@ -0,0 +1,151 @@ +import getpass +import sys + +import requests +from terminaltables import AsciiTable + +import frappe +import frappe.utils.backups + + +def choose(plans_list): + plans_table = [] + available_plans = [] + selected_plan = None + + print(f"{len(plans_list)} plans available") + + plans_table.append([x for x in plans_list[0].keys()]) + for plan in plans_list: + row_data = [x for x in plan.values()] + available_plans.append(row_data[0]) + plans_table.append(row_data) + + print(AsciiTable(plans_table).table) + + while True: + if selected_plan: + break + else: + input_plan = input("Send plan?: ") + if input_plan in available_plans: + return selected_plan + else: + print("Invalid selection...try again") + + +def filter_apps(app_groups): + from frappe.utils import get_installed_apps_info + + allowed_apps = [] + filtered_apps = [] + existing_apps = [] + + for group in app_groups: + for app in group.get("apps"): + app_name = group.get('scrubbed') + branch = group.get('branch') + allowed_apps.append(tuple(app_name, branch)) + + for app in get_installed_apps_info(): + app_name = app.get('app_name') + branch = app.get('branch') + existing_apps.append(tuple(app_name, branch)) + + filtered_apps = [app[0] for app in existing_apps if app in allowed_apps] + + return "Vanilla Version 12", filtered_apps + + +def migrate_to(local_site, remote_site): + if remote_site in ("frappe.cloud", "frappecloud.com"): + remote_site = "cloud:8002" + # remote_site = "frappecloud.com" + return frappecloud_migrator(local_site, remote_site) + else: + print(f"{remote_site} is not supported yet") + sys.exit(1) + + +def frappecloud_migrator(local_site, remote_site): + # test: + login_url = f"http://{remote_site}/api/method/login" + upload_url = f"http://{remote_site}/api/method/press.api.site.new" + files_url = f"http://{remote_site}/api/method/upload_file" + options_url = f"http://{remote_site}/api/method/press.api.site.options_for_new" + + # production: + # login_url = f"https://{remote_site}/api/method/login" + # upload_url = f"https://{remote_site}/api/method/press.api.site.new_from_existing_account" + # options_url = f"https://{remote_site}/api/method/press.api.site.options_for_new" + + print(f"Frappe Cloud credentials @ {remote_site}") + + username = input("Username: ") + password = getpass.unix_getpass() + auth_credentials = {"usr": username, "pwd": password} + + # create frapp_cloud session + session = requests.Session() + login_sc = session.post(login_url, auth_credentials) + + if login_sc.ok: + print(f"Authorization Successful!") + + # get options + session.headers.update({"X-Press-Team": username}) + site_options_sc = session.post(options_url) + + if site_options_sc.ok: + site_options = site_options_sc.json()["message"] + app_groups = site_options_sc.json()["groups"] + + else: + print(f"Request failed with Status Code: {site_options_sc.status_code}") + sys.exit(1) + + # set preferences from options + subdomain = input("Enter subdomain: ") + plan = choose(site_options['plans']) + + frappe.init(site=local_site) + frappe.connect() + + # apps currently on site....vanilla. + selected_group, filtered_apps = filter_apps(app_groups) + + # take backup + print(f"Taking backup for site {local_site}") + odb = frappe.utils.backups.new_backup(ignore_files=False, force=True) + files_session = {} + + # upload files + for file_type, file_path in [("database", odb.backup_path_db), ("public", odb.backup_path_files), ("private", odb.backup_path_private_files)]: + file_upload_response = session.post(files_url, data={}, files={ + "file": open(file_path, "rb"), + "is_private": 1, + "folder": "Home", + "method": "press.api.site.upload_backup", + "type": file_type + }) + if file_upload_response.ok: + files_session[file_type] = file_upload_response.json()["message"] + else: + print(f"Upload failed for: {file_path}") + + files_uploaded = { k, v["file_url"] for k, v in files_session.items() } + + # push to frappe_cloud + session.post(upload_url, data={ + "site": { + "apps": filtered_apps, + "files": files_uploaded, + "group": selected_group, + "name": subdomain, + "plan": plan + } + }) + frappe.destroy() + + else: + print(f"Request failed with Status Code: {login_sc.status_code}") diff --git a/requirements.txt b/requirements.txt index 6c22d66139..c4cb79892a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,6 +60,7 @@ semantic-version==2.8.4 six==1.14.0 sqlparse==0.2.4 stripe==2.40.0 +terminaltables unittest-xml-reporting==2.5.2 urllib3==1.25.8 watchdog==0.8.0 From 355393ed0a1307e3a4597a322ff7fe8167f6c11a Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 11 May 2020 15:53:29 +0530 Subject: [PATCH 035/145] fix: Port Tailwind styles to Bootstrap 4 SCSS --- frappe/public/scss/base.scss | 43 +++ frappe/public/scss/markdown.scss | 117 ++++++++ frappe/public/scss/page-builder.scss | 252 ++++++++++++++++++ frappe/public/scss/variables.scss | 39 ++- frappe/public/scss/website-image.scss | 4 +- frappe/public/scss/website.scss | 226 ++++++++++++---- .../templates/components/image_with_blur.html | 5 +- frappe/templates/components/web_block.html | 7 +- .../full_width_image/full_width_image.html | 2 +- frappe/website/web_template/hero/hero.html | 17 +- .../hero_with_right_image.html | 28 +- .../web_template/markdown/markdown.html | 6 +- .../section_with_cards.html | 66 +++-- .../section_with_cta/section_with_cta.html | 24 +- .../section_with_image.html | 6 +- .../section_with_left_image.html | 10 +- .../section_with_tabs/section_with_tabs.html | 128 +++------ 17 files changed, 743 insertions(+), 237 deletions(-) create mode 100644 frappe/public/scss/base.scss create mode 100644 frappe/public/scss/markdown.scss create mode 100644 frappe/public/scss/page-builder.scss diff --git a/frappe/public/scss/base.scss b/frappe/public/scss/base.scss new file mode 100644 index 0000000000..a00996780e --- /dev/null +++ b/frappe/public/scss/base.scss @@ -0,0 +1,43 @@ +html { + height: 100%; +} + +body { + -webkit-font-smoothing: antialiased; + font-size: 16px; + color: $black; +} + +img { + max-width: 100%; + height: auto; +} + +h1 { + font-size: $font-size-3xl; + font-weight: 800; + line-height: 1.25; + letter-spacing: -0.025em; + + @include media-breakpoint-up(sm) { + line-height: 2.5rem; + font-size: $font-size-4xl; + } + @include media-breakpoint-up(xl) { + line-height: 1; + font-size: $font-size-5xl; + } +} + +h2 { + font-size: $font-size-xl; + font-weight: bold; + + @include media-breakpoint-up(sm) { + font-size: $font-size-2xl; + } + @include media-breakpoint-up(md) { + font-size: $font-size-3xl; + } +} + diff --git a/frappe/public/scss/markdown.scss b/frappe/public/scss/markdown.scss new file mode 100644 index 0000000000..440a4cfe88 --- /dev/null +++ b/frappe/public/scss/markdown.scss @@ -0,0 +1,117 @@ +.from-markdown { + line-height: 1.625; + + > * + * { + margin-top: 1rem; + } + + > :first-child { + margin-top: 0; + } + + ul, + ol { + padding-left: 2.5rem; + } + + ul { + list-style-type: disc; + } + + ol { + list-style: decimal; + } + + li > * + * { + margin-top: 1rem; + } + + > ul > * + *, + > ol > * + * { + margin-top: 1rem; + } + + > blockquote { + padding: 0.75rem 1rem; + font-size: $font-size-sm; + font-weight: 500; + color: $gray-900; + border-left: 4px solid $yellow; + background-color: lighten($yellow, 42%); + border-top-left-radius: 0.1rem; + border-bottom-left-radius: 0.1rem; + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; + margin: 1.5rem 0; + } + + blockquote p:last-child { + margin-bottom: 0; + } + + h1 + p { + max-width: 42rem; + margin-top: 0.75rem; + font-size: $font-size-base; + color: $gray-900; + + @include media-breakpoint-up(sm) { + margin-top: 1.25rem; + font-size: 1.125rem; + } + @include media-breakpoint-up(md) { + font-size: 1.25rem; + } + } + + h2 { + margin-bottom: 1rem; + margin-top: 3.5rem; + } + + h3 { + margin-top: 3rem; + margin-bottom: 1rem; + font-weight: 600; + line-height: 1.25; + font-size: $font-size-xl; + } + + h4 { + margin-top: 2.5rem; + margin-bottom: 1rem; + font-size: 1.125rem; + font-weight: 600; + line-height: 1.25; + } + + h5 { + margin-top: 2rem; + margin-bottom: 1rem; + font-size: $font-size-base; + font-weight: 600; + line-height: 1.25; + } + + h6 { + margin-top: 1.5rem; + margin-bottom: 1rem; + font-size: $font-size-sm; + font-weight: 600; + line-height: 1.25; + } + + tr > td, + tr > th { + font-size: $font-size-sm; + } + + th:empty { + display: none; + } + + .screenshot { + border: 1px solid $gray-400; + border-radius: 0.375rem; + } +} diff --git a/frappe/public/scss/page-builder.scss b/frappe/public/scss/page-builder.scss new file mode 100644 index 0000000000..8ba894ccf8 --- /dev/null +++ b/frappe/public/scss/page-builder.scss @@ -0,0 +1,252 @@ +.hero-subtitle { + @extend .lead; + max-width: 42rem; +} + +.section-description { + max-width: 56rem; + margin-top: 0.5rem; + font-size: $font-size-base; + color: $gray-900; + + @include media-breakpoint-up(lg) { + font-size: $font-size-lg; + } +} + +.section-image { + margin-top: 2rem; + border-radius: 0.75rem; + width: 100%; +} + +.section-padding { + padding-top: 3rem; + padding-bottom: 3rem; + + @include media-breakpoint-up(sm) { + padding-top: 5rem; + padding-bottom: 5rem; + } + @include media-breakpoint-up(xl) { + padding-top: 8rem; + padding-bottom: 8rem; + } +} + +.section-padding-top { + padding-top: 3rem; + + @include media-breakpoint-up(sm) { + padding-top: 5rem; + } + @include media-breakpoint-up(xl) { + padding-top: 8rem; + } +} + +.section-padding-bottom { + padding-bottom: 3rem; + + @include media-breakpoint-up(sm) { + padding-bottom: 5rem; + } + @include media-breakpoint-up(xl) { + padding-bottom: 8rem; + } +} + +.hero-with-right-image { + position: relative; + + .hero-content { + display: flex; + align-items: center; + } + + .hero-image { + width: auto; + display: none; + object-fit: contain; + max-height: 36rem; + + &.contain-image { + right: 0; + } + + @include media-breakpoint-up(md) { + display: block; + max-width: 28rem; + } + @include media-breakpoint-up(lg) { + max-width: 32rem; + } + @include media-breakpoint-up(xl) { + max-width: 42rem; + } + } +} + +.card { + .card-title { + color: $black; + } + + .card-body { + color: $gray-900; + } + + &:hover { + border-color: $gray-600; + } + + &.card-sm { + .card-body { + padding: 1.5rem; + } + + .card-title { + font-size: $font-size-base; + font-weight: 600; + } + + .card-text { + font-size: $font-size-sm; + } + } + &.card-md { + .card-body { + padding: 1.75rem; + } + + .card-title { + font-size: $font-size-lg; + font-weight: 600; + + @include media-breakpoint-up(md) { + font-size: $font-size-xl; + } + } + .card-text { + font-size: $font-size-base; + } + } + &.card-lg { + .card-body { + padding: 2rem; + } + + .card-title { + font-size: $font-size-xl; + font-weight: bold; + + @include media-breakpoint-up(md) { + font-size: $font-size-2xl; + } + } + + .card-text { + font-size: $font-size-base; + + @include media-breakpoint-up(xl) { + font-size: $font-size-lg; + } + } + } +} + +.nav-tabs { + .nav-link.active, + .nav-item.show .nav-link { + color: darken($primary, 5%); + background-color: #fff; + border-bottom: 2px solid $primary; + } + + .nav-link { + color: $gray-700; + font-weight: 500; + border: none; + padding: 1rem 0.5rem; + margin-right: 2rem; + + &:hover { + color: $primary; + } + } +} + +.section-markdown > .from-markdown { + max-width: 42rem; +} + +.section-cta { + padding: 3rem 2rem; + text-align: center; + background-color: lighten($primary, 42%); + border-radius: 0.75rem; + + @include media-breakpoint-up(sm) { + padding-left: 3rem; + padding-right: 3rem; + } + @include media-breakpoint-up(md) { + padding-top: 5rem; + padding-bottom: 5rem; + } + + .title { + margin: 0 auto; + max-width: 36rem; + font-size: $font-size-2xl; + font-weight: 800; + line-height: 1.25; + @include media-breakpoint-up(md) { + font-size: $font-size-4xl; + } + } + .subtitle { + max-width: 36rem; + margin: 0 auto; + margin-top: 0.5rem; + font-size: $font-size-base; + color: $gray-900; + @include media-breakpoint-up(md) { + font-size: $font-size-lg; + } + } + .description { + max-width: 36rem; + margin: 0 auto; + margin-top: 0.5rem; + font-size: $font-size-xs; + color: $gray-900; + } +} + +.section-cta-container { + position: relative; + .confetti { + position: absolute; + width: 1rem; + height: 1rem; + border-radius: 99999px; + } + .confetti-1 { + top: 0; + margin-top: -0.5rem; + background-color: #84e1bc; + left: 25%; + } + .confetti-2 { + background-color: #fdba8c; + top: 66.67%; + right: 16.67%; + } + .confetti-3 { + bottom: 0; + margin-bottom: -0.5rem; + background-color: #f8b4b4; + left: 16.67%; + } +} diff --git a/frappe/public/scss/variables.scss b/frappe/public/scss/variables.scss index 6ee7cda884..e5f3a47f6f 100644 --- a/frappe/public/scss/variables.scss +++ b/frappe/public/scss/variables.scss @@ -8,14 +8,45 @@ $gray-600: #8d99a6 !default; $gray-700: #495057 !default; $gray-800: #36414c !default; $gray-900: #2e3338 !default; -$primary: #5e64ff !default; +$primary: #2490ef !default; $black: #000 !default; $body-color: $gray-800 !default; $text-muted: $gray-600 !default; -$border-color: $gray-200 !default; +$border-color: $gray-300 !default; -@import "~bootstrap/scss/functions"; -@import "~bootstrap/scss/variables"; +$font-size-xs: 0.75rem !default; +$font-size-sm: 0.875rem !default; +$font-size-base: 1rem !default; +$font-size-lg: 1.125rem !default; +$font-size-xl: 1.25rem !default; +$font-size-2xl: 1.5rem !default; +$font-size-3xl: 1.875rem !default; +$font-size-4xl: 2.25rem !default; +$font-size-5xl: 3rem !default; +$font-size-6xl: 4rem !default; +$btn-padding-y-lg: 1rem !default; +$btn-padding-x-lg: 2.5rem !default; +$btn-font-size-lg: 1.125rem !default; +$btn-line-height-lg: 1 !default; +$btn-border-radius-lg: 0.5rem !default; +$btn-border-radius: 0.375rem !default; +$btn-font-size: $font-size-sm; +$btn-padding-x: 1rem !default; +$btn-padding-y: 0.5rem !default; +$btn-font-weight: 500 !default; + +$navbar-nav-link-padding-x: 1rem !default; +$navbar-padding-y: 1rem; +$card-border-radius: 0.75rem !default; +$card-spacer-y: 1rem !default; + +$dropdown-font-size: $font-size-sm !default; +$dropdown-border-radius: 0.375rem !default; +$dropdown-item-padding-y: 0.5rem !default; +$dropdown-item-padding-x: 0.5rem !default; + +@import '~bootstrap/scss/functions'; +@import '~bootstrap/scss/variables'; diff --git a/frappe/public/scss/website-image.scss b/frappe/public/scss/website-image.scss index 18adae4acc..8c32e821fe 100644 --- a/frappe/public/scss/website-image.scss +++ b/frappe/public/scss/website-image.scss @@ -34,7 +34,7 @@ img:after { display: flex; justify-content: center; align-items: center; - font-size: 3rem; + font-size: $font-size-5xl; color: $gray-300; background: $light; } @@ -85,4 +85,4 @@ img:after { .object-fit-cover { object-fit: cover; -} \ No newline at end of file +} diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.scss index 6f82e25ee0..4fbd57bc0b 100644 --- a/frappe/public/scss/website.scss +++ b/frappe/public/scss/website.scss @@ -1,31 +1,63 @@ -@import "variables"; -@import "frappe/public/css/font-awesome"; -@import "~bootstrap/scss/bootstrap"; -@import "multilevel-dropdown"; -@import "website-image"; +@import 'variables'; +@import 'frappe/public/css/font-awesome'; +@import '~bootstrap/scss/bootstrap'; +@import 'base'; +@import 'multilevel-dropdown'; +@import 'website-image'; +@import 'page-builder'; +@import 'markdown'; -html { - height: 100%; +.container { + padding-left: 1.25rem; + padding-right: 1.25rem; } -body { - min-height: 100%; - display: flex; - flex-direction: column; - font-size: 16px; - - > div { - flex: 1 0 auto; +@include media-breakpoint-up(sm) { + .container { + padding-left: 1rem; + padding-right: 1rem; } } -footer { - flex-shrink: 0; +@include media-breakpoint-up(md) { + .container { + padding-left: 1rem; + padding-right: 1rem; + } +} + +@include media-breakpoint-up(lg) { + .container { + padding-left: 1rem; + padding-right: 1rem; + } +} + +@include media-breakpoint-up(xl) { + .container { + padding-left: 1.5rem; + padding-right: 1.5rem; + } +} + +.navbar-light { + border-bottom: 1px solid $border-color; +} + +.navbar-light .navbar-nav .nav-link { + color: $gray-900; + font-size: $font-size-sm; + font-weight: 500; + + &:hover, + &:focus, &.active { + color: $primary; + } } .navbar.bg-dark { .dropdown-menu { - font-size: .75rem; + font-size: 0.75rem; background-color: $dark; border-radius: 0; } @@ -53,6 +85,13 @@ footer { } } +.dropdown-menu { + padding: 0.25rem; +} + +.dropdown-item { + border-radius: $dropdown-border-radius; +} .input-dark { background-color: $dark; @@ -61,25 +100,21 @@ footer { } .breadcrumb { - padding-left: 0; - padding-right: 0; - background-color: white; + padding-left: 0; + padding-right: 0; + background-color: white; } a.card { text-decoration: none; } -img { - max-width: 100%; -} - .hidden { @extend .d-none; } .hide-control { - @extend .d-none; + @extend .d-none; } .text-underline { @@ -90,10 +125,49 @@ img { color: #d1d8dd !important; } +// footer + .web-footer { padding: 5rem 0; min-height: 140px; - border-top: 1px solid $border-color; +} + +.footer-logo { + width: 5rem; + height: 2rem; +} + +.footer-col-left, .footer-col-right { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.footer-col-right { + @include media-breakpoint-up(sm) { + text-align: right; + } +} + +.footer-col-left .footer-link { + margin-right: 1rem; +} + +.footer-col-right .footer-link { + margin-right: 1rem; + @include media-breakpoint-up(sm) { + margin-right: 0; + margin-left: 1rem; + } +} + +.footer-link, .footer-child-item a { + font-weight: 500; + color: $gray-900; + + &:hover { + color: $primary; + text-decoration: none; + } } .footer-group-label { @@ -101,41 +175,75 @@ img { } .footer-parent-item { - margin-bottom: 1rem; + margin-bottom: 0.5rem; +} + +.footer-info { + border-top: 1px solid $border-color; + color: $text-muted; + font-size: $font-size-sm; } .no-underline { - text-decoration: none !important; + text-decoration: none !important; } .indicator { - font-size: inherit; + font-size: inherit; } h4.modal-title { - font-size: 1em; + font-size: 1em; } h5.modal-title { - margin: 0px !important; + margin: 0px !important; } -.col-xs-1 { @extend .col-1; } -.col-xs-2 { @extend .col-2; } -.col-xs-3 { @extend .col-3; } -.col-xs-4 { @extend .col-4; } -.col-xs-5 { @extend .col-5; } -.col-xs-6 { @extend .col-6; } -.col-xs-7 { @extend .col-7; } -.col-xs-8 { @extend .col-8; } -.col-xs-9 { @extend .col-9; } -.col-xs-10 { @extend .col-10; } -.col-xs-11 { @extend .col-11; } -.col-xs-12 { @extend .col-12; } +.col-xs-1 { + @extend .col-1; +} +.col-xs-2 { + @extend .col-2; +} +.col-xs-3 { + @extend .col-3; +} +.col-xs-4 { + @extend .col-4; +} +.col-xs-5 { + @extend .col-5; +} +.col-xs-6 { + @extend .col-6; +} +.col-xs-7 { + @extend .col-7; +} +.col-xs-8 { + @extend .col-8; +} +.col-xs-9 { + @extend .col-9; +} +.col-xs-10 { + @extend .col-10; +} +.col-xs-11 { + @extend .col-11; +} +.col-xs-12 { + @extend .col-12; +} -.btn-default { @extend .btn-light; } +.btn-default { + @extend .btn-light; +} -.btn-xs { @extend .btn-sm; } +.btn-xs { + @extend .btn-sm; +} .hidden-xs { @extend .d-none; @@ -160,3 +268,29 @@ h5.modal-title { .pull-right { float: right; } + +.btn-primary-light { + $primary-light: lighten($primary, 42%); + @include button-variant( + $background: $primary-light, + $border: $primary-light, + $hover-background: lighten($primary-light, 1%), + $hover-border: $primary-light, + $active-background: lighten($primary-light, 1%), + $active-border: darken($primary-light, 12.5%) + ); + + color: darken($primary, 5%); + &:hover { + color: darken($primary, 5%); + } +} + +.image-with-blur { + transition: filter 300ms ease-in-out; + filter: blur(1.5rem); +} + +.image-loaded { + filter: blur(0rem); +} diff --git a/frappe/templates/components/image_with_blur.html b/frappe/templates/components/image_with_blur.html index cbee369608..20b0380b88 100644 --- a/frappe/templates/components/image_with_blur.html +++ b/frappe/templates/components/image_with_blur.html @@ -1,6 +1,6 @@ {%- set res = frappe.utils.get_thumbnail_base64_for_image(src) if src else false -%} {%- if res and res['base64'].startswith('data:') -%} -{{ alt or '' }} {%- else -%} {{ alt or '' }} @@ -18,8 +18,7 @@ img.onload = function () { image.src = image_source; - image.classList.remove('blur-md'); - image.classList.add('blur-none'); + image.classList.add('image-loaded'); }; if (image_source) { diff --git a/frappe/templates/components/web_block.html b/frappe/templates/components/web_block.html index f0ed8f2df4..1da71036c2 100644 --- a/frappe/templates/components/web_block.html +++ b/frappe/templates/components/web_block.html @@ -1,14 +1,15 @@ {%- set htmltag = htmltag or 'section' -%} {%- set classes = resolve_class([ { - 'py-12 sm:py-20 xl:py-32': web_block.add_padding, - 'bg-gray-100': web_block.add_shade, + 'section-padding-top': web_block.add_top_padding, + 'section-padding-bottom': web_block.add_bottom_padding, + 'bg-light': web_block.add_shade, }, web_block.css_class ]) -%} {%- if not web_block.hide_block -%} -<{{htmltag}} class="{{ classes }}" data-section-idx="{{ web_block.idx | e }}" +<{{htmltag}} class="section {{ classes }}" data-section-idx="{{ web_block.idx | e }}" data-section-template="{{ web_block.web_template | e }}"> {%- if web_block.add_container -%}
diff --git a/frappe/website/web_template/full_width_image/full_width_image.html b/frappe/website/web_template/full_width_image/full_width_image.html index 19bd17801a..6a0f40e7bc 100644 --- a/frappe/website/web_template/full_width_image/full_width_image.html +++ b/frappe/website/web_template/full_width_image/full_width_image.html @@ -1 +1 @@ -{{ c('image_with_blur', src=url, alt=description, class="w-full") }} +{{ c('image_with_blur', src=url, alt=description, class="full-width-image") }} diff --git a/frappe/website/web_template/hero/hero.html b/frappe/website/web_template/hero/hero.html index e7b69ab782..5f96dacc7c 100644 --- a/frappe/website/web_template/hero/hero.html +++ b/frappe/website/web_template/hero/hero.html @@ -1,20 +1,23 @@ -
-

+
+

{{ title }}

{%- if subtitle -%} -

+

{{ subtitle }}

{%- endif -%} {%- if primary_action or secondary_action -%} -
+
{%- if primary_action -%} - {{ c('button', label=primary_action_label, url=primary_action, variant="primary", size="large") }} + + {{ primary_action_label }} + {%- endif -%} {%- if secondary_action -%} - {{ c('button', label=secondary_action_label, url=secondary_action, variant="secondary", size="large", class="ml-4") }} + + {{ secondary_action_label }} + {%- endif -%}
{%- endif -%} diff --git a/frappe/website/web_template/hero_with_right_image/hero_with_right_image.html b/frappe/website/web_template/hero_with_right_image/hero_with_right_image.html index 015bf8b222..b14f1ef054 100644 --- a/frappe/website/web_template/hero_with_right_image/hero_with_right_image.html +++ b/frappe/website/web_template/hero_with_right_image/hero_with_right_image.html @@ -1,37 +1,33 @@ -
-
+
+
-

+

{{ title }}

{%- if subtitle -%} -

+

{{ subtitle }}

{%- endif -%} -
+
{%- if primary_action -%} - {{ c('button', label=primary_action_label, url=primary_action, variant="primary", size="large") }} + + {{ primary_action_label }} + {%- endif -%} {%- if secondary_action -%} - {{ c('button', label=secondary_action_label, url=secondary_action, variant="secondary", size="large", class="ml-4") }} + + {{ secondary_action_label }} + {%- endif -%}
{%- if image -%} {{ c('image_with_blur', - class=["hidden md:block max-h-144 object-contain", "w-full md:w-6/12" if contain_image else "md:max-w-md lg:max-w-lg xl:max-w-xl xxl:max-w-2xl"], + class=["hero-image", "contain-image" if contain_image else ""], src=image, alt="") }} {%- endif -%}
- -{%- if not contain_image -%} - -{%- endif -%} diff --git a/frappe/website/web_template/markdown/markdown.html b/frappe/website/web_template/markdown/markdown.html index b086dd327c..4f09d6aa88 100644 --- a/frappe/website/web_template/markdown/markdown.html +++ b/frappe/website/web_template/markdown/markdown.html @@ -1,3 +1,5 @@ -
- {{ frappe.utils.md_to_html(content) }} +
+
+ {{ frappe.utils.md_to_html(content) }} +
diff --git a/frappe/website/web_template/section_with_cards/section_with_cards.html b/frappe/website/web_template/section_with_cards/section_with_cards.html index d408275b44..1f0f71a15b 100644 --- a/frappe/website/web_template/section_with_cards/section_with_cards.html +++ b/frappe/website/web_template/section_with_cards/section_with_cards.html @@ -1,47 +1,41 @@ {%- macro card(title, content, url) -%} +{%- set col_classes = resolve_class({ + 'col-12 col-sm-6 col-lg-3': card_size == 'Small', + 'col-12 col-sm-6 col-lg-4': card_size == 'Medium', + 'col-12 col-md-6': card_size == 'Large', +}) -%} {%- set card_classes = resolve_class({ - 'p-6': card_size == 'Small', - 'p-7': card_size == 'Medium', - 'p-8': card_size == 'Large' + 'card-sm': card_size == 'Small', + 'card-md': card_size == 'Medium', + 'card-lg': card_size == 'Large' }) -%} -{%- set title_classes = resolve_class({ - 'text-base font-semibold': card_size == 'Small', - 'text-lg md:text-xl font-semibold': card_size == 'Medium', - 'text-xl md:text-2xl font-bold': card_size == 'Large' -}) -%} -{%- set content_classes = resolve_class({ - 'text-sm': card_size == 'Small', - 'text-base': card_size == 'Medium', - 'text-base xxl:text-lg': card_size == 'Large' -}) -%} - - -

{{ title }}

-

{{ content or '' }}

-
+
+
+
+

{{ title or '' }}

+

{{ content or '' }}

+
+ +
+
{%- endmacro -%} {%- if title -%} -

{{ title }}

+

{{ title }}

{%- endif -%} {%- if subtitle -%} -

{{ subtitle }}

+

{{ subtitle }}

{%- endif -%} {%- set card_size = card_size or 'Small' -%} -{%- set classes = resolve_class({ - 'mt-8': title, - 'sm:grid-cols-2 lg:grid-cols-4': card_size == 'Small', - 'sm:grid-cols-2 lg:grid-cols-3': card_size == 'Medium', - 'sm:grid-cols-2': card_size == 'Large', -}) -%} -
- {%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%} - {%- set title = values['card_' + index + '_title'] -%} - {%- set content = values['card_' + index + '_content'] -%} - {%- set url = values['card_' + index + '_url'] -%} - {%- if title -%} - {{ card(title, content, url) }} - {%- endif -%} - {%- endfor -%} +
+
+ {%- for index in ['1', '2', '3', '4', '5', '6', '7', '8'] -%} + {%- set title = values['card_' + index + '_title'] -%} + {%- set content = values['card_' + index + '_content'] -%} + {%- set url = values['card_' + index + '_url'] -%} + {%- if title -%} + {{ card(title, content, url) }} + {%- endif -%} + {%- endfor -%} +
diff --git a/frappe/website/web_template/section_with_cta/section_with_cta.html b/frappe/website/web_template/section_with_cta/section_with_cta.html index 415392f751..313f49dde3 100644 --- a/frappe/website/web_template/section_with_cta/section_with_cta.html +++ b/frappe/website/web_template/section_with_cta/section_with_cta.html @@ -1,21 +1,19 @@ -
-
-

{{ title }}

-

{{ subtitle }}

-

- {{ c('button', label=cta_label, url=cta_url, variant="primary", size="large") }} -

+
+
+

{{ title }}

+

{{ subtitle }}

+ {%- if cta_description -%} -
+
{{ cta_description }}
{%- endif -%}
{%- if show_confetti -%} -
-
-
-
-
+
+
+
{%- endif -%}
diff --git a/frappe/website/web_template/section_with_image/section_with_image.html b/frappe/website/web_template/section_with_image/section_with_image.html index 9a7753cc4a..3cd9d97872 100644 --- a/frappe/website/web_template/section_with_image/section_with_image.html +++ b/frappe/website/web_template/section_with_image/section_with_image.html @@ -1,5 +1,5 @@ -

{{ title }}

-

{{ subtitle }}

+

{{ title }}

+

{{ subtitle }}

-{{ c('image_with_blur', src=image, alt=image_description, class="w-full mt-8 rounded-xl") }} +{{ c('image_with_blur', src=image, alt=image_description, class="section-image") }} diff --git a/frappe/website/web_template/section_with_left_image/section_with_left_image.html b/frappe/website/web_template/section_with_left_image/section_with_left_image.html index d2d1568708..3daaf87ffb 100644 --- a/frappe/website/web_template/section_with_left_image/section_with_left_image.html +++ b/frappe/website/web_template/section_with_left_image/section_with_left_image.html @@ -1,9 +1,9 @@ -
-
+
+
{{ title }}
-
-

{{ title }}

-

{{ content }}

+
+

{{ title }}

+

{{ content }}

diff --git a/frappe/website/web_template/section_with_tabs/section_with_tabs.html b/frappe/website/web_template/section_with_tabs/section_with_tabs.html index 67b4ac9426..a03b99b139 100644 --- a/frappe/website/web_template/section_with_tabs/section_with_tabs.html +++ b/frappe/website/web_template/section_with_tabs/section_with_tabs.html @@ -1,39 +1,43 @@ -

{{ title }}

-

{{ subtitle }}

+

{{ title }}

+

{{ subtitle }}

-
-
- {% set ns = namespace(tabs=[]) %} +
+ {% set ns = namespace(tabs=[]) %} - {%- for index in ['1', '2', '3', '4', '5', '6'] -%} + {%- for index in ['1', '2', '3', '4', '5', '6'] -%} - {%- set buttonid = 'id-' + frappe.utils.generate_hash('TabButton', 12) -%} - {%- set panelid = 'id-' + frappe.utils.generate_hash('TabPanel', 12) -%} + {%- set buttonid = 'id-' + frappe.utils.generate_hash('TabButton', 12) -%} + {%- set panelid = 'id-' + frappe.utils.generate_hash('TabPanel', 12) -%} - {%- set tab = { - 'title': values['tab_' + index + '_title'], - 'content': values['tab_' + index + '_content'], - 'buttonid': buttonid, - 'panelid': panelid, } - -%} + {%- set tab = { + 'title': values['tab_' + index + '_title'], + 'content': values['tab_' + index + '_content'], + 'buttonid': buttonid, + 'panelid': panelid, } + -%} - {%- if tab.title and tab.content -%} - {%- set ns.tabs = ns.tabs + [tab] -%} - {%- endif -%} + {%- if tab.title and tab.content -%} + {%- set ns.tabs = ns.tabs + [tab] -%} + {%- endif -%} - {%- endfor -%} -
- {%- for tab in ns.tabs -%} - {%- set first_tab = true if loop.index0 == 0 else false -%} - - {%- endfor -%} -
+ {%- endfor -%} + +
+ {%- for tab in ns.tabs -%} + {%- set first_tab = true if loop.index0 == 0 else false -%} +
{{ frappe.utils.md_to_html(tab.content) }}
@@ -41,71 +45,3 @@ {%- endfor -%}
- - From fcf9c9d1397a4c46c61cd1e8c246a3ec783a9c0b Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 11 May 2020 15:54:22 +0530 Subject: [PATCH 036/145] fix: Separate footer group links with normal links - Add icon for footer item - Obey "Right" value for footer item --- frappe/templates/includes/footer/footer.html | 61 ++++++++++--------- .../includes/footer/footer_grouped_links.html | 28 +++++++++ .../includes/footer/footer_links.html | 27 ++++++++ 3 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 frappe/templates/includes/footer/footer_grouped_links.html create mode 100644 frappe/templates/includes/footer/footer_links.html diff --git a/frappe/templates/includes/footer/footer.html b/frappe/templates/includes/footer/footer.html index 7fe6a955f7..671e928d32 100644 --- a/frappe/templates/includes/footer/footer.html +++ b/frappe/templates/includes/footer/footer.html @@ -1,45 +1,46 @@ -{%- if theme.based_on == 'Bootstrap 4' or doctype != 'Web Page' -%}
- +
- -{%- else -%} -
-{{ c('web_blocks', web_blocks=theme.footer) }} -
-{%- endif -%} diff --git a/frappe/templates/includes/footer/footer_grouped_links.html b/frappe/templates/includes/footer/footer_grouped_links.html new file mode 100644 index 0000000000..6e20c51279 --- /dev/null +++ b/frappe/templates/includes/footer/footer_grouped_links.html @@ -0,0 +1,28 @@ +{% for page in footer_items if page.child_items %} + +{% endfor %} diff --git a/frappe/templates/includes/footer/footer_links.html b/frappe/templates/includes/footer/footer_links.html new file mode 100644 index 0000000000..fe9f69fed3 --- /dev/null +++ b/frappe/templates/includes/footer/footer_links.html @@ -0,0 +1,27 @@ +{% macro footer_link(item) %} + + {%- if item.icon -%} + {{ item.label }} + {%- else -%} + {{ item.label }} + {%- endif -%} + +{% endmacro %} + +{% if footer_items -%} + +{% endif %} From 850848f20b3519caf9a930d1e82db7e89a06af9f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 11 May 2020 15:57:51 +0530 Subject: [PATCH 037/145] fix: Navbar - CTA button - Unique id for every dropdown --- frappe/templates/includes/navbar/navbar.html | 2 +- .../includes/navbar/navbar_items.html | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frappe/templates/includes/navbar/navbar.html b/frappe/templates/includes/navbar/navbar.html index 9d48390170..d669eee9d3 100644 --- a/frappe/templates/includes/navbar/navbar.html +++ b/frappe/templates/includes/navbar/navbar.html @@ -1,4 +1,4 @@ -
`); this.widget_area = widget_area; + if (this.hidden) this.widget_area.hide() this.title_area = widget_area.find(".widget-group-title"); this.control_area = widget_area.find(".widget-group-control"); this.body = widget_area.find(".widget-group-body"); @@ -96,7 +97,7 @@ export default class WidgetGroup { } customize() { - this.widget_area.show(); + if (!this.hidden) this.widget_area.show(); this.widgets_list.forEach((wid) => { wid.customize(this.options); }); From a48c24e4bf9bf96671a4f1d4359fc34a0c59faac Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 13:01:46 +0530 Subject: [PATCH 103/145] chore: consistent functions used for inputs, removed unused imports --- frappe/utils/commands.py | 14 ++++++++++++++ frappe/utils/remote_migrations.py | 21 +++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/frappe/utils/commands.py b/frappe/utils/commands.py index 3c16193173..babefc56e2 100644 --- a/frappe/utils/commands.py +++ b/frappe/utils/commands.py @@ -23,3 +23,17 @@ def padme(me): print() return result return empty_line + + +def log(message, colour=''): + colours = { + "nc": '\033[0m', + "blue": '\033[94m', + "green": '\033[92m', + "yellow": '\033[93m', + "red": '\033[91m', + "silver": '\033[90m' + } + colour = colours.get(colour, "") + end_line = '\033[0m' + print(colour + message + end_line) diff --git a/frappe/utils/remote_migrations.py b/frappe/utils/remote_migrations.py index c89134f27c..656fb803de 100644 --- a/frappe/utils/remote_migrations.py +++ b/frappe/utils/remote_migrations.py @@ -14,8 +14,7 @@ import requests import frappe import frappe.utils.backups from frappe.utils import get_installed_apps_info -from frappe.utils.commands import get_first_party_apps, render_table, padme - +from frappe.utils.commands import render_table, padme def get_new_site_options(): @@ -69,12 +68,12 @@ def choose_plan(plans_list): render_plan_table(plans_list) while True: - input_plan = input("Send plan?: ").strip() + input_plan = click.prompt("Select Plan").strip() if input_plan in available_plans: print("{} Plan selected ✅".format(input_plan)) return input_plan else: - print("Invalid selection...try again ❌") + print("Invalid Selection ❌") @padme @@ -133,15 +132,17 @@ def filter_apps(app_groups): render_group_table(app_groups) while True: + app_group_index = click.prompt("Select App Group #", type=int) - 1 try: - app_group_index = int(input("Select App Group #: ").strip()) - 1 selected_group = app_groups[app_group_index] - is_compat, filtered_apps = check_app_compat(selected_group) except: - print("Invalid Selection") - sys.exit(1) + print("Invalid Selection ❌") + break + + is_compat, filtered_apps = check_app_compat(selected_group) if is_compat or click.confirm("Continue anyway?"): + print("App Group {} selected! ✅".format(selected_group["name"])) break return selected_group["name"], filtered_apps @@ -149,7 +150,7 @@ def filter_apps(app_groups): @padme def create_session(): # take user input from STDIN - username = input("Username: ").strip() + username = click.prompt("Username").strip() password = getpass.unix_getpass() auth_credentials = {"usr": username, "pwd": password} @@ -168,7 +169,7 @@ def create_session(): @padme def get_subdomain(domain): while True: - subdomain = input("Enter subdomain: ").strip() + subdomain = click.prompt("Enter subdomain: ").strip() if is_valid_subdomain(subdomain) and is_subdomain_available(subdomain): print("Site Domain: {}.{}".format(subdomain, domain)) return subdomain From 3fcc15685ab85929b6f594e137251c38a3c99974 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Sun, 10 May 2020 04:07:14 +0530 Subject: [PATCH 104/145] fix: dont show any output unless verbose set --- frappe/utils/backups.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index a4c2c4bb70..0a04db2c3e 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -103,7 +103,8 @@ class BackupGenerator: cmd_string = """tar -cf %s %s""" % (backup_path, files_path) err, out = frappe.utils.execute_in_shell(cmd_string) - print('Backed up files', os.path.abspath(backup_path)) + if verbose: + print('Backed up files', os.path.abspath(backup_path)) def take_dump(self): import frappe.utils @@ -151,7 +152,6 @@ def get_backup(): This function is executed when the user clicks on Toos > Download Backup """ - #if verbose: print frappe.db.cur_db_name + " " + conf.db_password delete_temp_backups() odb = BackupGenerator(frappe.conf.db_name, frappe.conf.db_name,\ frappe.conf.db_password, db_host = frappe.db.host) From 00bace4d3fcff50372e34e2c0d2772a7098cf926 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 14:38:38 +0530 Subject: [PATCH 105/145] fix: linting issues sider --- frappe/public/js/frappe/widgets/widget_group.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/widgets/widget_group.js b/frappe/public/js/frappe/widgets/widget_group.js index 2147cd0dee..e82cbc6edf 100644 --- a/frappe/public/js/frappe/widgets/widget_group.js +++ b/frappe/public/js/frappe/widgets/widget_group.js @@ -52,7 +52,7 @@ export default class WidgetGroup {
`); this.widget_area = widget_area; - if (this.hidden) this.widget_area.hide() + if (this.hidden) this.widget_area.hide(); this.title_area = widget_area.find(".widget-group-title"); this.control_area = widget_area.find(".widget-group-control"); this.body = widget_area.find(".widget-group-body"); From 94b6fa4319a0bff37428f7875e8843a06bc1607e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 14 May 2020 15:27:17 +0530 Subject: [PATCH 106/145] fix: report filters in dialog --- frappe/public/js/frappe/views/reports/query_report.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 5105494862..e79e43ae02 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -330,8 +330,8 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { evaluate_depends_on_value(expression, filter_label) { let out = null; - let filters = this.get_filter_values(); - if (filters) { + let doc = this.get_filter_values(); + if (doc) { if (typeof expression === 'boolean') { out = expression; } else if (expression.substr(0, 5) == 'eval:') { @@ -341,7 +341,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { frappe.throw(__(`Invalid "depends_on" expression set in filter ${filter_label}`)); } } else { - var value = filters[expression]; + var value = doc[expression]; if ($.isArray(value)) { out = !!value.length; } else { From e5d5d0b6bb6c74007da312fb647d9a16b3f2e61d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 16:07:57 +0530 Subject: [PATCH 107/145] feat: allow linking dashboard in desk page --- frappe/desk/desktop.py | 2 ++ frappe/desk/doctype/desk_shortcut/desk_shortcut.json | 4 ++-- frappe/public/js/frappe/widgets/utils.js | 2 ++ frappe/public/js/frappe/widgets/widget_dialog.js | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index ddcfb670d4..e2fe020eca 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -127,6 +127,8 @@ class Workspace: return name in self.allowed_reports if item_type == "help": return True + if item_type == "dashboard": + return True return False diff --git a/frappe/desk/doctype/desk_shortcut/desk_shortcut.json b/frappe/desk/doctype/desk_shortcut/desk_shortcut.json index 550ea609c8..f3fd546a77 100644 --- a/frappe/desk/doctype/desk_shortcut/desk_shortcut.json +++ b/frappe/desk/doctype/desk_shortcut/desk_shortcut.json @@ -23,7 +23,7 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Type", - "options": "DocType\nReport\nPage", + "options": "DocType\nReport\nPage\nDashboard", "reqd": 1 }, { @@ -88,7 +88,7 @@ ], "istable": 1, "links": [], - "modified": "2020-05-13 19:26:34.229669", + "modified": "2020-05-14 16:02:15.420993", "modified_by": "Administrator", "module": "Desk", "name": "Desk Shortcut", diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index 0d93bb3784..f336335d1c 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -24,6 +24,8 @@ function generate_route(item) { route = "List/" + item.doctype + "/Report/" + item.name; } else if (type === "page") { route = item.name; + } else if (type === "dashboard") { + route = "dashboard/" + item.name; } route = "#" + route; diff --git a/frappe/public/js/frappe/widgets/widget_dialog.js b/frappe/public/js/frappe/widgets/widget_dialog.js index 31215a40c3..5c44533b37 100644 --- a/frappe/public/js/frappe/widgets/widget_dialog.js +++ b/frappe/public/js/frappe/widgets/widget_dialog.js @@ -145,7 +145,7 @@ class ShortcutDialog extends WidgetDialog { fieldname: "type", label: "Type", reqd: 1, - options: "DocType\nReport\nPage", + options: "DocType\nReport\nPage\nDashboard", onchange: () => { if (this.dialog.get_value("type") == "DocType") { this.dialog.fields_dict.link_to.get_query = () => { From c14b6c592a1eacd4158801ad9865dd7ed00c9a87 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Thu, 14 May 2020 16:27:34 +0530 Subject: [PATCH 108/145] fix: move code to meta.py --- .../custom/doctype/custom_link/custom_link.js | 4 +++ .../custom/doctype/custom_link/custom_link.py | 33 ------------------ frappe/model/meta.py | 34 ++++++++++++++++++- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/frappe/custom/doctype/custom_link/custom_link.js b/frappe/custom/doctype/custom_link/custom_link.js index f1c06daeeb..9540ec5662 100644 --- a/frappe/custom/doctype/custom_link/custom_link.js +++ b/frappe/custom/doctype/custom_link/custom_link.js @@ -12,5 +12,9 @@ frappe.ui.form.on('Custom Link', { } } }); + + frm.add_custom_button(__('Go to {0} List', [frm.doc.document_type]), function() { + frappe.set_route('List', frm.doc.document_type); + }); } }); diff --git a/frappe/custom/doctype/custom_link/custom_link.py b/frappe/custom/doctype/custom_link/custom_link.py index b9a88b58f2..be57d256f2 100644 --- a/frappe/custom/doctype/custom_link/custom_link.py +++ b/frappe/custom/doctype/custom_link/custom_link.py @@ -8,36 +8,3 @@ from frappe.model.document import Document class CustomLink(Document): pass - -def get_custom_doctype_links(doctype, data): - if frappe.get_all("Custom Link", {"document_type": doctype}): - doc = frappe.get_doc("Custom Link", doctype) - - if not data.transactions: - # init groups - data.transactions = [] - data.non_standard_fieldnames = {} - - for link in doc.links: - link.added = False - for group in data.transactions: - # group found - if group.get("label") == link.group: - if not link.link_doctype in group.get("items"): - group.get("items").append(link.link_doctype) - link.added = True - - if not link.added: - # group not found, make a new group - data.transactions.append({ - "label": link.group, - "items": [link.link_doctype] - }) - - if link.link_fieldname != data.fieldname: - if data.fieldname: - data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname - else: - data.fieldname = link.link_fieldname - - return data \ No newline at end of file diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 156fe2dba3..717070a217 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -26,7 +26,6 @@ from frappe.model.base_document import BaseDocument from frappe.modules import load_doctype_module from frappe.model.workflow import get_workflow_name from frappe import _ -from frappe.custom.doctype.custom_link.custom_link import get_custom_doctype_links def get_meta(doctype, cached=True): if cached: @@ -609,3 +608,36 @@ def trim_tables(doctype=None): query = """alter table `tab{doctype}` {columns}""".format( doctype=doctype, columns=columns_to_remove) frappe.db.sql_ddl(query) + +def get_custom_doctype_links(doctype, data): + if frappe.get_all("Custom Link", {"document_type": doctype}): + doc = frappe.get_doc("Custom Link", doctype) + + if not data.transactions: + # init groups + data.transactions = [] + data.non_standard_fieldnames = {} + + for link in doc.links: + link.added = False + for group in data.transactions: + # group found + if group.get("label") == link.group: + if not link.link_doctype in group.get("items"): + group.get("items").append(link.link_doctype) + link.added = True + + if not link.added: + # group not found, make a new group + data.transactions.append({ + "label": link.group, + "items": [link.link_doctype] + }) + + if link.link_fieldname != data.fieldname: + if data.fieldname: + data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname + else: + data.fieldname = link.link_fieldname + + return data \ No newline at end of file From aa98d6ffb6f32af4f9a15701350b05fce104967c Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Thu, 14 May 2020 16:37:14 +0530 Subject: [PATCH 109/145] fix: sider changes --- frappe/custom/doctype/custom_link/custom_link.js | 2 +- frappe/custom/doctype/custom_link/custom_link.py | 2 +- frappe/model/meta.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/custom/doctype/custom_link/custom_link.js b/frappe/custom/doctype/custom_link/custom_link.js index 9540ec5662..8662724b1a 100644 --- a/frappe/custom/doctype/custom_link/custom_link.js +++ b/frappe/custom/doctype/custom_link/custom_link.js @@ -10,7 +10,7 @@ frappe.ui.form.on('Custom Link', { istable: 0, module: ['not in', ["Email", "Core", "Custom", "Event Streaming", "Social", "Data Migration", "Geo", "Desk"]] } - } + }; }); frm.add_custom_button(__('Go to {0} List', [frm.doc.document_type]), function() { diff --git a/frappe/custom/doctype/custom_link/custom_link.py b/frappe/custom/doctype/custom_link/custom_link.py index be57d256f2..11316d5751 100644 --- a/frappe/custom/doctype/custom_link/custom_link.py +++ b/frappe/custom/doctype/custom_link/custom_link.py @@ -3,7 +3,7 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe +# import frappe from frappe.model.document import Document class CustomLink(Document): diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 717070a217..a9ae19af6d 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -623,7 +623,7 @@ def get_custom_doctype_links(doctype, data): for group in data.transactions: # group found if group.get("label") == link.group: - if not link.link_doctype in group.get("items"): + if link.link_doctype not in group.get("items"): group.get("items").append(link.link_doctype) link.added = True From 69afa4f10cabc89846fc321c96c9856c32132460 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 16:57:35 +0530 Subject: [PATCH 110/145] feat: onboarding enhancements (#10356) * feat: added go to path option in onboarding step * feat: added show full form check and doctype cleanup * feat: added show full form controller to onboarding widget * feat: don't mark complete step on go to page * feat: make callback message optional * feat: mark go to page as non mandatory * feat: use check for skipped step * fix: spaces * feat: set form as dirty on routing * style: remove unused variable --- .../onboarding_step/onboarding_step.json | 59 ++++++++++++++-- .../onboarding_step/onboarding_step.py | 4 ++ .../js/frappe/widgets/onboarding_widget.js | 68 ++++++++++++++++--- 3 files changed, 116 insertions(+), 15 deletions(-) diff --git a/frappe/desk/doctype/onboarding_step/onboarding_step.json b/frappe/desk/doctype/onboarding_step/onboarding_step.json index 3bc9d5f286..37d1d63dbe 100644 --- a/frappe/desk/doctype/onboarding_step/onboarding_step.json +++ b/frappe/desk/doctype/onboarding_step/onboarding_step.json @@ -15,11 +15,16 @@ "action", "column_break_7", "reference_document", + "show_full_form", "is_single", "reference_report", "report_reference_doctype", "report_type", "report_description", + "path", + "callback_title", + "callback_message", + "validate_action", "field", "value_to_validate", "video_url" @@ -58,7 +63,7 @@ "fieldname": "action", "fieldtype": "Select", "label": "Action", - "options": "Create Entry\nUpdate Settings\nShow Form Tour\nView Report\nWatch Video", + "options": "Create Entry\nUpdate Settings\nShow Form Tour\nView Report\nGo to Page\nWatch Video", "reqd": 1 }, { @@ -70,6 +75,7 @@ "fieldname": "reference_document", "fieldtype": "Link", "label": "Reference Document", + "mandatory_depends_on": "eval:doc.action == \"Create Entry\" || doc.action == \"Update Settings\" || doc.action == \"Create Entry\" || doc.action == \"Show Form Tour\"", "options": "DocType" }, { @@ -84,7 +90,8 @@ "depends_on": "eval:doc.action == \"Watch Video\"", "fieldname": "video_url", "fieldtype": "Data", - "label": "Video URL" + "label": "Video URL", + "mandatory_depends_on": "eval:doc.action == \"Watch Video\"" }, { "depends_on": "eval:doc.action == \"View Report\"", @@ -102,17 +109,19 @@ "label": "Is Skipped" }, { - "depends_on": "eval:doc.action == \"Update Settings\"", + "depends_on": "eval:doc.action == \"Update Settings\" && doc.validate_action", "fieldname": "field", "fieldtype": "Select", - "label": "Field" + "label": "Field", + "mandatory_depends_on": "eval:doc.action == \"Update Settings\" && doc.validate_action" }, { - "depends_on": "eval:doc.action == \"Update Settings\"", + "depends_on": "eval:doc.action == \"Update Settings\" && doc.validate_action", "description": "Use % for any non empty value.", "fieldname": "value_to_validate", "fieldtype": "Data", - "label": "Value to Validate" + "label": "Value to Validate", + "mandatory_depends_on": "eval:doc.action == \"Update Settings\" && doc.validate_action" }, { "depends_on": "eval:doc.action == \"View Report\"", @@ -136,10 +145,46 @@ "fieldname": "is_single", "fieldtype": "Check", "label": "Is Single" + }, + { + "depends_on": "eval:doc.action == \"Go to Page\"", + "description": "Example: #Tree/Account", + "fieldname": "path", + "fieldtype": "Data", + "label": "Path", + "mandatory_depends_on": "eval:doc.action == \"Go to Page\"" + }, + { + "depends_on": "eval:doc.action == \"Go to Page\"", + "fieldname": "callback_title", + "fieldtype": "Data", + "label": "Callback Title" + }, + { + "depends_on": "eval:doc.action == \"Go to Page\"", + "description": "This will be shown in a modal after routing", + "fieldname": "callback_message", + "fieldtype": "Small Text", + "label": "Callback Message" + }, + { + "default": "1", + "depends_on": "eval:doc.action == \"Update Settings\"", + "fieldname": "validate_action", + "fieldtype": "Check", + "label": "Validate Field" + }, + { + "default": "0", + "depends_on": "eval:doc.action == \"Create Entry\"", + "description": "Show full form instead of a quick entry modal", + "fieldname": "show_full_form", + "fieldtype": "Check", + "label": "Show Full Form?" } ], "links": [], - "modified": "2020-05-11 13:24:05.457160", + "modified": "2020-05-14 15:10:05.627706", "modified_by": "Administrator", "module": "Desk", "name": "Onboarding Step", diff --git a/frappe/desk/doctype/onboarding_step/onboarding_step.py b/frappe/desk/doctype/onboarding_step/onboarding_step.py index e1cc5dfba4..8086acbb2a 100644 --- a/frappe/desk/doctype/onboarding_step/onboarding_step.py +++ b/frappe/desk/doctype/onboarding_step/onboarding_step.py @@ -10,3 +10,7 @@ class OnboardingStep(Document): def before_export(self, doc): doc.is_complete = 0 doc.is_skipped = 0 + + def validate(self): + if self.action == "Go to Page": + self.is_mandatory = 0 diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index e347a70036..e869b281ae 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -25,7 +25,7 @@ export default class OnboardingWidget extends Widget { if (step.is_skipped) { status = "skipped"; - icon_class = "fa-times-circle-o"; + icon_class = "fa-check-circle-o"; } if (step.is_complete) { @@ -56,10 +56,17 @@ export default class OnboardingWidget extends Widget { // Setup actions let actions = { "Watch Video": () => this.show_video(step), - "Create Entry": () => this.show_quick_entry(step), + "Create Entry": () => { + if (step.show_full_form) { + this.create_entry(step); + } else { + this.show_quick_entry(step); + } + }, "Show Form Tour": () => this.show_form_tour(step), "Update Settings": () => this.update_settings(step), "View Report": () => this.open_report(step), + "Go to Page": () => this.go_to_page(step), }; $step.find("#title").on("click", actions[step.action]); @@ -68,6 +75,24 @@ export default class OnboardingWidget extends Widget { return $step; } + go_to_page(step) { + frappe.set_route(step.path).then(() => { + if (step.callback_message) { + let msg_dialog = frappe.msgprint({ + message: __(step.callback_message), + title: __(step.callback_title), + primary_action: { + action: () => { + msg_dialog.hide(); + }, + label: () => __("Continue"), + }, + wide: true, + }); + } + }); + } + open_report(step) { let route = generate_route({ name: step.reference_report, @@ -75,10 +100,9 @@ export default class OnboardingWidget extends Widget { is_query_report: ["Query Report", "Script Report"].includes( step.report_type ), - doctype: step.report_reference_doctype + doctype: step.report_reference_doctype, }); - let current_route = frappe.get_route(); frappe.set_route(route).then(() => { @@ -133,7 +157,7 @@ export default class OnboardingWidget extends Widget { msg_dialog.hide(); }, label: () => __("Continue"), - } + }, }); }); }; @@ -147,6 +171,7 @@ export default class OnboardingWidget extends Widget { frappe.route_hooks = {}; frappe.route_hooks.after_load = (frm) => { frm.scroll_to_field(step.field); + frm.doc.__unsaved = true; }; frappe.route_hooks.after_save = (frm) => { @@ -204,6 +229,33 @@ export default class OnboardingWidget extends Widget { frappe.set_route("Form", step.reference_document); } + create_entry(step) { + let current_route = frappe.get_route(); + + frappe.route_hooks = {}; + + frappe.route_hooks.after_save = () => { + frappe.msgprint({ + message: __("You're doing great, let's take you back to the onboarding page."), + title: __("Good Work 🎉"), + primary_action: { + action: () => { + frappe.set_route(current_route).then(() => { + this.mark_complete(step); + }); + }, + label: __("Continue"), + }, + }); + + frappe.msg_dialog.custom_onhide = () => { + this.mark_complete(step); + }; + }; + + frappe.set_route(`Form/${step.reference_document}/New ${step.reference_document} 1`); + } + show_quick_entry(step) { let current_route = frappe.get_route_str(); frappe.ui.form.make_quick_entry( @@ -221,7 +273,7 @@ export default class OnboardingWidget extends Widget { }); }, label: __("Continue"), - } + }, }); frappe.msg_dialog.custom_onhide = () => { @@ -271,7 +323,7 @@ export default class OnboardingWidget extends Widget { update_step_status(step, status, value, callback) { let icon_class = { is_complete: "fa-check-circle-o", - is_skipped: "fa-times-circle-o", + is_skipped: "fa-check-circle-o", }; frappe @@ -394,4 +446,4 @@ export default class OnboardingWidget extends Widget { }); dismiss.appendTo(this.action_area); } -} \ No newline at end of file +} From 8df9cb6bede5733ba372f75e413cb89f76ea87cc Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 17:09:27 +0530 Subject: [PATCH 111/145] chore: optimize imports, style fixes --- frappe/utils/remote_migrations.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/utils/remote_migrations.py b/frappe/utils/remote_migrations.py index 656fb803de..90f8db0b74 100644 --- a/frappe/utils/remote_migrations.py +++ b/frappe/utils/remote_migrations.py @@ -1,5 +1,4 @@ # imports - standard imports -import functools import getpass import json import re @@ -78,7 +77,6 @@ def choose_plan(plans_list): @padme def check_app_compat(available_group): - frappe_upgrade_msg = "" is_compat = True incompatible_apps, filtered_apps, branch_msgs = [], [], [] existing_group = [(app["app_name"], app["branch"]) for app in get_installed_apps_info()] @@ -135,7 +133,7 @@ def filter_apps(app_groups): app_group_index = click.prompt("Select App Group #", type=int) - 1 try: selected_group = app_groups[app_group_index] - except: + except IndexError: print("Invalid Selection ❌") break @@ -169,7 +167,7 @@ def create_session(): @padme def get_subdomain(domain): while True: - subdomain = click.prompt("Enter subdomain: ").strip() + subdomain = click.prompt("Enter subdomain").strip() if is_valid_subdomain(subdomain) and is_subdomain_available(subdomain): print("Site Domain: {}.{}".format(subdomain, domain)) return subdomain From 30a4fd7ac0a4a30dc33baee8745f0d89986ba43b Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Thu, 14 May 2020 17:16:37 +0530 Subject: [PATCH 112/145] fix: allow validations for all fieldtypes --- frappe/public/js/frappe/form/controls/data.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/data.js b/frappe/public/js/frappe/form/controls/data.js index 25f3ef76af..c943ec89bb 100644 --- a/frappe/public/js/frappe/form/controls/data.js +++ b/frappe/public/js/frappe/form/controls/data.js @@ -87,9 +87,6 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({ return val==null ? "" : val; }, validate: function(v) { - if (this.df.fieldtype !== "Data") { - return v; - } if (!v) { return ''; } From e5a2171a66f19e1900d5316f2a1c7e17cc6f54b8 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 14 May 2020 17:18:05 +0530 Subject: [PATCH 113/145] fix: set query report object for chart filters --- .../doctype/dashboard_chart/dashboard_chart.js | 14 +++----------- frappe/public/js/frappe/widgets/chart_widget.js | 12 +++--------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js index f8d5886b26..fb6f9252ce 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.js +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.js @@ -283,17 +283,7 @@ frappe.ui.form.on('Dashboard Chart', { }); } } else if (frm.chart_filters.length) { - fields = frm.chart_filters.filter(f => { - if (f.on_change && !f.reqd) { - return false; - } - if (f.get_query || f.get_data) { - f.read_only = 1; - } - - return f.fieldname; - }); - + fields = frm.chart_filters.filter(f => f.fieldname); fields.map( f => { if (filters[f.fieldname]) { let condition = '='; @@ -353,6 +343,8 @@ frappe.ui.form.on('Dashboard Chart', { } dialog.show(); + //Set query report object so that it can be used while fetching filter values in the report + frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list}); dialog.set_values(filters); }); }, diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index a50acfcd9d..b4c622f151 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -332,15 +332,7 @@ export default class ChartWidget extends Widget { } ]; } else { - fields = filters.filter(f => { - if (f.on_change && !f.reqd) { - return false; - } - if (f.get_query || f.get_data) { - f.read_only = 1; - } - return f.fieldname; - }); + fields = filters.filter(f => f.fieldname); } } else { fields = [ @@ -384,6 +376,8 @@ export default class ChartWidget extends Widget { } dialog.show(); + //Set query report object so that it can be used while fetching filter values in the report + frappe.query_report = new frappe.views.QueryReport({'filters': dialog.fields_list}); dialog.set_values(this.filters); } From 12ca630c522f668e92995a4451b177f83a42d1a8 Mon Sep 17 00:00:00 2001 From: Himanshu Warekar Date: Thu, 14 May 2020 17:22:51 +0530 Subject: [PATCH 114/145] fix: merge code --- frappe/model/meta.py | 89 +++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/frappe/model/meta.py b/frappe/model/meta.py index a9ae19af6d..c8fd1a2ac2 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -434,7 +434,6 @@ class Meta(Document): pass self.add_doctype_links(data) - get_custom_doctype_links(self.name, data) if not self.custom: for hook in frappe.get_hooks("override_doctype_dashboards", {}).get(self.name, []): @@ -444,34 +443,41 @@ class Meta(Document): def add_doctype_links(self, data): '''add `links` child table in standard link dashboard format''' + dashboard_links = [] + if hasattr(self, 'links') and self.links: - if not data.transactions: - # init groups - data.transactions = [] - data.non_standard_fieldnames = {} + dashboard_links.extend(self.links) - for link in self.links: - link.added = False - for group in data.transactions: - group = frappe._dict(group) - # group found - if link.group and group.label == link.group: - if link.link_doctype not in group.get('items'): - group.get('items').append(link.link_doctype) - link.added = True + if frappe.get_all("Custom Link", {"document_type": self.name}): + dashboard_links.extend(frappe.get_doc("Custom Link", self.name).links) - if not link.added: - # group not found, make a new group - data.transactions.append(dict( - label = link.group, - items = [link.link_doctype] - )) + if not data.transactions: + # init groups + data.transactions = [] + data.non_standard_fieldnames = {} - if link.link_fieldname != data.fieldname: - if data.fieldname: - data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname - else: - data.fieldname = link.link_fieldname + for link in dashboard_links: + link.added = False + for group in data.transactions: + group = frappe._dict(group) + # group found + if link.group and group.label == link.group: + if link.link_doctype not in group.get('items'): + group.get('items').append(link.link_doctype) + link.added = True + + if not link.added: + # group not found, make a new group + data.transactions.append(dict( + label = link.group, + items = [link.link_doctype] + )) + + if link.link_fieldname != data.fieldname: + if data.fieldname: + data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname + else: + data.fieldname = link.link_fieldname def get_row_template(self): @@ -608,36 +614,3 @@ def trim_tables(doctype=None): query = """alter table `tab{doctype}` {columns}""".format( doctype=doctype, columns=columns_to_remove) frappe.db.sql_ddl(query) - -def get_custom_doctype_links(doctype, data): - if frappe.get_all("Custom Link", {"document_type": doctype}): - doc = frappe.get_doc("Custom Link", doctype) - - if not data.transactions: - # init groups - data.transactions = [] - data.non_standard_fieldnames = {} - - for link in doc.links: - link.added = False - for group in data.transactions: - # group found - if group.get("label") == link.group: - if link.link_doctype not in group.get("items"): - group.get("items").append(link.link_doctype) - link.added = True - - if not link.added: - # group not found, make a new group - data.transactions.append({ - "label": link.group, - "items": [link.link_doctype] - }) - - if link.link_fieldname != data.fieldname: - if data.fieldname: - data.non_standard_fieldnames[link.link_doctype] = link.link_fieldname - else: - data.fieldname = link.link_fieldname - - return data \ No newline at end of file From f4b9f8a31453c02733d2ee82a5db5f63c3014fbd Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 19:27:09 +0530 Subject: [PATCH 115/145] feat: trigger after insert for submittable quick entry --- frappe/public/js/frappe/form/quick_entry.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 9996389a4e..dbb3792262 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -213,8 +213,15 @@ frappe.ui.form.QuickEntryForm = Class.extend({ me.dialog.doc = r.message; if (frappe._from_link) { frappe.ui.form.update_calling_link(me.dialog.doc); + } else { + if(me.after_insert) { + me.after_insert(me.dialog.doc); + } else { + me.open_form_if_not_list(); + } } - cur_frm.reload_doc(); + + cur_frm && cur_frm.reload_doc(); } }); }, From 657d001eefda12759f075d416044cf39c8609ac5 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 19:28:08 +0530 Subject: [PATCH 116/145] feat: don't show full link option if force is set in quick entry --- frappe/public/js/frappe/form/quick_entry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index dbb3792262..5b427feb1c 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -107,7 +107,7 @@ frappe.ui.form.QuickEntryForm = Class.extend({ }); this.register_primary_action(); - this.render_edit_in_full_page_link(); + !this.force && this.render_edit_in_full_page_link(); // ctrl+enter to save this.dialog.wrapper.keydown(function(e) { if((e.ctrlKey || e.metaKey) && e.which==13) { From dae9eb5a2a5a24fd2b63079a7052a21a66986065 Mon Sep 17 00:00:00 2001 From: prssanna Date: Thu, 14 May 2020 19:32:01 +0530 Subject: [PATCH 117/145] fix: don't get filters if string type --- frappe/desk/notifications.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 109dd25f4f..4a1302788b 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -212,7 +212,10 @@ def get_notification_config(): def get_filters_for(doctype): '''get open filters for doctype''' config = get_notification_config() - return config.get("for_doctype").get(doctype, {}) + doctype_config = config.get("for_doctype").get(doctype, {}) + filters = doctype_config if not isinstance(doctype_config, string_types) else None + + return filters @frappe.whitelist() @frappe.read_only() From 21d7926d60288a3fac6f46b5da9a2cba1548667d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 19:41:55 +0530 Subject: [PATCH 118/145] fix: linting --- frappe/public/js/frappe/form/quick_entry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/quick_entry.js b/frappe/public/js/frappe/form/quick_entry.js index 5b427feb1c..68444c8a3b 100644 --- a/frappe/public/js/frappe/form/quick_entry.js +++ b/frappe/public/js/frappe/form/quick_entry.js @@ -214,7 +214,7 @@ frappe.ui.form.QuickEntryForm = Class.extend({ if (frappe._from_link) { frappe.ui.form.update_calling_link(me.dialog.doc); } else { - if(me.after_insert) { + if (me.after_insert) { me.after_insert(me.dialog.doc); } else { me.open_form_if_not_list(); From 76c8e62e354f30a7e21ecbe7d86831d3ac047543 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 19:51:58 +0530 Subject: [PATCH 119/145] feat: store if document is submitable --- frappe/desk/desktop.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index e2fe020eca..06aff0b714 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -274,6 +274,8 @@ class Workspace: for doc in self.onboarding_doc.get_steps(): step = doc.as_dict().copy() step.label = _(doc.title) + if step.action == "Create Entry": + step.is_submittable = frappe.db.get_value("DocType", step.reference_document, 'is_submittable') steps.append(step) return steps @@ -516,4 +518,5 @@ def update_onboarding_step(name, field, value): value: Value to be updated """ + return frappe.db.set_value("Onboarding Step", name, field, value) From 5fe6ef8c4a91915a30862d3f9d68fac67a8e47f9 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 19:52:08 +0530 Subject: [PATCH 120/145] feat: added after submit hooks --- frappe/public/js/frappe/form/form.js | 6 ++++++ .../js/frappe/widgets/onboarding_widget.js | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 01dfbf81f9..bad7c877fc 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -651,6 +651,12 @@ frappe.ui.form.Form = class FrappeForm { callback && callback(); me.script_manager.trigger("on_submit") .then(() => resolve(me)); + if (frappe.route_hooks.after_submit) { + let route_callback = frappe.route_hooks.after_submit; + delete frappe.route_hooks.after_submit; + + route_callback(me); + } } }, btn, () => me.handle_save_fail(btn, on_error), resolve); }); diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index e869b281ae..821824a2d2 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -233,8 +233,7 @@ export default class OnboardingWidget extends Widget { let current_route = frappe.get_route(); frappe.route_hooks = {}; - - frappe.route_hooks.after_save = () => { + let callback = () => { frappe.msgprint({ message: __("You're doing great, let's take you back to the onboarding page."), title: __("Good Work 🎉"), @@ -253,6 +252,18 @@ export default class OnboardingWidget extends Widget { }; }; + if (step.is_submittable) { + frappe.route_hooks.after_save = () => { + frappe.msgprint({ + message: __("Submit this document to complete this step."), + title: __("Great") + }); + }; + frappe.route_hooks.after_submit = callback; + } else { + frappe.route_hooks.after_save = callback; + } + frappe.set_route(`Form/${step.reference_document}/New ${step.reference_document} 1`); } @@ -325,6 +336,8 @@ export default class OnboardingWidget extends Widget { is_complete: "fa-check-circle-o", is_skipped: "fa-check-circle-o", }; + // Clear any hooks + frappe.route_hooks = {}; frappe .call("frappe.desk.desktop.update_onboarding_step", { From 0091f514b5c984c71467f7093b86b09bacf253d5 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 20:00:34 +0530 Subject: [PATCH 121/145] fix: remove return --- frappe/desk/desktop.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index 06aff0b714..29f9aea4be 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -518,5 +518,4 @@ def update_onboarding_step(name, field, value): value: Value to be updated """ - return frappe.db.set_value("Onboarding Step", name, field, value) From ba2da078af338530543a29d070e4ac2b24c19ff7 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 20:00:43 +0530 Subject: [PATCH 122/145] feat: use cached db value --- frappe/desk/desktop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/desktop.py b/frappe/desk/desktop.py index 29f9aea4be..512b3f2890 100644 --- a/frappe/desk/desktop.py +++ b/frappe/desk/desktop.py @@ -275,7 +275,7 @@ class Workspace: step = doc.as_dict().copy() step.label = _(doc.title) if step.action == "Create Entry": - step.is_submittable = frappe.db.get_value("DocType", step.reference_document, 'is_submittable') + step.is_submittable = frappe.db.get_value("DocType", step.reference_document, 'is_submittable', cache=True) steps.append(step) return steps From 0f94edd87cceaa741cd400a078b0f83d361e69f0 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 14 May 2020 21:31:02 +0530 Subject: [PATCH 123/145] feat: allow overriding filters in dashboards --- frappe/public/js/frappe/widgets/chart_widget.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 35ddaab4cf..c42e6053eb 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -361,7 +361,12 @@ export default class ChartWidget extends Widget { } ]; } else { - fields = filters.filter(f => f.fieldname); + fields = filters + .filter(df => df.fieldname) + .map(df => { + Object.assign(df, df.dashboard_config || {}); + return df; + }); } } else { fields = [ From bc8620d42038d1974e9c8e286395d2cc7522662a Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 28 Apr 2020 16:46:22 +0530 Subject: [PATCH 124/145] feat: add default custom options to dashboard --- frappe/desk/doctype/dashboard/dashboard.json | 10 +++- frappe/desk/doctype/dashboard/dashboard.py | 8 ++- .../dashboard_chart/dashboard_chart.json | 2 +- .../public/js/frappe/widgets/chart_widget.js | 53 +++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/dashboard/dashboard.json b/frappe/desk/doctype/dashboard/dashboard.json index c17bc3235c..a3a6d492f1 100644 --- a/frappe/desk/doctype/dashboard/dashboard.json +++ b/frappe/desk/doctype/dashboard/dashboard.json @@ -9,6 +9,7 @@ "dashboard_name", "is_default", "charts", + "default_chart_custom_options", "cards" ], "fields": [ @@ -33,6 +34,13 @@ "options": "Dashboard Chart Link", "reqd": 1 }, + { + "description": "Set Default Options for all charts on this Dashboard (Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"])", + "fieldname": "default_chart_custom_options", + "fieldtype": "Code", + "label": "Default Chart Custom Options", + "options": "JSON" + }, { "fieldname": "cards", "fieldtype": "Table", @@ -41,7 +49,7 @@ } ], "links": [], - "modified": "2020-04-19 17:44:36.237163", + "modified": "2020-04-28 14:17:02.391084", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard", diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index b85e135071..952db21042 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -19,7 +19,13 @@ def get_permitted_charts(dashboard_name): dashboard = frappe.get_doc('Dashboard', dashboard_name) for chart in dashboard.charts: if frappe.has_permission('Dashboard Chart', doc=chart.chart): - permitted_charts.append(chart) + chart_dict = frappe._dict() + chart_dict.update(chart.as_dict()) + + if dashboard.get('default_chart_custom_options'): + chart_dict.custom_options = dashboard.get('default_chart_custom_options') + permitted_charts.append(chart_dict) + return permitted_charts @frappe.whitelist() diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index e377ef740e..472d02a75e 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -219,7 +219,7 @@ "options": "Dashboard Chart Field" }, { - "description": "Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"]", + "description": " Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"] (the options set here will override the default custom options set in the Dashboard)", "fieldname": "custom_options", "fieldtype": "Code", "label": "Custom Options" diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index c42e6053eb..a0211284bf 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -593,6 +593,59 @@ export default class ChartWidget extends Widget { } } + get_chart_args() { + let colors = this.get_chart_colors(); + + const chart_type_map = { + Line: "line", + Bar: "bar", + Percentage: "percentage", + Pie: "pie", + Donut: "donut" + }; + + let chart_args = { + data: this.data, + type: chart_type_map[this.chart_doc.type], + colors: colors, + height: this.height, + axisOptions: { + xIsSeries: this.chart_doc.timeseries, + shortenYAxisNumbers: 1 + } + }; + + let set_options = (options) => { + let custom_options = JSON.parse(options); + for (let key in custom_options) { + chart_args[key] = custom_options[key]; + } + }; + + if (this.custom_options) { + set_options(this.custom_options); + } + + if (this.chart_doc.custom_options) { + set_options(this.chart_doc.custom_options); + } + + return chart_args; + } + + get_chart_colors() { + let colors = []; + if (this.chart_doc.y_axis.length) { + this.chart_doc.y_axis.map(field => { + colors.push(field.color); + }); + } else if (["Line", "Bar"].includes(this.chart_doc.type)) { + colors = [this.chart_doc.color || "light-blue"]; + } + + return colors; + } + update_last_synced() { let last_synced_text = __("Last synced {0}", [ comment_when(this.chart_doc.last_synced_on) From 08f740acf8cb3fc5704fc4be1e971fcba0f11fbd Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 29 Apr 2020 13:30:05 +0530 Subject: [PATCH 125/145] fix: better naming --- frappe/desk/doctype/dashboard/dashboard.json | 6 +++++- frappe/desk/doctype/dashboard/dashboard.py | 4 ++-- frappe/desk/doctype/dashboard_chart/dashboard_chart.json | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/frappe/desk/doctype/dashboard/dashboard.json b/frappe/desk/doctype/dashboard/dashboard.json index a3a6d492f1..e17fb66436 100644 --- a/frappe/desk/doctype/dashboard/dashboard.json +++ b/frappe/desk/doctype/dashboard/dashboard.json @@ -9,8 +9,12 @@ "dashboard_name", "is_default", "charts", +<<<<<<< HEAD "default_chart_custom_options", "cards" +======= + "chart_options" +>>>>>>> fix: better naming ], "fields": [ { @@ -49,7 +53,7 @@ } ], "links": [], - "modified": "2020-04-28 14:17:02.391084", + "modified": "2020-04-29 13:26:37.362482", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard", diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 952db21042..9368315343 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -22,8 +22,8 @@ def get_permitted_charts(dashboard_name): chart_dict = frappe._dict() chart_dict.update(chart.as_dict()) - if dashboard.get('default_chart_custom_options'): - chart_dict.custom_options = dashboard.get('default_chart_custom_options') + if dashboard.get('chart_options'): + chart_dict.custom_options = dashboard.get('chart_options') permitted_charts.append(chart_dict) return permitted_charts diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index 472d02a75e..3332534de6 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -219,7 +219,7 @@ "options": "Dashboard Chart Field" }, { - "description": " Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"] (the options set here will override the default custom options set in the Dashboard)", + "description": " Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"] (the options set here will override the chart options set in the Dashboard)", "fieldname": "custom_options", "fieldtype": "Code", "label": "Custom Options" From d5364f759bb47139b35adc714b15abb497d69f40 Mon Sep 17 00:00:00 2001 From: prssanna Date: Wed, 29 Apr 2020 18:47:14 +0530 Subject: [PATCH 126/145] fix: validate chart options json --- frappe/desk/doctype/dashboard/dashboard.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 9368315343..3d86a1e48a 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from frappe.model.document import Document import frappe +import json class Dashboard(Document): def on_update(self): @@ -13,6 +14,16 @@ class Dashboard(Document): frappe.db.sql('''update tabDashboard set is_default = 0 where name != %s''', self.name) + def validate(self): + self.validate_custom_options() + + def validate_custom_options(self): + if self.chart_options: + try: + json.loads(self.chart_options) + except ValueError as error: + frappe.throw("Invalid json added in the custom options: %s" % error) + @frappe.whitelist() def get_permitted_charts(dashboard_name): permitted_charts = [] From e34e8715d360195c7e3356f57b916e5a584447d2 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 12:17:04 +0530 Subject: [PATCH 127/145] fix: translate messages --- frappe/desk/doctype/dashboard/dashboard.py | 2 +- frappe/desk/doctype/dashboard_chart/dashboard_chart.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 3d86a1e48a..daf065949c 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -22,7 +22,7 @@ class Dashboard(Document): try: json.loads(self.chart_options) except ValueError as error: - frappe.throw("Invalid json added in the custom options: %s" % error) + frappe.throw(_("Invalid json added in the custom options: %s" % error)) @frappe.whitelist() def get_permitted_charts(dashboard_name): diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index e7e4aefe09..4044a66638 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -435,11 +435,11 @@ class DashboardChart(Document): def check_document_type(self): if frappe.get_meta(self.document_type).issingle: - frappe.throw("You cannot create a dashboard chart from single DocTypes") + frappe.throw(_("You cannot create a dashboard chart from single DocTypes")) def validate_custom_options(self): if self.custom_options: try: json.loads(self.custom_options) except ValueError as error: - frappe.throw("Invalid json added in the custom options: %s" % error) \ No newline at end of file + frappe.throw(_("Invalid json added in the custom options: %s" % error)) \ No newline at end of file From 7425e5cc6c2f2e5798d4edd144b043964f852e06 Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 12:29:21 +0530 Subject: [PATCH 128/145] fix: invalid json --- frappe/desk/doctype/dashboard/dashboard.json | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/frappe/desk/doctype/dashboard/dashboard.json b/frappe/desk/doctype/dashboard/dashboard.json index e17fb66436..c0e2bddcf8 100644 --- a/frappe/desk/doctype/dashboard/dashboard.json +++ b/frappe/desk/doctype/dashboard/dashboard.json @@ -9,12 +9,8 @@ "dashboard_name", "is_default", "charts", -<<<<<<< HEAD - "default_chart_custom_options", + "chart_options", "cards" -======= - "chart_options" ->>>>>>> fix: better naming ], "fields": [ { @@ -40,9 +36,9 @@ }, { "description": "Set Default Options for all charts on this Dashboard (Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"])", - "fieldname": "default_chart_custom_options", + "fieldname": "chart_options", "fieldtype": "Code", - "label": "Default Chart Custom Options", + "label": "Chart Options", "options": "JSON" }, { From 58d75ad5d7f40ba71f3ba40685d03354321ef2ed Mon Sep 17 00:00:00 2001 From: prssanna Date: Tue, 5 May 2020 12:40:15 +0530 Subject: [PATCH 129/145] fix: import _ --- frappe/desk/doctype/dashboard/dashboard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index daf065949c..621ab19ecd 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from frappe.model.document import Document import frappe +from frappe import _ import json class Dashboard(Document): From 3a090e71382c19cda42ca3bce5b7c6bb5dd4fad4 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 8 May 2020 16:18:49 +0530 Subject: [PATCH 130/145] fix: translation --- frappe/desk/doctype/dashboard/dashboard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/doctype/dashboard/dashboard.py b/frappe/desk/doctype/dashboard/dashboard.py index 621ab19ecd..af0c48d9c6 100644 --- a/frappe/desk/doctype/dashboard/dashboard.py +++ b/frappe/desk/doctype/dashboard/dashboard.py @@ -23,7 +23,7 @@ class Dashboard(Document): try: json.loads(self.chart_options) except ValueError as error: - frappe.throw(_("Invalid json added in the custom options: %s" % error)) + frappe.throw(_("Invalid json added in the custom options: {0}").format(error)) @frappe.whitelist() def get_permitted_charts(dashboard_name): From ee292ed2d0b5f51791fddb98c6994304c86833e8 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 8 May 2020 16:20:35 +0530 Subject: [PATCH 131/145] style: remove leading space --- frappe/desk/doctype/dashboard_chart/dashboard_chart.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index 3332534de6..72f5c43316 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -219,7 +219,7 @@ "options": "Dashboard Chart Field" }, { - "description": " Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"] (the options set here will override the chart options set in the Dashboard)", + "description": "Ex: \"colors\": [\"#d1d8dd\", \"#ff5858\"] (the options set here will override the chart options set in the Dashboard)", "fieldname": "custom_options", "fieldtype": "Code", "label": "Custom Options" @@ -283,4 +283,4 @@ "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 -} \ No newline at end of file +} From 0bba2e8c28b0d434bc09a3e0fb6d6ecff42c4e5d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 8 May 2020 16:20:52 +0530 Subject: [PATCH 132/145] fix: minor translation issue --- frappe/desk/doctype/dashboard_chart/dashboard_chart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 4044a66638..7e375e835f 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -442,4 +442,4 @@ class DashboardChart(Document): try: json.loads(self.custom_options) except ValueError as error: - frappe.throw(_("Invalid json added in the custom options: %s" % error)) \ No newline at end of file + frappe.throw(_("Invalid json added in the custom options: {0}").format(error)) From 9c412d60df01b5f0c555f102b950092a669ba14e Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 15 May 2020 00:40:01 +0530 Subject: [PATCH 133/145] fix: fix rebase --- .../public/js/frappe/widgets/chart_widget.js | 69 ++++--------------- 1 file changed, 15 insertions(+), 54 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index a0211284bf..e5378cf2ab 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -523,7 +523,6 @@ export default class ChartWidget extends Widget { } } - get_chart_args() { let colors = this.get_chart_colors(); @@ -553,6 +552,21 @@ export default class ChartWidget extends Widget { chart_args.data.end = new Date(`${heatmap_year+1}-01-01`); } + let set_options = (options) => { + let custom_options = JSON.parse(options); + for (let key in custom_options) { + chart_args[key] = custom_options[key]; + } + }; + + if (this.custom_options) { + set_options(this.custom_options); + } + + if (this.chart_doc.custom_options) { + set_options(this.chart_doc.custom_options); + } + return chart_args; } @@ -593,59 +607,6 @@ export default class ChartWidget extends Widget { } } - get_chart_args() { - let colors = this.get_chart_colors(); - - const chart_type_map = { - Line: "line", - Bar: "bar", - Percentage: "percentage", - Pie: "pie", - Donut: "donut" - }; - - let chart_args = { - data: this.data, - type: chart_type_map[this.chart_doc.type], - colors: colors, - height: this.height, - axisOptions: { - xIsSeries: this.chart_doc.timeseries, - shortenYAxisNumbers: 1 - } - }; - - let set_options = (options) => { - let custom_options = JSON.parse(options); - for (let key in custom_options) { - chart_args[key] = custom_options[key]; - } - }; - - if (this.custom_options) { - set_options(this.custom_options); - } - - if (this.chart_doc.custom_options) { - set_options(this.chart_doc.custom_options); - } - - return chart_args; - } - - get_chart_colors() { - let colors = []; - if (this.chart_doc.y_axis.length) { - this.chart_doc.y_axis.map(field => { - colors.push(field.color); - }); - } else if (["Line", "Bar"].includes(this.chart_doc.type)) { - colors = [this.chart_doc.color || "light-blue"]; - } - - return colors; - } - update_last_synced() { let last_synced_text = __("Last synced {0}", [ comment_when(this.chart_doc.last_synced_on) From 76db5e11c8cb8ee5f12e71e46c29e6c78d5d71bd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 27 Apr 2020 16:51:31 +0530 Subject: [PATCH 134/145] feat: Section Break without border --- frappe/core/doctype/docfield/docfield.json | 10 +++++++++- .../custom/doctype/custom_field/custom_field.json | 10 +++++++++- .../doctype/customize_form/customize_form.py | 3 ++- .../customize_form_field/customize_form_field.json | 10 +++++++++- frappe/database/mariadb/framework_mariadb.sql | 1 + frappe/database/postgres/framework_postgres.sql | 1 + frappe/public/js/frappe/form/layout.js | 14 ++++++++++++++ frappe/public/less/form.less | 11 ++++++++++- 8 files changed, 55 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json index 6d8ee41a5a..8e7516cd0a 100644 --- a/frappe/core/doctype/docfield/docfield.json +++ b/frappe/core/doctype/docfield/docfield.json @@ -43,6 +43,7 @@ "report_hide", "remember_last_selected_value", "ignore_xss_filter", + "hide_border", "property_depends_on_section", "mandatory_depends_on", "column_break_38", @@ -448,12 +449,19 @@ { "fieldname": "column_break_38", "fieldtype": "Column Break" + }, + { + "default": "0", + "depends_on": "eval:doc.fieldtype=='Section Break'", + "fieldname": "hide_border", + "fieldtype": "Check", + "label": "Hide Border" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2020-04-19 21:54:13.783908", + "modified": "2020-04-27 11:38:21.223185", "modified_by": "Administrator", "module": "Core", "name": "DocField", diff --git a/frappe/custom/doctype/custom_field/custom_field.json b/frappe/custom/doctype/custom_field/custom_field.json index 394f38b56c..122e6c7070 100644 --- a/frappe/custom/doctype/custom_field/custom_field.json +++ b/frappe/custom/doctype/custom_field/custom_field.json @@ -48,6 +48,7 @@ "allow_in_quick_entry", "ignore_xss_filter", "translatable", + "hide_border", "description", "permlevel", "width", @@ -378,12 +379,19 @@ "fieldname": "in_preview", "fieldtype": "Check", "label": "In Preview" + }, + { + "default": "0", + "depends_on": "eval:doc.fieldtype=='Section Break'", + "fieldname": "hide_border", + "fieldtype": "Check", + "label": "Hide Border" } ], "icon": "fa fa-glass", "idx": 1, "links": [], - "modified": "2020-04-10 11:57:10.392218", + "modified": "2020-04-27 11:40:48.325481", "modified_by": "Administrator", "module": "Custom", "name": "Custom Field", diff --git a/frappe/custom/doctype/customize_form/customize_form.py b/frappe/custom/doctype/customize_form/customize_form.py index ebf01d11b3..6a54d9c7e6 100644 --- a/frappe/custom/doctype/customize_form/customize_form.py +++ b/frappe/custom/doctype/customize_form/customize_form.py @@ -76,7 +76,8 @@ docfield_properties = { 'remember_last_selected_value': 'Check', 'allow_bulk_edit': 'Check', 'auto_repeat': 'Link', - 'allow_in_quick_entry': 'Check' + 'allow_in_quick_entry': 'Check', + 'hide_border': 'Check' } allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'), diff --git a/frappe/custom/doctype/customize_form_field/customize_form_field.json b/frappe/custom/doctype/customize_form_field/customize_form_field.json index d7887cf8bd..2c5fb874f7 100644 --- a/frappe/custom/doctype/customize_form_field/customize_form_field.json +++ b/frappe/custom/doctype/customize_form_field/customize_form_field.json @@ -39,6 +39,7 @@ "allow_on_submit", "report_hide", "remember_last_selected_value", + "hide_border", "property_depends_on_section", "mandatory_depends_on", "column_break_33", @@ -388,12 +389,19 @@ "fieldname": "in_preview", "fieldtype": "Check", "label": "In Preview" + }, + { + "default": "0", + "depends_on": "eval:doc.fieldtype=='Section Break'", + "fieldname": "hide_border", + "fieldtype": "Check", + "label": "Hide Border" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2020-04-10 11:58:44.573537", + "modified": "2020-04-27 11:39:26.389300", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form Field", diff --git a/frappe/database/mariadb/framework_mariadb.sql b/frappe/database/mariadb/framework_mariadb.sql index 46940cc846..bd93069a3f 100644 --- a/frappe/database/mariadb/framework_mariadb.sql +++ b/frappe/database/mariadb/framework_mariadb.sql @@ -63,6 +63,7 @@ CREATE TABLE `tabDocField` ( `precision` varchar(255) DEFAULT NULL, `length` int(11) NOT NULL DEFAULT 0, `translatable` int(1) NOT NULL DEFAULT 0, + `hide_border` int(1) NOT NULL DEFAULT 0, PRIMARY KEY (`name`), KEY `parent` (`parent`), KEY `label` (`label`), diff --git a/frappe/database/postgres/framework_postgres.sql b/frappe/database/postgres/framework_postgres.sql index 26760dbcc9..76309e7347 100644 --- a/frappe/database/postgres/framework_postgres.sql +++ b/frappe/database/postgres/framework_postgres.sql @@ -63,6 +63,7 @@ CREATE TABLE "tabDocField" ( "precision" varchar(255) DEFAULT NULL, "length" bigint NOT NULL DEFAULT 0, "translatable" smallint NOT NULL DEFAULT 0, + "hide_border" smallint NOT NULL DEFAULT 0, PRIMARY KEY ("name") ) ; diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 5aeb29b1ed..26131fc9c7 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -236,6 +236,7 @@ frappe.ui.form.Layout = Class.extend({ // collapse sections if(this.frm) { this.refresh_section_collapse(); + this.refresh_section_border(); } }, @@ -307,6 +308,16 @@ frappe.ui.form.Layout = Class.extend({ } }, + refresh_section_border: function() { + if(!this.doc) return; + this.sections.forEach(section => { + const df = section.df; + if (df && cint(df.hide_border)) { + section.hide_border(true); + } + }) + }, + attach_doc_and_docfields: function(refresh) { var me = this; for(var i=0, l=this.fields_list.length; i Date: Mon, 11 May 2020 17:29:24 +0530 Subject: [PATCH 135/145] fix: linting issue --- frappe/public/js/frappe/form/layout.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index 26131fc9c7..c8d5c9b422 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -309,13 +309,13 @@ frappe.ui.form.Layout = Class.extend({ }, refresh_section_border: function() { - if(!this.doc) return; + if (!this.doc) return; this.sections.forEach(section => { const df = section.df; if (df && cint(df.hide_border)) { section.hide_border(true); } - }) + }); }, attach_doc_and_docfields: function(refresh) { From 30c22ba3e576770bea3e28287e912637d4720918 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 15 May 2020 10:11:42 +0530 Subject: [PATCH 136/145] fix: hide section border on make, instead of refresh --- frappe/public/js/frappe/form/layout.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/frappe/public/js/frappe/form/layout.js b/frappe/public/js/frappe/form/layout.js index c8d5c9b422..d6106255a0 100644 --- a/frappe/public/js/frappe/form/layout.js +++ b/frappe/public/js/frappe/form/layout.js @@ -236,7 +236,6 @@ frappe.ui.form.Layout = Class.extend({ // collapse sections if(this.frm) { this.refresh_section_collapse(); - this.refresh_section_border(); } }, @@ -308,16 +307,6 @@ frappe.ui.form.Layout = Class.extend({ } }, - refresh_section_border: function() { - if (!this.doc) return; - this.sections.forEach(section => { - const df = section.df; - if (df && cint(df.hide_border)) { - section.hide_border(true); - } - }); - }, - attach_doc_and_docfields: function(refresh) { var me = this; for(var i=0, l=this.fields_list.length; i').appendTo(this.wrapper); }, + make_head: function() { var me = this; if(!this.df.collapsible) { @@ -674,12 +666,11 @@ frappe.ui.form.Section = Class.extend({ } }); }, - hide_border(hide) { - this.body.parent().toggleClass("hide-border", hide); - }, + is_collapsed() { return this.body.hasClass('hide'); }, + has_missing_mandatory: function() { var missing_mandatory = false; for (var j=0, l=this.fields_list.length; j < l; j++) { From 85d86fbedfd0707e9d9493470349e884b8fe74ac Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 11:21:24 +0530 Subject: [PATCH 137/145] refactor: moved remote_migrations to frappe.integrations.frappe_providers fix: exit code fixes and minor bug fix --- frappe/commands/site.py | 8 +++---- .../integrations/frappe_providers/__init__.py | 11 +++++++++ .../frappe_providers/frappecloud.py} | 23 ++++++++----------- 3 files changed, 24 insertions(+), 18 deletions(-) create mode 100644 frappe/integrations/frappe_providers/__init__.py rename frappe/{utils/remote_migrations.py => integrations/frappe_providers/frappecloud.py} (95%) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 10bf700340..1f22650930 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -257,12 +257,12 @@ def migrate(context, rebuild_website=False, skip_failing=False): compileall.compile_dir('../apps', quiet=1, rx=re.compile('.*node_modules.*')) @click.command('migrate-to') -@click.argument('site_url') +@click.argument('frappe_provider') @pass_context -def migrate_to(context, site_url): - from frappe.utils.remote_migrations import migrate_to +def migrate_to(context, frappe_provider): + from frappe.integrations.frappe_providers import migrate_to for site in context.sites: - migrate_to(site, site_url) + migrate_to(site, frappe_provider) @click.command('run-patch') @click.argument('module') diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py new file mode 100644 index 0000000000..31a0cf1c04 --- /dev/null +++ b/frappe/integrations/frappe_providers/__init__.py @@ -0,0 +1,11 @@ +# imports - module imports +from frappe.integrations.frappe_providers.frappecloud import frappecloud_migrator + + +def migrate_to(local_site, frappe_provider): + if frappe_provider in ("frappe.cloud", "frappecloud.com"): + frappe_provider = "staging.frappe.cloud" + return frappecloud_migrator(local_site, frappe_provider) + else: + print("{} is not supported yet".format(frappe_provider)) + sys.exit(1) diff --git a/frappe/utils/remote_migrations.py b/frappe/integrations/frappe_providers/frappecloud.py similarity index 95% rename from frappe/utils/remote_migrations.py rename to frappe/integrations/frappe_providers/frappecloud.py index 90f8db0b74..1785823a2d 100644 --- a/frappe/utils/remote_migrations.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -13,7 +13,7 @@ import requests import frappe import frappe.utils.backups from frappe.utils import get_installed_apps_info -from frappe.utils.commands import render_table, padme +from frappe.utils.commands import render_table, add_line_after def get_new_site_options(): @@ -27,7 +27,7 @@ def get_new_site_options(): def is_valid_subdomain(subdomain): - if len(subdomain) < 6: + if len(subdomain) < 5: print("Subdomain too short. Use 5 or more characters") return False matched = re.match("^[a-z0-9][a-z0-9-]*[a-z0-9]$", subdomain) @@ -60,7 +60,7 @@ def render_plan_table(plans_list): render_table(plans_table) -@padme +@add_line_after def choose_plan(plans_list): print("{} plans available".format(len(plans_list))) available_plans = [plan["name"] for plan in plans_list] @@ -75,7 +75,7 @@ def choose_plan(plans_list): print("Invalid Selection ❌") -@padme +@add_line_after def check_app_compat(available_group): is_compat = True incompatible_apps, filtered_apps, branch_msgs = [], [], [] @@ -125,7 +125,7 @@ def render_group_table(app_groups): render_table(app_groups_table) -@padme +@add_line_after def filter_apps(app_groups): render_group_table(app_groups) @@ -145,7 +145,7 @@ def filter_apps(app_groups): return selected_group["name"], filtered_apps -@padme +@add_line_after def create_session(): # take user input from STDIN username = click.prompt("Username").strip() @@ -164,7 +164,7 @@ def create_session(): print("Authorization Failed with Error Code {}".format(login_sc.status_code)) -@padme +@add_line_after def get_subdomain(domain): while True: subdomain = click.prompt("Enter subdomain").strip() @@ -173,7 +173,7 @@ def get_subdomain(domain): return subdomain -@padme +@add_line_after def upload_backup(local_site): # take backup files_session = {} @@ -256,12 +256,7 @@ def frappecloud_migrator(local_site, remote_site): print("Request failed with error code {}".format(site_creation_request.status_code)) reason = html2text(site_creation_request.text) print(reason) + sys.exit(1) - -def migrate_to(local_site, remote_site): - if remote_site in ("frappe.cloud", "frappecloud.com"): - remote_site = "frappecloud.com" - return frappecloud_migrator(local_site, remote_site) else: - print("{} is not supported yet".format(remote_site)) sys.exit(1) From ed344ae8cf2d303a55c1cee07b30765babf1fdad Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 11:23:42 +0530 Subject: [PATCH 138/145] chore: updated docstrings for command APIs --- frappe/commands/site.py | 1 + frappe/utils/commands.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/commands/site.py b/frappe/commands/site.py index 1f22650930..d92c727dc7 100755 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -260,6 +260,7 @@ def migrate(context, rebuild_website=False, skip_failing=False): @click.argument('frappe_provider') @pass_context def migrate_to(context, frappe_provider): + "Migrates site to the specified provider" from frappe.integrations.frappe_providers import migrate_to for site in context.sites: migrate_to(site, frappe_provider) diff --git a/frappe/utils/commands.py b/frappe/utils/commands.py index babefc56e2..99322b50ba 100644 --- a/frappe/utils/commands.py +++ b/frappe/utils/commands.py @@ -5,6 +5,7 @@ from terminaltables import AsciiTable @functools.lru_cache(maxsize=1024) def get_first_party_apps(): + """Get list of all apps under orgs: frappe. erpnext from GitHub""" apps = [] for org in ["frappe", "erpnext"]: req = requests.get(f"https://api.github.com/users/{org}/repos", {"type": "sources", "per_page": 200}) @@ -17,15 +18,17 @@ def render_table(data): print(AsciiTable(data).table) -def padme(me): +def add_line_after(function): + """Adds an extra line to STDOUT after the execution of a function this decorates""" def empty_line(*args, **kwargs): - result = me(*args, **kwargs) + result = function(*args, **kwargs) print() return result return empty_line def log(message, colour=''): + """Coloured log outputs to STDOUT""" colours = { "nc": '\033[0m', "blue": '\033[94m', From c6a66eb47b895521fa2a3660316fcaf46d149d0b Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 15 May 2020 13:31:13 +0530 Subject: [PATCH 139/145] fix: use different number system for india --- .../js/frappe/widgets/number_card_widget.js | 3 +- frappe/public/js/frappe/widgets/utils.js | 45 ++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/frappe/public/js/frappe/widgets/number_card_widget.js b/frappe/public/js/frappe/widgets/number_card_widget.js index cda17e08bc..77cb8a59c2 100644 --- a/frappe/public/js/frappe/widgets/number_card_widget.js +++ b/frappe/public/js/frappe/widgets/number_card_widget.js @@ -119,7 +119,8 @@ export default class NumberCardWidget extends Widget { get_formatted_number() { const based_on_df = frappe.meta.get_docfield(this.card_doc.document_type, this.card_doc.aggregate_function_based_on); - const shortened_number = shorten_number(this.number); + const default_country = frappe.sys_defaults.country; + const shortened_number = shorten_number(this.number, default_country); let number_parts = shortened_number.split(' '); const symbol = number_parts[1] || ''; diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index f336335d1c..ab807bb0b1 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -127,19 +127,44 @@ function go_to_list_with_filters(doctype, filters) { }); } -function shorten_number(number) { +function shorten_number(number, country) { + country = country || ''; + const number_system = get_number_system(country); let x = Math.abs(Math.round(number)); + for (const map of number_system) { + if (x >= map.divisor) { + return Math.round(number/map.divisor) + ' ' + map.symbol; + } + }; + return number.toFixed(); +} - switch (true) { - case x >= 1.0e+12: - return Math.round(number/1.0e+12) + " T"; - case x >= 1.0e+9: - return Math.round(number/1.0e+9) + " B"; - case x >= 1.0e+6: - return Math.round(number/1.0e+6) + " M"; - default: - return number.toFixed(); +function get_number_system(country) { + let number_system_map = { + 'India': + [{ + divisor: 1.0e+7, + symbol: 'Cr' + }, + { + divisor: 1.0e+5, + symbol: 'Lakh' + }], + '': + [{ + divisor: 1.0e+12, + symbol: 'T' + }, + { + divisor: 1.0e+9, + symbol: 'B' + }, + { + divisor: 1.0e+6, + symbol: 'M' + }] } + return number_system_map[country]; } export { generate_route, generate_grid, build_summary_item, go_to_list_with_filters, shorten_number }; \ No newline at end of file From 2ebdb292f93823f242b40360bdeda8785de6020c Mon Sep 17 00:00:00 2001 From: prssanna Date: Fri, 15 May 2020 13:35:21 +0530 Subject: [PATCH 140/145] style: fix semicolon --- frappe/public/js/frappe/widgets/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index ab807bb0b1..c92bdc1b5f 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -135,7 +135,7 @@ function shorten_number(number, country) { if (x >= map.divisor) { return Math.round(number/map.divisor) + ' ' + map.symbol; } - }; + } return number.toFixed(); } @@ -163,7 +163,7 @@ function get_number_system(country) { divisor: 1.0e+6, symbol: 'M' }] - } + }; return number_system_map[country]; } From db3b57116d84a7f3d94fff1c2e63ecbc42b2ad76 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 15:16:56 +0530 Subject: [PATCH 141/145] fix: consistent UI and minor fixes --- .../frappe_providers/frappecloud.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/frappe/integrations/frappe_providers/frappecloud.py b/frappe/integrations/frappe_providers/frappecloud.py index 1785823a2d..3815042e9d 100644 --- a/frappe/integrations/frappe_providers/frappecloud.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -50,12 +50,13 @@ def render_plan_table(plans_list): plans_table = [] # title row - visible_headers = ["name", "concurrent_users", "cpu_time_per_day"] - plans_table.append(visible_headers) + visible_headers = ["name", "cpu_time_per_day"] + plans_table.append(["Plan", "CPU Time"]) # all rows for plan in plans_list: - plans_table.append([plan[header] for header in visible_headers]) + plan, cpu_time = [plan[header] for header in visible_headers] + plans_table.append([plan, "{} hour{}/day".format(cpu_time, "" if cpu_time < 2 else "s")]) render_table(plans_table) @@ -83,13 +84,13 @@ def check_app_compat(available_group): print("Checking availability of existing app group") for (app, branch) in existing_group: - info = [ (a["name"], a["branch"]) for a in available_group["apps"] if a["scrubbed"] == app] + info = [ (a["name"], a["branch"]) for a in available_group["apps"] if a["scrubbed"] == app ] if info: app_title, available_branch = info[0] if branch != available_branch: - print("⚠️ {}:{} => {}".format(app, branch, available_branch)) - branch_msgs.append([app.title(), branch, available_branch]) + print("⚠️ App {}:{} => {}".format(app, branch, available_branch)) + branch_msgs.append([app, branch, available_branch]) filtered_apps.append(app_title) is_compat = False @@ -103,8 +104,8 @@ def check_app_compat(available_group): is_compat = False start_msg = "\nSelecting this group will " - incompatible_apps = "drop {} apps: ".format(len(incompatible_apps)) + ", ".join(incompatible_apps) + " and " if incompatible_apps else "" - branch_change = "upgrade:\n" + "\n".join(["{}: {} => {}".format(*x) for x in branch_msgs]) if branch_msgs else "" + incompatible_apps = ("\n\nDrop the following apps:\n" + "\n".join(incompatible_apps)) if incompatible_apps else "" + branch_change = ("\n\nUpgrade the following apps:\n" + "\n".join(["{}: {} => {}".format(*x) for x in branch_msgs])) if branch_msgs else "" changes = (incompatible_apps + branch_change) or "be perfect for you :)" warning_message = start_msg + changes print(warning_message) @@ -130,12 +131,14 @@ def filter_apps(app_groups): render_group_table(app_groups) while True: - app_group_index = click.prompt("Select App Group #", type=int) - 1 + app_group_index = click.prompt("Select App Group Number", type=int) - 1 try: + if app_group_index == -1: + raise IndexError selected_group = app_groups[app_group_index] except IndexError: print("Invalid Selection ❌") - break + continue is_compat, filtered_apps = check_app_compat(selected_group) @@ -251,7 +254,9 @@ def frappecloud_migrator(local_site, remote_site): frappe.destroy() if site_creation_request.ok: - print("Site creation started at {}".format(site_creation_request.json()["message"])) + site_url = site_creation_request.json()["message"] + print("View your site dashboard at {}/dashboard/#/sites/{} ✨".format(remote_site, site_url)) + print("Your site URL: {}".format(site_url)) else: print("Request failed with error code {}".format(site_creation_request.status_code)) reason = html2text(site_creation_request.text) From a8c01a091518ee1e0f823bd4e9190e31aa14c875 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 15 May 2020 15:32:13 +0530 Subject: [PATCH 142/145] fix: Success message --- frappe/integrations/frappe_providers/frappecloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/integrations/frappe_providers/frappecloud.py b/frappe/integrations/frappe_providers/frappecloud.py index 3815042e9d..4f33c990f9 100644 --- a/frappe/integrations/frappe_providers/frappecloud.py +++ b/frappe/integrations/frappe_providers/frappecloud.py @@ -255,7 +255,8 @@ def frappecloud_migrator(local_site, remote_site): if site_creation_request.ok: site_url = site_creation_request.json()["message"] - print("View your site dashboard at {}/dashboard/#/sites/{} ✨".format(remote_site, site_url)) + print("Your site {} is being migrated ✨".format(local_site)) + print("View your site dashboard at {}/dashboard/#/sites/{}".format(remote_site, site_url)) print("Your site URL: {}".format(site_url)) else: print("Request failed with error code {}".format(site_creation_request.status_code)) From 4af13edc87fee4083491fcc14197040300b4575f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 15 May 2020 16:13:16 +0530 Subject: [PATCH 143/145] fix: Remove hardcoded url --- frappe/integrations/frappe_providers/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py index 31a0cf1c04..ec762627d0 100644 --- a/frappe/integrations/frappe_providers/__init__.py +++ b/frappe/integrations/frappe_providers/__init__.py @@ -4,7 +4,6 @@ from frappe.integrations.frappe_providers.frappecloud import frappecloud_migrato def migrate_to(local_site, frappe_provider): if frappe_provider in ("frappe.cloud", "frappecloud.com"): - frappe_provider = "staging.frappe.cloud" return frappecloud_migrator(local_site, frappe_provider) else: print("{} is not supported yet".format(frappe_provider)) From 7a58cbeff287a36700a4c316463f060be885ab62 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 16:30:17 +0530 Subject: [PATCH 144/145] fix: hardcode url frappe.cloud => frappecloud.com --- frappe/integrations/frappe_providers/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py index ec762627d0..a5cf284151 100644 --- a/frappe/integrations/frappe_providers/__init__.py +++ b/frappe/integrations/frappe_providers/__init__.py @@ -4,6 +4,7 @@ from frappe.integrations.frappe_providers.frappecloud import frappecloud_migrato def migrate_to(local_site, frappe_provider): if frappe_provider in ("frappe.cloud", "frappecloud.com"): + frappe_provider = "frappecloud.com" return frappecloud_migrator(local_site, frappe_provider) else: print("{} is not supported yet".format(frappe_provider)) From f7f81a0843cb7d988f340eeae67e7cea258afd02 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 15 May 2020 17:52:40 +0530 Subject: [PATCH 145/145] chore: add missed import --- frappe/integrations/frappe_providers/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/integrations/frappe_providers/__init__.py b/frappe/integrations/frappe_providers/__init__.py index a5cf284151..0b689478d2 100644 --- a/frappe/integrations/frappe_providers/__init__.py +++ b/frappe/integrations/frappe_providers/__init__.py @@ -1,3 +1,6 @@ +# imports - standard imports +import sys + # imports - module imports from frappe.integrations.frappe_providers.frappecloud import frappecloud_migrator