From 87576916bd7dd72488b3624e2153fc70761156ad Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 13 Jun 2024 17:30:40 +0000 Subject: [PATCH 1/3] fix: fix workspace actions options --- .../WorkspaceActions/Buttons.tsx | 24 +++++++--- .../WorkspaceActions.stories.tsx | 10 +++++ .../WorkspaceActions/WorkspaceActions.tsx | 44 +++++++------------ .../WorkspaceActions/constants.ts | 29 ++++++------ 4 files changed, 59 insertions(+), 48 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx index ecfde9e97aa9b..576e5fb84ead2 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx @@ -99,6 +99,21 @@ export const StartButton: FC = ({ ); }; +export const UpdateAndStartButton: FC = ({ + handleAction, +}) => { + return ( + + } + onClick={() => handleAction()} + > + Update and start… + + + ); +}; + export const StopButton: FC = ({ handleAction, loading, @@ -148,16 +163,13 @@ export const RestartButton: FC = ({ ); }; -export const UpdateAndStartButton: FC = ({ +export const UpdateAndRestartButton: FC = ({ handleAction, }) => { return ( - } - onClick={() => handleAction()} - > - Update and start… + } onClick={() => handleAction()}> + Update and restart… ); diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx index 3e663dafba1a9..fa00615b0534f 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx @@ -103,6 +103,16 @@ export const RequireActiveVersionStarted: Story = { }, }; +export const RequireActiveVersionStarting: Story = { + args: { + workspace: { + ...Mocks.MockStartingWorkspace, + template_require_active_version: true, + }, + canChangeVersions: false, + }, +}; + export const RequireActiveVersionStopped: Story = { args: { workspace: Mocks.MockOutdatedStoppedWorkspaceRequireActiveVersion, diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx index 86a53d592243e..e58f8190e900f 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx @@ -26,6 +26,7 @@ import { ActivateButton, FavoriteButton, UpdateAndStartButton, + UpdateAndRestartButton, } from "./Buttons"; import { type ActionType, abilitiesByWorkspaceStatus } from "./constants"; import { DebugButton } from "./DebugButton"; @@ -89,12 +90,12 @@ export const WorkspaceActions: FC = ({ const mustUpdate = mustUpdateWorkspace(workspace, canChangeVersions); const tooltipText = getTooltipText(workspace, mustUpdate, canChangeVersions); - const canBeUpdated = workspace.outdated && canAcceptJobs; // A mapping of button type to the corresponding React component const buttonMapping: Record = { update: , updateAndStart: , + updateAndRestart: , updating: , start: ( = ({ enableBuildParameters={workspace.latest_build.transition === "start"} /> ), - toggleFavorite: ( - - ), }; return ( @@ -166,30 +160,22 @@ export const WorkspaceActions: FC = ({ css={{ display: "flex", alignItems: "center", gap: 8 }} data-testid="workspace-actions" > - {canBeUpdated && ( - <> - {isUpdating - ? buttonMapping.updating - : workspace.template_require_active_version - ? buttonMapping.updateAndStart - : buttonMapping.update} - - )} - - {!canBeUpdated && - !isUpdating && - workspace.template_require_active_version && - buttonMapping.start} - - {isRestarting - ? buttonMapping.restarting - : actions.map((action) => ( - {buttonMapping[action]} - ))} + {/* Restarting must be handled separately, because it otherwise would appear as stopping */} + {isUpdating + ? buttonMapping.updating + : isRestarting + ? buttonMapping.restarting + : actions.map((action) => ( + {buttonMapping[action]} + ))} {showCancel && } - {buttonMapping.toggleFavorite} + diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts index c2a85da8cb121..26b3bcfa2cc48 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts +++ b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts @@ -6,16 +6,19 @@ import type { Workspace } from "api/typesGenerated"; export const actionTypes = [ "start", "starting", + // Replaces start when an update is required. + "updateAndStart", "stop", "stopping", "restart", "restarting", + // Replaces restart when an update is required. + "updateAndRestart", "deleting", "update", "updating", "activate", "activating", - "toggleFavorite", // There's no need for a retrying state because retrying starts a transition // into one of the starting, stopping, or deleting states (based on the @@ -23,10 +26,6 @@ export const actionTypes = [ "retry", "debug", - // When a template requires updates, we aim to display a distinct update - // button that clearly indicates a mandatory update. - "updateAndStart", - // These are buttons that should be used with disabled UI elements "canceling", "deleted", @@ -73,10 +72,12 @@ export const abilitiesByWorkspaceStatus = ( case "running": { const actions: ActionType[] = ["stop"]; - // If the template requires the latest version, we prevent the user from - // restarting the workspace without updating it first. In the Buttons - // component, we display an UpdateAndStart component to facilitate this. - if (!workspace.template_require_active_version) { + if (workspace.template_require_active_version && workspace.outdated) { + actions.push("updateAndRestart"); + } else { + if (workspace.outdated) { + actions.unshift("update"); + } actions.push("restart"); } @@ -96,10 +97,12 @@ export const abilitiesByWorkspaceStatus = ( case "stopped": { const actions: ActionType[] = []; - // If the template requires the latest version, we prevent the user from - // starting the workspace without updating it first. In the Buttons - // component, we display an UpdateAndStart component to facilitate this. - if (!workspace.template_require_active_version) { + if (workspace.template_require_active_version && workspace.outdated) { + actions.push("updateAndStart"); + } else { + if (workspace.outdated) { + actions.unshift("update"); + } actions.push("start"); } From c8c9dc4c66d6c97ad7fa9308255af3061eb91910 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Jun 2024 19:41:31 +0000 Subject: [PATCH 2/3] more stories --- .../WorkspaceActions.stories.tsx | 106 +++++++++++------- .../WorkspaceActions/constants.ts | 33 +++--- site/src/testHelpers/entities.ts | 4 - 3 files changed, 83 insertions(+), 60 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx index fa00615b0534f..e4188b7b88041 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.stories.tsx @@ -34,103 +34,128 @@ export const Running: Story = { }, }; -export const Stopping: Story = { +export const RunningUpdateAvailable: Story = { + name: "Running (Update available)", args: { - workspace: Mocks.MockStoppingWorkspace, + workspace: { + ...Mocks.MockWorkspace, + outdated: true, + }, }, }; -export const Stopped: Story = { +export const RunningRequireActiveVersion: Story = { + name: "Running (No required update)", args: { - workspace: Mocks.MockStoppedWorkspace, + workspace: { + ...Mocks.MockWorkspace, + template_require_active_version: true, + }, }, }; -export const Canceling: Story = { +export const RunningUpdateRequired: Story = { + name: "Running (Update Required)", args: { - workspace: Mocks.MockCancelingWorkspace, + workspace: { + ...Mocks.MockWorkspace, + template_require_active_version: true, + outdated: true, + }, }, }; -export const Canceled: Story = { +export const Stopping: Story = { args: { - workspace: Mocks.MockCanceledWorkspace, + workspace: Mocks.MockStoppingWorkspace, }, }; -export const Deleting: Story = { +export const Stopped: Story = { args: { - workspace: Mocks.MockDeletingWorkspace, + workspace: Mocks.MockStoppedWorkspace, }, }; -export const Deleted: Story = { +export const StoppedUpdateAvailable: Story = { + name: "Stopped (Update available)", args: { - workspace: Mocks.MockDeletedWorkspace, + workspace: { + ...Mocks.MockStoppedWorkspace, + outdated: true, + }, }, }; -export const Outdated: Story = { +export const StoppedRequireActiveVersion: Story = { + name: "Stopped (No required update)", args: { - workspace: Mocks.MockOutdatedWorkspace, + workspace: { + ...Mocks.MockStoppedWorkspace, + template_require_active_version: true, + }, }, }; -export const Failed: Story = { +export const StoppedUpdateRequired: Story = { + name: "Stopped (Update Required)", args: { - workspace: Mocks.MockFailedWorkspace, + workspace: { + ...Mocks.MockStoppedWorkspace, + template_require_active_version: true, + outdated: true, + }, }, }; -export const FailedWithDebug: Story = { +export const Updating: Story = { args: { - workspace: Mocks.MockFailedWorkspace, - canDebug: true, + workspace: Mocks.MockOutdatedWorkspace, + isUpdating: true, }, }; -export const Updating: Story = { +export const Restarting: Story = { args: { - isUpdating: true, - workspace: Mocks.MockOutdatedWorkspace, + workspace: Mocks.MockStoppingWorkspace, + isRestarting: true, }, }; -export const RequireActiveVersionStarted: Story = { +export const Canceling: Story = { args: { - workspace: Mocks.MockOutdatedRunningWorkspaceRequireActiveVersion, - canChangeVersions: false, + workspace: Mocks.MockCancelingWorkspace, }, }; -export const RequireActiveVersionStarting: Story = { +export const Deleting: Story = { args: { - workspace: { - ...Mocks.MockStartingWorkspace, - template_require_active_version: true, - }, - canChangeVersions: false, + workspace: Mocks.MockDeletingWorkspace, + }, +}; + +export const Deleted: Story = { + args: { + workspace: Mocks.MockDeletedWorkspace, }, }; -export const RequireActiveVersionStopped: Story = { +export const Outdated: Story = { args: { - workspace: Mocks.MockOutdatedStoppedWorkspaceRequireActiveVersion, - canChangeVersions: false, + workspace: Mocks.MockOutdatedWorkspace, }, }; -export const AlwaysUpdateStarted: Story = { +export const Failed: Story = { args: { - workspace: Mocks.MockOutdatedRunningWorkspaceAlwaysUpdate, - canChangeVersions: true, + workspace: Mocks.MockFailedWorkspace, }, }; -export const AlwaysUpdateStopped: Story = { +export const FailedWithDebug: Story = { args: { - workspace: Mocks.MockOutdatedStoppedWorkspaceAlwaysUpdate, - canChangeVersions: true, + workspace: Mocks.MockFailedWorkspace, + canDebug: true, }, }; @@ -143,6 +168,7 @@ export const CancelShownForOwner: Story = { isOwner: true, }, }; + export const CancelShownForUser: Story = { args: { workspace: Mocks.MockStartingWorkspace, diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts index 26b3bcfa2cc48..267da36335bdd 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts +++ b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts @@ -53,13 +53,6 @@ export const abilitiesByWorkspaceStatus = ( } const status = workspace.latest_build.status; - if (status === "failed" && canDebug) { - return { - actions: ["retry", "debug"], - canCancel: false, - canAcceptJobs: true, - }; - } switch (status) { case "starting": { @@ -120,6 +113,14 @@ export const abilitiesByWorkspaceStatus = ( }; } case "failed": { + if (canDebug) { + return { + actions: ["retry", "debug"], + canCancel: false, + canAcceptJobs: true, + }; + } + return { actions: ["retry"], canCancel: false, @@ -128,6 +129,13 @@ export const abilitiesByWorkspaceStatus = ( } // Disabled states + case "pending": { + return { + actions: ["pending"], + canCancel: false, + canAcceptJobs: false, + }; + } case "canceling": { return { actions: ["canceling"], @@ -149,15 +157,8 @@ export const abilitiesByWorkspaceStatus = ( canAcceptJobs: false, }; } - case "pending": { - return { - actions: ["pending"], - canCancel: false, - canAcceptJobs: false, - }; - } - default: { + + default: throw new Error(`Unknown workspace status: ${status}`); - } } }; diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index bd7627f070fdf..055093570c7ab 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -1175,10 +1175,6 @@ export const MockOutdatedRunningWorkspaceRequireActiveVersion: TypesGen.Workspac id: "test-outdated-workspace-require-active-version", outdated: true, template_require_active_version: true, - latest_build: { - ...MockWorkspaceBuild, - status: "running", - }, }; export const MockOutdatedRunningWorkspaceAlwaysUpdate: TypesGen.Workspace = { From 00638e196c3761fda754a568f68631801e6b6b45 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 14 Jun 2024 21:07:06 +0000 Subject: [PATCH 3/3] fix test --- .../WorkspacePage/WorkspaceActions/constants.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts index 267da36335bdd..f6d9f8f1cfa20 100644 --- a/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts +++ b/site/src/pages/WorkspacePage/WorkspaceActions/constants.ts @@ -113,16 +113,18 @@ export const abilitiesByWorkspaceStatus = ( }; } case "failed": { + const actions: ActionType[] = ["retry"]; + if (canDebug) { - return { - actions: ["retry", "debug"], - canCancel: false, - canAcceptJobs: true, - }; + actions.push("debug"); + } + + if (workspace.outdated) { + actions.unshift("update"); } return { - actions: ["retry"], + actions, canCancel: false, canAcceptJobs: true, };