From d33fa86ab0d4cd54d2db43349224d6d751bf67cc Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Fri, 6 May 2022 17:23:01 +0300
Subject: [PATCH] Fix pasting non-numeric values into numeric filters (#22453)

---
 .../metabase/components/FieldValuesWidget.jsx |  5 ++--
 .../src/metabase/components/TokenField.jsx    |  8 ++----
 .../9339-clipboard-numeric-filter.cy.spec.js  | 26 +++++++++++++++++++
 3 files changed, 31 insertions(+), 8 deletions(-)
 create mode 100644 frontend/test/metabase/scenarios/filters/reproductions/9339-clipboard-numeric-filter.cy.spec.js

diff --git a/frontend/src/metabase/components/FieldValuesWidget.jsx b/frontend/src/metabase/components/FieldValuesWidget.jsx
index ba08d7abcef..5af49a7af6d 100644
--- a/frontend/src/metabase/components/FieldValuesWidget.jsx
+++ b/frontend/src/metabase/components/FieldValuesWidget.jsx
@@ -481,8 +481,9 @@ export class FieldValuesWidget extends Component {
               }
               // if the field is numeric we need to parse the string into an integer
               if (fields[0].isNumeric()) {
-                if (/^-?\d+(\.\d+)?$/.test(v)) {
-                  return parseFloat(v);
+                const n = Number.parseFloat(v);
+                if (Number.isFinite(n)) {
+                  return n;
                 } else {
                   return null;
                 }
diff --git a/frontend/src/metabase/components/TokenField.jsx b/frontend/src/metabase/components/TokenField.jsx
index 5dca1bf410c..a89f4e2390e 100644
--- a/frontend/src/metabase/components/TokenField.jsx
+++ b/frontend/src/metabase/components/TokenField.jsx
@@ -300,12 +300,8 @@ export default class TokenField extends Component {
     if (this.props.parseFreeformValue) {
       e.preventDefault();
       const string = e.clipboardData.getData("Text");
-      const values = this.props.multi
-        ? string
-            .split(/\n|,/g)
-            .map(this.props.parseFreeformValue)
-            .filter(s => s)
-        : [string];
+      const lines = this.props.multi ? string.split(/\n|,/g) : [string];
+      const values = lines.map(this.props.parseFreeformValue).filter(s => s);
       if (values.length > 0) {
         this.addValue(values);
       }
diff --git a/frontend/test/metabase/scenarios/filters/reproductions/9339-clipboard-numeric-filter.cy.spec.js b/frontend/test/metabase/scenarios/filters/reproductions/9339-clipboard-numeric-filter.cy.spec.js
new file mode 100644
index 00000000000..f57f47fa8b6
--- /dev/null
+++ b/frontend/test/metabase/scenarios/filters/reproductions/9339-clipboard-numeric-filter.cy.spec.js
@@ -0,0 +1,26 @@
+import { openOrdersTable, restore } from "__support__/e2e/cypress";
+
+describe("issue 9339", () => {
+  beforeEach(() => {
+    restore();
+    cy.signInAsAdmin();
+  });
+
+  it("should not paste non-numeric values into single-value numeric filters (metabase#9339)", () => {
+    openOrdersTable();
+
+    cy.findByText("Total").click();
+    cy.findByText("Filter by this column").click();
+    cy.findByText("Equal to").click();
+    cy.findByText("Greater than").click();
+
+    paste(cy.findByPlaceholderText("Enter a number"), "9339,1234");
+    cy.findByText("9,339").should("be.visible");
+    cy.findByText("1,234").should("not.exist");
+    cy.button("Add filter").should("be.enabled");
+  });
+});
+
+const paste = (selection, text) => {
+  selection.trigger("paste", { clipboardData: { getData: () => text } });
+};
-- 
GitLab