From e20c00b15523a313262c0977293d57c594421dd7 Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Fri, 25 Oct 2024 12:10:34 -0400
Subject: [PATCH] Fix actions without parameters (#49125)

* Fix actions without parameters

* Update frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.unit.spec.tsx

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>

---------

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
---
 frontend/src/metabase-types/api/actions.ts     |  2 +-
 .../src/metabase-types/api/mocks/actions.ts    |  4 ++--
 .../ActionViz/ActionDashcardSettings.tsx       |  4 ++--
 .../ActionDashcardSettings.unit.spec.tsx       | 10 ++++++++++
 .../hooks/use-action-form/use-action-form.ts   | 18 ++++++++++--------
 5 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/frontend/src/metabase-types/api/actions.ts b/frontend/src/metabase-types/api/actions.ts
index cf69fdf9465..193458b91f3 100644
--- a/frontend/src/metabase-types/api/actions.ts
+++ b/frontend/src/metabase-types/api/actions.ts
@@ -18,7 +18,7 @@ export interface WritebackActionBase {
   model_id: CardId;
   name: string;
   description: string | null;
-  parameters: WritebackParameter[];
+  parameters?: WritebackParameter[];
   visualization_settings?: ActionFormSettings;
   archived: boolean;
   creator_id: UserId;
diff --git a/frontend/src/metabase-types/api/mocks/actions.ts b/frontend/src/metabase-types/api/mocks/actions.ts
index daba99ef685..5b62571d294 100644
--- a/frontend/src/metabase-types/api/mocks/actions.ts
+++ b/frontend/src/metabase-types/api/mocks/actions.ts
@@ -41,7 +41,7 @@ export const createMockQueryAction = ({
     description: null,
     model_id: 1,
     database_id: 1,
-    parameters: [],
+    parameters: undefined,
     creator_id: creator.id,
     creator,
     archived: false,
@@ -66,7 +66,7 @@ export const createMockImplicitQueryAction = ({
   description: "",
   model_id: 1,
   database_id: 1,
-  parameters: [],
+  parameters: undefined,
   visualization_settings: undefined,
   creator_id: creator.id,
   creator,
diff --git a/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.tsx b/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.tsx
index 56056b3ed9b..30c79093cd5 100644
--- a/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.tsx
+++ b/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.tsx
@@ -71,8 +71,8 @@ export function ActionDashcardSettings({
   );
 
   const isFormInvalid =
-    !!action &&
-    action.parameters.some(actionParameter => {
+    action != null &&
+    action.parameters?.some(actionParameter => {
       const isHidden = isParameterHidden(action, actionParameter);
       const isRequired = isParameterRequired(action, actionParameter);
       const isParameterMapped =
diff --git a/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.unit.spec.tsx b/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.unit.spec.tsx
index 27b4ff6e4c4..440c7e1f21f 100644
--- a/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.unit.spec.tsx
+++ b/frontend/src/metabase/actions/components/ActionViz/ActionDashcardSettings.unit.spec.tsx
@@ -456,6 +456,16 @@ describe("ActionViz > ActionDashcardSettings", () => {
     ).toBeInTheDocument();
   });
 
+  it("should be valid and not crash when the action does not have parameters (metabase#32665)", async () => {
+    const { closeSpy } = setup({
+      dashcard: createMockActionDashboardCard({
+        action: createMockQueryAction(),
+      }),
+    });
+    await userEvent.click(screen.getByRole("button", { name: "Done" }));
+    expect(closeSpy).toHaveBeenCalled();
+  });
+
   it("shows parameters for an action", async () => {
     setup({
       dashcard: actionDashcardWithAction,
diff --git a/frontend/src/metabase/actions/hooks/use-action-form/use-action-form.ts b/frontend/src/metabase/actions/hooks/use-action-form/use-action-form.ts
index cef65992305..95f904d3cfc 100644
--- a/frontend/src/metabase/actions/hooks/use-action-form/use-action-form.ts
+++ b/frontend/src/metabase/actions/hooks/use-action-form/use-action-form.ts
@@ -6,6 +6,7 @@ import type {
   ActionFormInitialValues,
   ParametersForActionExecution,
   WritebackAction,
+  WritebackParameter,
 } from "metabase-types/api";
 
 import {
@@ -22,27 +23,28 @@ type Opts = {
 };
 
 const INITIAL_VALUES = {};
+const DEFAULT_PARAMETERS: WritebackParameter[] = [];
 
 function useActionForm({
-  action,
+  action: { parameters = DEFAULT_PARAMETERS, visualization_settings },
   initialValues = INITIAL_VALUES,
   prefetchesInitialValues,
 }: Opts) {
   const fieldSettings = useMemo(() => {
     return getOrGenerateFieldSettings(
-      action.parameters,
-      action.visualization_settings?.fields,
+      parameters,
+      visualization_settings?.fields,
     );
-  }, [action]);
+  }, [parameters, visualization_settings]);
 
   const form = useMemo(
-    () => getForm(action.parameters, fieldSettings),
-    [action.parameters, fieldSettings],
+    () => getForm(parameters, fieldSettings),
+    [parameters, fieldSettings],
   );
 
   const validationSchema = useMemo(
-    () => getFormValidationSchema(action.parameters, fieldSettings),
-    [action.parameters, fieldSettings],
+    () => getFormValidationSchema(parameters, fieldSettings),
+    [parameters, fieldSettings],
   );
 
   const cleanedInitialValues = useMemo(() => {
-- 
GitLab