From e1ffb582f02c1a1ddc8134874daf25442b263af2 Mon Sep 17 00:00:00 2001
From: Oisin Coveney <oisin@metabase.com>
Date: Wed, 26 Jun 2024 12:54:04 +0300
Subject: [PATCH] Split SummarizeContent from SummarizeSidebar (#44539)

---
 .../SummarizeContent/SummarizeContent.tsx     |  84 +++++++++
 .../SummarizeContent/index.ts                 |   2 +
 .../SummarizeContent/use-summarize-query.ts   | 120 ++++++++++++
 .../SummarizeSidebar/SummarizeSidebar.tsx     | 173 +++---------------
 4 files changed, 235 insertions(+), 144 deletions(-)
 create mode 100644 frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/SummarizeContent.tsx
 create mode 100644 frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/index.ts
 create mode 100644 frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/use-summarize-query.ts

diff --git a/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/SummarizeContent.tsx b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/SummarizeContent.tsx
new file mode 100644
index 00000000000..49abef055b0
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/SummarizeContent.tsx
@@ -0,0 +1,84 @@
+import { t } from "ttag";
+
+import * as Lib from "metabase-lib";
+
+import { AddAggregationButton } from "../AddAggregationButton";
+import { AggregationItem } from "../AggregationItem";
+import { BreakoutColumnList } from "../BreakoutColumnList";
+import {
+  AggregationsContainer,
+  ColumnListContainer,
+  SectionTitle,
+} from "../SummarizeSidebar.styled";
+
+import { STAGE_INDEX } from "./use-summarize-query";
+
+export type SummarizeContentProps = {
+  query: Lib.Query;
+  aggregations: Lib.AggregationClause[];
+  hasAggregations: boolean;
+  onAddAggregations: (aggregations: Lib.Aggregable[]) => void;
+  onUpdateAggregation: (
+    aggregation: Lib.AggregationClause,
+    nextAggregation: Lib.Aggregable,
+  ) => void;
+  onRemoveAggregation: (aggregation: Lib.AggregationClause) => void;
+  onAddBreakout: (column: Lib.ColumnMetadata) => void;
+  onUpdateBreakout: (
+    clause: Lib.BreakoutClause,
+    column: Lib.ColumnMetadata,
+  ) => void;
+  onRemoveBreakout: (column: Lib.ColumnMetadata) => void;
+  onReplaceBreakouts: (column: Lib.ColumnMetadata) => void;
+};
+
+export const SummarizeContent = ({
+  query,
+  aggregations,
+  hasAggregations,
+  onAddAggregations,
+  onUpdateAggregation,
+  onRemoveAggregation,
+  onAddBreakout,
+  onUpdateBreakout,
+  onRemoveBreakout,
+  onReplaceBreakouts,
+}: SummarizeContentProps) => {
+  return (
+    <>
+      <AggregationsContainer>
+        {aggregations.map((aggregation, aggregationIndex) => (
+          <AggregationItem
+            key={
+              Lib.displayInfo(query, STAGE_INDEX, aggregation).longDisplayName
+            }
+            query={query}
+            aggregation={aggregation}
+            aggregationIndex={aggregationIndex}
+            onAdd={onAddAggregations}
+            onUpdate={nextAggregation =>
+              onUpdateAggregation(aggregation, nextAggregation)
+            }
+            onRemove={() => onRemoveAggregation(aggregation)}
+          />
+        ))}
+        <AddAggregationButton
+          query={query}
+          onAddAggregations={onAddAggregations}
+        />
+      </AggregationsContainer>
+      {hasAggregations && (
+        <ColumnListContainer>
+          <SectionTitle>{t`Group by`}</SectionTitle>
+          <BreakoutColumnList
+            query={query}
+            onAddBreakout={onAddBreakout}
+            onUpdateBreakout={onUpdateBreakout}
+            onRemoveBreakout={onRemoveBreakout}
+            onReplaceBreakout={onReplaceBreakouts}
+          />
+        </ColumnListContainer>
+      )}
+    </>
+  );
+};
diff --git a/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/index.ts b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/index.ts
new file mode 100644
index 00000000000..a64cebbdd55
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/index.ts
@@ -0,0 +1,2 @@
+export * from "./use-summarize-query";
+export * from "./SummarizeContent";
diff --git a/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/use-summarize-query.ts b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/use-summarize-query.ts
new file mode 100644
index 00000000000..09297b7af41
--- /dev/null
+++ b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/use-summarize-query.ts
@@ -0,0 +1,120 @@
+import { useCallback, useMemo, useState } from "react";
+
+import * as Lib from "metabase-lib";
+
+export const STAGE_INDEX = -1;
+export const useSummarizeQuery = (
+  initialQuery: Lib.Query,
+  onQueryChange: (query: Lib.Query) => void,
+) => {
+  const [isDefaultAggregationRemoved, setDefaultAggregationRemoved] =
+    useState(false);
+
+  const query = useMemo(
+    () => getQuery(initialQuery, isDefaultAggregationRemoved),
+    [initialQuery, isDefaultAggregationRemoved],
+  );
+
+  const aggregations = Lib.aggregations(query, STAGE_INDEX);
+  const hasAggregations = aggregations.length > 0;
+
+  const handleAddAggregations = useCallback(
+    (aggregations: Lib.Aggregable[]) => {
+      const nextQuery = aggregations.reduce(
+        (query, aggregation) => Lib.aggregate(query, STAGE_INDEX, aggregation),
+        query,
+      );
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+
+  const handleUpdateAggregation = useCallback(
+    (aggregation: Lib.AggregationClause, nextAggregation: Lib.Aggregable) => {
+      const nextQuery = Lib.replaceClause(
+        query,
+        STAGE_INDEX,
+        aggregation,
+        nextAggregation,
+      );
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+
+  const handleRemoveAggregation = useCallback(
+    (aggregation: Lib.AggregationClause) => {
+      const nextQuery = Lib.removeClause(query, STAGE_INDEX, aggregation);
+      const nextAggregations = Lib.aggregations(nextQuery, STAGE_INDEX);
+      if (nextAggregations.length === 0) {
+        setDefaultAggregationRemoved(true);
+      }
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+
+  const handleAddBreakout = useCallback(
+    (column: Lib.ColumnMetadata) => {
+      const nextQuery = Lib.breakout(query, STAGE_INDEX, column);
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+
+  const handleUpdateBreakout = useCallback(
+    (clause: Lib.BreakoutClause, column: Lib.ColumnMetadata) => {
+      const nextQuery = Lib.replaceClause(query, STAGE_INDEX, clause, column);
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+
+  const handleRemoveBreakout = useCallback(
+    (column: Lib.ColumnMetadata) => {
+      const { breakoutPosition } = Lib.displayInfo(query, STAGE_INDEX, column);
+      if (typeof breakoutPosition === "number") {
+        const breakouts = Lib.breakouts(query, STAGE_INDEX);
+        const clause = breakouts[breakoutPosition];
+        const nextQuery = Lib.removeClause(query, STAGE_INDEX, clause);
+        onQueryChange(nextQuery);
+      }
+    },
+    [query, onQueryChange],
+  );
+
+  const handleReplaceBreakouts = useCallback(
+    (column: Lib.ColumnMetadata) => {
+      const nextQuery = Lib.replaceBreakouts(query, STAGE_INDEX, column);
+      onQueryChange(nextQuery);
+    },
+    [query, onQueryChange],
+  );
+  return {
+    query,
+    aggregations,
+    hasAggregations,
+    handleAddAggregations,
+    handleUpdateAggregation,
+    handleRemoveAggregation,
+    handleAddBreakout,
+    handleUpdateBreakout,
+    handleRemoveBreakout,
+    handleReplaceBreakouts,
+  };
+};
+
+function getQuery(query: Lib.Query, isDefaultAggregationRemoved: boolean) {
+  const hasAggregations = Lib.aggregations(query, STAGE_INDEX).length > 0;
+
+  const shouldAddDefaultAggregation =
+    !hasAggregations &&
+    !Lib.isMetricBased(query, STAGE_INDEX) &&
+    !isDefaultAggregationRemoved;
+
+  if (!shouldAddDefaultAggregation) {
+    return query;
+  }
+
+  return Lib.aggregateByCount(query);
+}
diff --git a/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeSidebar.tsx b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeSidebar.tsx
index 400ac4dba79..e4ce79c7a18 100644
--- a/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeSidebar.tsx
+++ b/frontend/src/metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeSidebar.tsx
@@ -1,20 +1,12 @@
-import { useCallback, useMemo, useState } from "react";
+import { useCallback } from "react";
 import { t } from "ttag";
 
 import { color } from "metabase/lib/colors";
-import * as Lib from "metabase-lib";
+import { SummarizeContent } from "metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/SummarizeContent";
+import { useSummarizeQuery } from "metabase/query_builder/components/view/sidebars/SummarizeSidebar/SummarizeContent/use-summarize-query";
+import type * as Lib from "metabase-lib";
 
-import { AddAggregationButton } from "./AddAggregationButton";
-import { AggregationItem } from "./AggregationItem";
-import { BreakoutColumnList } from "./BreakoutColumnList";
-import {
-  AggregationsContainer,
-  ColumnListContainer,
-  SectionTitle,
-  SidebarView,
-} from "./SummarizeSidebar.styled";
-
-const STAGE_INDEX = -1;
+import { SidebarView } from "./SummarizeSidebar.styled";
 
 interface SummarizeSidebarProps {
   className?: string;
@@ -29,89 +21,18 @@ export function SummarizeSidebar({
   onQueryChange,
   onClose,
 }: SummarizeSidebarProps) {
-  const [isDefaultAggregationRemoved, setDefaultAggregationRemoved] =
-    useState(false);
-
-  const query = useMemo(
-    () => getQuery(initialQuery, isDefaultAggregationRemoved),
-    [initialQuery, isDefaultAggregationRemoved],
-  );
-
-  const aggregations = Lib.aggregations(query, STAGE_INDEX);
-  const hasAggregations = aggregations.length > 0;
-
-  const handleAddAggregations = useCallback(
-    (aggregations: Lib.Aggregable[]) => {
-      const nextQuery = aggregations.reduce(
-        (query, aggregation) => Lib.aggregate(query, STAGE_INDEX, aggregation),
-        query,
-      );
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
-
-  const handleUpdateAggregation = useCallback(
-    (aggregation: Lib.AggregationClause, nextAggregation: Lib.Aggregable) => {
-      const nextQuery = Lib.replaceClause(
-        query,
-        STAGE_INDEX,
-        aggregation,
-        nextAggregation,
-      );
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
-
-  const handleRemoveAggregation = useCallback(
-    (aggregation: Lib.AggregationClause) => {
-      const nextQuery = Lib.removeClause(query, STAGE_INDEX, aggregation);
-      const nextAggregations = Lib.aggregations(nextQuery, STAGE_INDEX);
-      if (nextAggregations.length === 0) {
-        setDefaultAggregationRemoved(true);
-      }
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
-
-  const handleAddBreakout = useCallback(
-    (column: Lib.ColumnMetadata) => {
-      const nextQuery = Lib.breakout(query, STAGE_INDEX, column);
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
-
-  const handleUpdateBreakout = useCallback(
-    (clause: Lib.BreakoutClause, column: Lib.ColumnMetadata) => {
-      const nextQuery = Lib.replaceClause(query, STAGE_INDEX, clause, column);
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
-
-  const handleRemoveBreakout = useCallback(
-    (column: Lib.ColumnMetadata) => {
-      const { breakoutPosition } = Lib.displayInfo(query, STAGE_INDEX, column);
-      if (typeof breakoutPosition === "number") {
-        const breakouts = Lib.breakouts(query, STAGE_INDEX);
-        const clause = breakouts[breakoutPosition];
-        const nextQuery = Lib.removeClause(query, STAGE_INDEX, clause);
-        onQueryChange(nextQuery);
-      }
-    },
-    [query, onQueryChange],
-  );
-
-  const handleReplaceBreakouts = useCallback(
-    (column: Lib.ColumnMetadata) => {
-      const nextQuery = Lib.replaceBreakouts(query, STAGE_INDEX, column);
-      onQueryChange(nextQuery);
-    },
-    [query, onQueryChange],
-  );
+  const {
+    query,
+    aggregations,
+    hasAggregations,
+    handleAddAggregations,
+    handleUpdateAggregation,
+    handleRemoveAggregation,
+    handleAddBreakout,
+    handleUpdateBreakout,
+    handleRemoveBreakout,
+    handleReplaceBreakouts,
+  } = useSummarizeQuery(initialQuery, onQueryChange);
 
   const handleDoneClick = useCallback(() => {
     onQueryChange(query);
@@ -125,54 +46,18 @@ export function SummarizeSidebar({
       color={color("summarize")}
       onDone={handleDoneClick}
     >
-      <AggregationsContainer>
-        {aggregations.map((aggregation, aggregationIndex) => (
-          <AggregationItem
-            key={
-              Lib.displayInfo(query, STAGE_INDEX, aggregation).longDisplayName
-            }
-            query={query}
-            aggregation={aggregation}
-            aggregationIndex={aggregationIndex}
-            onAdd={handleAddAggregations}
-            onUpdate={nextAggregation =>
-              handleUpdateAggregation(aggregation, nextAggregation)
-            }
-            onRemove={() => handleRemoveAggregation(aggregation)}
-          />
-        ))}
-        <AddAggregationButton
-          query={query}
-          onAddAggregations={handleAddAggregations}
-        />
-      </AggregationsContainer>
-      {hasAggregations && (
-        <ColumnListContainer>
-          <SectionTitle>{t`Group by`}</SectionTitle>
-          <BreakoutColumnList
-            query={query}
-            onAddBreakout={handleAddBreakout}
-            onUpdateBreakout={handleUpdateBreakout}
-            onRemoveBreakout={handleRemoveBreakout}
-            onReplaceBreakout={handleReplaceBreakouts}
-          />
-        </ColumnListContainer>
-      )}
+      <SummarizeContent
+        query={query}
+        aggregations={aggregations}
+        hasAggregations={hasAggregations}
+        onAddAggregations={handleAddAggregations}
+        onUpdateAggregation={handleUpdateAggregation}
+        onRemoveAggregation={handleRemoveAggregation}
+        onAddBreakout={handleAddBreakout}
+        onUpdateBreakout={handleUpdateBreakout}
+        onRemoveBreakout={handleRemoveBreakout}
+        onReplaceBreakouts={handleReplaceBreakouts}
+      />
     </SidebarView>
   );
 }
-
-function getQuery(query: Lib.Query, isDefaultAggregationRemoved: boolean) {
-  const hasAggregations = Lib.aggregations(query, STAGE_INDEX).length > 0;
-
-  const shouldAddDefaultAggregation =
-    !hasAggregations &&
-    !Lib.isMetricBased(query, STAGE_INDEX) &&
-    !isDefaultAggregationRemoved;
-
-  if (!shouldAddDefaultAggregation) {
-    return query;
-  }
-
-  return Lib.aggregateByCount(query);
-}
-- 
GitLab