From dd14ac5f93dad9f931f61f0914718b34730692d9 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 8 Jun 2022 11:37:11 +0530 Subject: [PATCH 01/10] feat(minor): add custom formatters for text type controls --- frappe/public/js/frappe/doctype/index.js | 20 +++++++++++++ frappe/public/js/frappe/form/dashboard.js | 2 +- frappe/public/js/frappe/form/formatters.js | 28 +++++++++++++++---- .../js/frappe/widgets/onboarding_widget.js | 18 ++++++------ frappe/public/scss/common/grid.scss | 2 +- frappe/public/scss/desk/desktop.scss | 4 +-- frappe/public/scss/login.bundle.scss | 3 +- 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/frappe/public/js/frappe/doctype/index.js b/frappe/public/js/frappe/doctype/index.js index 09f020f370..e31e2dab7a 100644 --- a/frappe/public/js/frappe/doctype/index.js +++ b/frappe/public/js/frappe/doctype/index.js @@ -5,6 +5,26 @@ frappe.provide("frappe.model"); apply to both DocType form and customize form. */ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form.Controller { + setup() { + // setup formatters for fieldtype + frappe.meta.docfield_map['DocField'].fieldtype.formatter = (value) => { + const prefix = { + 'Tab Break': '🔴', + 'Section Break': '🔵', + 'Column Break': '🟡', + 'Check': '☑', + 'Link': '🔗', + 'Currency': '💲', + 'Date': '📆', + 'Table': '🗂' + } + if (prefix[value]) { + value = prefix[value] + ' ' + value; + } + return value; + } + } + max_attachments() { if (!this.frm.doc.max_attachments) { return; diff --git a/frappe/public/js/frappe/form/dashboard.js b/frappe/public/js/frappe/form/dashboard.js index 0731bdf8fb..c057903a63 100644 --- a/frappe/public/js/frappe/form/dashboard.js +++ b/frappe/public/js/frappe/form/dashboard.js @@ -19,7 +19,7 @@ frappe.ui.form.Dashboard = class FormDashboard { }); this.heatmap_area = this.make_section({ - label: __("Overview"), + label: __("Activity"), css_class: 'form-heatmap', hidden: 1, collapsible: 1, diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index 2b0f996661..a5425eeb9f 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -15,17 +15,35 @@ frappe.form.formatters = { return "
" + value + "
"; } }, + _apply_custom_formatter: function(value, df) { + /* you can add an arbitrary formatter in df.formatter + example: + frappe.meta.docfield_map[df.parent][df.fieldname].formatter = (value) => { + if (value==='Test') return '😜'; + } + */ + + if (df) { + const std_df = frappe.meta.docfield_map[df.parent] && frappe.meta.docfield_map[df.parent][df.fieldname]; + if (std_df && std_df.formatter && typeof std_df.formatter==='function') { + value = std_df.formatter(value); + } + } + return value; + }, Data: function(value, df) { if (df && df.options == "URL") { return `${value}`; } - return value==null ? "" : value; + value = value==null ? "" : value + + return frappe.form.formatters._apply_custom_formatter(value, df); }, - Autocomplete: function(value) { - return __(frappe.form.formatters["Data"](value)); + Autocomplete: function(value, df) { + return __(frappe.form.formatters["Data"](value, df)); }, - Select: function(value) { - return __(frappe.form.formatters["Data"](value)); + Select: function(value, df) { + return __(frappe.form.formatters["Data"](value, df)); }, Float: function(value, docfield, options, doc) { // don't allow 0 precision for Floats, hence or'ing with null diff --git a/frappe/public/js/frappe/widgets/onboarding_widget.js b/frappe/public/js/frappe/widgets/onboarding_widget.js index 7d379d4531..128d7e691a 100644 --- a/frappe/public/js/frappe/widgets/onboarding_widget.js +++ b/frappe/public/js/frappe/widgets/onboarding_widget.js @@ -222,7 +222,7 @@ export default class OnboardingWidget extends Widget { const on_finish = () => { let msg_dialog = frappe.msgprint({ message: __("Let's take you back to onboarding"), - title: __("Great Job"), + title: __("Onboarding complete"), primary_action: { action: () => { frappe.set_route(current_route).then(() => { @@ -265,7 +265,7 @@ export default class OnboardingWidget extends Widget { if (success) { args.message = __("Let's take you back to onboarding"); - args.title = __("Looks Great"); + args.title = __("Action Complete"); args.primary_action = { action: () => { frappe.set_route(current_route).then(() => { @@ -278,7 +278,7 @@ export default class OnboardingWidget extends Widget { custom_onhide = () => args.primary_action.action(); } else { args.message = __("Looks like you didn't change the value"); - args.title = __("Oops"); + args.title = __("Try Again"); args.secondary_action = { action: () => frappe.set_route(current_route), label: __("Go Back"), @@ -314,7 +314,7 @@ export default class OnboardingWidget extends Widget { const on_finish = () => { frappe.msgprint({ message: __("Awesome, now try making an entry yourself"), - title: __("Great"), + title: __("Document Saved"), primary_action: { action: () => { frappe.set_route(current_route).then(() => { @@ -337,8 +337,8 @@ export default class OnboardingWidget extends Widget { let callback = () => { frappe.msgprint({ - message: __("You're doing great, let's take you back to the onboarding page."), - title: __("Good Work 🎉"), + message: __("Let's take you back to onboarding"), + title: __("Action Complete"), primary_action: { action: () => { frappe.set_route(current_route).then(() => { @@ -358,7 +358,7 @@ export default class OnboardingWidget extends Widget { frappe.route_hooks.after_save = () => { frappe.msgprint({ message: __("Submit this document to complete this step."), - title: __("Great") + title: __("Document Saved") }); }; frappe.route_hooks.after_submit = callback; @@ -377,7 +377,7 @@ export default class OnboardingWidget extends Widget { if (frappe.get_route_str() != current_route) { let success_dialog = frappe.msgprint({ message: __("Let's take you back to onboarding"), - title: __("Looks Great"), + title: __("Document Saved"), primary_action: { action: () => { success_dialog.hide(); @@ -397,7 +397,7 @@ export default class OnboardingWidget extends Widget { } else { frappe.msgprint({ message: __("Let us continue with the onboarding"), - title: __("Looks Great") + title: __("Document Saved") }); this.mark_complete(step); } diff --git a/frappe/public/scss/common/grid.scss b/frappe/public/scss/common/grid.scss index d1f89abbcd..07ab6d75a9 100644 --- a/frappe/public/scss/common/grid.scss +++ b/frappe/public/scss/common/grid.scss @@ -201,7 +201,7 @@ } .link-btn { - top: 8px; + top: 2px; } .form-control:focus { diff --git a/frappe/public/scss/desk/desktop.scss b/frappe/public/scss/desk/desktop.scss index 8be8abed35..c0fef60162 100644 --- a/frappe/public/scss/desk/desktop.scss +++ b/frappe/public/scss/desk/desktop.scss @@ -421,8 +421,8 @@ body { display: none; } - i { - color: var(--green-600); + .icon { + stroke: var(--white); } span { diff --git a/frappe/public/scss/login.bundle.scss b/frappe/public/scss/login.bundle.scss index 8d0a32846f..488dd4106e 100644 --- a/frappe/public/scss/login.bundle.scss +++ b/frappe/public/scss/login.bundle.scss @@ -16,7 +16,7 @@ body { .for-forgot, .for-signup, .for-email-login { - padding: max(15vh, 70px) 0; + padding: max(10vh, 60px) 0; @include media-breakpoint-up(sm) { .page-card { @@ -177,6 +177,7 @@ body { } h4 { + margin-top: 1rem; font-size: var(--text-xl); color: var(--text-color); } From 9bbc592ed4d723a455909dd0161bb058bffc628a Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 8 Jun 2022 12:00:43 +0530 Subject: [PATCH 02/10] chore: add semis --- frappe/public/js/frappe/doctype/index.js | 2 +- frappe/public/js/frappe/form/formatters.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/doctype/index.js b/frappe/public/js/frappe/doctype/index.js index e31e2dab7a..c3618e6fd8 100644 --- a/frappe/public/js/frappe/doctype/index.js +++ b/frappe/public/js/frappe/doctype/index.js @@ -17,7 +17,7 @@ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form. 'Currency': '💲', 'Date': '📆', 'Table': '🗂' - } + }; if (prefix[value]) { value = prefix[value] + ' ' + value; } diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index a5425eeb9f..70b637671a 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -35,7 +35,7 @@ frappe.form.formatters = { if (df && df.options == "URL") { return `${value}`; } - value = value==null ? "" : value + value = value==null ? "" : value; return frappe.form.formatters._apply_custom_formatter(value, df); }, From cc10479e1123dbff0e42ce9bd99789edd3dfd410 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 8 Jun 2022 12:54:17 +0530 Subject: [PATCH 03/10] fix(minor): fix for customize form --- frappe/public/js/frappe/doctype/index.js | 5 +++-- frappe/public/js/frappe/form/formatters.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/doctype/index.js b/frappe/public/js/frappe/doctype/index.js index c3618e6fd8..f8b342217f 100644 --- a/frappe/public/js/frappe/doctype/index.js +++ b/frappe/public/js/frappe/doctype/index.js @@ -6,8 +6,9 @@ frappe.provide("frappe.model"); */ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form.Controller { setup() { + console.log(this.frm.doctype); // setup formatters for fieldtype - frappe.meta.docfield_map['DocField'].fieldtype.formatter = (value) => { + frappe.meta.docfield_map[this.frm.doctype==='DocType' ? 'DocField' : 'Customize Form Field'].fieldtype.formatter = (value) => { const prefix = { 'Tab Break': '🔴', 'Section Break': '🔵', @@ -22,7 +23,7 @@ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form. value = prefix[value] + ' ' + value; } return value; - } + }; } max_attachments() { diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index 70b637671a..15bbd53a1b 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -16,7 +16,7 @@ frappe.form.formatters = { } }, _apply_custom_formatter: function(value, df) { - /* you can add an arbitrary formatter in df.formatter + /* you can add a custom formatter in df.formatter example: frappe.meta.docfield_map[df.parent][df.fieldname].formatter = (value) => { if (value==='Test') return '😜'; From 17d537517b00baaa3fb8faf8a040aae00eb744d0 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 8 Jun 2022 13:04:58 +0530 Subject: [PATCH 04/10] chore: remove console.log --- frappe/public/js/frappe/doctype/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/doctype/index.js b/frappe/public/js/frappe/doctype/index.js index f8b342217f..a8b84d3ff0 100644 --- a/frappe/public/js/frappe/doctype/index.js +++ b/frappe/public/js/frappe/doctype/index.js @@ -6,7 +6,6 @@ frappe.provide("frappe.model"); */ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form.Controller { setup() { - console.log(this.frm.doctype); // setup formatters for fieldtype frappe.meta.docfield_map[this.frm.doctype==='DocType' ? 'DocField' : 'Customize Form Field'].fieldtype.formatter = (value) => { const prefix = { From 378b44a382741b4dc9b58e7867431a562ecb35f3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 8 Jun 2022 16:36:19 +0530 Subject: [PATCH 05/10] fix(minor): fix flaky test --- cypress/integration/customize_form.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/integration/customize_form.js b/cypress/integration/customize_form.js index 70615085c3..3857d7ccd8 100644 --- a/cypress/integration/customize_form.js +++ b/cypress/integration/customize_form.js @@ -1,5 +1,6 @@ context('Customize Form', () => { before(() => { + cy.login(); cy.visit('/app/customize-form'); }); it('Changing to naming rule should update autoname', () => { @@ -19,4 +20,4 @@ context('Customize Form', () => { cy.get_field("autoname", "Data").should("have.value", value); }); }); -}); \ No newline at end of file +}); From 3ceafc42fd7dbc42e2f79563a7af24cb5894c506 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 9 Jun 2022 09:14:47 +0530 Subject: [PATCH 06/10] fix(minor): fewer emojis --- frappe/public/js/frappe/doctype/index.js | 5 ----- frappe/public/js/frappe/form/formatters.js | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/frappe/public/js/frappe/doctype/index.js b/frappe/public/js/frappe/doctype/index.js index a8b84d3ff0..d8ffa1097a 100644 --- a/frappe/public/js/frappe/doctype/index.js +++ b/frappe/public/js/frappe/doctype/index.js @@ -12,11 +12,6 @@ frappe.model.DocTypeController = class DocTypeController extends frappe.ui.form. 'Tab Break': '🔴', 'Section Break': '🔵', 'Column Break': '🟡', - 'Check': '☑', - 'Link': '🔗', - 'Currency': '💲', - 'Date': '📆', - 'Table': '🗂' }; if (prefix[value]) { value = prefix[value] + ' ' + value; diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index 15bbd53a1b..955a956b90 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -218,7 +218,7 @@ frappe.form.formatters = { } } - return frappe.form.formatters.Data(value); + return frappe.form.formatters.Data(value, df); }, Time: function(value) { if (value) { From 65f5910dc39706cd9a86424b9f0aca1889874da3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 9 Jun 2022 10:31:08 +0530 Subject: [PATCH 07/10] fix(minor): missing parameter --- frappe/public/js/frappe/form/formatters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/formatters.js b/frappe/public/js/frappe/form/formatters.js index 955a956b90..3bf36c86af 100644 --- a/frappe/public/js/frappe/form/formatters.js +++ b/frappe/public/js/frappe/form/formatters.js @@ -201,7 +201,7 @@ frappe.form.formatters = { return ""; } }, - Text: function(value) { + Text: function(value, df) { if(value) { var tags = [" Date: Thu, 9 Jun 2022 12:34:09 +0530 Subject: [PATCH 08/10] fix(minor): added UI test --- cypress/integration/control_data.js | 16 +++++++++++----- cypress/support/commands.js | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cypress/integration/control_data.js b/cypress/integration/control_data.js index 01f9168667..78cece627b 100644 --- a/cypress/integration/control_data.js +++ b/cypress/integration/control_data.js @@ -34,6 +34,12 @@ context('Data Control', () => { }); }); }); + + it('check custom formatters', () => { + cy.visit(`/app/doctype/User`); + cy.get('[data-fieldname="fields"] .grid-row[data-idx="2"] [data-fieldname="fieldtype"] .static-area').should('have.text', '🔵 Section Break'); + }); + it('Verifying data control by inputting different patterns for "Name" field', () => { cy.new_form('Test Data Control'); @@ -54,7 +60,7 @@ context('Data Control', () => { //Checking if the border color of the field changes to red cy.get('.frappe-control[data-fieldname="name1"]').should('have.class', 'has-error'); - cy.findByRole('button', {name: 'Save'}).click(); + cy.save(); //Checking for the error message cy.get('.modal-title').should('have.text', 'Message'); @@ -64,7 +70,7 @@ context('Data Control', () => { cy.get_field('name1', 'Data').clear({force: true}); cy.fill_field('name1', 'Komal{}/!', 'Data'); cy.get('.frappe-control[data-fieldname="name1"]').should('have.class', 'has-error'); - cy.findByRole('button', {name: 'Save'}).click(); + cy.save(); cy.get('.modal-title').should('have.text', 'Message'); cy.get('.msgprint').should('have.text', 'Komal{}/! is not a valid Name'); cy.hide_dialog(); @@ -76,14 +82,14 @@ context('Data Control', () => { cy.get_field('email', 'Data').clear({force: true}); cy.fill_field('email', 'komal', 'Data'); cy.get('.frappe-control[data-fieldname="email"]').should('have.class', 'has-error'); - cy.findByRole('button', {name: 'Save'}).click(); + cy.save(); cy.get('.modal-title').should('have.text', 'Message'); cy.get('.msgprint').should('have.text', 'komal is not a valid Email Address'); cy.hide_dialog(); cy.get_field('email', 'Data').clear({force: true}); cy.fill_field('email', 'komal@test', 'Data'); cy.get('.frappe-control[data-fieldname="email"]').should('have.class', 'has-error'); - cy.findByRole('button', {name: 'Save'}).click(); + cy.save(); cy.get('.modal-title').should('have.text', 'Message'); cy.get('.msgprint').should('have.text', 'komal@test is not a valid Email Address'); cy.hide_dialog(); @@ -125,4 +131,4 @@ context('Data Control', () => { cy.get('.actions-btn-group > .dropdown-menu [data-label="Delete"]').click(); cy.click_modal_primary_button('Yes'); }); -}); \ No newline at end of file +}); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 6398018e10..d3b13127cb 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -27,6 +27,7 @@ import "cypress-real-events/support"; // // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }); + Cypress.Commands.add('login', (email, password) => { if (!email) { email = 'Administrator'; @@ -139,6 +140,10 @@ Cypress.Commands.add('create_records', doc => { .then(r => r.message); }); +Cypress.Commands.add('open_doc', (doctype, name) => { + cy.visit(`/app/${doctype}/${name}`) +}); + Cypress.Commands.add('set_value', (doctype, name, obj) => { return cy.call('frappe.client.set_value', { doctype, @@ -265,9 +270,15 @@ Cypress.Commands.add('get_open_dialog', () => { return cy.get('.modal:visible').last(); }); +Cypress.Commands.add('save', () => { + cy.intercept('/api').as('api'); + cy.get(`button[data-label="Save"]:visible`).click({scrollBehavior: false, force:true}); + cy.wait('@api'); +}); + Cypress.Commands.add('hide_dialog', () => { - cy.wait(300); - cy.get_open_dialog().find('.btn-modal-close').click(); + cy.wait(400); + cy.get_open_dialog().find('.btn-modal-close').click({force:true}); cy.get('.modal:visible').should('not.exist'); }); From da9ac52ffb3a32612da4e640310239192c0b7c2d Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 9 Jun 2022 12:44:47 +0530 Subject: [PATCH 09/10] fix(minor): lint --- cypress/support/commands.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index d3b13127cb..6b4348df7c 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -140,10 +140,6 @@ Cypress.Commands.add('create_records', doc => { .then(r => r.message); }); -Cypress.Commands.add('open_doc', (doctype, name) => { - cy.visit(`/app/${doctype}/${name}`) -}); - Cypress.Commands.add('set_value', (doctype, name, obj) => { return cy.call('frappe.client.set_value', { doctype, @@ -272,13 +268,13 @@ Cypress.Commands.add('get_open_dialog', () => { Cypress.Commands.add('save', () => { cy.intercept('/api').as('api'); - cy.get(`button[data-label="Save"]:visible`).click({scrollBehavior: false, force:true}); + cy.get(`button[data-label="Save"]:visible`).click({scrollBehavior: false, force: true}); cy.wait('@api'); }); Cypress.Commands.add('hide_dialog', () => { cy.wait(400); - cy.get_open_dialog().find('.btn-modal-close').click({force:true}); + cy.get_open_dialog().find('.btn-modal-close').click({force: true}); cy.get('.modal:visible').should('not.exist'); }); From e66cd830fb1db25e78cfc061fb2ed9001336a9c1 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 9 Jun 2022 14:17:43 +0530 Subject: [PATCH 10/10] fix(minor): test + tabs --- cypress/support/commands.js | 2 +- frappe/public/js/frappe/form/tab.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 6b4348df7c..c64f0bf469 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -274,7 +274,7 @@ Cypress.Commands.add('save', () => { Cypress.Commands.add('hide_dialog', () => { cy.wait(400); - cy.get_open_dialog().find('.btn-modal-close').click({force: true}); + cy.get('.btn-modal-close:visible').click({force: true}); cy.get('.modal:visible').should('not.exist'); }); diff --git a/frappe/public/js/frappe/form/tab.js b/frappe/public/js/frappe/form/tab.js index 0e740ce49c..3fad807f06 100644 --- a/frappe/public/js/frappe/form/tab.js +++ b/frappe/public/js/frappe/form/tab.js @@ -3,7 +3,7 @@ export default class Tab { this.parent = parent; this.df = df || {}; this.frm = frm; - this.doctype = 'User'; + this.doctype = this.frm.doctype; this.label = this.df && this.df.label; this.tabs_list = tabs_list; this.tabs_content = tabs_content;