diff --git a/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js b/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js index 601f17c92453bb89ce00375dd83b125e077f49fd..87a6401d13077464830aa29ebacb6dc8ff7d181d 100644 --- a/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js +++ b/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js @@ -19,6 +19,7 @@ import { getLinkCardDetails, getTextCardDetails, modal, + multiAutocompleteInput, openStaticEmbeddingModal, popover, queryBuilderHeader, @@ -133,6 +134,15 @@ const DASHBOARD_FILTER_NUMBER = createMockActionParameter({ sectionId: "number", }); +const DASHBOARD_FILTER_TEXT_WITH_DEFAULT = createMockActionParameter({ + id: "4", + name: "Text filter with default", + slug: "filter-with-default", + type: "string/=", + sectionId: "string", + default: "Hello", +}); + const QUERY_FILTER_CREATED_AT = [ "between", [ @@ -636,6 +646,171 @@ describe("scenarios > dashboard > dashboard cards > click behavior", () => { }); }); + it("sets non-specified parameters to default values when accessed from a click action", () => { + cy.createDashboard( + { + ...TARGET_DASHBOARD, + parameters: [ + DASHBOARD_FILTER_TEXT, + DASHBOARD_FILTER_TEXT_WITH_DEFAULT, + ], + }, + { + wrapId: true, + idAlias: "targetDashboardId", + }, + ) + .then(dashboardId => { + return cy + .request("PUT", `/api/dashboard/${dashboardId}`, { + dashcards: [ + createMockDashboardCard({ + card_id: ORDERS_QUESTION_ID, + parameter_mappings: [ + createTextFilterMapping({ card_id: ORDERS_QUESTION_ID }), + createTextFilterWithDefaultMapping({ + card_id: ORDERS_QUESTION_ID, + }), + ], + }), + ], + }) + .then(() => dashboardId); + }) + .then(dashboardId => { + visitDashboard(dashboardId); + }); + + filterWidget().contains("Hello").click(); + popover().within(() => { + multiAutocompleteInput().type("{backspace}World{enter}"); + cy.button("Update filter").click(); + }); + + cy.createQuestionAndDashboard({ questionDetails }).then( + ({ body: card }) => { + visitDashboard(card.dashboard_id); + }, + ); + + editDashboard(); + + getDashboardCard().realHover().icon("click").click(); + addDashboardDestination(); + cy.get("aside").findByText("Select a dashboard tab").should("not.exist"); + cy.get("aside").findByText("No available targets").should("not.exist"); + addTextParameter(); + cy.get("aside").button("Done").click(); + + saveDashboard({ waitMs: 250 }); + + clickLineChartPoint(); + + cy.findAllByTestId("field-set") + .contains(DASHBOARD_FILTER_TEXT.name) + .parent() + .should("contain.text", POINT_COUNT); + cy.findAllByTestId("field-set") + .contains(DASHBOARD_FILTER_TEXT_WITH_DEFAULT.name) + .parent() + .should("contain.text", DASHBOARD_FILTER_TEXT_WITH_DEFAULT.default); + + cy.get("@targetDashboardId").then(targetDashboardId => { + cy.location().should(({ pathname, search }) => { + expect(pathname).to.equal(`/dashboard/${targetDashboardId}`); + expect(search).to.equal( + `?${DASHBOARD_FILTER_TEXT.slug}=${POINT_COUNT}&${DASHBOARD_FILTER_TEXT_WITH_DEFAULT.slug}=Hello`, + ); + }); + }); + }); + + it("sets parameters with default values to the correct value when accessed via click action", () => { + cy.createDashboard( + { + ...TARGET_DASHBOARD, + parameters: [ + DASHBOARD_FILTER_TEXT, + DASHBOARD_FILTER_TEXT_WITH_DEFAULT, + ], + }, + { + wrapId: true, + idAlias: "targetDashboardId", + }, + ) + .then(dashboardId => { + return cy + .request("PUT", `/api/dashboard/${dashboardId}`, { + dashcards: [ + createMockDashboardCard({ + card_id: ORDERS_QUESTION_ID, + parameter_mappings: [ + createTextFilterMapping({ card_id: ORDERS_QUESTION_ID }), + createTextFilterWithDefaultMapping({ + card_id: ORDERS_QUESTION_ID, + }), + ], + }), + ], + }) + .then(() => dashboardId); + }) + .then(dashboardId => { + visitDashboard(dashboardId); + }); + + cy.findAllByTestId("field-set") + .contains(DASHBOARD_FILTER_TEXT.name) + .parent() + .click(); + popover().within(() => { + multiAutocompleteInput().type("John Doe{enter}"); + cy.button("Add filter").click(); + }); + + cy.findAllByTestId("field-set") + .contains(DASHBOARD_FILTER_TEXT_WITH_DEFAULT.name) + .parent() + .click(); + popover().within(() => { + multiAutocompleteInput().type("{backspace}World{enter}"); + cy.button("Update filter").click(); + }); + + cy.createQuestionAndDashboard({ questionDetails }).then( + ({ body: card }) => { + visitDashboard(card.dashboard_id); + }, + ); + + editDashboard(); + + getDashboardCard().realHover().icon("click").click(); + addDashboardDestination(); + cy.get("aside").findByText("Select a dashboard tab").should("not.exist"); + cy.get("aside").findByText("No available targets").should("not.exist"); + addTextWithDefaultParameter(); + cy.get("aside").button("Done").click(); + + saveDashboard({ waitMs: 250 }); + + clickLineChartPoint(); + cy.findAllByTestId("field-set") + .contains(DASHBOARD_FILTER_TEXT_WITH_DEFAULT.name) + .parent() + .should("contain.text", POINT_COUNT); + + cy.get("@targetDashboardId").then(targetDashboardId => { + cy.location().should(({ pathname, search }) => { + expect(pathname).to.equal(`/dashboard/${targetDashboardId}`); + expect(search).to.equal( + `?${DASHBOARD_FILTER_TEXT.slug}=&${DASHBOARD_FILTER_TEXT_WITH_DEFAULT.slug}=${POINT_COUNT}`, + ); + }); + }); + }); + it("does not allow setting dashboard as custom destination if user has no permissions to it", () => { cy.createCollection({ name: RESTRICTED_COLLECTION_NAME }).then( ({ body: restrictedCollection }) => { @@ -2280,6 +2455,14 @@ const addTextParameter = () => { }); }; +const addTextWithDefaultParameter = () => { + cy.get("aside").findByText(DASHBOARD_FILTER_TEXT_WITH_DEFAULT.name).click(); + popover().within(() => { + cy.findByText(CREATED_AT_COLUMN_NAME).should("exist"); + cy.findByText(COUNT_COLUMN_NAME).should("exist").click(); + }); +}; + const addTimeParameter = () => { cy.get("aside").findByText(DASHBOARD_FILTER_TIME.name).click(); popover().within(() => { @@ -2313,6 +2496,23 @@ const createTextFilterMapping = ({ card_id }) => { }; }; +const createTextFilterWithDefaultMapping = ({ card_id }) => { + const fieldRef = [ + "field", + PEOPLE.NAME, + { + "base-type": "type/Text", + "source-field": ORDERS.USER_ID, + }, + ]; + + return { + card_id, + parameter_id: DASHBOARD_FILTER_TEXT_WITH_DEFAULT.id, + target: ["dimension", fieldRef], + }; +}; + const createTimeFilterMapping = ({ card_id }) => { const fieldRef = [ "field", diff --git a/frontend/src/metabase-lib/v1/queries/drills/dashboard-click-drill.js b/frontend/src/metabase-lib/v1/queries/drills/dashboard-click-drill.js index 619139cc9a70b2b905b80c4ecb5ab3976da1cfad..4cfbd09a7d31ef7f727de58d62a4ab6c583104d5 100644 --- a/frontend/src/metabase-lib/v1/queries/drills/dashboard-click-drill.js +++ b/frontend/src/metabase-lib/v1/queries/drills/dashboard-click-drill.js @@ -82,16 +82,30 @@ export function getDashboardDrillUrl(clicked) { clickBehavior, ); + const targetDashboard = extraData.dashboards[targetId]; + const targetDefaultParameters = Object.fromEntries( + targetDashboard.parameters.map(parameter => [ + parameter.slug, + parameter.default ?? "", + ]), + ); + const baseQueryParams = getParameterValuesBySlug(parameterMapping, { data, extraData, clickBehavior, }); - const queryParams = + const tabParams = typeof clickBehavior.tabId === "undefined" - ? baseQueryParams - : { ...baseQueryParams, tab: clickBehavior.tabId }; + ? {} + : { tab: clickBehavior.tabId }; + + const queryParams = { + ...targetDefaultParameters, + ...baseQueryParams, + ...tabParams, + }; const path = Urls.dashboard({ id: targetId }); return `${path}?${querystring.stringify(queryParams)}`;