Skip to content

Commit 78deaba

Browse files
feat(site): show "update and start" button when update is forced (#13334)
1 parent f27f5c0 commit 78deaba

File tree

3 files changed

+123
-71
lines changed

3 files changed

+123
-71
lines changed

site/src/pages/WorkspacePage/WorkspaceActions/Buttons.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,8 @@ export const RestartButton: FC<ActionButtonPropsWithWorkspace> = ({
117117
handleAction,
118118
loading,
119119
workspace,
120-
disabled,
121-
tooltipText,
122120
}) => {
123-
const buttonContent = (
121+
return (
124122
<ButtonGroup
125123
variant="outlined"
126124
css={{
@@ -129,13 +127,12 @@ export const RestartButton: FC<ActionButtonPropsWithWorkspace> = ({
129127
borderLeft: "1px solid #FFF",
130128
},
131129
}}
132-
disabled={disabled}
133130
>
134131
<TopbarButton
135132
startIcon={<ReplayIcon />}
136133
onClick={() => handleAction()}
137134
data-testid="workspace-restart-button"
138-
disabled={disabled || loading}
135+
disabled={loading}
139136
>
140137
{loading ? <>Restarting&hellip;</> : <>Restart&hellip;</>}
141138
</TopbarButton>
@@ -147,11 +144,20 @@ export const RestartButton: FC<ActionButtonPropsWithWorkspace> = ({
147144
/>
148145
</ButtonGroup>
149146
);
147+
};
150148

151-
return tooltipText ? (
152-
<Tooltip title={tooltipText}>{buttonContent}</Tooltip>
153-
) : (
154-
buttonContent
149+
export const UpdateAndStartButton: FC<ActionButtonProps> = ({
150+
handleAction,
151+
}) => {
152+
return (
153+
<Tooltip title="This template requires automatic updates on workspace startup. Contact your administrator if you want to preserve the template version.">
154+
<TopbarButton
155+
startIcon={<PlayCircleOutlineIcon />}
156+
onClick={() => handleAction()}
157+
>
158+
Update and start&hellip;
159+
</TopbarButton>
160+
</Tooltip>
155161
);
156162
};
157163

site/src/pages/WorkspacePage/WorkspaceActions/WorkspaceActions.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
UpdateButton,
2525
ActivateButton,
2626
FavoriteButton,
27+
UpdateAndStartButton,
2728
} from "./Buttons";
2829
import { type ActionType, abilitiesByWorkspaceStatus } from "./constants";
2930
import { DebugButton } from "./DebugButton";
@@ -89,6 +90,7 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
8990
// A mapping of button type to the corresponding React component
9091
const buttonMapping: Record<ActionType, ReactNode> = {
9192
update: <UpdateButton handleAction={handleUpdate} />,
93+
updateAndStart: <UpdateAndStartButton handleAction={handleUpdate} />,
9294
updating: <UpdateButton loading handleAction={handleUpdate} />,
9395
start: (
9496
<StartButton
@@ -161,7 +163,13 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
161163
data-testid="workspace-actions"
162164
>
163165
{canBeUpdated && (
164-
<>{isUpdating ? buttonMapping.updating : buttonMapping.update}</>
166+
<>
167+
{isUpdating
168+
? buttonMapping.updating
169+
: workspace.template_require_active_version
170+
? buttonMapping.updateAndStart
171+
: buttonMapping.update}
172+
</>
165173
)}
166174

167175
{isRestarting
@@ -236,10 +244,6 @@ function getTooltipText(
236244
return "This template requires automatic updates on workspace startup, but template administrators can ignore this policy.";
237245
}
238246

239-
if (workspace.template_require_active_version) {
240-
return "This template requires automatic updates on workspace startup. Contact your administrator if you want to preserve the template version.";
241-
}
242-
243247
if (workspace.automatic_updates === "always") {
244248
return "Automatic updates are enabled for this workspace. Modify the update policy in workspace settings if you want to preserve the template version.";
245249
}
Lines changed: 99 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Workspace, WorkspaceStatus } from "api/typesGenerated";
1+
import type { Workspace } from "api/typesGenerated";
22

33
/**
44
* An iterable of all action types supported by the workspace UI
@@ -23,6 +23,10 @@ export const actionTypes = [
2323
"retry",
2424
"debug",
2525

26+
// When a template requires updates, we aim to display a distinct update
27+
// button that clearly indicates a mandatory update.
28+
"updateAndStart",
29+
2630
// These are buttons that should be used with disabled UI elements
2731
"canceling",
2832
"deleted",
@@ -52,67 +56,105 @@ export const abilitiesByWorkspaceStatus = (
5256
const status = workspace.latest_build.status;
5357
if (status === "failed" && canDebug) {
5458
return {
55-
...statusToAbility.failed,
5659
actions: ["retry", "debug"],
60+
canCancel: false,
61+
canAcceptJobs: true,
5762
};
5863
}
5964

60-
return statusToAbility[status];
61-
};
65+
switch (status) {
66+
case "starting": {
67+
return {
68+
actions: ["starting"],
69+
canCancel: true,
70+
canAcceptJobs: false,
71+
};
72+
}
73+
case "running": {
74+
const actions: ActionType[] = ["stop"];
6275

63-
const statusToAbility: Record<WorkspaceStatus, WorkspaceAbilities> = {
64-
starting: {
65-
actions: ["starting"],
66-
canCancel: true,
67-
canAcceptJobs: false,
68-
},
69-
running: {
70-
actions: ["stop", "restart"],
71-
canCancel: false,
72-
canAcceptJobs: true,
73-
},
74-
stopping: {
75-
actions: ["stopping"],
76-
canCancel: true,
77-
canAcceptJobs: false,
78-
},
79-
stopped: {
80-
actions: ["start"],
81-
canCancel: false,
82-
canAcceptJobs: true,
83-
},
84-
canceled: {
85-
actions: ["start", "stop"],
86-
canCancel: false,
87-
canAcceptJobs: true,
88-
},
76+
// If the template requires the latest version, we prevent the user from
77+
// restarting the workspace without updating it first. In the Buttons
78+
// component, we display an UpdateAndStart component to facilitate this.
79+
if (!workspace.template_require_active_version) {
80+
actions.push("restart");
81+
}
8982

90-
// in the case of an error
91-
failed: {
92-
actions: ["retry"],
93-
canCancel: false,
94-
canAcceptJobs: true,
95-
},
83+
return {
84+
actions,
85+
canCancel: false,
86+
canAcceptJobs: true,
87+
};
88+
}
89+
case "stopping": {
90+
return {
91+
actions: ["stopping"],
92+
canCancel: true,
93+
canAcceptJobs: false,
94+
};
95+
}
96+
case "stopped": {
97+
const actions: ActionType[] = [];
9698

97-
// Disabled states
98-
canceling: {
99-
actions: ["canceling"],
100-
canCancel: false,
101-
canAcceptJobs: false,
102-
},
103-
deleting: {
104-
actions: ["deleting"],
105-
canCancel: true,
106-
canAcceptJobs: false,
107-
},
108-
deleted: {
109-
actions: ["deleted"],
110-
canCancel: false,
111-
canAcceptJobs: false,
112-
},
113-
pending: {
114-
actions: ["pending"],
115-
canCancel: false,
116-
canAcceptJobs: false,
117-
},
99+
// If the template requires the latest version, we prevent the user from
100+
// starting the workspace without updating it first. In the Buttons
101+
// component, we display an UpdateAndStart component to facilitate this.
102+
if (!workspace.template_require_active_version) {
103+
actions.push("start");
104+
}
105+
106+
return {
107+
actions,
108+
canCancel: false,
109+
canAcceptJobs: true,
110+
};
111+
}
112+
case "canceled": {
113+
return {
114+
actions: ["start", "stop"],
115+
canCancel: false,
116+
canAcceptJobs: true,
117+
};
118+
}
119+
case "failed": {
120+
return {
121+
actions: ["retry"],
122+
canCancel: false,
123+
canAcceptJobs: true,
124+
};
125+
}
126+
127+
// Disabled states
128+
case "canceling": {
129+
return {
130+
actions: ["canceling"],
131+
canCancel: false,
132+
canAcceptJobs: false,
133+
};
134+
}
135+
case "deleting": {
136+
return {
137+
actions: ["deleting"],
138+
canCancel: true,
139+
canAcceptJobs: false,
140+
};
141+
}
142+
case "deleted": {
143+
return {
144+
actions: ["deleted"],
145+
canCancel: false,
146+
canAcceptJobs: false,
147+
};
148+
}
149+
case "pending": {
150+
return {
151+
actions: ["pending"],
152+
canCancel: false,
153+
canAcceptJobs: false,
154+
};
155+
}
156+
default: {
157+
throw new Error(`Unknown workspace status: ${status}`);
158+
}
159+
}
118160
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy