fix: update workspace table icons in WorkspacesTable (#18525)

Updates icons in WorkspacesTable to better differentiate between "start"
and "update and start".

Note: the logic I'm currently using is as follows:
* Workspace does not require active version and is outdated -> cloud
icon
* Workspace requires active version and is outdated -> circle play icon

I also, on a whim, updated the stories for the component to make the
workspace names more identifiably reflect their content.


![Screenshot 2025-06-24 at 11 49
17](https://github.com/user-attachments/assets/682183fc-2171-44ee-80c4-914932718163)
This commit is contained in:
Cian Johnston
2025-06-24 19:23:59 +01:00
committed by GitHub
parent 99d124e276
commit 7070e47489
2 changed files with 96 additions and 5 deletions

View File

@ -33,6 +33,7 @@ import {
import { WorkspacesPageView } from "./WorkspacesPageView"; import { WorkspacesPageView } from "./WorkspacesPageView";
const createWorkspace = ( const createWorkspace = (
name: string,
status: WorkspaceStatus, status: WorkspaceStatus,
outdated = false, outdated = false,
lastUsedAt = "0001-01-01", lastUsedAt = "0001-01-01",
@ -42,6 +43,7 @@ const createWorkspace = (
return { return {
...MockWorkspace, ...MockWorkspace,
id: uniqueId("workspace"), id: uniqueId("workspace"),
name: name,
outdated, outdated,
latest_build: { latest_build: {
...MockWorkspace.latest_build, ...MockWorkspace.latest_build,
@ -59,17 +61,50 @@ const createWorkspace = (
// This is type restricted to prevent future statuses from slipping // This is type restricted to prevent future statuses from slipping
// through the cracks unchecked! // through the cracks unchecked!
const workspaces = WorkspaceStatuses.map((status) => createWorkspace(status)); const workspaces = WorkspaceStatuses.map((status) =>
createWorkspace(status, status),
);
// Additional Workspaces depending on time // Additional Workspaces depending on time
const additionalWorkspaces: Record<string, Workspace> = { const additionalWorkspaces: Record<string, Workspace> = {
today: createWorkspace( today: createWorkspace(
"running-outdated",
"running", "running",
true, true,
dayjs().subtract(3, "hour").toString(), dayjs().subtract(3, "hour").toString(),
), ),
old: createWorkspace("running", true, dayjs().subtract(1, "week").toString()), old: createWorkspace(
"old-outdated",
"running",
true,
dayjs().subtract(1, "week").toString(),
),
oldStopped: createWorkspace(
"old-stopped-outdated",
"stopped",
true,
dayjs().subtract(1, "week").toString(),
),
oldRequireActiveVersion: {
...createWorkspace(
"old-require-active-version-outdated",
"running",
true,
dayjs().subtract(1, "week").toString(),
),
template_require_active_version: true,
},
oldStoppedRequireActiveVersion: {
...createWorkspace(
"old-stopped-require-active-version-outdated",
"stopped",
true,
dayjs().subtract(1, "week").toString(),
),
template_require_active_version: true,
},
veryOld: createWorkspace( veryOld: createWorkspace(
"very-old-running-outdated",
"running", "running",
true, true,
dayjs().subtract(1, "month").subtract(4, "day").toString(), dayjs().subtract(1, "month").subtract(4, "day").toString(),
@ -78,12 +113,14 @@ const additionalWorkspaces: Record<string, Workspace> = {
const dormantWorkspaces: Record<string, Workspace> = { const dormantWorkspaces: Record<string, Workspace> = {
dormantNoDelete: createWorkspace( dormantNoDelete: createWorkspace(
"dormant-no-delete",
"stopped", "stopped",
false, false,
dayjs().subtract(1, "month").toString(), dayjs().subtract(1, "month").toString(),
dayjs().subtract(1, "month").toString(), dayjs().subtract(1, "month").toString(),
), ),
dormantAutoDelete: createWorkspace( dormantAutoDelete: createWorkspace(
"dormant-auto-delete",
"stopped", "stopped",
false, false,
dayjs().subtract(1, "month").toString(), dayjs().subtract(1, "month").toString(),
@ -245,7 +282,7 @@ export const UnhealthyWorkspace: Story = {
args: { args: {
workspaces: [ workspaces: [
{ {
...createWorkspace("running"), ...createWorkspace("unhealthy", "running"),
health: { health: {
healthy: false, healthy: false,
failing_agents: [], failing_agents: [],
@ -282,6 +319,7 @@ export const MultipleApps: Story = {
workspaces: [ workspaces: [
{ {
...MockWorkspace, ...MockWorkspace,
name: "multiple-apps",
latest_build: { latest_build: {
...MockWorkspace.latest_build, ...MockWorkspace.latest_build,
resources: [ resources: [
@ -315,7 +353,13 @@ export const MultipleApps: Story = {
export const ShowOrganizations: Story = { export const ShowOrganizations: Story = {
args: { args: {
workspaces: [{ ...MockWorkspace, organization_name: "limbus-co" }], workspaces: [
{
...MockWorkspace,
name: "other-org-workspace",
organization_name: "limbus-co",
},
],
}, },
parameters: { parameters: {
@ -347,6 +391,7 @@ export const WithLatestAppStatus: Story = {
workspaces: [ workspaces: [
{ {
...MockWorkspace, ...MockWorkspace,
name: "long-app-status",
latest_app_status: { latest_app_status: {
...MockWorkspaceAppStatus, ...MockWorkspaceAppStatus,
message: message:
@ -355,10 +400,12 @@ export const WithLatestAppStatus: Story = {
}, },
{ {
...MockWorkspace, ...MockWorkspace,
name: "no-app-status",
latest_app_status: null, latest_app_status: null,
}, },
{ {
...MockWorkspace, ...MockWorkspace,
name: "app-status-working",
latest_app_status: { latest_app_status: {
...MockWorkspaceAppStatus, ...MockWorkspaceAppStatus,
state: "working", state: "working",
@ -367,6 +414,7 @@ export const WithLatestAppStatus: Story = {
}, },
{ {
...MockWorkspace, ...MockWorkspace,
name: "app-status-failure",
latest_app_status: { latest_app_status: {
...MockWorkspaceAppStatus, ...MockWorkspaceAppStatus,
state: "failure", state: "failure",
@ -381,6 +429,7 @@ export const WithLatestAppStatus: Story = {
resources: [], resources: [],
}, },
}, },
name: "stopped-app-status-failure",
latest_app_status: { latest_app_status: {
...MockWorkspaceAppStatus, ...MockWorkspaceAppStatus,
state: "failure", state: "failure",
@ -390,6 +439,7 @@ export const WithLatestAppStatus: Story = {
}, },
{ {
...MockWorkspace, ...MockWorkspace,
name: "app-status-working-with-uri",
latest_app_status: { latest_app_status: {
...MockWorkspaceAppStatus, ...MockWorkspaceAppStatus,
state: "working", state: "working",

View File

@ -48,6 +48,8 @@ import { ExternalLinkIcon, FileIcon, StarIcon } from "lucide-react";
import { EllipsisVertical } from "lucide-react"; import { EllipsisVertical } from "lucide-react";
import { import {
BanIcon, BanIcon,
CirclePlayIcon,
CloudIcon,
PlayIcon, PlayIcon,
RefreshCcwIcon, RefreshCcwIcon,
SquareIcon, SquareIcon,
@ -558,7 +560,46 @@ const WorkspaceActionsCell: FC<WorkspaceActionsCellProps> = ({
isLoading={workspaceUpdate.isUpdating} isLoading={workspaceUpdate.isUpdating}
label="Update and start workspace" label="Update and start workspace"
> >
<PlayIcon /> <CloudIcon />
</PrimaryAction>
<WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} />
</>
)}
{abilities.actions.includes("updateAndStartRequireActiveVersion") && (
<>
<PrimaryAction
onClick={workspaceUpdate.update}
isLoading={workspaceUpdate.isUpdating}
label="This template requires automatic updates on workspace startup. Contact your administrator if you want to preserve the template version."
>
<CirclePlayIcon />
</PrimaryAction>
<WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} />
</>
)}
{abilities.actions.includes("updateAndRestart") && (
<>
<PrimaryAction
onClick={workspaceUpdate.update}
isLoading={workspaceUpdate.isUpdating}
label="Update and restart workspace"
>
<CloudIcon />
</PrimaryAction>
<WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} />
</>
)}
{abilities.actions.includes("updateAndRestartRequireActiveVersion") && (
<>
<PrimaryAction
onClick={workspaceUpdate.update}
isLoading={workspaceUpdate.isUpdating}
label="This template requires automatic updates on workspace restart. Contact your administrator if you want to preserve the template version."
>
<CirclePlayIcon />
</PrimaryAction> </PrimaryAction>
<WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} /> <WorkspaceUpdateDialogs {...workspaceUpdate.dialogs} />
</> </>