From 754ecb8edc31a04df031f9cf56ea46ba8f520ff8 Mon Sep 17 00:00:00 2001
From: Gustavo Saiani <gustavo@poe.ma>
Date: Fri, 7 May 2021 11:49:40 -0300
Subject: [PATCH] Omit revision history item from list if no `diff` (#15942)

* Omit dashboard revision history items if no description

* Skip Revert button on topmost visible revision history entry

* Test that topmost revision history entry omits Revert button

* Lint

* Use diff as criterion for omitting revision entry

* Detail comment in shouldRenderRevisionHistory

* Render revision item if either before or after in diff is populated

* Update e2e test

* Use a more durable string to find element in test
---
 .../src/metabase/components/HistoryModal.jsx  | 75 +++++++++++++------
 .../collections/permissions.cy.spec.js        | 20 +++--
 2 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/frontend/src/metabase/components/HistoryModal.jsx b/frontend/src/metabase/components/HistoryModal.jsx
index e86226781b4..9224bde9deb 100644
--- a/frontend/src/metabase/components/HistoryModal.jsx
+++ b/frontend/src/metabase/components/HistoryModal.jsx
@@ -24,7 +24,7 @@ export default class HistoryModal extends Component {
     onClose: PropTypes.func.isRequired,
   };
 
-  revisionDescription(revision) {
+  getRevisionDescription(revision) {
     if (revision.is_creation) {
       return t`First revision.`;
     } else if (revision.is_reversion) {
@@ -34,10 +34,27 @@ export default class HistoryModal extends Component {
     }
   }
 
+  shouldRenderRevisionEntry({ diff }) {
+    // diff may be null in "First revision"
+    // or in the earliest revision kept in store
+    if (diff === null) {
+      return true;
+    }
+
+    const { before, after } = diff;
+    return before !== null || after !== null;
+  }
+
   render() {
     const { revisions, onRevert, onClose } = this.props;
     const cellClassName = "p1 border-bottom";
 
+    // We must keep track of having skipped the Revert button
+    // because we are omitting certain revision entries,
+    // see function shouldRenderRevisionEntry
+    // They may be the very top entry so we have to use dedicated logic.
+    let hasSkippedMostRecentRevisionRevertButton = false;
+
     return (
       <ModalContent title={t`Revision history`} onClose={onClose}>
         <table className="full">
@@ -50,29 +67,39 @@ export default class HistoryModal extends Component {
             </tr>
           </thead>
           <tbody>
-            {revisions.map((revision, index) => (
-              <tr key={revision.id}>
-                <td className={cellClassName}>
-                  {formatDate(revision.timestamp)}
-                </td>
-                <td className={cellClassName}>{revision.user.common_name}</td>
-                <td className={cellClassName}>
-                  <span>{this.revisionDescription(revision)}</span>
-                </td>
-                <td className={cellClassName}>
-                  {index !== 0 && onRevert && (
-                    <ActionButton
-                      actionFn={() => onRevert(revision)}
-                      className="Button Button--small Button--danger text-uppercase"
-                      normalText={t`Revert`}
-                      activeText={t`Reverting…`}
-                      failedText={t`Revert failed`}
-                      successText={t`Reverted`}
-                    />
-                  )}
-                </td>
-              </tr>
-            ))}
+            {revisions.map((revision, index) => {
+              if (this.shouldRenderRevisionEntry(revision)) {
+                const shouldRenderRevertButton =
+                  onRevert && hasSkippedMostRecentRevisionRevertButton;
+                hasSkippedMostRecentRevisionRevertButton = true;
+
+                return (
+                  <tr key={revision.id}>
+                    <td className={cellClassName}>
+                      {formatDate(revision.timestamp)}
+                    </td>
+                    <td className={cellClassName}>
+                      {revision.user.common_name}
+                    </td>
+                    <td className={cellClassName}>
+                      <span>{this.getRevisionDescription(revision)}</span>
+                    </td>
+                    <td className={cellClassName}>
+                      {shouldRenderRevertButton && (
+                        <ActionButton
+                          actionFn={() => onRevert(revision)}
+                          className="Button Button--small Button--danger text-uppercase"
+                          normalText={t`Revert`}
+                          activeText={t`Reverting…`}
+                          failedText={t`Revert failed`}
+                          successText={t`Reverted`}
+                        />
+                      )}
+                    </td>
+                  </tr>
+                );
+              }
+            })}
           </tbody>
         </table>
       </ModalContent>
diff --git a/frontend/test/metabase/scenarios/collections/permissions.cy.spec.js b/frontend/test/metabase/scenarios/collections/permissions.cy.spec.js
index 6af46ef2f30..96e6ae936f4 100644
--- a/frontend/test/metabase/scenarios/collections/permissions.cy.spec.js
+++ b/frontend/test/metabase/scenarios/collections/permissions.cy.spec.js
@@ -528,17 +528,22 @@ describe("collection permissions", () => {
         cy.signInAsAdmin();
       });
 
-      it.skip("shouldn't record history steps when there was no diff (metabase#1926)", () => {
+      it("shouldn't render revision history steps when there was no diff (metabase#1926)", () => {
         cy.signInAsAdmin();
         cy.createDashboard("foo").then(({ body }) => {
           visitAndEditDashboard(body.id);
         });
+
         // Save the dashboard without any changes made to it (TODO: we should probably disable "Save" button in the first place)
         saveDashboard();
-        // Take a look at the generated history - there shouldn't be anything other than "First revision" (dashboard created)
-        cy.icon("ellipsis").click();
-        cy.findByText("Revision history").click();
-        cy.findAllByRole("button", { name: "Revert" }).should("not.exist");
+        cy.icon("pencil").click();
+        saveDashboard();
+
+        openRevisionHistory();
+
+        cy.findByText("First revision.");
+
+        cy.findAllByText("Revert").should("not.exist");
       });
 
       it.skip("dashboard should update properly on revert (metabase#6884)", () => {
@@ -706,3 +711,8 @@ function saveDashboard() {
   clickButton("Save");
   cy.findByText("You're editing this dashboard.").should("not.exist");
 }
+
+function openRevisionHistory() {
+  cy.icon("ellipsis").click();
+  cy.findByText("Revision history").click();
+}
-- 
GitLab