From f94ec2cce8c4a91f105784217147f41b41d5180c Mon Sep 17 00:00:00 2001
From: "Mahatthana (Kelvin) Nomsawadi" <me@bboykelvin.dev>
Date: Wed, 3 Apr 2024 16:07:17 +0700
Subject: [PATCH] Migrate `dashboard.module.css` (#40918)

* Migrate .DashEditing

* Migrate .CardTitle

* Migrate .PinMap

* Migrate .PinMapUpdateButtonDisabled

* Migrate .BrandColorResizeHandle

* Migrate .VisualizationSlowSpinner

* Migrate .AddSeriesModal

* Migrate 2 more classes
---
 .../20637-add-series-to-dashcard.cy.spec.js   |  4 +-
 .../official-collections.cy.spec.js           |  6 +-
 ...subscription-bar-sent-as-scalar.cy.spec.js |  4 +-
 ...-maps-only-nulls-crash-frontend.cy.spec.js |  6 +-
 ...65-multi-series-frontend-reload.cy.spec.js |  4 +-
 .../30058-32075-map-visualizations.cy.spec.js |  8 +--
 .../src/metabase/css/dashboard.module.css     | 57 ++++++++++---------
 .../DashCardActionsPanel.styled.tsx           |  2 +-
 .../dashboard/components/DashboardGrid.tsx    | 10 ++--
 .../components/LegendHeader.jsx               |  3 +-
 .../visualizations/components/PinMap.jsx      |  6 +-
 .../Visualization/Visualization.jsx           |  3 +-
 .../visualizations/Scalar/Scalar.jsx          |  2 +-
 13 files changed, 58 insertions(+), 57 deletions(-)

diff --git a/e2e/test/scenarios/dashboard-cards/reproductions/20637-add-series-to-dashcard.cy.spec.js b/e2e/test/scenarios/dashboard-cards/reproductions/20637-add-series-to-dashcard.cy.spec.js
index af4e397f30b..6fc3bae3e65 100644
--- a/e2e/test/scenarios/dashboard-cards/reproductions/20637-add-series-to-dashcard.cy.spec.js
+++ b/e2e/test/scenarios/dashboard-cards/reproductions/20637-add-series-to-dashcard.cy.spec.js
@@ -23,9 +23,7 @@ describe("adding an additional series to a dashcard (metabase#20637)", () => {
     // make sure the card query endpoint was used
     cy.wait("@additionalSeriesCardQuery");
 
-    cy.get(".AddSeriesModal").within(() => {
-      cy.findByText("Done").click();
-    });
+    cy.findByTestId("add-series-modal").button("Done").click();
     saveDashboard();
 
     // refresh the page and make sure the dashcard query endpoint was used
diff --git a/e2e/test/scenarios/organization/official-collections.cy.spec.js b/e2e/test/scenarios/organization/official-collections.cy.spec.js
index 327f797fcfe..2886e88e599 100644
--- a/e2e/test/scenarios/organization/official-collections.cy.spec.js
+++ b/e2e/test/scenarios/organization/official-collections.cy.spec.js
@@ -235,9 +235,9 @@ function testOfficialQuestionBadgeInRegularDashboard(expectBadge = true) {
   cy.visit("/collection/root");
   cy.findByText("Regular Dashboard").click();
 
-  cy.get(".DashboardGrid").within(() => {
-    cy.icon("badge").should(expectBadge ? "exist" : "not.exist");
-  });
+  cy.findByTestId("dashboard-grid")
+    .icon("badge")
+    .should(expectBadge ? "exist" : "not.exist");
 }
 
 function openCollection(collectionName) {
diff --git a/e2e/test/scenarios/sharing/reproductions/21559-subscription-bar-sent-as-scalar.cy.spec.js b/e2e/test/scenarios/sharing/reproductions/21559-subscription-bar-sent-as-scalar.cy.spec.js
index 82cfc2cb03c..03d6672c938 100644
--- a/e2e/test/scenarios/sharing/reproductions/21559-subscription-bar-sent-as-scalar.cy.spec.js
+++ b/e2e/test/scenarios/sharing/reproductions/21559-subscription-bar-sent-as-scalar.cy.spec.js
@@ -53,9 +53,7 @@ describe("issue 21559", { tags: "@external" }, () => {
 
     // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
     cy.findByText(q2Details.name).click();
-    cy.get(".AddSeriesModal").within(() => {
-      cy.findByText("Done").click();
-    });
+    cy.findByTestId("add-series-modal").button("Done").click();
 
     // Make sure visualization changed to bars
     cy.get(".bar").should("have.length", 2);
diff --git a/e2e/test/scenarios/visualizations-charts/reproductions/18061-maps-only-nulls-crash-frontend.cy.spec.js b/e2e/test/scenarios/visualizations-charts/reproductions/18061-maps-only-nulls-crash-frontend.cy.spec.js
index 1def7b39a13..af1b08437f8 100644
--- a/e2e/test/scenarios/visualizations-charts/reproductions/18061-maps-only-nulls-crash-frontend.cy.spec.js
+++ b/e2e/test/scenarios/visualizations-charts/reproductions/18061-maps-only-nulls-crash-frontend.cy.spec.js
@@ -116,7 +116,7 @@ describe("issue 18061", () => {
       cy.findByTestId("qb-filters-panel")
         .findByText("ID is less than 2")
         .should("be.visible");
-      cy.get(".PinMap").should("be.visible");
+      cy.get("[data-element-id=pin-map]").should("be.visible");
 
       cy.window().should("have.prop", "beforeReload", true);
     });
@@ -146,12 +146,12 @@ describe("issue 18061", () => {
       cy.findByText("18061D");
       // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
       cy.findByText("18061");
-      cy.get(".PinMap");
+      cy.get("[data-element-id=pin-map]");
 
       addFilter("Twitter");
       cy.location("search").should("eq", "?category=Twitter");
       cy.findAllByTestId("no-results-image");
-      cy.get(".PinMap").should("not.exist");
+      cy.get("[data-element-id=pin-map]").should("not.exist");
     });
   });
 });
diff --git a/e2e/test/scenarios/visualizations-charts/reproductions/21665-multi-series-frontend-reload.cy.spec.js b/e2e/test/scenarios/visualizations-charts/reproductions/21665-multi-series-frontend-reload.cy.spec.js
index dbf2ea04917..62d0b1c1313 100644
--- a/e2e/test/scenarios/visualizations-charts/reproductions/21665-multi-series-frontend-reload.cy.spec.js
+++ b/e2e/test/scenarios/visualizations-charts/reproductions/21665-multi-series-frontend-reload.cy.spec.js
@@ -47,9 +47,7 @@ describe("issue 21665", () => {
     // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
     cy.findByText(Q2.name).click();
 
-    cy.get(".AddSeriesModal").within(() => {
-      cy.button("Done").click();
-    });
+    cy.findByTestId("add-series-modal").button("Done").click();
 
     saveDashboard();
     cy.wait("@getDashboard");
diff --git a/e2e/test/scenarios/visualizations-charts/reproductions/30058-32075-map-visualizations.cy.spec.js b/e2e/test/scenarios/visualizations-charts/reproductions/30058-32075-map-visualizations.cy.spec.js
index f0f4e8f1226..40df657977a 100644
--- a/e2e/test/scenarios/visualizations-charts/reproductions/30058-32075-map-visualizations.cy.spec.js
+++ b/e2e/test/scenarios/visualizations-charts/reproductions/30058-32075-map-visualizations.cy.spec.js
@@ -51,7 +51,7 @@ describe("issue 32075", () => {
     visualize();
 
     cy.findByTestId("TableInteractive-root").should("not.exist");
-    cy.get(".PinMap").should("exist");
+    cy.get("[data-element-id=pin-map]").should("exist");
   });
 
   it("should still display visualization as a map after adding another column to group by", () => {
@@ -63,7 +63,7 @@ describe("issue 32075", () => {
     visualize();
 
     cy.findByTestId("TableInteractive-root").should("not.exist");
-    cy.get(".PinMap").should("exist");
+    cy.get("[data-element-id=pin-map]").should("exist");
   });
 
   it("should still display visualization as a map after adding another aggregation", () => {
@@ -75,7 +75,7 @@ describe("issue 32075", () => {
     visualize();
 
     cy.findByTestId("TableInteractive-root").should("not.exist");
-    cy.get(".PinMap").should("exist");
+    cy.get("[data-element-id=pin-map]").should("exist");
   });
 
   it("should change display to default after removing a column to group by when map is not sensible anymore", () => {
@@ -86,7 +86,7 @@ describe("issue 32075", () => {
     removeSummaryGroupingField({ field: "Latitude: Auto binned" });
     visualize();
 
-    cy.get(".PinMap").should("not.exist");
+    cy.get("[data-element-id=pin-map]").should("not.exist");
     cy.get(".LineAreaBarChart").should("exist");
   });
 });
diff --git a/frontend/src/metabase/css/dashboard.module.css b/frontend/src/metabase/css/dashboard.module.css
index c1721d125e4..858a9dae069 100644
--- a/frontend/src/metabase/css/dashboard.module.css
+++ b/frontend/src/metabase/css/dashboard.module.css
@@ -59,67 +59,68 @@
   transition: background-color 1s linear, border 1s linear;
 }
 
-:global(.Dash--editing) {
+.DashEditing {
   margin-top: 1.5em;
 }
 
-:global(.Dash--editing) .DashCard .Card {
+.DashEditing .DashCard .Card {
   transition: border 0.3s, background-color 0.3s;
 }
 
-:global(.Dash--editing .Card-title:first-of-type) {
+.DashEditing .CardTitle:first-of-type {
   margin-top: 0.5rem;
 }
 
-:global(.Dash--editing .Card-title) {
+.DashEditing .CardTitle {
   pointer-events: none;
 }
 
-:global(.Dash--editing .PinMap) {
+.DashEditing .PinMap {
   /* allow map to pan. need to stopPropagation in PinMap to prevent weird dragging interaction */
   pointer-events: all;
 }
 
-:global(.PinMapUpdateButton--disabled) {
+.PinMapUpdateButtonDisabled {
   pointer-events: none;
   color: var(--color-text-light);
 }
 
-:global(.Dash--editing) .DashCard:global(.react-draggable-dragging) .Card {
+/* .react-draggable*, .react-resizable* are 3rd party library classes */
+.DashEditing .DashCard:global(.react-draggable-dragging) .Card {
   box-shadow: 3px 3px 8px var(--color-shadow);
 }
 
-:global(.BrandColorResizeHandle .react-resizable-handle::after) {
+.BrandColorResizeHandle :global(.react-resizable-handle::after) {
   border-color: var(--color-brand) !important;
 }
 
-:global(.Dash--editing) .DashCard:global(.react-draggable-dragging),
-:global(.Dash--editing) .DashCard:global(.react-resizable-resizing) {
+.DashEditing .DashCard:global(.react-draggable-dragging),
+.DashEditing .DashCard:global(.react-resizable-resizing) {
   z-index: 3;
 }
 
-:global(.Dash--editing) .DashCard:global(.react-draggable-dragging) .Card,
-:global(.Dash--editing) .DashCard:global(.react-resizable-resizing) .Card {
+.DashEditing .DashCard:global(.react-draggable-dragging) .Card,
+.DashEditing .DashCard:global(.react-resizable-resizing) .Card {
   background-color: var(--color-bg-medium) !important;
   border: 1px solid var(--color-brand);
 }
 
-:global(.Dash--editing) .DashCard :global(.Visualization-slow-spinner) {
+.DashEditing .DashCard .VisualizationSlowSpinner {
   position: absolute;
   right: -2px;
   top: -2px;
 }
 
-:global(.Dash--editing) .DashCard:hover :global(.Visualization-slow-spinner) {
+.DashEditing .DashCard:hover .VisualizationSlowSpinner {
   opacity: 0;
   transition: opacity 0.15s linear;
 }
 
-:global(.Dash--editing) .DashCard {
+.DashEditing .DashCard {
   cursor: move;
 }
 
-:global(.Dash--editing) .DashCard :global(.react-resizable-handle) {
+.DashEditing .DashCard :global(.react-resizable-handle) {
   position: absolute;
   width: 40px;
   height: 40px;
@@ -132,7 +133,7 @@
   background: none; /* hide default RGL's resize handle */
 }
 
-:global(.Dash--editing) .DashCard :global(.react-resizable-handle::after) {
+.DashEditing .DashCard :global(.react-resizable-handle::after) {
   content: "";
   position: absolute;
   width: 8px;
@@ -146,32 +147,34 @@
   opacity: 0.01;
 }
 
-:global(.Dash--editing)
-  .DashCard
-  :global(.react-resizable-handle:hover::after) {
+.DashEditing .DashCard :global(.react-resizable-handle:hover::after) {
   border-color: var(--color-border);
 }
 
-:global(.Dash--editing)
-  .DashCard:hover
-  :global(.react-resizable-handle::after) {
+.DashEditing .DashCard:hover :global(.react-resizable-handle::after) {
   opacity: 1;
 }
 
-:global(.Dash--editing)
+.DashEditing
   .DashCard:global(.react-draggable-dragging .react-resizable-handle::after),
-:global(.Dash--editing)
+.DashEditing
   .DashCard:global(.react-resizable-resizing .react-resizable-handle::after) {
   opacity: 0.01;
 }
 
-:global(.Dash--editing .react-grid-placeholder) {
+/* .react-grid-placeholder is a global class from `react-grid-layout` */
+.DashEditing :global(.react-grid-placeholder) {
   z-index: 0;
   background-color: var(--color-bg-light) !important;
   transition: all 0.15s linear;
 }
 
-:global(.Modal.AddSeriesModal) {
+/* Used in frontend/src/metabase/dashboard/components/DashCard/DashCardActionsPanel/DashCardActionsPanel.styled.tsx */
+/* stylelint-disable-next-line block-no-empty */
+.DashDragging {
+}
+
+:global(.Modal).AddSeriesModal {
   height: 80%;
   max-height: 600px;
   width: 80%;
diff --git a/frontend/src/metabase/dashboard/components/DashCard/DashCardActionsPanel/DashCardActionsPanel.styled.tsx b/frontend/src/metabase/dashboard/components/DashCard/DashCardActionsPanel/DashCardActionsPanel.styled.tsx
index 406af144230..0b54a892f4e 100644
--- a/frontend/src/metabase/dashboard/components/DashCard/DashCardActionsPanel/DashCardActionsPanel.styled.tsx
+++ b/frontend/src/metabase/dashboard/components/DashCard/DashCardActionsPanel/DashCardActionsPanel.styled.tsx
@@ -54,7 +54,7 @@ export const DashCardActionsPanelContainer = styled("div", {
     pointer-events: all;
   }
 
-  .Dash--dragging & {
+  .${DashboardS.DashDragging} & {
     display: none;
   }
 `;
diff --git a/frontend/src/metabase/dashboard/components/DashboardGrid.tsx b/frontend/src/metabase/dashboard/components/DashboardGrid.tsx
index ffe6ba70227..48faaa0aaeb 100644
--- a/frontend/src/metabase/dashboard/components/DashboardGrid.tsx
+++ b/frontend/src/metabase/dashboard/components/DashboardGrid.tsx
@@ -372,7 +372,7 @@ class DashboardGrid extends Component<DashboardGridProps, DashboardGridState> {
       !!addSeriesModalDashCard && isQuestionDashCard(addSeriesModalDashCard);
     return (
       <Modal
-        className="Modal AddSeriesModal"
+        className={cx("Modal", DashboardS.AddSeriesModal)}
         data-testid="add-series-modal"
         isOpen={isOpen}
       >
@@ -574,7 +574,7 @@ class DashboardGrid extends Component<DashboardGridProps, DashboardGridState> {
           EmbedFrameS.DashCard,
           LegendS.DashCard,
           {
-            BrandColorResizeHandle: shouldChangeResizeHandle,
+            [DashboardS.BrandColorResizeHandle]: shouldChangeResizeHandle,
           },
         )}
         isAnimationDisabled={this.state.isAnimationPaused}
@@ -594,9 +594,9 @@ class DashboardGrid extends Component<DashboardGridProps, DashboardGridState> {
     const rowHeight = this.getRowHeight();
     return (
       <GridLayout
-        className={cx("DashboardGrid", {
-          "Dash--editing": this.isEditingLayout,
-          "Dash--dragging": this.state.isDragging,
+        className={cx({
+          [DashboardS.DashEditing]: this.isEditingLayout,
+          [DashboardS.DashDragging]: this.state.isDragging,
         })}
         layouts={layouts}
         breakpoints={GRID_BREAKPOINTS}
diff --git a/frontend/src/metabase/visualizations/components/LegendHeader.jsx b/frontend/src/metabase/visualizations/components/LegendHeader.jsx
index e90e67668d5..375f9f7e7ed 100644
--- a/frontend/src/metabase/visualizations/components/LegendHeader.jsx
+++ b/frontend/src/metabase/visualizations/components/LegendHeader.jsx
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
 import { Component } from "react";
 
 import CS from "metabase/css/core/index.css";
+import DashboardS from "metabase/css/dashboard.module.css";
 import { getAccentColors } from "metabase/lib/colors/groups";
 
 import ExplicitSize from "../../components/ExplicitSize";
@@ -59,7 +60,7 @@ class LegendHeader extends Component {
       <div
         className={cx(
           styles.LegendHeader,
-          "Card-title",
+          DashboardS.CardTitle,
           CS.textDefault,
           CS.textSmaller,
           CS.mx1,
diff --git a/frontend/src/metabase/visualizations/components/PinMap.jsx b/frontend/src/metabase/visualizations/components/PinMap.jsx
index 50118c1ffba..14320bf95c9 100644
--- a/frontend/src/metabase/visualizations/components/PinMap.jsx
+++ b/frontend/src/metabase/visualizations/components/PinMap.jsx
@@ -8,6 +8,7 @@ import _ from "underscore";
 
 import ButtonsS from "metabase/css/components/buttons.module.css";
 import CS from "metabase/css/core/index.css";
+import DashboardS from "metabase/css/dashboard.module.css";
 import { LatitudeLongitudeError } from "metabase/visualizations/lib/errors";
 import { hasLatitudeAndLongitudeColumns } from "metabase-lib/v1/types/utils/isa";
 
@@ -186,9 +187,10 @@ export default class PinMap extends Component {
 
     return (
       <div
+        data-element-id="pin-map"
         className={cx(
           className,
-          "PinMap",
+          DashboardS.PinMap,
           CS.relative,
           CS.hoverParent,
           CS.hoverVisibility,
@@ -241,7 +243,7 @@ export default class PinMap extends Component {
                 ButtonsS.ButtonSmall,
                 CS.mb1,
                 {
-                  "PinMapUpdateButton--disabled": disableUpdateButton,
+                  [DashboardS.PinMapUpdateButtonDisabled]: disableUpdateButton,
                 },
               )}
               onClick={this.updateSettings}
diff --git a/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx b/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx
index 44fbb7f7f7a..41b7ca8a4da 100644
--- a/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx
+++ b/frontend/src/metabase/visualizations/components/Visualization/Visualization.jsx
@@ -9,6 +9,7 @@ import _ from "underscore";
 import ErrorBoundary from "metabase/ErrorBoundary";
 import ExplicitSize from "metabase/components/ExplicitSize";
 import CS from "metabase/css/core/index.css";
+import DashboardS from "metabase/css/dashboard.module.css";
 import * as MetabaseAnalytics from "metabase/lib/analytics";
 import { formatNumber } from "metabase/lib/formatting";
 import { equals } from "metabase/lib/utils";
@@ -418,7 +419,7 @@ class Visualization extends PureComponent {
       <VisualizationActionButtonsContainer>
         {isSlow && !loading && (
           <VisualizationSlowSpinner
-            className="Visualization-slow-spinner"
+            className={DashboardS.VisualizationSlowSpinner}
             size={18}
             isUsuallySlow={isSlow === "usually-slow"}
           />
diff --git a/frontend/src/metabase/visualizations/visualizations/Scalar/Scalar.jsx b/frontend/src/metabase/visualizations/visualizations/Scalar/Scalar.jsx
index fd5563faa3c..dd3e41be65a 100644
--- a/frontend/src/metabase/visualizations/visualizations/Scalar/Scalar.jsx
+++ b/frontend/src/metabase/visualizations/visualizations/Scalar/Scalar.jsx
@@ -224,7 +224,7 @@ export class Scalar extends Component {
       <ScalarWrapper>
         <div
           className={cx(
-            "Card-title",
+            DashboardS.CardTitle,
             CS.textDefault,
             CS.textSmaller,
             CS.absolute,
-- 
GitLab