diff --git a/e2e/test/scenarios/dashboard-filters/dashboard-filters-auto-wiring.cy.spec.js b/e2e/test/scenarios/dashboard-filters/dashboard-filters-auto-wiring.cy.spec.js index 17a8154ded5fce9487e45679f066acd724810ba6..d0c4d83d1865eea1d9863c5da3e20ee4d84e1e1b 100644 --- a/e2e/test/scenarios/dashboard-filters/dashboard-filters-auto-wiring.cy.spec.js +++ b/e2e/test/scenarios/dashboard-filters/dashboard-filters-auto-wiring.cy.spec.js @@ -660,6 +660,38 @@ describe("dashboard filters auto-wiring", () => { .should("have.length", 1) .should("contain", "Removed card"); }); + + it("should dismiss toasts on timeout", () => { + createDashboardWithCards({ cards }).then(dashboardId => { + visitDashboard(dashboardId); + }); + + editDashboard(); + setFilter("Text or Category", "Is"); + + cy.clock(); + selectDashboardFilter(getDashboardCard(0), "Name"); + + undoToast().should("be.visible"); + + // AUTO_WIRE_TOAST_TIMEOUT + cy.tick(12000); + + undoToast().should("not.exist"); + + removeFilterFromDashCard(0); + + selectDashboardFilter(getDashboardCard(0), "Name"); + + cy.clock(); + undoToast().findByRole("button", { name: "Auto-connect" }).click(); + + undoToast().should("be.visible"); + + // AUTO_WIRE_UNDO_TOAST_TIMEOUT + cy.tick(8000); + undoToast().should("not.exist"); + }); }); }); diff --git a/frontend/src/metabase/containers/UndoListing.jsx b/frontend/src/metabase/containers/UndoListing.jsx index 78acca33901b312e0343ba0c2482350cb96e2b09..6692dc4f3ac9d4e4e36be25c24476e7f4e963198 100644 --- a/frontend/src/metabase/containers/UndoListing.jsx +++ b/frontend/src/metabase/containers/UndoListing.jsx @@ -121,7 +121,12 @@ function UndoToast({ undo, onUndo, onDismiss }) { pos="absolute" top={0} left={0} + w="100%" className={CS.progress} + /* override animation duration based on timeout */ + style={{ + animationDuration: `${undo.initialTimeout}ms`, + }} /> )} <CardContent> diff --git a/frontend/src/metabase/containers/UndoListing.module.css b/frontend/src/metabase/containers/UndoListing.module.css index 1d6e9a827c41c431a7b04800b76a7434ee66dc8c..61df95e06569b032f5dcf68939de6aea510e3608 100644 --- a/frontend/src/metabase/containers/UndoListing.module.css +++ b/frontend/src/metabase/containers/UndoListing.module.css @@ -9,10 +9,8 @@ } .progress { - /* it must be in sync with AUTO_WIRE_TOAST_TIMEOUT */ - animation: animated-progress 12s linear; + animation: animated-progress linear; transform-origin: left; - width: 100%; } .toast:hover .progress { diff --git a/frontend/src/metabase/dashboard/actions/auto-wire-parameters/constants.ts b/frontend/src/metabase/dashboard/actions/auto-wire-parameters/constants.ts index 176927ff8274b2773a79f7220f0e5414e7fc78d0..6220c698476205b7ae05f4295a48407ec9ba00d8 100644 --- a/frontend/src/metabase/dashboard/actions/auto-wire-parameters/constants.ts +++ b/frontend/src/metabase/dashboard/actions/auto-wire-parameters/constants.ts @@ -1 +1,2 @@ export const AUTO_WIRE_TOAST_TIMEOUT = 12000; +export const AUTO_WIRE_UNDO_TOAST_TIMEOUT = 8000; diff --git a/frontend/src/metabase/dashboard/actions/auto-wire-parameters/toasts.ts b/frontend/src/metabase/dashboard/actions/auto-wire-parameters/toasts.ts index 1a50e362146697d883040ab2b6e0fe014ed2f361..cda2ca467844cfa22988d8b7f7f376d6048bd5ec 100644 --- a/frontend/src/metabase/dashboard/actions/auto-wire-parameters/toasts.ts +++ b/frontend/src/metabase/dashboard/actions/auto-wire-parameters/toasts.ts @@ -16,7 +16,10 @@ import type { } from "metabase-types/api"; import type { Dispatch, GetState } from "metabase-types/store"; -import { AUTO_WIRE_TOAST_TIMEOUT } from "./constants"; +import { + AUTO_WIRE_TOAST_TIMEOUT, + AUTO_WIRE_UNDO_TOAST_TIMEOUT, +} from "./constants"; export const AUTO_WIRE_TOAST_ID = _.uniqueId(); @@ -75,7 +78,7 @@ export const showAutoWireParametersToast = message: t`The filter was auto-connected to all questions containing “${columnName}â€.`, actionLabel: t`Undo`, showProgress: true, - timeout: 12000, + timeout: AUTO_WIRE_UNDO_TOAST_TIMEOUT, type: "filterAutoConnectDone", extraInfo: { dashcardIds: dashcardAttributes.map(({ id }) => id), @@ -155,7 +158,7 @@ export const showAddedCardAutoWireParametersToast = addUndo({ message, showProgress: true, - timeout: AUTO_WIRE_TOAST_TIMEOUT, + timeout: AUTO_WIRE_UNDO_TOAST_TIMEOUT, type: "filterAutoConnect", action: revertAutoWireParametersToNewCard, }), diff --git a/frontend/src/metabase/redux/undo.js b/frontend/src/metabase/redux/undo.js index 6a4f5277feb7dcada4712bd13d693baeec52e41a..a5422096b209deb5ce2110c80ed05c11922d6244 100644 --- a/frontend/src/metabase/redux/undo.js +++ b/frontend/src/metabase/redux/undo.js @@ -129,6 +129,7 @@ export default function (state = [], { type, payload, error }) { const undo = { ...payload, + initialTimeout: payload.timeout, // normalize "action" to "actions" actions: payload.action ? [payload.action] : payload.actions || [], action: null, diff --git a/frontend/src/metabase/redux/undo.unit.spec.ts b/frontend/src/metabase/redux/undo.unit.spec.ts index c5f41f30521c87e88b5f0dae9bb5007f3ecef914..abfeb61fa4dbba14b079bdc546e4dca1cb13a2e4 100644 --- a/frontend/src/metabase/redux/undo.unit.spec.ts +++ b/frontend/src/metabase/redux/undo.unit.spec.ts @@ -123,6 +123,20 @@ describe("metabase/redux/undo", () => { // undo is dismissed, timeout passed expect(store.getState().undo.length).toBe(0); }); + + it("should hide toast after timeout is passed", async () => { + const store = createMockStore(); + const timeout = 1000; + + store.dispatch(addUndo({ id: MOCK_ID, timeout })); + + // await act is required to simulate store update on the next tick + await act(async () => { + jest.advanceTimersByTime(timeout); + }); + + expect(store.getState().undo.length).toBe(0); + }); }); const createMockStore = () => {