Repository: metabase/metabase
Pull request #55010: feat(sdk): Ensure that all dashboards use entity ID the same way
Author: login: oisincoveney
Labels: name: .Team/Embedding
name: double-backport
Created: 2025-03-12T12:37:48Z | Merged: 2025-03-13T13:55:43Z

Moves the `dashboardId` entity ID logic into `useSdkDashboardParams` to simplify the code within the three dashboard components. This will be the first step in simplifying the dashboard code. It also adds entity IDs to `EditableDashboard`, which it was missing for some reason

To test: there are e2e tests for each of these components for entity IDs, so they should still pass.

You can manually test these by using `yarn run storybook-embedding-sdk`, and selecting `InteractiveDashboard`, `EditableDashboard`, and `StaticDashboard`. Go into the controls, and select `Entity ID` in the `dashboardId` dropdown:

![image](https://github.com/user-attachments/assets/55edaeea-e0fa-4c20-b971-b9075e3e31ef)

everything should continue to work.


Diff:
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx b/enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx
index 28ee75d65ec2..6d5ad1f8cc8a 100644
--- a/enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx
@@ -36,7 +36,7 @@ const DefaultErrorMessage = ({ message }: SdkErrorComponentProps) => (
 );
 
 interface ResourceNotFoundErrorProps {
-  id: string | number | null | undefined;
+  id: string | number;
 }
 
 const ResourceNotFoundError = ({
diff --git a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx
index 09d34212922f..5568ffbef942 100644
--- a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx
@@ -129,7 +129,7 @@ export const CollectionBrowserInner = ({
 };
 
 const CollectionBrowserWrapper = ({
-  collectionId,
+  collectionId = "personal",
   ...restProps
 }: CollectionBrowserProps) => {
   const { id, isLoading } = useValidatedEntityId<
diff --git a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/ConnectedDashboard.tsx b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/ConnectedDashboard.tsx
index 86fea326c82e..b3cb1ced53ab 100644
--- a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/ConnectedDashboard.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/ConnectedDashboard.tsx
@@ -1,14 +1,9 @@
 import type { Query } from "history";
-import { type ComponentType, type FC, useEffect } from "react";
+import type { ComponentType, FC } from "react";
 import type { ConnectedProps } from "react-redux";
 import _ from "underscore";
 
 import type { MetabasePluginsConfig } from "embedding-sdk";
-import {
-  DashboardNotFoundError,
-  SdkLoader,
-} from "embedding-sdk/components/private/PublicComponentWrapper";
-import { useSdkDispatch, useSdkSelector } from "embedding-sdk/store";
 import * as dashboardActions from "metabase/dashboard/actions";
 import type { NavigateToNewCardFromDashboardOpts } from "metabase/dashboard/components/DashCard/types";
 import { Dashboard } from "metabase/dashboard/components/Dashboard/Dashboard";
@@ -39,12 +34,11 @@ import type {
   DashboardLoaderWrapperProps,
   DashboardRefreshPeriodControls,
 } from "metabase/dashboard/types";
-import { useValidatedEntityId } from "metabase/lib/entity-id/hooks/use-validated-entity-id";
 import { connect } from "metabase/lib/redux";
 import type { PublicOrEmbeddedDashboardEventHandlersProps } from "metabase/public/containers/PublicOrEmbeddedDashboard/types";
 import { useDashboardLoadHandlers } from "metabase/public/containers/PublicOrEmbeddedDashboard/use-dashboard-load-handlers";
 import { closeNavbar, setErrorPage } from "metabase/redux/app";
-import { getErrorPage, getIsNavbarOpen } from "metabase/selectors/app";
+import { getIsNavbarOpen } from "metabase/selectors/app";
 import {
   canManageSubscriptions,
   getUserIsAdmin,
@@ -91,6 +85,7 @@ type ReduxProps = ConnectedProps<typeof connector>;
 
 type ConnectedDashboardProps = {
   dashboardId: DashboardId;
+  isLoading: boolean;
   parameterQueryParams: Query;
 
   downloadsEnabled?: boolean;
@@ -130,29 +125,4 @@ const ConnectedDashboardInner = ({
 
 export const ConnectedDashboard = connector<
   ComponentType<ConnectedDashboardProps & ReduxProps>
->(({ dashboardId: initialDashboardId, ...rest }) => {
-  const { id: resolvedDashboardId, isLoading } = useValidatedEntityId({
-    type: "dashboard",
-    id: initialDashboardId,
-  });
-
-  const errorPage = useSdkSelector(getErrorPage);
-  const dispatch = useSdkDispatch();
-  useEffect(() => {
-    if (resolvedDashboardId) {
-      dispatch(setErrorPage(null));
-    }
-  }, [dispatch, resolvedDashboardId]);
-
-  if (isLoading) {
-    return <SdkLoader />;
-  }
-
-  if (!resolvedDashboardId || errorPage?.status === 404) {
-    return <DashboardNotFoundError id={initialDashboardId} />;
-  }
-
-  return (
-    <ConnectedDashboardInner dashboardId={resolvedDashboardId} {...rest} />
-  );
-}) as FC<ConnectedDashboardProps>;
+>(ConnectedDashboardInner) as FC<ConnectedDashboardProps>;
diff --git a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx
index 8d21fb4faa17..c6ab310db922 100644
--- a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx
@@ -1,19 +1,25 @@
-import type { CSSProperties } from "react";
+import { type CSSProperties, useEffect } from "react";
 
 import type { MetabasePluginsConfig } from "embedding-sdk";
 import { InteractiveAdHocQuestion } from "embedding-sdk/components/private/InteractiveAdHocQuestion";
+import {
+  DashboardNotFoundError,
+  SdkLoader,
+} from "embedding-sdk/components/private/PublicComponentWrapper";
 import { StyledPublicComponentWrapper } from "embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.styled";
 import {
   type SdkDashboardDisplayProps,
   useSdkDashboardParams,
 } from "embedding-sdk/hooks/private/use-sdk-dashboard-params";
-import { useSdkSelector } from "embedding-sdk/store";
+import { useSdkDispatch, useSdkSelector } from "embedding-sdk/store";
 import {
   DASHBOARD_EDITING_ACTIONS,
   SDK_DASHBOARD_VIEW_ACTIONS,
 } from "metabase/dashboard/components/DashboardHeader/DashboardHeaderButtonRow/constants";
 import { getIsEditing } from "metabase/dashboard/selectors";
 import type { PublicOrEmbeddedDashboardEventHandlersProps } from "metabase/public/containers/PublicOrEmbeddedDashboard/types";
+import { setErrorPage } from "metabase/redux/app";
+import { getErrorPage } from "metabase/selectors/app";
 
 import { ConnectedDashboard } from "./ConnectedDashboard";
 import { InteractiveDashboardProvider } from "./context";
@@ -28,7 +34,7 @@ export type EditableDashboardProps = {
   PublicOrEmbeddedDashboardEventHandlersProps;
 
 export const EditableDashboard = ({
-  dashboardId,
+  dashboardId: initialDashboardId,
   initialParameters = {},
   withDownloads = false,
   drillThroughQuestionHeight,
@@ -45,8 +51,10 @@ export const EditableDashboard = ({
     refreshPeriod,
     onRefreshPeriodChange,
     setRefreshElapsedHook,
-  } = useSdkDashboardParams({
+    isLoading,
     dashboardId,
+  } = useSdkDashboardParams({
+    dashboardId: initialDashboardId,
     withDownloads,
     withTitle: true,
     hiddenParameters: undefined,
@@ -67,6 +75,22 @@ export const EditableDashboard = ({
     ? DASHBOARD_EDITING_ACTIONS
     : SDK_DASHBOARD_VIEW_ACTIONS;
 
+  const errorPage = useSdkSelector(getErrorPage);
+  const dispatch = useSdkDispatch();
+  useEffect(() => {
+    if (dashboardId) {
+      dispatch(setErrorPage(null));
+    }
+  }, [dispatch, dashboardId]);
+
+  if (isLoading) {
+    return <SdkLoader />;
+  }
+
+  if (!dashboardId || errorPage?.status === 404) {
+    return <DashboardNotFoundError id={initialDashboardId} />;
+  }
+
   return (
     <StyledPublicComponentWrapper className={className} style={style} ref={ref}>
       {adhocQuestionUrl ? (
@@ -85,6 +109,7 @@ export const EditableDashboard = ({
         >
           <ConnectedDashboard
             dashboardId={dashboardId}
+            isLoading={isLoading}
             parameterQueryParams={initialParameters}
             refreshPeriod={refreshPeriod}
             onRefreshPeriodChange={onRefreshPeriodChange}
diff --git a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/InteractiveDashboard.tsx b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/InteractiveDashboard.tsx
index ef9bc27873ce..6fbd9557693e 100644
--- a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/InteractiveDashboard.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/InteractiveDashboard.tsx
@@ -22,7 +22,6 @@ import {
 import { useSdkDispatch, useSdkSelector } from "embedding-sdk/store";
 import { DASHBOARD_DISPLAY_ACTIONS } from "metabase/dashboard/components/DashboardHeader/DashboardHeaderButtonRow/constants";
 import { useEmbedTheme } from "metabase/dashboard/hooks";
-import { useValidatedEntityId } from "metabase/lib/entity-id/hooks/use-validated-entity-id";
 import { PublicOrEmbeddedDashboard } from "metabase/public/containers/PublicOrEmbeddedDashboard/PublicOrEmbeddedDashboard";
 import type { PublicOrEmbeddedDashboardEventHandlersProps } from "metabase/public/containers/PublicOrEmbeddedDashboard/types";
 import { setErrorPage } from "metabase/redux/app";
@@ -50,7 +49,7 @@ export type InteractiveDashboardProps = {
   PublicOrEmbeddedDashboardEventHandlersProps;
 
 const InteractiveDashboardInner = ({
-  dashboardId,
+  dashboardId: initialDashboardId,
   initialParameters = {},
   withTitle = true,
   withCardTitle = true,
@@ -73,8 +72,10 @@ const InteractiveDashboardInner = ({
     refreshPeriod,
     onRefreshPeriodChange,
     setRefreshElapsedHook,
-  } = useSdkDashboardParams({
     dashboardId,
+    isLoading,
+  } = useSdkDashboardParams({
+    dashboardId: initialDashboardId,
     withDownloads,
     withTitle,
     withFooter,
@@ -102,6 +103,30 @@ const InteractiveDashboardInner = ({
     [plugins],
   );
 
+  const errorPage = useSdkSelector(getErrorPage);
+  const dispatch = useSdkDispatch();
+  useEffect(() => {
+    if (dashboardId) {
+      dispatch(setErrorPage(null));
+    }
+  }, [dispatch, dashboardId]);
+
+  if (isLoading) {
+    return (
+      <StyledPublicComponentWrapper className={className} style={style}>
+        <SdkLoader />
+      </StyledPublicComponentWrapper>
+    );
+  }
+
+  if (!dashboardId || errorPage?.status === 404) {
+    return (
+      <StyledPublicComponentWrapper className={className} style={style}>
+        <DashboardNotFoundError id={initialDashboardId} />
+      </StyledPublicComponentWrapper>
+    );
+  }
+
   return (
     <StyledPublicComponentWrapper className={className} style={style} ref={ref}>
       {adhocQuestionUrl ? (
@@ -151,39 +176,5 @@ const InteractiveDashboardInner = ({
 };
 
 export const InteractiveDashboard = renderOnlyInSdkProvider(
-  ({ dashboardId: initialDashboardId, ...rest }: InteractiveDashboardProps) => {
-    const { id: resolvedDashboardId, isLoading } = useValidatedEntityId({
-      type: "dashboard",
-      id: initialDashboardId,
-    });
-
-    const errorPage = useSdkSelector(getErrorPage);
-    const dispatch = useSdkDispatch();
-    useEffect(() => {
-      if (resolvedDashboardId) {
-        dispatch(setErrorPage(null));
-      }
-    }, [dispatch, resolvedDashboardId]);
-
-    const { style, className } = rest;
-    if (isLoading) {
-      return (
-        <StyledPublicComponentWrapper className={className} style={style}>
-          <SdkLoader />
-        </StyledPublicComponentWrapper>
-      );
-    }
-
-    if (!resolvedDashboardId || errorPage?.status === 404) {
-      return (
-        <StyledPublicComponentWrapper className={className} style={style}>
-          <DashboardNotFoundError id={initialDashboardId} />
-        </StyledPublicComponentWrapper>
-      );
-    }
-
-    return (
-      <InteractiveDashboardInner dashboardId={resolvedDashboardId} {...rest} />
-    );
-  },
+  InteractiveDashboardInner,
 );
diff --git a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/use-common-dashboard-params.tsx b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/use-common-dashboard-params.tsx
index 6c655b59c28c..982a6f06f4c9 100644
--- a/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/use-common-dashboard-params.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/use-common-dashboard-params.tsx
@@ -17,7 +17,7 @@ import type { DashboardId, QuestionDashboardCard } from "metabase-types/api";
 export const useCommonDashboardParams = ({
   dashboardId,
 }: {
-  dashboardId: DashboardId;
+  dashboardId: DashboardId | null;
 }) => {
   const dispatch = useSdkDispatch();
   const store = useSdkStore();
@@ -47,7 +47,7 @@ export const useCommonDashboardParams = ({
       const state = store.getState();
       const metadata = getMetadata(state);
       const { dashboards, parameterValues } = state.dashboard;
-      const dashboard = dashboards[dashboardId];
+      const dashboard = dashboardId && dashboards[dashboardId];
 
       if (dashboard) {
         const url = getNewCardUrl({
diff --git a/enterprise/frontend/src/embedding-sdk/hooks/private/use-sdk-dashboard-params.ts b/enterprise/frontend/src/embedding-sdk/hooks/private/use-sdk-dashboard-params.ts
index 762bec0257fc..5c01ac775da6 100644
--- a/enterprise/frontend/src/embedding-sdk/hooks/private/use-sdk-dashboard-params.ts
+++ b/enterprise/frontend/src/embedding-sdk/hooks/private/use-sdk-dashboard-params.ts
@@ -9,6 +9,7 @@ import {
   useRefreshDashboard,
 } from "metabase/dashboard/hooks";
 import type { EmbedDisplayParams } from "metabase/dashboard/types";
+import { useValidatedEntityId } from "metabase/lib/entity-id/hooks/use-validated-entity-id";
 import { isNotNull } from "metabase/lib/types";
 import type { DashboardId } from "metabase-types/api";
 
@@ -25,13 +26,18 @@ export type SdkDashboardDisplayProps = {
 };
 
 export const useSdkDashboardParams = ({
-  dashboardId,
+  dashboardId: initialDashboardId,
   withDownloads,
   withTitle,
   withFooter,
   hiddenParameters,
   initialParameters = {},
 }: SdkDashboardDisplayProps) => {
+  const { id: dashboardId, isLoading } = useValidatedEntityId({
+    type: "dashboard",
+    id: initialDashboardId,
+  });
+
   // temporary name until we change `hideDownloadButton` to `downloads`
   const hideDownloadButton = !withDownloads;
 
@@ -66,5 +72,7 @@ export const useSdkDashboardParams = ({
     onRefreshPeriodChange,
     refreshPeriod,
     setRefreshElapsedHook,
+    dashboardId,
+    isLoading,
   };
 };


Reviews:
user: login: heypoom
body: Nice refactoring!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-13T08:59:32Z
user: login: oisincoveney
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T11:20:34Z
user: login: oisincoveney
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T11:24:23Z

Review comments:
diff_hunk: @@ -36,36 +36,40 @@ const DefaultErrorMessage = ({ message }: SdkErrorComponentProps) => (
 );
 
 interface ResourceNotFoundErrorProps {
-  id: string | number;
+  id: string | number | null;
path: enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx
user: login: heypoom
body: In which cases would be resource id be missing?
created_at: 2025-03-13T08:56:55Z
author_association: MEMBER
diff_hunk: @@ -67,6 +75,22 @@ export const EditableDashboard = ({
     ? DASHBOARD_EDITING_ACTIONS
     : SDK_DASHBOARD_VIEW_ACTIONS;
 
+  const errorPage = useSdkSelector(getErrorPage);
+  const dispatch = useSdkDispatch();
+  useEffect(() => {
+    if (dashboardId) {
+      dispatch(setErrorPage(null));
+    }
+  }, [dispatch, dashboardId]);
path: enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx
user: login: heypoom
body: Could the error still be there even if a `dashboardId` is present, e.g. other causes of errors? I wonder if this can potentially overwrite legit errors
created_at: 2025-03-13T08:58:04Z
author_association: MEMBER
diff_hunk: @@ -67,6 +75,22 @@ export const EditableDashboard = ({
     ? DASHBOARD_EDITING_ACTIONS
     : SDK_DASHBOARD_VIEW_ACTIONS;
 
+  const errorPage = useSdkSelector(getErrorPage);
+  const dispatch = useSdkDispatch();
+  useEffect(() => {
+    if (dashboardId) {
+      dispatch(setErrorPage(null));
+    }
+  }, [dispatch, dashboardId]);
path: enterprise/frontend/src/embedding-sdk/components/public/InteractiveDashboard/EditableDashboard.tsx
user: login: oisincoveney
body: I honestly don't know why this is here and I'd be up for getting rid of it if it doesn't cause any errors. what do you think?
created_at: 2025-03-13T11:20:34Z
author_association: NONE
diff_hunk: @@ -36,36 +36,40 @@ const DefaultErrorMessage = ({ message }: SdkErrorComponentProps) => (
 );
 
 interface ResourceNotFoundErrorProps {
-  id: string | number;
+  id: string | number | null;
path: enterprise/frontend/src/embedding-sdk/components/private/PublicComponentWrapper/SdkError.tsx
user: login: oisincoveney
body: great question, they shouldn't. you've caught something - I was doing this
```
if (!dashboardId || errorPage?.status === 404) {
    return <DashboardNotFoundError id={dashboardId} />;
  }
```

in `EditableDashboard`, but `dashboardId` is the value after going through `useValidatedEntityId` so that could be `null`. but we should be doing

```
if (!dashboardId || errorPage?.status === 404) {
    return <DashboardNotFoundError id={initialDashboardId} />;
  }
```

which is the prop that the user passes, and makes more sense to a user and also can't be null
created_at: 2025-03-13T11:24:23Z
author_association: NONE

PR comments:
user: login: oisincoveney
created_at: 2025-03-12T12:37:50Z
body: This change is part of the following stack:

- #55010 ◀

<sub>Change managed by [git-spice](https://abhinav.github.io/git-spice/).</sub>
<!-- gs:navigation comment -->

author_association: NONE
user: login: trunk-io[bot]
created_at: 2025-03-12T13:33:02Z
body: <!-- Trunk Test Analytics -->


[![Static Badge](https://img.shields.io/badge/14008_tests-b391be77-purple)](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment) &ensp; [![Static Badge](https://img.shields.io/badge/0-failed-crimson)](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE) &ensp; [![Static Badge](https://img.shields.io/badge/5-flaky-red)](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE) &ensp; [![Static Badge](https://img.shields.io/badge/0-quarantined-yellow)](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=QUARANTINED)


| Flaky Test | Failure Summary | Logs |
| --- | --- | --- |
| <code>scenarios > visualizations > line/bar chart > tooltips should be enterable and scollable to view all rows in long tooltips (metabase\#53586) (metab...</code> | The test timed out while trying to find an element with data-testid "echarts-tooltip". | [Logs ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE&runId=b15144bc-4a94-5bd2-83a3-6944f731b85f) |
| <code>issue 39487 calendar has constant size when using single date picker filter (metabase\#39487)</code> | The test timed out while trying to find an element with specific text, possibly due to the text being broken up by multiple elements. | [Logs ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE&runId=906d9c23-2a71-55bc-ba33-c9d5bf902b45) |
| <code>issue 39487 calendar has constant size when using date range picker filter (metabase\#39487)</code> | The test timed out while trying to find an element with specific text, possibly due to the text being broken up by multiple elements. | [Logs ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE&runId=78623138-e1d0-50aa-95f2-9d901c3baec6) |
| <code>issue 29951 should allow to run the model query after changing custom columns (metabase\#29951)</code> | Cypress command chain failed due to the page updating after a trigger event, causing the subject to detach from the DOM. | [Logs ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE&runId=e6431eb7-4755-5e6f-b8de-3e5e775445d9) |

[... and 1 more](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment&runConclusion=FAILURE)
<sub>

[View Full Report ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/55010?repo=metabase/metabase&commitHash=b391be77b3c77dd4dc99b493ec4ec18dbd8da61f&utm_source=gh-comment) ⋅ [Docs](https://docs.trunk.io/flaky-tests?utm_source=gh-comment)

</sub>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-13T12:57:37Z
body: 
  ## e2e tests failed on `b391be77b3c77dd4dc99b493ec4ec18dbd8da61f-1`

  [e2e test run](https://github.com/metabase/metabase/actions/runs/13834941694?pr=55010)

  File | Test Name
  ---- | ---------
  `dashboard.cy.spec.js` | (_flaky_) scenarios > dashboard > warn before leave > should warn a user before leaving after adding, removed, moving, or duplicating a tab
`reproductions.cy.spec.js` | (_flaky_) issue 29951 > should allow to run the model query after changing custom columns (metabase#29951)
`reproductions.cy.spec.ts` | (_flaky_) issue 39487 > calendar has constant size when using single date picker filter (metabase#39487)
`reproductions.cy.spec.ts` | (_flaky_) issue 39487 > calendar has constant size when using date range picker filter (metabase#39487)
`line-bar-tooltips.cy.spec.js` | (_flaky_) scenarios > visualizations > line/bar chart > tooltips > should be enterable and scollable to view all rows in long tooltips (metabase#53586) (metabase#48347)

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-13T15:14:04Z
body: 🚀 This should also be released by [v0.53.7](https://github.com/metabase/metabase/milestone/317)
author_association: CONTRIBUTOR