From f909d1a16acd15be467b293be682fa4e2808f03d Mon Sep 17 00:00:00 2001
From: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
Date: Thu, 8 Dec 2022 23:15:45 -0300
Subject: [PATCH] allow to hide column and row totals on pivot tables (#27023)

---
 frontend/src/metabase/lib/data_grid.js        | 19 ++++---
 .../visualizations/PivotTable.jsx             | 14 ++++++
 .../test/metabase/lib/data_grid.unit.spec.js  | 49 +++++++++++++++++--
 3 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/frontend/src/metabase/lib/data_grid.js b/frontend/src/metabase/lib/data_grid.js
index 1cd177fe217..31f1bb2c282 100644
--- a/frontend/src/metabase/lib/data_grid.js
+++ b/frontend/src/metabase/lib/data_grid.js
@@ -130,7 +130,10 @@ export function multiLevelPivot(data, settings) {
     topIndexFormatters,
     topIndexColumns,
   );
-  if (formattedColumnTreeWithoutValues.length > 1) {
+  if (
+    formattedColumnTreeWithoutValues.length > 1 &&
+    settings["pivot.show_row_totals"]
+  ) {
     // if there are multiple columns, we should add another for row totals
     formattedColumnTreeWithoutValues.push({
       value: t`Row totals`,
@@ -161,11 +164,15 @@ export function multiLevelPivot(data, settings) {
   const showSubtotalsByColumn = rowColumnIndexes.map(
     index => getIn(columnSettings, [index, COLUMN_SHOW_TOTALS]) !== false,
   );
-  const formattedRowTree = addSubtotals(
-    formattedRowTreeWithoutSubtotals,
-    showSubtotalsByColumn,
-  );
-  if (formattedRowTreeWithoutSubtotals.length > 1) {
+
+  const formattedRowTree = settings["pivot.show_column_totals"]
+    ? addSubtotals(formattedRowTreeWithoutSubtotals, showSubtotalsByColumn)
+    : formattedRowTreeWithoutSubtotals;
+
+  if (
+    formattedRowTreeWithoutSubtotals.length > 1 &&
+    settings["pivot.show_column_totals"]
+  ) {
     // if there are multiple columns, we should add another for row totals
     formattedRowTree.push({
       value: t`Grand totals`,
diff --git a/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx b/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx
index f7554570ac8..0d1c85cb827 100644
--- a/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx
+++ b/frontend/src/metabase/visualizations/visualizations/PivotTable.jsx
@@ -185,6 +185,20 @@ class PivotTable extends Component {
         return addMissingCardBreakouts(setting, card);
       },
     },
+    "pivot.show_row_totals": {
+      section: t`Columns`,
+      title: t`Show row totals`,
+      widget: "toggle",
+      default: true,
+      inline: true,
+    },
+    "pivot.show_column_totals": {
+      section: t`Columns`,
+      title: t`Show column totals`,
+      widget: "toggle",
+      default: true,
+      inline: true,
+    },
     [COLUMN_FORMATTING_SETTING]: {
       section: t`Conditional Formatting`,
       widget: ChartSettingsTableFormatting,
diff --git a/frontend/test/metabase/lib/data_grid.unit.spec.js b/frontend/test/metabase/lib/data_grid.unit.spec.js
index 6631c3ea1d4..8745dcbd4ce 100644
--- a/frontend/test/metabase/lib/data_grid.unit.spec.js
+++ b/frontend/test/metabase/lib/data_grid.unit.spec.js
@@ -169,7 +169,13 @@ describe("data_grid", () => {
       columns,
       rows,
       values,
-      { collapsedRows = [], columnSorts = [], columnShowTotals = [] } = {},
+      {
+        collapsedRows = [],
+        columnSorts = [],
+        columnShowTotals = [],
+        showColumnTotals = true,
+        showRowTotals = true,
+      } = {},
     ) => {
       const settings = {
         column: column => {
@@ -185,6 +191,8 @@ describe("data_grid", () => {
           indexes => indexes.map(index => ["fake field ref", index]),
         ),
         [COLLAPSED_ROWS_SETTING]: { value: collapsedRows },
+        "pivot.show_row_totals": showRowTotals,
+        "pivot.show_column_totals": showColumnTotals,
       };
       data = {
         ...data,
@@ -204,7 +212,7 @@ describe("data_grid", () => {
       ["b", "y", 5],
       ["b", "z", 6],
     ]);
-    it("should produce multi-level top header", () => {
+    it("should produce multi-level top header with row totals", () => {
       const { topHeaderItems, leftHeaderItems, rowCount, columnCount } =
         multiLevelPivotForIndexes(data, [0, 1], [], [2]);
       expect(getPathsAndValues(topHeaderItems)).toEqual([
@@ -222,7 +230,22 @@ describe("data_grid", () => {
       expect(rowCount).toEqual(1);
       expect(columnCount).toEqual(7);
     });
-    it("should produce multi-level left header", () => {
+
+    it("should produce multi-level top header without row totals", () => {
+      const { topHeaderItems } = multiLevelPivotForIndexes(
+        data,
+        [0, 1],
+        [],
+        [2],
+        { showColumnTotals: true, showRowTotals: false },
+      );
+      const pathsAndValues = getPathsAndValues(topHeaderItems);
+      expect(pathsAndValues[pathsAndValues.length - 1].value).not.toEqual(
+        "Row totals",
+      );
+    });
+
+    it("should produce multi-level left header with totals", () => {
       const { topHeaderItems, leftHeaderItems, rowCount, columnCount } =
         multiLevelPivotForIndexes(data, [], [0, 1], [2]);
       expect(getPathsAndValues(leftHeaderItems)).toEqual([
@@ -242,6 +265,26 @@ describe("data_grid", () => {
       expect(rowCount).toEqual(9);
       expect(columnCount).toEqual(1);
     });
+
+    it("should produce multi-level left header without totals", () => {
+      const { topHeaderItems, leftHeaderItems, rowCount, columnCount } =
+        multiLevelPivotForIndexes(data, [], [0, 1], [2], {
+          showColumnTotals: false,
+        });
+      expect(getPathsAndValues(leftHeaderItems)).toEqual([
+        { value: "a", path: ["a"] },
+        { value: "x", path: ["a", "x"] },
+        { value: "y", path: ["a", "y"] },
+        { value: "z", path: ["a", "z"] },
+        { value: "b", path: ["b"] },
+        { value: "x", path: ["b", "x"] },
+        { value: "y", path: ["b", "y"] },
+        { value: "z", path: ["b", "z"] },
+      ]);
+      expect(getValues(topHeaderItems)).toEqual(["Metric"]);
+      expect(rowCount).toEqual(6);
+      expect(columnCount).toEqual(1);
+    });
     it("should allow unspecified values", () => {
       const data = makePivotData([
         ["a", "x", 1],
-- 
GitLab