Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { expect, spyOn, userEvent, within } from "storybook/test";
import { expect, spyOn, userEvent, waitFor, within } from "storybook/test";
import {
reactRouterOutlet,
reactRouterParameters,
Expand Down Expand Up @@ -73,7 +73,58 @@ export const EnablingAutostopUsesTemplateDefault: Story = {
},
};

export const ChangingAutostopShowsRestartDialog: Story = {
export const EnablingAutostopShowsRestartDialog: Story = {
parameters: {
reactRouter: workspaceRouterParameters(autostopDisabledWorkspace),
queries: workspaceQueries(autostopDisabledWorkspace),
},
beforeEach: () => {
spyOn(API, "getWorkspaceByOwnerAndName").mockResolvedValue(
autostopDisabledWorkspace,
);
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const body = within(document.body);
const user = userEvent.setup();
await user.click(await canvas.findByLabelText("Enable Autostop"));
await user.click(await canvas.findByRole("button", { name: /save/i }));
await body.findByText(
`Schedule for workspace "${MockWorkspace.name}" updated successfully.`,
);
await body.findByText("Restart workspace?");
},
};

export const ApplyLaterKeepsUserOnSchedulePage: Story = {
parameters: {
reactRouter: workspaceRouterParameters(autostopDisabledWorkspace),
queries: workspaceQueries(autostopDisabledWorkspace),
},
beforeEach: () => {
spyOn(API, "getWorkspaceByOwnerAndName").mockResolvedValue(
autostopDisabledWorkspace,
);
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const body = within(document.body);
const user = userEvent.setup();
const restartSpy = spyOn(API, "restartWorkspace");
await user.click(await canvas.findByLabelText("Enable Autostop"));
await user.click(await canvas.findByRole("button", { name: /save/i }));
await body.findByText("Restart workspace?");
await user.click(await body.findByRole("button", { name: /apply later/i }));
// The dialog closes without restarting or leaving the schedule page.
await waitFor(() =>
expect(body.queryByText("Restart workspace?")).not.toBeInTheDocument(),
);
expect(restartSpy).not.toHaveBeenCalled();
await canvas.findByLabelText("Enable Autostop");
},
};

export const ChangingAutostopValueShowsRestartDialog: Story = {
parameters: {
reactRouter: workspaceRouterParameters(MockWorkspace),
queries: workspaceQueries(MockWorkspace),
Expand All @@ -85,7 +136,11 @@ export const ChangingAutostopShowsRestartDialog: Story = {
const canvas = within(canvasElement);
const body = within(document.body);
const user = userEvent.setup();
await user.click(await canvas.findByLabelText("Enable Autostop"));
const ttlInput = await canvas.findByLabelText(
"Time until shutdown (hours)",
);
await user.clear(ttlInput);
await user.type(ttlInput, "4");
await user.click(await canvas.findByRole("button", { name: /save/i }));
await body.findByText(
`Schedule for workspace "${MockWorkspace.name}" updated successfully.`,
Expand All @@ -94,19 +149,41 @@ export const ChangingAutostopShowsRestartDialog: Story = {
},
};

const stoppedWorkspace: Workspace = {
...MockWorkspace,
export const DisablingAutostopSkipsRestartDialog: Story = {
parameters: {
reactRouter: workspaceRouterParameters(MockWorkspace),
queries: workspaceQueries(MockWorkspace),
},
beforeEach: () => {
spyOn(API, "getWorkspaceByOwnerAndName").mockResolvedValue(MockWorkspace);
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const body = within(document.body);
const user = userEvent.setup();
// MockWorkspace has autostop enabled, so clicking the toggle disables it.
await user.click(await canvas.findByLabelText("Enable Autostop"));
await user.click(await canvas.findByRole("button", { name: /save/i }));
await body.findByText(
`Schedule for workspace "${MockWorkspace.name}" updated successfully.`,
);
expect(body.queryByText("Restart workspace?")).not.toBeInTheDocument();
},
};

const stoppedAutostopDisabledWorkspace: Workspace = {
...autostopDisabledWorkspace,
latest_build: { ...MockWorkspaceBuild, status: "stopped" },
};

export const ChangingAutostopWhileStoppedSkipsDialog: Story = {
export const EnablingAutostopWhileStoppedSkipsDialog: Story = {
parameters: {
reactRouter: workspaceRouterParameters(stoppedWorkspace),
queries: workspaceQueries(stoppedWorkspace),
reactRouter: workspaceRouterParameters(stoppedAutostopDisabledWorkspace),
queries: workspaceQueries(stoppedAutostopDisabledWorkspace),
},
beforeEach: () => {
spyOn(API, "getWorkspaceByOwnerAndName").mockResolvedValue(
stoppedWorkspace,
stoppedAutostopDisabledWorkspace,
);
},
play: async ({ canvasElement }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,19 @@ const WorkspaceSchedulePage: FC = () => {

await submitScheduleMutation.mutateAsync(data);

// A running build's autostop deadline is calculated when the
// build starts, so updating the TTL does not retroactively
// change it. Prompt the user to restart so the new value takes
// effect immediately, but only when all of the following hold:
// - autostop actually changed (toggled or new TTL value),
// - autostop is enabled after the change; disabling clears the
// running build's deadline server-side, so no restart is
// needed, and
Comment on lines +146 to +150

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Condense the restart-predicate comment

Keep the useful backend invariant, but remove the bullet-by-bullet walkthrough of the three conditions directly below it. This ten-line comment largely restates the if control flow and exceeds the frontend guidance to reserve comments for non-obvious constraints in one to three lines.

AGENTS.md reference: site/AGENTS.md:L15-L15

Useful? React with πŸ‘Β / πŸ‘Ž.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this area is pretty ambiguous, someone else can comment to this fact but this is an implementation detail that was already a problem once. I like the verbosity. YOMV.

// - the workspace is running; a stopped workspace picks up the
// new value on its next start.
if (
data.autostopChanged &&
getAutostop(workspace).autostopEnabled &&
values.autostopEnabled &&
workspace.latest_build.status === "running"
) {
setIsConfirmingApply(true);
Expand All @@ -163,7 +173,9 @@ const WorkspaceSchedulePage: FC = () => {
navigate(`/@${username}/${workspaceName}`);
}}
onClose={() => {
navigate(`/@${username}/${workspaceName}`);
// Keep the user on the schedule page; the saved value still
// applies on the next workspace start.
setIsConfirmingApply(false);
}}
/>
</div>
Expand Down
Loading