Repository: metabase/metabase
Pull request #56051: 🤖 backported "QueryDownloadPopover -> QuestionDownloadWidget + QueryDownloadWidget -> QuestionDownloadPopover"
Author: login: github-automation-metabase
Labels: name: was-backported
description: apply this to PRs that are themselves backports
Created: 2025-04-01T07:02:40Z | Merged: 2025-04-03T09:59:00Z

  #55894
  > [!IMPORTANT]
  > Manual conflict resolution is required.
  Checkout the branch and run `./backport.sh` script. Force push your changes after cherry-picking.


Diff:
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/DownloadWidget/DownloadWidget.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/DownloadWidget/DownloadWidget.tsx
index 192bd647708c..7128641025e1 100644
--- a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/DownloadWidget/DownloadWidget.tsx
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/DownloadWidget/DownloadWidget.tsx
@@ -1,8 +1,8 @@
-import { QueryDownloadPopover } from "metabase/query_builder/components/QueryDownloadPopover";
+import { QuestionDownloadWidget } from "metabase/query_builder/components/QuestionDownloadWidget";
 import {
   type UseDownloadDataParams,
   useDownloadData,
-} from "metabase/query_builder/components/QueryDownloadPopover/use-download-data";
+} from "metabase/query_builder/components/QuestionDownloadWidget/use-download-data";
 import type { StackProps } from "metabase/ui";
 
 import { useInteractiveQuestionContext } from "../../context";
@@ -23,7 +23,7 @@ const DownloadWidgetInner = ({
   });
 
   return (
-    <QueryDownloadPopover
+    <QuestionDownloadWidget
       question={question}
       result={result}
       onDownload={handleDownload}
diff --git a/frontend/src/metabase/dashboard/components/DashCard/DashCardMenu/DashCardMenu.tsx b/frontend/src/metabase/dashboard/components/DashCard/DashCardMenu/DashCardMenu.tsx
index b0548f7862ca..7c5beaf77ad3 100644
--- a/frontend/src/metabase/dashboard/components/DashCard/DashCardMenu/DashCardMenu.tsx
+++ b/frontend/src/metabase/dashboard/components/DashCard/DashCardMenu/DashCardMenu.tsx
@@ -15,8 +15,8 @@ import {
 } from "metabase/dashboard/components/DashCard/DashCardMenu/utils";
 import { getParameterValuesBySlugMap } from "metabase/dashboard/selectors";
 import { useStore } from "metabase/lib/redux";
-import { QueryDownloadPopover } from "metabase/query_builder/components/QueryDownloadPopover";
-import { useDownloadData } from "metabase/query_builder/components/QueryDownloadPopover/use-download-data";
+import { QuestionDownloadWidget } from "metabase/query_builder/components/QuestionDownloadWidget";
+import { useDownloadData } from "metabase/query_builder/components/QuestionDownloadWidget/use-download-data";
 import {
   ActionIcon,
   Icon,
@@ -113,7 +113,7 @@ export const DashCardMenu = ({
 
     if (menuView === "download") {
       return (
-        <QueryDownloadPopover
+        <QuestionDownloadWidget
           question={question}
           result={result}
           onDownload={(opts) => {
@@ -155,7 +155,7 @@ export const DashCardMenu = ({
   );
 };
 
-interface QueryDownloadWidgetOpts {
+interface ShouldRenderDashcardMenuProps {
   question: Question;
   result?: Dataset;
   isXray?: boolean;
@@ -172,7 +172,7 @@ DashCardMenu.shouldRender = ({
   isPublicOrEmbedded,
   isEditing,
   downloadsEnabled,
-}: QueryDownloadWidgetOpts) => {
+}: ShouldRenderDashcardMenuProps) => {
   // Do not remove this check until we completely remove the old code related to Audit V1!
   // MLv2 doesn't handle `internal` queries used for Audit V1.
   const isInternalQuery = InternalQuery.isDatasetQueryType(
diff --git a/frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion/PublicOrEmbeddedQuestionView.tsx b/frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion/PublicOrEmbeddedQuestionView.tsx
index 42746e66ac5b..be1d308e2b99 100644
--- a/frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion/PublicOrEmbeddedQuestionView.tsx
+++ b/frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion/PublicOrEmbeddedQuestionView.tsx
@@ -6,7 +6,7 @@ import { LoadingAndErrorWrapper } from "metabase/components/LoadingAndErrorWrapp
 import CS from "metabase/css/core/index.css";
 import { EmbedFrame } from "metabase/public/components/EmbedFrame";
 import type { DisplayTheme } from "metabase/public/lib/types";
-import QueryDownloadWidget from "metabase/query_builder/components/QueryDownloadWidget";
+import QuestionDownloadPopover from "metabase/query_builder/components/QuestionDownloadPopover";
 import { PublicMode } from "metabase/visualizations/click-actions/modes/PublicMode";
 import Visualization from "metabase/visualizations/components/Visualization";
 import Question from "metabase-lib/v1/Question";
@@ -60,7 +60,7 @@ export function PublicOrEmbeddedQuestionView({
   const question = new Question(card, metadata);
   const actionButtons =
     result && downloadsEnabled ? (
-      <QueryDownloadWidget
+      <QuestionDownloadPopover
         className={cx(CS.m1, CS.textMediumHover)}
         question={question}
         result={result}
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/index.ts b/frontend/src/metabase/query_builder/components/QueryDownloadPopover/index.ts
deleted file mode 100644
index 546d4a72152a..000000000000
--- a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { QueryDownloadPopover } from "./QueryDownloadPopover";
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.tsx b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.tsx
similarity index 79%
rename from frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.tsx
rename to frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.tsx
index 22dbeeae2980..07462354783e 100644
--- a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.tsx
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.tsx
@@ -6,18 +6,18 @@ import { PLUGIN_FEATURE_LEVEL_PERMISSIONS } from "metabase/plugins";
 import { Flex, Popover } from "metabase/ui";
 import type { Dataset } from "metabase-types/api";
 
-import { QueryDownloadPopover } from "../QueryDownloadPopover";
+import { QuestionDownloadWidget } from "../QuestionDownloadWidget";
 import {
   type UseDownloadDataParams,
   useDownloadData,
-} from "../QueryDownloadPopover/use-download-data";
+} from "../QuestionDownloadWidget/use-download-data";
 
-export type QueryDownloadWidgetProps = {
+export type QuestionDownloadPopoverProps = {
   className?: string;
 } & Pick<UseDownloadDataParams, "question" | "result"> &
   Partial<Omit<UseDownloadDataParams, "question" | "result">>;
 
-const QueryDownloadWidget = ({
+const QuestionDownloadPopover = ({
   className,
   question,
   result,
@@ -26,7 +26,7 @@ const QueryDownloadWidget = ({
   uuid,
   token,
   visualizationSettings,
-}: QueryDownloadWidgetProps) => {
+}: QuestionDownloadPopoverProps) => {
   const [isPopoverOpen, setIsPopoverOpen] = useState(false);
 
   const [, handleDownload] = useDownloadData({
@@ -52,7 +52,7 @@ const QueryDownloadWidget = ({
         </Flex>
       </Popover.Target>
       <Popover.Dropdown p="0.75rem">
-        <QueryDownloadPopover
+        <QuestionDownloadWidget
           question={question}
           result={result}
           onDownload={(opts) => {
@@ -65,11 +65,13 @@ const QueryDownloadWidget = ({
   );
 };
 
-interface QueryDownloadWidgetOpts {
+interface ShouldRenderDownloadPopoverProps {
   result?: Dataset;
 }
 
-QueryDownloadWidget.shouldRender = ({ result }: QueryDownloadWidgetOpts) => {
+QuestionDownloadPopover.shouldRender = ({
+  result,
+}: ShouldRenderDownloadPopoverProps) => {
   return (
     result &&
     !result.error &&
@@ -78,4 +80,4 @@ QueryDownloadWidget.shouldRender = ({ result }: QueryDownloadWidgetOpts) => {
 };
 
 // eslint-disable-next-line import/no-default-export -- deprecated usage
-export default QueryDownloadWidget;
+export default QuestionDownloadPopover;
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.unit.spec.tsx b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.unit.spec.tsx
similarity index 89%
rename from frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.unit.spec.tsx
rename to frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.unit.spec.tsx
index 806777e25976..ae6431a5aba9 100644
--- a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/QueryDownloadWidget.unit.spec.tsx
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/QuestionDownloadPopover.unit.spec.tsx
@@ -14,7 +14,7 @@ import {
 import { ORDERS_ID, SAMPLE_DB_ID } from "metabase-types/api/mocks/presets";
 import { createMockState } from "metabase-types/store/mocks";
 
-import QueryDownloadWidget from "./QueryDownloadWidget";
+import QuestionDownloadPopover from "./QuestionDownloadPopover";
 
 const TEST_CARD = createMockCard({
   dataset_query: createMockStructuredDatasetQuery({
@@ -45,11 +45,11 @@ const setup = ({ card = TEST_CARD, result = TEST_RESULT }: SetupOpts = {}) => {
   setupCardQueryDownloadEndpoint(card, "json");
 
   renderWithProviders(
-    <QueryDownloadWidget question={question} result={result} />,
+    <QuestionDownloadPopover question={question} result={result} />,
   );
 };
 
-describe("QueryDownloadWidget", () => {
+describe("QuestionDownloadPopover", () => {
   it("should display query export options", async () => {
     setup();
 
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/index.ts b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/index.ts
similarity index 57%
rename from frontend/src/metabase/query_builder/components/QueryDownloadWidget/index.ts
rename to frontend/src/metabase/query_builder/components/QuestionDownloadPopover/index.ts
index 155a802e3d31..968a9c00a4a7 100644
--- a/frontend/src/metabase/query_builder/components/QueryDownloadWidget/index.ts
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadPopover/index.ts
@@ -1,2 +1,2 @@
 // eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./QueryDownloadWidget";
+export { default } from "./QuestionDownloadPopover";
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.tsx
similarity index 96%
rename from frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx
rename to frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.tsx
index 025c1e8fa95d..f8b849c18d71 100644
--- a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.tsx
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.tsx
@@ -18,7 +18,7 @@ import { canSavePng } from "metabase/visualizations";
 import type Question from "metabase-lib/v1/Question";
 import type { Dataset } from "metabase-types/api";
 
-type QueryDownloadPopoverProps = {
+type QuestionDownloadWidgetProps = {
   question: Question;
   result: Dataset;
   onDownload: (opts: {
@@ -33,13 +33,13 @@ const canPivotResults = (format: string, display: string) =>
   display === "pivot" && format !== "json";
 const canConfigureFormatting = (format: string) => format !== "png";
 
-export const QueryDownloadPopover = ({
+export const QuestionDownloadWidget = ({
   question,
   result,
   onDownload,
   disabled = false,
   ...stackProps
-}: QueryDownloadPopoverProps) => {
+}: QuestionDownloadWidgetProps) => {
   const canDownloadPng = canSavePng(question.display());
   const formats = canDownloadPng
     ? [...exportFormats, exportFormatPng]
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.unit.spec.tsx
similarity index 97%
rename from frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx
rename to frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.unit.spec.tsx
index 9715adb4783f..ed1310f76297 100644
--- a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/QueryDownloadPopover.unit.spec.tsx
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/QuestionDownloadWidget.unit.spec.tsx
@@ -16,7 +16,7 @@ import {
 import { ORDERS_ID, SAMPLE_DB_ID } from "metabase-types/api/mocks/presets";
 import { createMockState } from "metabase-types/store/mocks";
 
-import { QueryDownloadPopover } from "./QueryDownloadPopover";
+import { QuestionDownloadWidget } from "./QuestionDownloadWidget";
 
 registerVisualizations();
 
@@ -57,7 +57,7 @@ const setup = ({
   setupCardQueryDownloadEndpoint(card, "json");
 
   renderWithProviders(
-    <QueryDownloadPopover
+    <QuestionDownloadWidget
       question={question}
       result={result}
       onDownload={onDownload}
@@ -70,7 +70,7 @@ const setup = ({
   return { onDownload };
 };
 
-describe("QueryDownloadPopover", () => {
+describe("QuestionDownloadWidget", () => {
   it("should display download options", async () => {
     setup();
 
diff --git a/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/index.ts b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/index.ts
new file mode 100644
index 000000000000..d714a5ac7bcb
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/index.ts
@@ -0,0 +1 @@
+export { QuestionDownloadWidget } from "./QuestionDownloadWidget";
diff --git a/frontend/src/metabase/query_builder/components/QueryDownloadPopover/use-download-data.ts b/frontend/src/metabase/query_builder/components/QuestionDownloadWidget/use-download-data.ts
similarity index 100%
rename from frontend/src/metabase/query_builder/components/QueryDownloadPopover/use-download-data.ts
rename to frontend/src/metabase/query_builder/components/QuestionDownloadWidget/use-download-data.ts
diff --git a/frontend/src/metabase/query_builder/components/view/ViewFooter/ViewFooterDownloadWidget.tsx b/frontend/src/metabase/query_builder/components/view/ViewFooter/ViewFooterDownloadWidget.tsx
index d61dfd7d18af..47376c431ac3 100644
--- a/frontend/src/metabase/query_builder/components/view/ViewFooter/ViewFooterDownloadWidget.tsx
+++ b/frontend/src/metabase/query_builder/components/view/ViewFooter/ViewFooterDownloadWidget.tsx
@@ -2,7 +2,7 @@ import cx from "classnames";
 
 import CS from "metabase/css/core/index.css";
 import { useSelector } from "metabase/lib/redux";
-import QueryDownloadWidget from "metabase/query_builder/components/QueryDownloadWidget";
+import QuestionDownloadPopover from "metabase/query_builder/components/QuestionDownloadPopover";
 import {
   getFirstQueryResult,
   getQuestion,
@@ -16,8 +16,8 @@ export const ViewFooterDownloadWidget = () => {
 
   return (
     question &&
-    QueryDownloadWidget.shouldRender({ result }) && (
-      <QueryDownloadWidget
+    QuestionDownloadPopover.shouldRender({ result }) && (
+      <QuestionDownloadPopover
         className={cx(CS.hide, CS.smShow)}
         question={question}
         result={result}


Reviews:
user: login: WiNloSt
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-01T13:17:16Z
user: login: oisincoveney
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-01T14:23:18Z
user: login: oisincoveney
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-01T14:24:47Z
user: login: WiNloSt
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-01T14:28:02Z
user: login: oisincoveney
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-01T14:34:30Z

Review comments:
path: frontend/src/metabase/query_builder/components/QueryDownloadPopover/DownloadButton.module.css
user: login: WiNloSt
body: I believe additional files are files that are unused on 52. Do they have anything to do with conflicts? My impression is that these files are irrelevant to the PR, but if they're part of the conflict, you can ignore my comment. If not, I'd rather not include it here.
created_at: 2025-04-01T13:16:52Z
author_association: MEMBER
path: frontend/src/metabase/query_builder/components/QueryDownloadPopover/DownloadButton.module.css
user: login: oisincoveney
body: Huh... I removed those. They don't seem to be used - you can see above I have a commit to remove them... and they're still in the PR. what lol
created_at: 2025-04-01T14:23:18Z
author_association: NONE
path: frontend/src/metabase/query_builder/components/QueryDownloadPopover/DownloadButton.module.css
user: login: oisincoveney
body: Ah! I'm silly. Yes they were there but it seems like they were orphaned files anyway. Not sure how they got caught up in this conflict. 
created_at: 2025-04-01T14:24:47Z
author_association: NONE
path: frontend/src/metabase/query_builder/components/QueryDownloadPopover/DownloadButton.module.css
user: login: WiNloSt
body: like I said. if it's the conflict, then cool leave it. If you're also not sure it's fine to leave it.

But if you remove them because they're unused I'd suggest we remove them out (the change that we remove these files, dang this is confusing) from the PR. I like the backport to stay true as much as possible to the original PRs if that makes sense.
created_at: 2025-04-01T14:28:02Z
author_association: MEMBER
path: frontend/src/metabase/query_builder/components/QueryDownloadPopover/DownloadButton.module.css
user: login: oisincoveney
body: Yeah, I started to feel uneasy about doing this here. I'm going to revert this
created_at: 2025-04-01T14:34:29Z
author_association: NONE

PR comments:
user: login: trunk-io[bot]
created_at: 2025-04-01T07:59:24Z
body: <!-- Trunk Test Analytics -->


[![Static Badge](https://img.shields.io/badge/13844_tests-56e33457-purple)](https://app.trunk.io/metabase/flaky-tests/pr/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&utm_source=gh-comment) &ensp; [![Static Badge](https://img.shields.io/badge/1-failed-crimson)](https://app.trunk.io/metabase/flaky-tests/pr/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&utm_source=gh-comment&runConclusion=FAILURE) &ensp; [![Static Badge](https://img.shields.io/badge/0-flaky-red)](https://app.trunk.io/metabase/flaky-tests/pr/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&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/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&utm_source=gh-comment&runConclusion=QUARANTINED)


| Failed Test | Failure Summary | Logs |
| --- | --- | --- |
| <code>issue 29786 should allow using field filters with null schema (metabase\#29786)</code> |  | [Logs ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&utm_source=gh-comment&runConclusion=FAILURE&runId=5efcf533-fc0f-5586-8c5b-3eccdcd469bd) |
<sub>

[View Full Report ↗︎](https://app.trunk.io/metabase/flaky-tests/pr/56051?repo=metabase/metabase&commitHash=56e33457a3a55e5850ef870fb343a9ce7b3ca36d&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-04-03T07:53:11Z
body: 
  ## e2e tests failed on `56e33457a3a55e5850ef870fb343a9ce7b3ca36d-1`

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

  File | Test Name
  ---- | ---------
  `native-filters-reproductions.cy.spec.js` | (_flaky_) issue 29786 > should allow using field filters with null schema (metabase#29786)

author_association: CONTRIBUTOR