Skip to content

Commit 1de952b

Browse files
authored
fix(site): allow updating workspace in TaskPage (#21316)
Relates to #20925 This PR modifies TaskPage to update an outdated workspace instead of starting it. Before, starting an outdated workspace where the template required the active version would fail with the error "cannot use non-active version: rbac: forbidden". For the case of a dormant workspace, I deemed it safe enough to simply unset dormancy on an attempted start (ref: #21306). However, automatically updating a workspace is a more risky option, so I instead elected to give the user the option of updating their workspace using the existing tooltip. **Note:** I made a change to the `WorkspaceOutdatedTooltip` components to allow it to have children so that the tooltip could trigger over a wider element instead of just the info icon. ``` <🤖 AI Disclaimer>I got some help from Gemini 3 Flash in "Ask" mode.</🤖 AI Disclaimer> ```
1 parent 73253df commit 1de952b

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

site/src/modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip.tsx

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {
1313
HelpTooltipLinksGroup,
1414
HelpTooltipText,
1515
HelpTooltipTitle,
16+
HelpTooltipTrigger,
1617
} from "components/HelpTooltip/HelpTooltip";
1718
import { InfoIcon, RotateCcwIcon } from "lucide-react";
1819
import { linkToTemplate, useLinks } from "modules/navigation";
19-
import { type FC, useState } from "react";
20+
import { type FC, type ReactNode, useState } from "react";
2021
import { useQuery } from "react-query";
2122
import {
2223
useWorkspaceUpdate,
@@ -25,20 +26,31 @@ import {
2526

2627
interface WorkspaceOutdatedTooltipProps {
2728
workspace: Workspace;
29+
children?: ReactNode;
2830
}
2931

30-
export const WorkspaceOutdatedTooltip: FC<WorkspaceOutdatedTooltipProps> = (
31-
props,
32-
) => {
32+
export const WorkspaceOutdatedTooltip: FC<WorkspaceOutdatedTooltipProps> = ({
33+
workspace,
34+
children,
35+
}) => {
3336
const [isOpen, setIsOpen] = useState(false);
3437

3538
return (
3639
<HelpTooltip open={isOpen} onOpenChange={setIsOpen}>
37-
<HelpTooltipIconTrigger size="small" hoverEffect={false}>
38-
<InfoIcon css={styles.icon} />
39-
<span className="sr-only">Outdated info</span>
40-
</HelpTooltipIconTrigger>
41-
<WorkspaceOutdatedTooltipContent isOpen={isOpen} {...props} />
40+
{children ? (
41+
<HelpTooltipTrigger asChild>
42+
<span className="flex items-center gap-1.5 cursor-help">
43+
<InfoIcon css={styles.icon} size={14} />
44+
<span>{children}</span>
45+
</span>
46+
</HelpTooltipTrigger>
47+
) : (
48+
<HelpTooltipIconTrigger size="small" hoverEffect={false}>
49+
<InfoIcon css={styles.icon} />
50+
<span className="sr-only">Outdated info</span>
51+
</HelpTooltipIconTrigger>
52+
)}
53+
<WorkspaceOutdatedTooltipContent isOpen={isOpen} workspace={workspace} />
4254
</HelpTooltip>
4355
);
4456
};

site/src/pages/TaskPage/TaskPage.stories.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from "testHelpers/entities";
2020
import {
2121
withAuthProvider,
22+
withDashboardProvider,
2223
withGlobalSnackbar,
2324
withProxyProvider,
2425
withWebSocket,
@@ -65,7 +66,7 @@ const MockVSCodeApp: WorkspaceApp = {
6566
const meta: Meta<typeof TaskPage> = {
6667
title: "pages/TaskPage",
6768
component: TaskPage,
68-
decorators: [withProxyProvider(), withAuthProvider],
69+
decorators: [withProxyProvider(), withAuthProvider, withDashboardProvider],
6970
beforeEach: () => {
7071
spyOn(API, "getTasks").mockResolvedValue(MockTasks);
7172
},
@@ -402,6 +403,50 @@ export const MainAppHealthy: Story = mainAppHealthStory("healthy");
402403
export const MainAppInitializing: Story = mainAppHealthStory("initializing");
403404
export const MainAppUnhealthy: Story = mainAppHealthStory("unhealthy");
404405

406+
export const OutdatedWorkspace: Story = {
407+
// Given: an 'outdated' workspace (that is, the latest build does not use template's active version)
408+
parameters: {
409+
queries: [
410+
{
411+
key: ["tasks", { owner: MockTask.owner_name }],
412+
data: [MockTask],
413+
},
414+
{
415+
key: ["tasks", MockTask.owner_name, MockTask.id],
416+
data: MockTask,
417+
},
418+
{
419+
key: [
420+
"workspace",
421+
MockTask.owner_name,
422+
MockTask.workspace_name,
423+
"settings",
424+
],
425+
data: {
426+
...MockStoppedWorkspace,
427+
outdated: true,
428+
},
429+
},
430+
{
431+
key: [
432+
"workspaceBuilds",
433+
MockStoppedWorkspace.latest_build.id,
434+
"parameters",
435+
],
436+
data: [],
437+
},
438+
],
439+
},
440+
// Then: a tooltip should be displayed prompting the user to update the workspace.
441+
play: async ({ canvasElement }) => {
442+
const canvas = within(canvasElement);
443+
const outdatedTooltip = await canvas.findByTestId(
444+
"workspace-outdated-tooltip",
445+
);
446+
expect(outdatedTooltip).toBeVisible();
447+
},
448+
};
449+
405450
export const Active: Story = {
406451
decorators: [withProxyProvider()],
407452
beforeEach: () => {

site/src/pages/TaskPage/TaskPage.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { getAllAppsWithAgent } from "modules/tasks/apps";
2626
import { TasksSidebar } from "modules/tasks/TasksSidebar/TasksSidebar";
2727
import { WorkspaceErrorDialog } from "modules/workspaces/ErrorDialog/WorkspaceErrorDialog";
2828
import { WorkspaceBuildLogs } from "modules/workspaces/WorkspaceBuildLogs/WorkspaceBuildLogs";
29+
import { WorkspaceOutdatedTooltip } from "modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip";
2930
import {
3031
type FC,
3132
type PropsWithChildren,
@@ -275,9 +276,20 @@ const WorkspaceNotRunning: FC<WorkspaceNotRunningProps> = ({
275276
<span className="text-content-secondary text-sm">
276277
Apps and previous statuses are not available
277278
</span>
279+
{workspace.outdated && (
280+
<div
281+
data-testid="workspace-outdated-tooltip"
282+
className="flex items-center gap-1.5 mt-1 text-content-secondary text-sm"
283+
>
284+
<WorkspaceOutdatedTooltip workspace={workspace}>
285+
You can update your task workspace to a newer version
286+
</WorkspaceOutdatedTooltip>
287+
</div>
288+
)}
278289
<div className="flex flex-row mt-4 gap-4">
279290
<Button
280291
size="sm"
292+
data-testid="task-start-workspace"
281293
disabled={isWaitingForStart}
282294
onClick={() => {
283295
mutateStartWorkspace.mutate({

0 commit comments

Comments
 (0)