From 6b61c8a32a8778bf2e5a65161ee2362d8aae0183 Mon Sep 17 00:00:00 2001 From: Bruno Quaresma Date: Wed, 1 Oct 2025 15:49:52 -0300 Subject: [PATCH] feat: add workspace status on tasks (#20037) Screenshot 2025-09-30 at 11 29 31 Closes https://github.com/coder/coder/issues/19988 --- .../WorkspaceStatus.stories.tsx | 22 +++++++++++++ .../WorkspaceStatus/WorkspaceStatus.tsx | 27 +++++++++++++++ site/src/pages/TasksPage/TasksTable.tsx | 10 +++++- .../pages/WorkspacesPage/WorkspacesTable.tsx | 33 +++---------------- 4 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx create mode 100644 site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx diff --git a/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx new file mode 100644 index 0000000000..60313bf116 --- /dev/null +++ b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx @@ -0,0 +1,22 @@ +import { MockDormantWorkspace, MockWorkspace } from "testHelpers/entities"; +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { WorkspaceStatus } from "./WorkspaceStatus"; + +const meta: Meta = { + title: "modules/workspaces/WorkspaceStatus", + component: WorkspaceStatus, + args: { + workspace: MockWorkspace, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Running: Story = {}; + +export const Dormant: Story = { + args: { + workspace: MockDormantWorkspace, + }, +}; diff --git a/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx new file mode 100644 index 0000000000..7888b1c77e --- /dev/null +++ b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx @@ -0,0 +1,27 @@ +import type { Workspace } from "api/typesGenerated"; +import type { FC } from "react"; +import { lastUsedMessage } from "utils/workspace"; +import { WorkspaceDormantBadge } from "../WorkspaceDormantBadge/WorkspaceDormantBadge"; +import { WorkspaceStatusIndicator } from "../WorkspaceStatusIndicator/WorkspaceStatusIndicator"; + +type WorkspaceStatusProps = { + workspace: Workspace; +}; + +export const WorkspaceStatus: FC = ({ workspace }) => { + return ( +
+ + {workspace.dormant_at && ( + + )} + + +
+ ); +}; diff --git a/site/src/pages/TasksPage/TasksTable.tsx b/site/src/pages/TasksPage/TasksTable.tsx index c1cddb75a8..c9ff75bb36 100644 --- a/site/src/pages/TasksPage/TasksTable.tsx +++ b/site/src/pages/TasksPage/TasksTable.tsx @@ -26,6 +26,7 @@ import { RotateCcwIcon, TrashIcon } from "lucide-react"; import { TaskDeleteDialog } from "modules/tasks/TaskDeleteDialog/TaskDeleteDialog"; import type { Task } from "modules/tasks/tasks"; import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus"; +import { WorkspaceStatus } from "modules/workspaces/WorkspaceStatus/WorkspaceStatus"; import { type FC, type ReactNode, useState } from "react"; import { Link as RouterLink } from "react-router"; import { relativeTime } from "utils/time"; @@ -54,7 +55,8 @@ export const TasksTable: FC = ({ tasks, error, onRetry }) => { Task - Status + Agent status + Workspace status Created by @@ -153,6 +155,9 @@ const TaskRow: FC = ({ task }) => { status={task.workspace.latest_app_status} /> + + + { + + + diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx index a6ba1e4a43..7ab941821d 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx @@ -65,10 +65,9 @@ import { useAppLink } from "modules/apps/useAppLink"; import { useDashboard } from "modules/dashboard/useDashboard"; import { abilitiesByWorkspaceStatus } from "modules/workspaces/actions"; import { WorkspaceBuildCancelDialog } from "modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog"; -import { WorkspaceDormantBadge } from "modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge"; import { WorkspaceMoreActions } from "modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions"; import { WorkspaceOutdatedTooltip } from "modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip"; -import { WorkspaceStatusIndicator } from "modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator"; +import { WorkspaceStatus } from "modules/workspaces/WorkspaceStatus/WorkspaceStatus"; import { useWorkspaceUpdate, WorkspaceUpdateDialogs, @@ -83,10 +82,7 @@ import { import { useMutation, useQuery, useQueryClient } from "react-query"; import { useNavigate } from "react-router"; import { cn } from "utils/cn"; -import { - getDisplayWorkspaceTemplateName, - lastUsedMessage, -} from "utils/workspace"; +import { getDisplayWorkspaceTemplateName } from "utils/workspace"; import { WorkspacesEmpty } from "./WorkspacesEmpty"; interface WorkspacesTableProps { @@ -256,7 +252,9 @@ export const WorkspacesTable: FC = ({ /> - + + + { return ["deleting", "pending"].includes(workspace.latest_build.status); }; -type WorkspaceStatusCellProps = { - workspace: Workspace; -}; - -const WorkspaceStatusCell: FC = ({ workspace }) => { - return ( - -
- - {workspace.dormant_at && ( - - )} - - - {lastUsedMessage(workspace.last_used_at)} - -
-
- ); -}; - type WorkspaceActionsCellProps = { workspace: Workspace; onActionSuccess: () => Promise;