diff --git a/site/src/api/api.ts b/site/src/api/api.ts index fa62afadee608..b3ce8bd0cf471 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1015,9 +1015,11 @@ class ApiMethods { { onMessage, onError, + onClose, }: { onMessage: (response: TypesGen.DynamicParametersResponse) => void; onError: (error: Error) => void; + onClose: () => void; }, ): WebSocket => { const socket = createWebSocket( @@ -1033,6 +1035,10 @@ class ApiMethods { socket.close(); }); + socket.addEventListener("close", () => { + onClose(); + }); + return socket; }; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx index 03da3bd477745..c02529c5d9446 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx @@ -1,4 +1,4 @@ -import type { ApiErrorResponse } from "api/errors"; +import { type ApiErrorResponse, DetailedError } from "api/errors"; import { checkAuthorization } from "api/queries/authCheck"; import { templateByName, @@ -107,6 +107,15 @@ const CreateWorkspacePageExperimental: FC = () => { onError: (error) => { setWsError(error); }, + onClose: () => { + // There is no reason for the websocket to close while a user is on the page + setWsError( + new DetailedError( + "Websocket connection for dynamic parameters unexpectedly closed.", + "Refresh the page to reset the form.", + ), + ); + }, }, ); @@ -141,7 +150,7 @@ const CreateWorkspacePageExperimental: FC = () => { } = useExternalAuth(realizedVersionId); const isLoadingFormData = - ws.current?.readyState !== WebSocket.OPEN || + ws.current?.readyState === WebSocket.CONNECTING || templateQuery.isLoading || permissionsQuery.isLoading; const loadFormDataError = templateQuery.error ?? permissionsQuery.error; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx new file mode 100644 index 0000000000000..a41e3a48c0ad9 --- /dev/null +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx @@ -0,0 +1,40 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { DetailedError } from "api/errors"; +import { chromatic } from "testHelpers/chromatic"; +import { MockTemplate, MockUser } from "testHelpers/entities"; +import { CreateWorkspacePageViewExperimental } from "./CreateWorkspacePageViewExperimental"; + +const meta: Meta = { + title: "Pages/CreateWorkspacePageViewExperimental", + parameters: { chromatic }, + component: CreateWorkspacePageViewExperimental, + args: { + autofillParameters: [], + diagnostics: [], + defaultName: "", + defaultOwner: MockUser, + externalAuth: [], + externalAuthPollingState: "idle", + hasAllRequiredExternalAuth: true, + mode: "form", + parameters: [], + permissions: { + createWorkspaceForAny: true, + }, + presets: [], + sendMessage: () => {}, + template: MockTemplate, + }, +}; + +export default meta; +type Story = StoryObj; + +export const WebsocketError: Story = { + args: { + error: new DetailedError( + "Websocket connection for dynamic parameters unexpectedly closed.", + "Refresh the page to reset the form.", + ), + }, +};