From b7cac72c3cd97f57aeac225c2645a32078756bcf Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Tue, 4 Jan 2022 23:50:13 +0300
Subject: [PATCH] Add storybook for database statuses (#19537)

---
 .storybook/preview.js                         |  2 ++
 .../api/database.ts}                          | 13 +++++---
 frontend/src/metabase-types/api/user.ts       |  8 +++++
 .../TextInput/TextInput.stories.jsx           | 14 --------
 .../DatabaseStatus/DatabaseStatus.tsx         |  3 +-
 .../DatabaseStatus.unit.spec.tsx              | 23 ++++---------
 .../DatabaseStatusLarge.stories.tsx           | 32 +++++++++++++++++++
 .../DatabaseStatusLarge.tsx                   | 18 ++++++++---
 .../DatabaseStatusLarge.unit.spec.tsx         | 30 +++++++----------
 .../DatabaseStatusSmall.stories.tsx           | 29 +++++++++++++++++
 .../DatabaseStatusSmall.styled.tsx            |  2 +-
 .../DatabaseStatusSmall.tsx                   |  2 +-
 .../DatabaseStatusSmall.unit.spec.tsx         | 22 ++++---------
 .../DatabaseStatus/DatabaseStatus.tsx         |  2 +-
 14 files changed, 123 insertions(+), 77 deletions(-)
 rename frontend/src/{metabase/status/types.ts => metabase-types/api/database.ts} (52%)
 create mode 100644 frontend/src/metabase-types/api/user.ts
 delete mode 100644 frontend/src/metabase/components/TextInput/TextInput.stories.jsx
 create mode 100644 frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.stories.tsx
 create mode 100644 frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.stories.tsx

diff --git a/.storybook/preview.js b/.storybook/preview.js
index f089c7f9d53..ec28b3af9ed 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,3 +1,5 @@
+import "metabase/css/index.css";
+
 export const parameters = {
   actions: { argTypesRegex: "^on[A-Z].*" },
   controls: {
diff --git a/frontend/src/metabase/status/types.ts b/frontend/src/metabase-types/api/database.ts
similarity index 52%
rename from frontend/src/metabase/status/types.ts
rename to frontend/src/metabase-types/api/database.ts
index a08bd6e2f4a..f88eb0f4917 100644
--- a/frontend/src/metabase/status/types.ts
+++ b/frontend/src/metabase-types/api/database.ts
@@ -1,9 +1,5 @@
 export type InitialSyncStatus = "incomplete" | "complete" | "aborted";
 
-export interface User {
-  id: number;
-}
-
 export interface Database {
   id: number;
   name: string;
@@ -11,3 +7,12 @@ export interface Database {
   creator_id?: number;
   initial_sync_status: InitialSyncStatus;
 }
+
+export const createDatabase = (opts?: Partial<Database>): Database => ({
+  id: 1,
+  name: "Database",
+  is_sample: false,
+  creator_id: undefined,
+  initial_sync_status: "complete",
+  ...opts,
+});
diff --git a/frontend/src/metabase-types/api/user.ts b/frontend/src/metabase-types/api/user.ts
new file mode 100644
index 00000000000..3041f062a1a
--- /dev/null
+++ b/frontend/src/metabase-types/api/user.ts
@@ -0,0 +1,8 @@
+export interface User {
+  id: number;
+}
+
+export const createUser = (opts?: Partial<User>): User => ({
+  id: 1,
+  ...opts,
+});
diff --git a/frontend/src/metabase/components/TextInput/TextInput.stories.jsx b/frontend/src/metabase/components/TextInput/TextInput.stories.jsx
deleted file mode 100644
index c2aa2a525aa..00000000000
--- a/frontend/src/metabase/components/TextInput/TextInput.stories.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React, { useState } from "react";
-import TextInput from "./TextInput";
-
-export default {
-  title: "Components/TextInput",
-  component: TextInput,
-};
-
-export const Default = args => {
-  const [value, setValue] = useState("");
-  return <TextInput {...args} value={value} onChange={setValue} />;
-};
-
-Default.args = { hasClearButton: false };
diff --git a/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.tsx b/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.tsx
index 648c702d064..ca39fcfe10c 100644
--- a/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.tsx
@@ -1,9 +1,10 @@
 import React, { useState } from "react";
 import { isSyncInProgress } from "metabase/lib/syncing";
+import { Database } from "metabase-types/api/database";
+import { User } from "metabase-types/api/user";
 import useStatusVisibility from "../../hooks/use-status-visibility";
 import DatabaseStatusLarge from "../DatabaseStatusLarge";
 import DatabaseStatusSmall from "../DatabaseStatusSmall";
-import { Database, User } from "../../types";
 
 export interface DatabaseStatusProps {
   user?: User;
diff --git a/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.unit.spec.tsx b/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.unit.spec.tsx
index fb55a9f8c66..4dc1b10dac0 100644
--- a/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.unit.spec.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatus/DatabaseStatus.unit.spec.tsx
@@ -1,14 +1,15 @@
 import React from "react";
 import { render, screen } from "@testing-library/react";
 import userEvent from "@testing-library/user-event";
+import { createDatabase } from "metabase-types/api/database";
+import { createUser } from "metabase-types/api/user";
 import DatabaseStatus from "./DatabaseStatus";
-import { Database, User } from "../../types";
 
 describe("DatabaseStatus", () => {
   it("should toggle between small and large versions", () => {
-    const user = getUser({ id: 1 });
+    const user = createUser({ id: 1 });
     const databases = [
-      getDatabase({ creator_id: 1, initial_sync_status: "incomplete" }),
+      createDatabase({ creator_id: 1, initial_sync_status: "incomplete" }),
     ];
 
     render(<DatabaseStatus user={user} databases={databases} />);
@@ -28,9 +29,9 @@ describe("DatabaseStatus", () => {
   });
 
   it("should not render when databases are created by another user", () => {
-    const user = getUser({ id: 1 });
+    const user = createUser({ id: 1 });
     const databases = [
-      getDatabase({ creator_id: 2, initial_sync_status: "incomplete" }),
+      createDatabase({ creator_id: 2, initial_sync_status: "incomplete" }),
     ];
 
     render(<DatabaseStatus user={user} databases={databases} />);
@@ -38,15 +39,3 @@ describe("DatabaseStatus", () => {
     expect(screen.queryByText("Syncing…")).not.toBeInTheDocument();
   });
 });
-
-const getUser = (opts?: Partial<User>): User => ({
-  id: 1,
-});
-
-const getDatabase = (opts?: Partial<Database>): Database => ({
-  id: 1,
-  name: "Our database",
-  is_sample: false,
-  initial_sync_status: "complete",
-  ...opts,
-});
diff --git a/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.stories.tsx b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.stories.tsx
new file mode 100644
index 00000000000..b3b2c7bbc42
--- /dev/null
+++ b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.stories.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import { ComponentStory } from "@storybook/react";
+import { createDatabase } from "metabase-types/api/database";
+import DatabaseStatusLarge from "./DatabaseStatusLarge";
+
+export default {
+  title: "Status/DatabaseStatusLarge",
+  component: DatabaseStatusLarge,
+  argTypes: { onCollapse: { action: "onCollapse" } },
+};
+
+const Template: ComponentStory<typeof DatabaseStatusLarge> = args => {
+  return <DatabaseStatusLarge {...args} />;
+};
+
+export const Incomplete = Template.bind({});
+Incomplete.args = {
+  databases: [createDatabase({ initial_sync_status: "incomplete" })],
+  isActive: true,
+};
+
+export const Complete = Template.bind({});
+Complete.args = {
+  databases: [createDatabase({ initial_sync_status: "complete" })],
+  isActive: true,
+};
+
+export const Aborted = Template.bind({});
+Aborted.args = {
+  databases: [createDatabase({ initial_sync_status: "aborted" })],
+  isActive: true,
+};
diff --git a/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.tsx b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.tsx
index cfcfa1f80ed..9d7edba9224 100644
--- a/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.tsx
@@ -5,7 +5,7 @@ import {
 } from "metabase/lib/syncing";
 import React from "react";
 import { t } from "ttag";
-import { Database } from "../../types";
+import { Database } from "metabase-types/api/database";
 import Icon from "../../../components/Icon";
 import {
   StatusCardRoot,
@@ -26,11 +26,13 @@ import useStatusVisibility from "../../hooks/use-status-visibility";
 
 export interface DatabaseStatusLargeProps {
   databases: Database[];
+  isActive?: boolean;
   onCollapse?: () => void;
 }
 
 const DatabaseStatusLarge = ({
   databases,
+  isActive,
   onCollapse,
 }: DatabaseStatusLargeProps): JSX.Element => {
   return (
@@ -43,7 +45,11 @@ const DatabaseStatusLarge = ({
       </StatusHeader>
       <StatusBody>
         {databases.map(database => (
-          <StatusCard key={database.id} database={database} />
+          <StatusCard
+            key={database.id}
+            database={database}
+            isActive={isActive}
+          />
         ))}
       </StatusBody>
     </StatusRoot>
@@ -52,10 +58,14 @@ const DatabaseStatusLarge = ({
 
 interface StatusCardProps {
   database: Database;
+  isActive?: boolean;
 }
 
-const StatusCard = ({ database }: StatusCardProps): JSX.Element | null => {
-  const isVisible = useStatusVisibility(isSyncInProgress(database));
+const StatusCard = ({
+  database,
+  isActive,
+}: StatusCardProps): JSX.Element | null => {
+  const isVisible = useStatusVisibility(isActive || isSyncInProgress(database));
 
   if (!isVisible) {
     return null;
diff --git a/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.unit.spec.tsx b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.unit.spec.tsx
index d1358150d04..285ee205ed1 100644
--- a/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.unit.spec.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatusLarge/DatabaseStatusLarge.unit.spec.tsx
@@ -1,15 +1,15 @@
 import React from "react";
 import { render, screen } from "@testing-library/react";
+import { createDatabase } from "metabase-types/api/database";
 import DatabaseStatusLarge from "./DatabaseStatusLarge";
-import { Database } from "../../types";
 
 describe("DatabaseStatusLarge", () => {
   it("should render in-progress status", () => {
     const databases = [
-      getDatabase({
+      createDatabase({
         initial_sync_status: "incomplete",
       }),
-      getDatabase({
+      createDatabase({
         initial_sync_status: "complete",
       }),
     ];
@@ -22,22 +22,22 @@ describe("DatabaseStatusLarge", () => {
 
   it("should render complete status", () => {
     const before = [
-      getDatabase({
+      createDatabase({
         id: 1,
         initial_sync_status: "incomplete",
       }),
-      getDatabase({
+      createDatabase({
         id: 2,
         initial_sync_status: "complete",
       }),
     ];
 
     const after = [
-      getDatabase({
+      createDatabase({
         id: 1,
         initial_sync_status: "complete",
       }),
-      getDatabase({
+      createDatabase({
         id: 2,
         initial_sync_status: "complete",
       }),
@@ -52,22 +52,22 @@ describe("DatabaseStatusLarge", () => {
 
   it("should render error status", () => {
     const before = [
-      getDatabase({
+      createDatabase({
         id: 1,
         initial_sync_status: "incomplete",
       }),
-      getDatabase({
+      createDatabase({
         id: 2,
         initial_sync_status: "complete",
       }),
     ];
 
     const after = [
-      getDatabase({
+      createDatabase({
         id: 1,
         initial_sync_status: "aborted",
       }),
-      getDatabase({
+      createDatabase({
         id: 2,
         initial_sync_status: "complete",
       }),
@@ -80,11 +80,3 @@ describe("DatabaseStatusLarge", () => {
     expect(screen.getByText("Sync failed")).toBeInTheDocument();
   });
 });
-
-const getDatabase = (opts?: Partial<Database>): Database => ({
-  id: 1,
-  name: "Our database",
-  is_sample: false,
-  initial_sync_status: "complete",
-  ...opts,
-});
diff --git a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.stories.tsx b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.stories.tsx
new file mode 100644
index 00000000000..a4021e2a652
--- /dev/null
+++ b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.stories.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+import { ComponentStory } from "@storybook/react";
+import { createDatabase } from "metabase-types/api/database";
+import DatabaseStatusSmall from "./DatabaseStatusSmall";
+
+export default {
+  title: "Status/DatabaseStatusSmall",
+  component: DatabaseStatusSmall,
+  argTypes: { onExpand: { action: "onExpand" } },
+};
+
+const Template: ComponentStory<typeof DatabaseStatusSmall> = args => {
+  return <DatabaseStatusSmall {...args} />;
+};
+
+export const Incomplete = Template.bind({});
+Incomplete.args = {
+  databases: [createDatabase({ initial_sync_status: "incomplete" })],
+};
+
+export const Complete = Template.bind({});
+Complete.args = {
+  databases: [createDatabase({ initial_sync_status: "complete" })],
+};
+
+export const Aborted = Template.bind({});
+Aborted.args = {
+  databases: [createDatabase({ initial_sync_status: "aborted" })],
+};
diff --git a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.styled.tsx b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.styled.tsx
index fed745c2201..76ed03f2db3 100644
--- a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.styled.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.styled.tsx
@@ -2,7 +2,7 @@ import styled from "styled-components";
 import { color, lighten } from "metabase/lib/colors";
 import Icon from "metabase/components/Icon";
 import LoadingSpinner from "metabase/components/LoadingSpinner";
-import { InitialSyncStatus } from "../../types";
+import { InitialSyncStatus } from "metabase-types/api/database";
 
 interface Props {
   status: InitialSyncStatus;
diff --git a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.tsx b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.tsx
index 7449634416b..af2976d0aeb 100644
--- a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.tsx
@@ -3,7 +3,7 @@ import { t } from "ttag";
 import { isReducedMotionPreferred } from "metabase/lib/dom";
 import { isSyncAborted, isSyncInProgress } from "metabase/lib/syncing";
 import Tooltip from "metabase/components/Tooltip";
-import { Database, InitialSyncStatus } from "../../types";
+import { Database, InitialSyncStatus } from "metabase-types/api/database";
 import {
   StatusRoot,
   StatusIconContainer,
diff --git a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.unit.spec.tsx b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.unit.spec.tsx
index 9a66d23b593..d393e4a6792 100644
--- a/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.unit.spec.tsx
+++ b/frontend/src/metabase/status/components/DatabaseStatusSmall/DatabaseStatusSmall.unit.spec.tsx
@@ -1,15 +1,15 @@
 import React from "react";
 import { render, screen } from "@testing-library/react";
+import { createDatabase } from "metabase-types/api/database";
 import DatabaseStatusSmall from "./DatabaseStatusSmall";
-import { Database } from "../../types";
 
 describe("DatabaseStatusSmall", () => {
   it("should render in-progress status", () => {
     const databases = [
-      getDatabase({
+      createDatabase({
         initial_sync_status: "incomplete",
       }),
-      getDatabase({
+      createDatabase({
         initial_sync_status: "complete",
       }),
     ];
@@ -21,10 +21,10 @@ describe("DatabaseStatusSmall", () => {
 
   it("should render complete status", () => {
     const databases = [
-      getDatabase({
+      createDatabase({
         initial_sync_status: "complete",
       }),
-      getDatabase({
+      createDatabase({
         initial_sync_status: "complete",
       }),
     ];
@@ -36,10 +36,10 @@ describe("DatabaseStatusSmall", () => {
 
   it("should render error status", () => {
     const databases = [
-      getDatabase({
+      createDatabase({
         initial_sync_status: "aborted",
       }),
-      getDatabase({
+      createDatabase({
         initial_sync_status: "complete",
       }),
     ];
@@ -49,11 +49,3 @@ describe("DatabaseStatusSmall", () => {
     expect(screen.getByLabelText("Error syncing")).toBeInTheDocument();
   });
 });
-
-const getDatabase = (opts?: Partial<Database>): Database => ({
-  id: 1,
-  name: "Our database",
-  is_sample: false,
-  initial_sync_status: "complete",
-  ...opts,
-});
diff --git a/frontend/src/metabase/status/containers/DatabaseStatus/DatabaseStatus.tsx b/frontend/src/metabase/status/containers/DatabaseStatus/DatabaseStatus.tsx
index 69f54973aa5..ddc428b7618 100644
--- a/frontend/src/metabase/status/containers/DatabaseStatus/DatabaseStatus.tsx
+++ b/frontend/src/metabase/status/containers/DatabaseStatus/DatabaseStatus.tsx
@@ -3,8 +3,8 @@ import _ from "underscore";
 import Databases from "metabase/entities/databases";
 import { isSyncInProgress } from "metabase/lib/syncing";
 import { getUser } from "metabase/selectors/user";
+import { Database } from "metabase-types/api/database";
 import DatabaseStatus from "../../components/DatabaseStatus";
-import { Database } from "../../types";
 
 const RELOAD_INTERVAL = 2000;
 
-- 
GitLab