fix: keep button in loading state after start request is made (#20294)

After requesting a workspace start, it may take a while to become ready.
Show a loading state in the meantime.
	
Fixes  https://github.com/coder/coder/issues/20233
This commit is contained in:
Bruno Quaresma
2025-10-15 10:03:34 -03:00
committed by GitHub
parent 05b037bdea
commit 24dddd56c5
2 changed files with 63 additions and 4 deletions
@@ -320,6 +320,60 @@ export const ActivePreview: Story = {
},
};
export const WorkspaceStarting: Story = {
decorators: [withGlobalSnackbar],
beforeEach: () => {
spyOn(API, "startWorkspace").mockResolvedValue(
MockStartingWorkspace.latest_build,
);
},
parameters: {
reactRouter: reactRouterParameters({
location: {
pathParams: {
username: MockStoppedWorkspace.owner_name,
workspace: MockStoppedWorkspace.name,
},
},
routing: {
path: "/tasks/:username/:workspace",
},
}),
queries: [
{
key: [
"tasks",
MockStoppedWorkspace.owner_name,
MockStoppedWorkspace.name,
],
data: {
prompt: "Create competitors page",
workspace: MockStoppedWorkspace,
},
},
{
key: ["workspace", MockStoppedWorkspace.id, "parameters"],
data: {
templateVersionRichParameters: [],
buildParameters: [],
},
},
],
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const startButton = await canvas.findByText("Start workspace");
expect(startButton).toBeInTheDocument();
await userEvent.click(startButton);
await waitFor(async () => {
expect(API.startWorkspace).toBeCalled();
});
},
};
export const WorkspaceStartFailure: Story = {
decorators: [withGlobalSnackbar],
beforeEach: () => {
+9 -4
View File
@@ -13,6 +13,7 @@ import { displayError } from "components/GlobalSnackbar/utils";
import { Loader } from "components/Loader/Loader";
import { Margins } from "components/Margins/Margins";
import { ScrollArea } from "components/ScrollArea/ScrollArea";
import { Spinner } from "components/Spinner/Spinner";
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
import { ArrowLeftIcon, RotateCcwIcon } from "lucide-react";
import { AgentLogs } from "modules/resources/AgentLogs/AgentLogs";
@@ -206,6 +207,11 @@ const WorkspaceNotRunning: FC<WorkspaceNotRunningProps> = ({ task }) => {
},
});
// After requesting a workspace start, it may take a while to become ready.
// Show a loading state in the meantime.
const isWaitingForStart =
mutateStartWorkspace.isPending || mutateStartWorkspace.isSuccess;
const apiError = isApiError(mutateStartWorkspace.error)
? mutateStartWorkspace.error
: undefined;
@@ -223,16 +229,15 @@ const WorkspaceNotRunning: FC<WorkspaceNotRunningProps> = ({ task }) => {
<div className="flex flex-row mt-4 gap-4">
<Button
size="sm"
disabled={mutateStartWorkspace.isPending}
disabled={isWaitingForStart}
onClick={() => {
mutateStartWorkspace.mutate({
buildParameters: parameters?.buildParameters,
});
}}
>
{mutateStartWorkspace.isPending
? "Starting workspace..."
: "Start workspace"}
<Spinner loading={isWaitingForStart} />
Start workspace
</Button>
</div>
</div>