From 198ebcf5d1dbaa827f4d173a322fbeef5a791206 Mon Sep 17 00:00:00 2001
From: Denis Berezin <denis.berezin@metabase.com>
Date: Thu, 18 Apr 2024 20:15:56 +0300
Subject: [PATCH] Fix Embedded dashboard parameters parse runtime error
 (#41545)

* Fix parameters parse

* Add e2e test

* Add e2e test
---
 .../scenarios/sharing/public-dashboard.cy.spec.js   | 12 ++++++++++++
 frontend/src/metabase/lib/browser.js                |  4 +++-
 frontend/src/metabase/lib/utils.ts                  | 13 +++++++++++++
 .../PublicDashboard/PublicDashboard.unit.spec.tsx   | 10 ++++++++++
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/e2e/test/scenarios/sharing/public-dashboard.cy.spec.js b/e2e/test/scenarios/sharing/public-dashboard.cy.spec.js
index a99eb9a389d..1e3d17cca03 100644
--- a/e2e/test/scenarios/sharing/public-dashboard.cy.spec.js
+++ b/e2e/test/scenarios/sharing/public-dashboard.cy.spec.js
@@ -245,4 +245,16 @@ describe("scenarios > public > dashboard", () => {
 
     assertDashboardFullWidth();
   });
+
+  it("should render when a filter passed with value starting from '0' (metabase#41483)", () => {
+    cy.get("@dashboardId").then(id => {
+      visitPublicDashboard(id, {
+        params: { text: "002" },
+      });
+    });
+
+    cy.url().should("include", "text=002");
+
+    filterWidget().findByText("002").should("be.visible");
+  });
 });
diff --git a/frontend/src/metabase/lib/browser.js b/frontend/src/metabase/lib/browser.js
index 94324621047..77a9cb778a7 100644
--- a/frontend/src/metabase/lib/browser.js
+++ b/frontend/src/metabase/lib/browser.js
@@ -1,5 +1,7 @@
 import querystring from "querystring";
 
+import { safeJsonParse } from "metabase/lib/utils";
+
 function parseQueryStringOptions(s) {
   const options = querystring.parse(s);
 
@@ -7,7 +9,7 @@ function parseQueryStringOptions(s) {
     if (options[name] === "") {
       options[name] = true;
     } else if (/^(true|false|-?\d+(\.\d+)?)$/.test(options[name])) {
-      options[name] = JSON.parse(options[name]);
+      options[name] = safeJsonParse(options[name]);
     }
   }
 
diff --git a/frontend/src/metabase/lib/utils.ts b/frontend/src/metabase/lib/utils.ts
index eef73460d82..a7dc02eb659 100644
--- a/frontend/src/metabase/lib/utils.ts
+++ b/frontend/src/metabase/lib/utils.ts
@@ -184,3 +184,16 @@ export function compareVersions(
 }
 
 export const isEEBuild = () => PLUGIN_IS_EE_BUILD.isEEBuild();
+
+export const safeJsonParse = (value: string | null | undefined) => {
+  if (!value) {
+    return null;
+  }
+
+  try {
+    return JSON.parse(value);
+  } catch (e) {
+    console.error("Unable to parse JSON: ", value, e);
+    return null;
+  }
+};
diff --git a/frontend/src/metabase/public/containers/PublicDashboard/PublicDashboard.unit.spec.tsx b/frontend/src/metabase/public/containers/PublicDashboard/PublicDashboard.unit.spec.tsx
index 9c1e8c125a8..30c5e9cfbe3 100644
--- a/frontend/src/metabase/public/containers/PublicDashboard/PublicDashboard.unit.spec.tsx
+++ b/frontend/src/metabase/public/containers/PublicDashboard/PublicDashboard.unit.spec.tsx
@@ -70,6 +70,16 @@ describe("PublicDashboard", () => {
 
     expect(firstTab).toHaveAttribute("aria-selected", "true");
   });
+
+  it("should render when a filter passed with value starting from '0' (metabase#41483)", async () => {
+    // note: as all slugs this is ignored and we only use the id
+    await setup({
+      queryString: "?my-filter-value=01",
+    });
+
+    // should not throw runtime error and render dashboard content
+    expect(screen.getByText(DASHBOARD_TITLE)).toBeInTheDocument();
+  });
 });
 
 async function setup({
-- 
GitLab