diff --git a/e2e/support/helpers/e2e-downloads-helpers.ts b/e2e/support/helpers/e2e-downloads-helpers.ts index 364750819476711fcee24e2dbce958103ec9a646..2a6fd2b6e74f8093f9185a379326df6a0045ba26 100644 --- a/e2e/support/helpers/e2e-downloads-helpers.ts +++ b/e2e/support/helpers/e2e-downloads-helpers.ts @@ -23,7 +23,7 @@ interface DownloadAndAssertParams { publicUuid?: string; dashboardId?: number; enableFormatting?: boolean; - enablePivoting?: boolean; + pivoting?: "pivoted" | "non-pivoted"; } export const exportFromDashcard = (format: string) => { @@ -51,7 +51,7 @@ export function downloadAndAssert( downloadMethod = "POST", isDashboard, enableFormatting = true, - enablePivoting = false, + pivoting, }: DownloadAndAssertParams, callback: (data: unknown) => void, ) { @@ -104,8 +104,17 @@ export function downloadAndAssert( cy.findByText(formattingButtonLabel).click(); - if (enablePivoting) { - cy.findByText("Keep data pivoted").click(); + if (pivoting != null) { + cy.findByTestId("keep-data-pivoted") + .as("keep-data-pivoted") + .then($checkbox => { + const isChecked = $checkbox.prop("checked"); + + const shouldPivot = pivoting === "pivoted"; + if (shouldPivot !== isChecked) { + cy.get("@keep-data-pivoted").click(); + } + }); } cy.findByTestId("download-results-button").click(); diff --git a/e2e/test/scenarios/sharing/downloads/downloads.cy.spec.js b/e2e/test/scenarios/sharing/downloads/downloads.cy.spec.js index c5c244fe672525aa7b632abeb299ad7a7b421f71..e6388750250253753b173c3760384380eca27a49 100644 --- a/e2e/test/scenarios/sharing/downloads/downloads.cy.spec.js +++ b/e2e/test/scenarios/sharing/downloads/downloads.cy.spec.js @@ -34,7 +34,7 @@ import { visualize, } from "e2e/support/helpers"; -const { ORDERS, ORDERS_ID } = SAMPLE_DATABASE; +const { ORDERS, ORDERS_ID, PRODUCTS, PRODUCTS_ID } = SAMPLE_DATABASE; const testCases = ["csv", "xlsx"]; @@ -68,6 +68,15 @@ describe("scenarios > question > download", () => { }); describeWithSnowplow("[snowplow]", () => { + beforeEach(() => { + resetSnowplow(); + enableTracking(); + }); + + afterEach(() => { + expectNoBadSnowplowEvents(); + }); + testCases.forEach(fileType => { it(`downloads ${fileType} file`, () => { startNewQuestion(); @@ -150,6 +159,47 @@ describe("scenarios > question > download", () => { }); }); + it("should allow downloading pivoted results", () => { + createQuestion( + { + name: "Pivot Table", + query: { + "source-table": PRODUCTS_ID, + aggregation: [["count"]], + breakout: [ + ["datetime-field", ["field-id", PRODUCTS.CREATED_AT], "year"], + ["field-id", PRODUCTS.CATEGORY], + ], + }, + display: "pivot", + }, + { visitQuestion: true }, + ); + + downloadAndAssert( + { + enableFormatting: true, + fileType: "csv", + }, + sheet => { + expect(sheet["B1"].v).to.eq("Doohickey"); + expect(sheet["B2"].w).to.eq("13"); + }, + ); + + downloadAndAssert( + { + enableFormatting: true, + pivoting: "non-pivoted", + fileType: "csv", + }, + sheet => { + expect(sheet["B1"].v).to.eq("Category"); + expect(sheet["B2"].w).to.eq("Doohickey"); + }, + ); + }); + it("respects renamed columns in self-joins", () => { const idLeftRef = [ "field", diff --git a/frontend/src/metabase/common/components/ExportSettingsWidget/ExportSettingsWidget.tsx b/frontend/src/metabase/common/components/ExportSettingsWidget/ExportSettingsWidget.tsx index 36904828db5d4507d25ecff09d23fe0de9eb2537..7ec364c9eda4ebecb1cc8616bfc55d09ea0b7aea 100644 --- a/frontend/src/metabase/common/components/ExportSettingsWidget/ExportSettingsWidget.tsx +++ b/frontend/src/metabase/common/components/ExportSettingsWidget/ExportSettingsWidget.tsx @@ -67,6 +67,7 @@ export const ExportSettingsWidget = ({ ) : null} {canConfigurePivoting ? ( <Checkbox + data-testid="keep-data-pivoted" label={t`Keep data pivoted`} checked={isPivotingEnabled} onChange={() => onTogglePivoting()} diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx b/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx index 07e46efb2e846cd386924c8080910cdb03b0bb14..6f688999181434b7cb86b12401189ca0133df284 100644 --- a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx +++ b/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx @@ -20,7 +20,7 @@ type QueryDownloadPopoverProps = { }) => void; }; -const canConfigurePivoting = (format: string, display: string) => +const canPivotResults = (format: string, display: string) => display === "pivot" && format !== "json"; const canConfigureFormatting = (format: string) => format !== "png"; @@ -34,9 +34,11 @@ export const QueryDownloadPopover = ({ ? [...exportFormats, exportFormatPng] : exportFormats; - const [isPivoted, setIsPivoted] = useState(false); - const [isFormatted, setIsFormatted] = useState(true); const [format, setFormat] = useState<ExportFormat>(formats[0]); + const canConfigurePivoting = canPivotResults(format, question.display()); + + const [isPivoted, setIsPivoted] = useState(canConfigurePivoting); + const [isFormatted, setIsFormatted] = useState(true); const hasTruncatedResults = result.data != null && result.data.rows_truncated != null; @@ -61,7 +63,7 @@ export const QueryDownloadPopover = ({ isFormattingEnabled={isFormatted} isPivotingEnabled={isPivoted} canConfigureFormatting={canConfigureFormatting(format)} - canConfigurePivoting={canConfigurePivoting(format, question.display())} + canConfigurePivoting={canConfigurePivoting} onChangeFormat={setFormat} onToggleFormatting={() => setIsFormatted(prev => !prev)} onTogglePivoting={() => setIsPivoted(prev => !prev)} diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx b/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx index 3fd23fc3ceb6d2b0cad39f34b7b9b54b4ad87480..b5acb2a9fd30986244b21678b2c69163d4834cf1 100644 --- a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx +++ b/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx @@ -170,7 +170,6 @@ describe("QueryDownloadPopover", () => { await userEvent.click(screen.getByLabelText(`.${format}`)); await userEvent.click(screen.getByLabelText(`Unformatted`)); - await userEvent.click(screen.getByLabelText("Keep data pivoted")); await userEvent.click( await screen.findByTestId("download-results-button"), );