feat: add workspace status on tasks (#20037)

<img width="1206" height="722" alt="Screenshot 2025-09-30 at 11 29 31"
src="https://github.com/user-attachments/assets/f109552d-af5e-41e1-a0e8-fdfcb3f973b7"
/>


Closes https://github.com/coder/coder/issues/19988
This commit is contained in:
Bruno Quaresma
2025-10-01 15:49:52 -03:00
committed by GitHub
parent 718f712c18
commit 6b61c8a32a
4 changed files with 63 additions and 29 deletions
@@ -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<typeof WorkspaceStatus> = {
title: "modules/workspaces/WorkspaceStatus",
component: WorkspaceStatus,
args: {
workspace: MockWorkspace,
},
};
export default meta;
type Story = StoryObj<typeof WorkspaceStatus>;
export const Running: Story = {};
export const Dormant: Story = {
args: {
workspace: MockDormantWorkspace,
},
};
@@ -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<WorkspaceStatusProps> = ({ workspace }) => {
return (
<div className="flex flex-col">
<WorkspaceStatusIndicator workspace={workspace}>
{workspace.dormant_at && (
<WorkspaceDormantBadge workspace={workspace} />
)}
</WorkspaceStatusIndicator>
<time
dateTime={workspace.last_used_at}
className="text-xs font-medium text-content-secondary ml-6 whitespace-nowrap"
>
{lastUsedMessage(workspace.last_used_at)}
</time>
</div>
);
};
+9 -1
View File
@@ -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<TasksTableProps> = ({ tasks, error, onRetry }) => {
<TableHeader>
<TableRow>
<TableHead>Task</TableHead>
<TableHead>Status</TableHead>
<TableHead>Agent status</TableHead>
<TableHead>Workspace status</TableHead>
<TableHead>Created by</TableHead>
<TableHead />
</TableRow>
@@ -153,6 +155,9 @@ const TaskRow: FC<TaskRowProps> = ({ task }) => {
status={task.workspace.latest_app_status}
/>
</TableCell>
<TableCell>
<WorkspaceStatus workspace={task.workspace} />
</TableCell>
<TableCell>
<AvatarData
title={task.workspace.owner_name}
@@ -205,6 +210,9 @@ const TasksSkeleton: FC = () => {
<TableCell>
<Skeleton className="w-[100px] h-6" />
</TableCell>
<TableCell>
<Skeleton className="w-[100px] h-6" />
</TableCell>
<TableCell>
<AvatarDataSkeleton />
</TableCell>
@@ -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<WorkspacesTableProps> = ({
/>
</TableCell>
<WorkspaceStatusCell workspace={workspace} />
<TableCell>
<WorkspaceStatus workspace={workspace} />
</TableCell>
<WorkspaceActionsCell
workspace={workspace}
@@ -354,27 +352,6 @@ const cantBeChecked = (workspace: Workspace) => {
return ["deleting", "pending"].includes(workspace.latest_build.status);
};
type WorkspaceStatusCellProps = {
workspace: Workspace;
};
const WorkspaceStatusCell: FC<WorkspaceStatusCellProps> = ({ workspace }) => {
return (
<TableCell>
<div className="flex flex-col">
<WorkspaceStatusIndicator workspace={workspace}>
{workspace.dormant_at && (
<WorkspaceDormantBadge workspace={workspace} />
)}
</WorkspaceStatusIndicator>
<span className="text-xs font-medium text-content-secondary ml-6 whitespace-nowrap">
{lastUsedMessage(workspace.last_used_at)}
</span>
</div>
</TableCell>
);
};
type WorkspaceActionsCellProps = {
workspace: Workspace;
onActionSuccess: () => Promise<void>;