diff --git a/.github/helper/consumer_db/mariadb.json b/.github/helper/consumer_db/mariadb.json index 2e32157e1ac..f167b58e1aa 100644 --- a/.github/helper/consumer_db/mariadb.json +++ b/.github/helper/consumer_db/mariadb.json @@ -13,5 +13,6 @@ "root_login": "root", "root_password": "travis", "host_name": "http://test_site:8000", + "monitor": 1, "server_script_enabled": true } diff --git a/cypress/integration/sidebar.js b/cypress/integration/sidebar.js index c29ba611f9e..55bbcf61c09 100644 --- a/cypress/integration/sidebar.js +++ b/cypress/integration/sidebar.js @@ -52,7 +52,7 @@ context("Sidebar", () => { cy.get('.group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item').should('contain', '1'); //To check if there is no filter added to the listview - cy.get('.filter-selector > .btn').should('contain', 'Filter'); + cy.get(".filter-button").should("contain", "Filter"); //To add a filter to display data into the listview cy.get('.group-by-field.show > .dropdown-menu > .group-by-item > .dropdown-item').click(); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 8656d0ce950..2927072a394 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -331,8 +331,8 @@ Cypress.Commands.add('click_listview_row_item_with_text', (text) => { .click({force: true}); }); -Cypress.Commands.add('click_filter_button', () => { - cy.get('.filter-selector > .btn').click(); +Cypress.Commands.add("click_filter_button", () => { + cy.get(".filter-button").click(); }); Cypress.Commands.add('click_listview_primary_button', (btn_name) => { diff --git a/frappe/__init__.py b/frappe/__init__.py index 007e4640aab..8a23e78fc91 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -179,9 +179,9 @@ def set_user_lang(user, user_language=None): # end: static analysis hack -def init(site, sites_path=None, new_site=False): +def init(site, sites_path=".", new_site=False, force=False): """Initialize frappe for the current site. Reset thread locals `frappe.local`""" - if getattr(local, "initialised", None): + if getattr(local, "initialised", None) and not force: return if not sites_path: diff --git a/frappe/app.py b/frappe/app.py index 33648c77541..93ab4fd2e38 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -90,12 +90,18 @@ def application(request): rollback = after_request(rollback) finally: + # Important note: + # this function *must* always return a response, hence any exception thrown outside of + # try..catch block like this finally block needs to be handled appropriately. + if request.method in ("POST", "PUT") and frappe.db and rollback: frappe.db.rollback() - if getattr(frappe.local, "initialised", False): - for after_request_task in frappe.get_hooks("after_request"): - frappe.call(after_request_task, response=response, request=request) + try: + run_after_request_hooks(request, response) + except Exception as e: + # We can not handle exceptions safely here. + frappe.logger().error("Failed to run after request hook", exc_info=True) log_request(request, response) process_response(response) @@ -104,12 +110,20 @@ def application(request): return response +def run_after_request_hooks(request, response): + if not getattr(frappe.local, "initialised", False): + return + + for after_request_task in frappe.get_hooks("after_request"): + frappe.call(after_request_task, response=response, request=request) + + def init_request(request): frappe.local.request = request frappe.local.is_ajax = frappe.get_request_header("X-Requested-With") == "XMLHttpRequest" site = _site or request.headers.get("X-Frappe-Site-Name") or get_site_name(request.host) - frappe.init(site=site, sites_path=_sites_path) + frappe.init(site=site, sites_path=_sites_path, force=True) if not (frappe.local.conf and frappe.local.conf.db_name): # site does not exist diff --git a/frappe/core/doctype/language/language.json b/frappe/core/doctype/language/language.json index 9ab8f55f6bc..9268c1599bc 100644 --- a/frappe/core/doctype/language/language.json +++ b/frappe/core/doctype/language/language.json @@ -51,7 +51,7 @@ "icon": "fa fa-globe", "in_create": 1, "links": [], - "modified": "2021-10-18 14:02:06.818219", + "modified": "2023-04-13 13:48:38.127995", "modified_by": "Administrator", "module": "Core", "name": "Language", @@ -66,13 +66,8 @@ "write": 1 }, { - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Guest", - "share": 1 + "role": "All", + "read": 1 } ], "search_fields": "language_name", @@ -80,4 +75,4 @@ "sort_order": "DESC", "title_field": "language_name", "track_changes": 1 -} \ No newline at end of file +} diff --git a/frappe/core/doctype/prepared_report/prepared_report.py b/frappe/core/doctype/prepared_report/prepared_report.py index 3568741baad..d32db6cc788 100644 --- a/frappe/core/doctype/prepared_report/prepared_report.py +++ b/frappe/core/doctype/prepared_report/prepared_report.py @@ -11,6 +11,7 @@ from frappe.desk.form.load import get_attachments from frappe.desk.query_report import generate_report_result from frappe.model.document import Document +from frappe.monitor import add_data_to_monitor from frappe.utils import gzip_compress, gzip_decompress from frappe.utils.background_jobs import enqueue @@ -28,6 +29,8 @@ def run_background(prepared_report): instance = frappe.get_doc("Prepared Report", prepared_report) report = frappe.get_doc("Report", instance.ref_report_doctype) + add_data_to_monitor(report=instance.ref_report_doctype) + try: report.custom_columns = [] diff --git a/frappe/core/doctype/report/report.json b/frappe/core/doctype/report/report.json index 4b98f1a3ebf..30f6443de2e 100644 --- a/frappe/core/doctype/report/report.json +++ b/frappe/core/doctype/report/report.json @@ -157,11 +157,13 @@ { "collapsible": 1, "collapsible_depends_on": "filters", + "depends_on": "eval:doc.report_type != \"Custom Report\"", "fieldname": "filters_section", "fieldtype": "Section Break", "label": "Filters" }, { + "depends_on": "eval:doc.report_type != \"Custom Report\"", "fieldname": "filters", "fieldtype": "Table", "label": "Filters", @@ -170,11 +172,13 @@ { "collapsible": 1, "collapsible_depends_on": "columns", + "depends_on": "eval:doc.report_type != \"Custom Report\"", "fieldname": "columns_section", "fieldtype": "Section Break", "label": "Columns" }, { + "depends_on": "eval:doc.report_type != \"Custom Report\"", "fieldname": "columns", "fieldtype": "Table", "label": "Columns", @@ -191,7 +195,7 @@ "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2022-09-15 13:37:24.531848", + "modified": "2023-04-07 18:18:11.782178", "modified_by": "Administrator", "module": "Core", "name": "Report", diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index 47388a11404..8bc5176ff6a 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -186,7 +186,7 @@ def get_data( return columns, result - def run_query_report(self, filters, user, ignore_prepared_report=False): + def run_query_report(self, filters=None, user=None, ignore_prepared_report=False): columns, result = [], [] data = frappe.desk.query_report.run( self.name, filters=filters, user=user, ignore_prepared_report=ignore_prepared_report diff --git a/frappe/core/doctype/report/test_report.py b/frappe/core/doctype/report/test_report.py index 059fd70da3e..ae931ab50d0 100644 --- a/frappe/core/doctype/report/test_report.py +++ b/frappe/core/doctype/report/test_report.py @@ -119,11 +119,10 @@ def test_custom_report(self): } ] ), + json.dumps({"user": "Administrator", "doctype": "User"}), ) custom_report = frappe.get_doc("Report", custom_report_name) - columns, result = custom_report.run_query_report( - filters={"user": "Administrator", "doctype": "User"}, user=frappe.session.user - ) + columns, result = custom_report.run_query_report(user=frappe.session.user) self.assertListEqual(["email"], [column.get("fieldname") for column in columns]) admin_dict = frappe.core.utils.find(result, lambda d: d["name"] == "Administrator") diff --git a/frappe/desk/doctype/bulk_update/bulk_update.js b/frappe/desk/doctype/bulk_update/bulk_update.js index bb9cf2af51f..327223e8828 100644 --- a/frappe/desk/doctype/bulk_update/bulk_update.js +++ b/frappe/desk/doctype/bulk_update/bulk_update.js @@ -14,23 +14,18 @@ frappe.ui.form.on('Bulk Update', { frm.page.set_primary_action(__('Update'), function() { if (!frm.doc.update_value) { - frappe.throw(__('Field "value" is mandatory. Please specify value to be updated')); + frappe.throw( + __('Field "value" is mandatory. Please specify value to be updated') + ); } else { - frappe.call({ - method: 'frappe.desk.doctype.bulk_update.bulk_update.update', - args: { - doctype: frm.doc.document_type, - field: frm.doc.field, - value: frm.doc.update_value, - condition: frm.doc.condition, - limit: frm.doc.limit - }, - }).then(r => { + frm.call('bulk_update').then(r => { let failed = r.message; if (!failed) failed = []; if (failed.length && !r._server_messages) { - frappe.throw(__('Cannot update {0}', [failed.map(f => f.bold ? f.bold(): f).join(', ')])); + frappe.throw( + __('Cannot update {0}', [failed.map(f => (f.bold ? f.bold() : f)).join(", ")]) + ); } else { frappe.msgprint({ title: __('Success'), diff --git a/frappe/desk/doctype/bulk_update/bulk_update.py b/frappe/desk/doctype/bulk_update/bulk_update.py index 65b0366615a..8456010f4e6 100644 --- a/frappe/desk/doctype/bulk_update/bulk_update.py +++ b/frappe/desk/doctype/bulk_update/bulk_update.py @@ -11,26 +11,24 @@ class BulkUpdate(Document): - pass - - -@frappe.whitelist() -def update(doctype, field, value, condition="", limit=500): - if not limit or cint(limit) > 500: - limit = 500 - - if condition: - condition = " where " + condition - - if ";" in condition: - frappe.throw(_("; not allowed in condition")) - - docnames = frappe.db.sql_list( - """select name from `tab{0}`{1} limit 0, {2}""".format(doctype, condition, limit) - ) - data = {} - data[field] = value - return submit_cancel_or_update_docs(doctype, docnames, "update", data) + @frappe.whitelist() + def bulk_update(self): + self.check_permission("write") + limit = self.limit if self.limit and cint(self.limit) < 500 else 500 + + condition = "" + if self.condition: + if ";" in self.condition: + frappe.throw(_("; not allowed in condition")) + + condition = f" where {self.condition}" + + docnames = frappe.db.sql_list( + f"""select name from `tab{self.document_type}`{condition} limit {limit} offset 0""" + ) + return submit_cancel_or_update_docs( + self.document_type, docnames, "update", {self.field: self.update_value} + ) @frappe.whitelist() diff --git a/frappe/desk/form/save.py b/frappe/desk/form/save.py index 44f25e3dcf9..fcf975aad2e 100644 --- a/frappe/desk/form/save.py +++ b/frappe/desk/form/save.py @@ -7,6 +7,7 @@ import frappe from frappe.desk.form.load import run_onload +from frappe.monitor import add_data_to_monitor @frappe.whitelist() @@ -27,6 +28,8 @@ def savedocs(doc, action): run_onload(doc) send_updated_docs(doc) + add_data_to_monitor(doctype=doc.doctype, action=action) + frappe.msgprint(frappe._("Saved"), indicator="green", alert=True) diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index aa6293c5865..3731343756f 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -15,6 +15,7 @@ from frappe.core.utils import ljust_list from frappe.model.utils import render_include from frappe.modules import get_module_path, scrub +from frappe.monitor import add_data_to_monitor from frappe.permissions import get_role_permissions from frappe.utils import ( cint, @@ -24,12 +25,14 @@ get_html_format, get_url_to_form, gzip_decompress, + sbool, ) def get_report_doc(report_name): doc = frappe.get_doc("Report", report_name) doc.custom_columns = [] + doc.custom_filters = [] if doc.report_type == "Custom Report": custom_report_doc = doc @@ -39,7 +42,8 @@ def get_report_doc(report_name): if custom_report_doc.json: data = json.loads(custom_report_doc.json) if data: - doc.custom_columns = data["columns"] + doc.custom_columns = data.get("columns") + doc.custom_filters = data.get("filters") doc.is_custom_report = True if not doc.is_permitted(): @@ -220,6 +224,7 @@ def run( custom_columns=None, is_tree=False, parent_field=None, + are_default_filters=True, ): report = get_report_doc(report_name) if not user: @@ -232,6 +237,9 @@ def run( result = None + if sbool(are_default_filters) and report.custom_filters: + filters = report.custom_filters + if ( report.prepared_report and not report.disable_prepared_report @@ -249,9 +257,13 @@ def run( result = get_prepared_report_result(report, filters, dn, user) else: result = generate_report_result(report, filters, user, custom_columns, is_tree, parent_field) + add_data_to_monitor(report=report.reference_report or report.name) result["add_total_row"] = report.add_total_row and not result.get("skip_total_row", False) + if sbool(are_default_filters) and report.custom_filters: + result["custom_filters"] = report.custom_filters + return result @@ -535,7 +547,7 @@ def get_data_for_custom_report(columns): @frappe.whitelist() -def save_report(reference_report, report_name, columns): +def save_report(reference_report, report_name, columns, filters): report_doc = get_report_doc(reference_report) docname = frappe.db.exists( @@ -551,6 +563,7 @@ def save_report(reference_report, report_name, columns): report = frappe.get_doc("Report", docname) existing_jd = json.loads(report.json) existing_jd["columns"] = json.loads(columns) + existing_jd["filters"] = json.loads(filters) report.update({"json": json.dumps(existing_jd, separators=(",", ":"))}) report.save() frappe.msgprint(_("Report updated successfully")) @@ -561,7 +574,7 @@ def save_report(reference_report, report_name, columns): { "doctype": "Report", "report_name": report_name, - "json": f'{{"columns":{columns}}}', + "json": f'{{"columns":{columns},"filters":{filters}}}', "ref_doctype": report_doc.ref_doctype, "is_standard": "No", "report_type": "Custom Report", diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index 63d0c5118b4..d9c68932165 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -683,7 +683,7 @@ def get_filters_cond( for f in filters: if isinstance(f[1], string_types) and f[1][0] == "!": flt.append([doctype, f[0], "!=", f[1][1:]]) - elif isinstance(f[1], (list, tuple)) and f[1][0] in ( + elif isinstance(f[1], (list, tuple)) and f[1][0].lower() in ( ">", "<", ">=", diff --git a/frappe/integrations/doctype/webhook/webhook.py b/frappe/integrations/doctype/webhook/webhook.py index 5fd7bb33d19..ad8c250bc4b 100644 --- a/frappe/integrations/doctype/webhook/webhook.py +++ b/frappe/integrations/doctype/webhook/webhook.py @@ -86,6 +86,7 @@ def enqueue_webhook(doc, webhook): webhook = frappe.get_doc("Webhook", webhook.get("name")) headers = get_webhook_headers(doc, webhook) data = get_webhook_data(doc, webhook) + r = None for i in range(3): try: diff --git a/frappe/monitor.py b/frappe/monitor.py index d8d507d6b3f..14da38e467a 100644 --- a/frappe/monitor.py +++ b/frappe/monitor.py @@ -28,6 +28,13 @@ def stop(response=None): frappe.local.monitor.dump(response) +def add_data_to_monitor(**kwargs) -> None: + """Add additional custom key-value pairs along with monitor log. + Note: Key-value pairs should be simple JSON exportable types.""" + if hasattr(frappe.local, "monitor"): + frappe.local.monitor.add_custom_data(**kwargs) + + def log_file(): return os.path.join(frappe.utils.get_bench_path(), "logs", "monitor.json.log") @@ -72,6 +79,10 @@ def collect_job_meta(self, method, kwargs): waitdiff = self.data.timestamp - job.enqueued_at self.data.job.wait = int(waitdiff.total_seconds() * 1000000) + def add_custom_data(self, **kwargs): + if self.data: + self.data.update(kwargs) + def dump(self, response=None): try: timediff = datetime.utcnow() - self.data.timestamp @@ -98,7 +109,7 @@ def dump(self, response=None): def store(self): if frappe.cache().llen(MONITOR_REDIS_KEY) > MONITOR_MAX_ENTRIES: frappe.cache().ltrim(MONITOR_REDIS_KEY, 1, -1) - serialized = json.dumps(self.data, sort_keys=True, default=str) + serialized = json.dumps(self.data, sort_keys=True, default=str, separators=(",", ":")) frappe.cache().rpush(MONITOR_REDIS_KEY, serialized) diff --git a/frappe/oauth.py b/frappe/oauth.py index 0b2770448fc..e009bd59299 100644 --- a/frappe/oauth.py +++ b/frappe/oauth.py @@ -3,7 +3,7 @@ import hashlib import re from http import cookies -from urllib.parse import unquote, urlparse +from urllib.parse import unquote, urljoin, urlparse import jwt import pytz @@ -573,7 +573,7 @@ def get_userinfo(user): if frappe.utils.validate_url(user.user_image, valid_schemes=valid_url_schemes): picture = user.user_image else: - picture = frappe_server_url + "/" + user.user_image + picture = urljoin(frappe_server_url, user.user_image) userinfo = frappe._dict( { diff --git a/frappe/public/icons/timeless/icons.svg b/frappe/public/icons/timeless/icons.svg index a84aebc7e4c..9bcac4a01fb 100644 --- a/frappe/public/icons/timeless/icons.svg +++ b/frappe/public/icons/timeless/icons.svg @@ -167,8 +167,13 @@ - - + + + + + + + diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index 11c84eb818f..476fa574aa4 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -958,7 +958,7 @@ export default class GridRow { this.wrapper.find('.grid-delete-row') .toggle(!(this.grid.df && this.grid.df.cannot_delete_rows)); - frappe.dom.freeze("", "dark"); + frappe.dom.freeze("", "dark grid-form"); if (cur_frm) cur_frm.cur_grid = this; this.wrapper.addClass("grid-row-open"); if (!frappe.dom.is_element_in_viewport(this.wrapper) diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index cda687db32b..46f69409d82 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -809,23 +809,31 @@ class FilterArea { make_filter_list() { $(`
- -
` - ).appendTo(this.$filter_list_wrapper); + + + + + `).appendTo(this.$filter_list_wrapper); - this.filter_button = this.$filter_list_wrapper.find('.filter-button'); + this.filter_button = this.$filter_list_wrapper.find(".filter-button"); + this.filter_x_button = this.$filter_list_wrapper.find(".filter-x-button"); this.filter_list = new frappe.ui.FilterGroup({ base_list: this.list_view, parent: this.$filter_list_wrapper, doctype: this.list_view.doctype, filter_button: this.filter_button, + filter_x_button: this.filter_x_button, default_filters: [], on_change: () => this.refresh_list_view(), }); diff --git a/frappe/public/js/frappe/ui/filters/filter_list.js b/frappe/public/js/frappe/ui/filters/filter_list.js index 0af24e4a3a0..97d78ff3af4 100644 --- a/frappe/public/js/frappe/ui/filters/filter_list.js +++ b/frappe/public/js/frappe/ui/filters/filter_list.js @@ -14,9 +14,29 @@ frappe.ui.FilterGroup = class { make_popover() { this.init_filter_popover(); + this.set_clear_all_filters_event(); this.set_popover_events(); } + set_clear_all_filters_event() { + this.filter_x_button.on("click", () => { + this.toggle_empty_filters(true); + if (typeof this.base_list !== "undefined") { + // It's a list view. Clear all the filters, also the ones in the + // FilterArea outside this FilterGroup + this.base_list.filter_area.clear(); + } else { + // Not a list view, just clear the filters in this FilterGroup + this.clear_filters(); + } + this.update_filter_button(); + }); + } + + hide_popover() { + this.filter_button.popover("hide"); + } + init_filter_popover() { this.filter_button.popover({ content: this.get_filter_area_template(), @@ -54,7 +74,7 @@ frappe.ui.FilterGroup = class { && !$(e.target).is(this.filter_button) && !in_datepicker ) { - this.wrapper && this.filter_button.popover('hide'); + this.wrapper && this.hide_popover(); } } }); @@ -83,9 +103,9 @@ frappe.ui.FilterGroup = class { }); // REDESIGN-TODO: (Temporary) Review and find best solution for this - frappe.router.on('change', () => { - if (this.wrapper && this.wrapper.is(':visible')) { - this.filter_button.popover('hide'); + frappe.router.on("change", () => { + if (this.wrapper && this.wrapper.is(":visible")) { + this.hide_popover(); } }); } @@ -132,11 +152,10 @@ frappe.ui.FilterGroup = class { this.toggle_empty_filters(true); this.clear_filters(); this.on_change(); + this.hide_popover(); }); - this.wrapper.find('.apply-filters').on('click', () => { - this.filter_button.popover('hide'); - }); + this.wrapper.find(".apply-filters").on("click", () => this.hide_popover()); } add_filters(filters) { diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index c8e44d7d1f2..78cb0c70bf0 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -502,7 +502,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { this.reset_report_view(); } else if (!this._no_refresh) { - this.refresh(); + this.refresh(true); } } }; @@ -554,10 +554,25 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { this.page.clear_fields(); } - refresh() { + refresh(have_filters_changed) { this.toggle_message(true); this.toggle_report(false); let filters = this.get_filter_values(true); + + // for custom reports, + // are_default_filters is true if the filters haven't been modified and for all filters, + // the filter value is the default value or there's no default value for the filter and the current value is empty. + // are_default_filters is false otherwise. + + let are_default_filters = this.filters + .map((filter) => { + return ( + !have_filters_changed && + (filter.default === filter.value || (!filter.default && !filter.value)) + ); + }) + .every((res) => res === true); + this.show_loading_screen(); // only one refresh at a time @@ -579,7 +594,8 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { report_name: this.report_name, filters: filters, is_tree: this.report_settings.tree, - parent_field: this.report_settings.parent_field + parent_field: this.report_settings.parent_field, + are_default_filters: are_default_filters, }, callback: resolve, always: () => this.page.btn_secondary.prop('disabled', false) @@ -591,6 +607,11 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { this.execution_time = data.execution_time || 0.1; + if (data.custom_filters) { + this.set_filters(data.custom_filters); + this.previous_filters = data.custom_filters; + } + if (data.prepared_report) { this.prepared_report = true; this.prepared_report_document = data.doc @@ -1619,7 +1640,8 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { args: { reference_report: this.report_name, report_name: values.report_name, - columns: this.get_visible_columns() + columns: this.get_visible_columns(), + filters: this.get_filter_values(), }, callback: function(r) { this.show_save = false; diff --git a/frappe/public/scss/common/css_variables.scss b/frappe/public/scss/common/css_variables.scss index c4e019fd295..a1aa8ec6a58 100644 --- a/frappe/public/scss/common/css_variables.scss +++ b/frappe/public/scss/common/css_variables.scss @@ -236,6 +236,8 @@ --highlight-color: var(--gray-50); --yellow-highlight-color: var(--yellow-50); + --btn-group-border-color: var(--gray-300); + // code block --code-block-bg: var(--gray-900); --code-block-text: var(--gray-400); diff --git a/frappe/public/scss/common/grid.scss b/frappe/public/scss/common/grid.scss index c8511077788..cd10703af36 100644 --- a/frappe/public/scss/common/grid.scss +++ b/frappe/public/scss/common/grid.scss @@ -286,7 +286,7 @@ overflow: hidden; height: 0; opacity: 0; - z-index: 1051; + z-index: 1021; border-radius: var(--border-radius-md); @include base-grid(); @@ -327,6 +327,10 @@ } } +#freeze.grid-form { + z-index: 1020; +} + .recorder-form-in-grid { z-index: 0; @include base-grid(); diff --git a/frappe/public/scss/desk/dark.scss b/frappe/public/scss/desk/dark.scss index 14fa0814f3b..2bc3d41da11 100644 --- a/frappe/public/scss/desk/dark.scss +++ b/frappe/public/scss/desk/dark.scss @@ -95,6 +95,8 @@ --highlight-color: var(--gray-700); --yellow-highlight-color: var(--yellow-700); + --btn-group-border-color: var(--gray-800); + // input --input-disabled-bg: none; diff --git a/frappe/public/scss/desk/filters.scss b/frappe/public/scss/desk/filters.scss index d7a7ffbee76..83f4a10b03f 100644 --- a/frappe/public/scss/desk/filters.scss +++ b/frappe/public/scss/desk/filters.scss @@ -1,7 +1,5 @@ .filter-icon.active { - use { - stroke: var(--blue-500); - } + --icon-stroke: var(--text-on-blue); } .filter-popover { diff --git a/frappe/public/scss/desk/global.scss b/frappe/public/scss/desk/global.scss index 9bcdaff60d3..aec849a474b 100644 --- a/frappe/public/scss/desk/global.scss +++ b/frappe/public/scss/desk/global.scss @@ -230,6 +230,21 @@ h2 { font-size: var(--text-md); } +.btn-group { + .btn { + box-shadow: none; + outline: 1px solid var(--btn-group-border-color); + + &:not(:first-child) { + margin-left: 1px; + } + + &:focus { + outline: 2px solid var(--dark-border-color); + } + } +} + .btn-xs { @extend .btn-sm; line-height: 1.2; @@ -414,7 +429,7 @@ kbd { // freeze backdrop text #freeze { - z-index: 1050; + z-index: 1055; bottom: 0; opacity: 0; background-color: var(--bg-color); diff --git a/frappe/public/scss/desk/list.scss b/frappe/public/scss/desk/list.scss index 791192fd9cd..608945f5a3a 100644 --- a/frappe/public/scss/desk/list.scss +++ b/frappe/public/scss/desk/list.scss @@ -180,27 +180,11 @@ $level-margin-right: 8px; .list-paging-area, .footnote-area { border-top: 1px solid var(--border-color); - .btn-group { - box-shadow: var(--drop-shadow); - border-radius: var(--border-radius-md); - - &> .btn:nth-child(2) { - border-left: none; - border-right: none; - } - - .btn-paging { - box-shadow: none; - margin-left: 0px !important; - border: 1px solid var(--dark-border-color); - - &.btn-info { - background-color: var(--gray-400); - border-color: var(--gray-400); - color: var(--white); - font-weight: var(--text-bold); - } - } + .btn-group .btn-paging.btn-info { + background-color: var(--gray-600); + border-color: var(--gray-600); + color: var(--white); + font-weight: var(--text-bold); } } @@ -385,13 +369,14 @@ input.list-check-all { padding: 0 var(--padding-xs); } - .filter-button { - margin: 5px; - // padding: 4px 8px; + .filter-selector .btn-group { + margin: var(--margin-xs); } .filter-button.btn-primary-light { - color: var(--blue-500); + color: var(--text-on-blue); + outline: 1px solid var(--bg-dark-blue); + z-index: 1; } .sort-selector { diff --git a/frappe/workflow/doctype/workflow_action_master/workflow_action_master.json b/frappe/workflow/doctype/workflow_action_master/workflow_action_master.json index 4931ac5b13d..98fb0a0ae8c 100644 --- a/frappe/workflow/doctype/workflow_action_master/workflow_action_master.json +++ b/frappe/workflow/doctype/workflow_action_master/workflow_action_master.json @@ -1,89 +1,48 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "field:workflow_action_name", - "beta": 0, - "creation": "2012-12-28 10:49:56", - "custom": 0, - "description": "Workflow Action Master", - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 0, + "actions": [], + "allow_rename": 1, + "autoname": "field:workflow_action_name", + "creation": "2012-12-28 10:49:56", + "description": "Workflow Action Master", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "workflow_action_name" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "workflow_action_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Workflow Action Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "workflow_action_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Workflow Action Name", + "reqd": 1, + "unique": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-flag", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-05-18 10:31:09.040701", - "modified_by": "Administrator", - "module": "Workflow", - "name": "Workflow Action Master", - "owner": "Administrator", + ], + "icon": "fa fa-flag", + "idx": 1, + "links": [], + "modified": "2023-04-14 15:11:21.447781", + "modified_by": "Administrator", + "module": "Workflow", + "name": "Workflow Action Master", + "naming_rule": "By fieldname", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "track_changes": 1 } \ No newline at end of file