From 8a60b96763f9a20694701453a53eb6da520e6c27 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 30 May 2025 00:37:35 +0000 Subject: [PATCH] refactor: minor improvements on app status and statuses --- site/src/modules/apps/AppStatusIcon.tsx | 8 +- .../WorkspaceAppStatus.stories.tsx | 7 + .../WorkspaceAppStatus/WorkspaceAppStatus.tsx | 32 ++- .../WorkspacePage/AppStatuses.stories.tsx | 212 +++++------------- site/src/pages/WorkspacePage/AppStatuses.tsx | 13 +- .../pages/WorkspacesPage/WorkspacesTable.tsx | 5 +- site/src/testHelpers/entities.ts | 80 +++++++ 7 files changed, 180 insertions(+), 177 deletions(-) diff --git a/site/src/modules/apps/AppStatusIcon.tsx b/site/src/modules/apps/AppStatusIcon.tsx index c73f0af0f1e65..3de4ef419460c 100644 --- a/site/src/modules/apps/AppStatusIcon.tsx +++ b/site/src/modules/apps/AppStatusIcon.tsx @@ -25,22 +25,22 @@ export const AppStatusIcon: FC = ({ switch (status.state) { case "complete": return ( - + ); case "failure": return ( - + ); case "working": return latest ? ( ) : ( - + ); default: return ( ); } diff --git a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx index bcb1af8de3acb..d95444e658d64 100644 --- a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx +++ b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.stories.tsx @@ -48,3 +48,10 @@ export const LongMessage: Story = { }, }, }; + +export const Disabled: Story = { + args: { + status: MockWorkspaceAppStatus, + disabled: true, + }, +}; diff --git a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx index f2eab7f2086ac..aba002b2cd37d 100644 --- a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx +++ b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx @@ -1,30 +1,22 @@ -import type { - WorkspaceAppStatus as APIWorkspaceAppStatus, - WorkspaceAppStatusState, -} from "api/typesGenerated"; -import { Spinner } from "components/Spinner/Spinner"; +import type { WorkspaceAppStatus as APIWorkspaceAppStatus } from "api/typesGenerated"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; -import { CircleAlertIcon, CircleCheckIcon } from "lucide-react"; -import type { ReactNode } from "react"; +import { AppStatusIcon } from "modules/apps/AppStatusIcon"; +import { cn } from "utils/cn"; -const iconByState: Record = { - complete: ( - - ), - failure: , - working: , +type WorkspaceAppStatusProps = { + status: APIWorkspaceAppStatus | null; + disabled?: boolean; }; export const WorkspaceAppStatus = ({ status, -}: { - status: APIWorkspaceAppStatus | null; -}) => { + disabled, +}: WorkspaceAppStatusProps) => { if (!status) { return ( @@ -39,7 +31,13 @@ export const WorkspaceAppStatus = ({
- {iconByState[status.state]} + {status.message} diff --git a/site/src/pages/WorkspacePage/AppStatuses.stories.tsx b/site/src/pages/WorkspacePage/AppStatuses.stories.tsx index 02e38a8c47107..56dff1c93c7c4 100644 --- a/site/src/pages/WorkspacePage/AppStatuses.stories.tsx +++ b/site/src/pages/WorkspacePage/AppStatuses.stories.tsx @@ -1,9 +1,12 @@ import type { Meta, StoryObj } from "@storybook/react"; +import type { WorkspaceAppStatus } from "api/typesGenerated"; import { MockWorkspace, MockWorkspaceAgent, MockWorkspaceApp, MockWorkspaceAppStatus, + MockWorkspaceAppStatuses, + createTimestamp, } from "testHelpers/entities"; import { withProxyProvider } from "testHelpers/storybook"; import { AppStatuses } from "./AppStatuses"; @@ -13,6 +16,8 @@ const meta: Meta = { component: AppStatuses, args: { referenceDate: new Date("2024-03-26T15:15:00Z"), + agent: mockAgent(MockWorkspaceAppStatuses), + workspace: MockWorkspace, }, decorators: [withProxyProvider()], }; @@ -21,163 +26,70 @@ export default meta; type Story = StoryObj; -export const Default: Story = { +export const Default: Story = {}; + +// Add a story with a "Working" status as the latest +export const WorkingState: Story = { args: { - workspace: MockWorkspace, - agent: { - ...MockWorkspaceAgent, - apps: [ - { - ...MockWorkspaceApp, - statuses: [ - { - // This is the latest status chronologically (15:04:38) - ...MockWorkspaceAppStatus, - id: "status-7", - icon: "/emojis/1f4dd.png", // 📝 - message: "Creating PR with gh CLI", - created_at: createTimestamp(4, 38), // 15:04:38 - uri: "https://github.com/coder/coder/pull/5678", - state: "complete" as const, - }, - { - // (15:03:56) - ...MockWorkspaceAppStatus, - id: "status-6", - icon: "/emojis/1f680.png", // 🚀 - message: "Pushing branch to remote", - created_at: createTimestamp(3, 56), // 15:03:56 - uri: "", - state: "complete" as const, - }, - { - // (15:02:29) - ...MockWorkspaceAppStatus, - id: "status-5", - icon: "/emojis/1f527.png", // 🔧 - message: "Configuring git identity", - created_at: createTimestamp(2, 29), // 15:02:29 - uri: "", - state: "complete" as const, - }, - { - // (15:02:04) - ...MockWorkspaceAppStatus, - id: "status-4", - icon: "/emojis/1f4be.png", // 💾 - message: "Committing changes", - created_at: createTimestamp(2, 4), // 15:02:04 - uri: "", - state: "complete" as const, - }, - { - // (15:01:44) - ...MockWorkspaceAppStatus, - id: "status-3", - icon: "/emojis/2795.png", // + - message: "Adding files to staging", - created_at: createTimestamp(1, 44), // 15:01:44 - uri: "", - state: "complete" as const, - }, - { - // (15:01:32) - ...MockWorkspaceAppStatus, - id: "status-2", - icon: "/emojis/1f33f.png", // 🌿 - message: "Creating a new branch for PR", - created_at: createTimestamp(1, 32), // 15:01:32 - uri: "", - state: "complete" as const, - }, - { - // (15:01:00) - Oldest - ...MockWorkspaceAppStatus, - id: "status-1", - icon: "/emojis/1f680.png", // 🚀 - message: "Starting to create a PR", - created_at: createTimestamp(1, 0), // 15:01:00 - uri: "", - state: "complete" as const, - }, - ].sort( - (a, b) => - new Date(b.created_at).getTime() - - new Date(a.created_at).getTime(), - ), // Ensure sorted correctly for component input if needed - }, - ], - }, + agent: mockAgent([ + { + // This is now the latest (15:05:15) and is "working" + ...MockWorkspaceAppStatus, + id: "status-8", + icon: "", // Let the component handle the spinner icon + message: "Processing final checks...", + created_at: createTimestamp(5, 15), // 15:05:15 (after referenceDate) + uri: "", + state: "working" as const, + }, + ...MockWorkspaceAppStatuses, + ]), + }, +}; - // Pass the reference date to the component for Storybook rendering +export const LongStatusText: Story = { + args: { + agent: mockAgent([ + { + // This is now the latest (15:05:15) and is "working" + ...MockWorkspaceAppStatus, + id: "status-8", + icon: "", // Let the component handle the spinner icon + message: + "Processing final checks with a very long message that exceeds the usual length to test how the component handles overflow and truncation in the UI. This should be long enough to ensure it wraps correctly and doesn't break the layout.", + created_at: createTimestamp(5, 15), // 15:05:15 (after referenceDate) + uri: "", + state: "complete" as const, + }, + ...MockWorkspaceAppStatuses, + ]), }, }; -// Add a story with a "Working" status as the latest -export const WorkingState: Story = { +export const SingleStatus: Story = { args: { - workspace: MockWorkspace, - agent: { - ...MockWorkspaceAgent, - apps: [ - { - ...MockWorkspaceApp, - statuses: [ - { - // This is now the latest (15:05:15) and is "working" - ...MockWorkspaceAppStatus, - id: "status-8", - icon: "", // Let the component handle the spinner icon - message: "Processing final checks...", - created_at: createTimestamp(5, 15), // 15:05:15 (after referenceDate) - uri: "", - state: "working" as const, - }, - { - // Previous latest (15:04:38) - ...MockWorkspaceAppStatus, - id: "status-7", - icon: "/emojis/1f4dd.png", // 📝 - message: "Creating PR with gh CLI", - created_at: createTimestamp(4, 38), // 15:04:38 - uri: "https://github.com/coder/coder/pull/5678", - state: "complete" as const, - }, - { - // (15:03:56) - ...MockWorkspaceAppStatus, - id: "status-6", - icon: "/emojis/1f680.png", // 🚀 - message: "Pushing branch to remote", - created_at: createTimestamp(3, 56), // 15:03:56 - uri: "", - state: "complete" as const, - }, - // ... include other older statuses if desired ... - { - // (15:01:00) - Oldest - ...MockWorkspaceAppStatus, - id: "status-1", - icon: "/emojis/1f680.png", // 🚀 - message: "Starting to create a PR", - created_at: createTimestamp(1, 0), // 15:01:00 - uri: "", - state: "complete" as const, - }, - ].sort( - (a, b) => - new Date(b.created_at).getTime() - - new Date(a.created_at).getTime(), - ), - }, - ], - }, + agent: mockAgent([ + { + ...MockWorkspaceAppStatus, + id: "status-1", + icon: "", + message: "Initial setup complete.", + created_at: createTimestamp(5, 10), // 15:05:10 (after referenceDate) + uri: "", + state: "complete" as const, + }, + ]), }, }; -function createTimestamp(minuteOffset: number, secondOffset: number) { - const baseDate = new Date("2024-03-26T15:00:00Z"); - baseDate.setMinutes(baseDate.getMinutes() + minuteOffset); - baseDate.setSeconds(baseDate.getSeconds() + secondOffset); - return baseDate.toISOString(); +function mockAgent(statuses: WorkspaceAppStatus[]) { + return { + ...MockWorkspaceAgent, + apps: [ + { + ...MockWorkspaceApp, + statuses, + }, + ], + }; } diff --git a/site/src/pages/WorkspacePage/AppStatuses.tsx b/site/src/pages/WorkspacePage/AppStatuses.tsx index bfa7131a9fbf1..9975fccbc05ed 100644 --- a/site/src/pages/WorkspacePage/AppStatuses.tsx +++ b/site/src/pages/WorkspacePage/AppStatuses.tsx @@ -103,15 +103,17 @@ export const AppStatuses: FC = ({
-
- +
+
- {latestStatus.message} - + + {latestStatus.message} + +
{timeFrom(new Date(latestStatus.created_at), comparisonDate)} @@ -154,6 +156,7 @@ export const AppStatuses: FC = ({