Skip to content

Commit 3d787da

Browse files
authored
feat: setup connection to dynamic parameters websocket (#17393)
resolves coder/preview#57
1 parent f670bc3 commit 3d787da

File tree

4 files changed

+94
-31
lines changed

4 files changed

+94
-31
lines changed

site/src/api/api.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,32 @@ class ApiMethods {
10091009
return response.data;
10101010
};
10111011

1012+
templateVersionDynamicParameters = (
1013+
versionId: string,
1014+
{
1015+
onMessage,
1016+
onError,
1017+
}: {
1018+
onMessage: (response: TypesGen.DynamicParametersResponse) => void;
1019+
onError: (error: Error) => void;
1020+
},
1021+
): WebSocket => {
1022+
const socket = createWebSocket(
1023+
`/api/v2/templateversions/${versionId}/dynamic-parameters`,
1024+
);
1025+
1026+
socket.addEventListener("message", (event) =>
1027+
onMessage(JSON.parse(event.data) as TypesGen.DynamicParametersResponse),
1028+
);
1029+
1030+
socket.addEventListener("error", () => {
1031+
onError(new Error("Connection for dynamic parameters failed."));
1032+
socket.close();
1033+
});
1034+
1035+
return socket;
1036+
};
1037+
10121038
/**
10131039
* @param organization Can be the organization's ID or name
10141040
*/

site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type {
2+
NullHCLString,
23
PreviewParameter,
34
PreviewParameterOption,
45
WorkspaceBuildParameter,
@@ -156,10 +157,8 @@ const ParameterField: FC<ParameterFieldProps> = ({
156157
disabled,
157158
id,
158159
}) => {
159-
const value = parameter.value.valid ? parameter.value.value : "";
160-
const defaultValue = parameter.default_value.valid
161-
? parameter.default_value.value
162-
: "";
160+
const value = validValue(parameter.value);
161+
const defaultValue = validValue(parameter.default_value);
163162

164163
switch (parameter.form_type) {
165164
case "dropdown":
@@ -376,9 +375,7 @@ export const getInitialParameterValues = (
376375
if (parameter.ephemeral) {
377376
return {
378377
name: parameter.name,
379-
value: parameter.default_value.valid
380-
? parameter.default_value.value
381-
: "",
378+
value: validValue(parameter.default_value),
382379
};
383380
}
384381

@@ -390,15 +387,19 @@ export const getInitialParameterValues = (
390387
name: parameter.name,
391388
value:
392389
autofillParam &&
393-
isValidValue(parameter, autofillParam) &&
390+
isValidParameterOption(parameter, autofillParam) &&
394391
autofillParam.value
395392
? autofillParam.value
396-
: "",
393+
: validValue(parameter.default_value),
397394
};
398395
});
399396
};
400397

401-
const isValidValue = (
398+
const validValue = (value: NullHCLString) => {
399+
return value.valid ? value.value : "";
400+
};
401+
402+
const isValidParameterOption = (
402403
previewParam: PreviewParameter,
403404
buildParam: WorkspaceBuildParameter,
404405
) => {
@@ -409,7 +410,7 @@ const isValidValue = (
409410
return validValues.includes(buildParam.value);
410411
}
411412

412-
return true;
413+
return false;
413414
};
414415

415416
export const useValidationSchemaForDynamicParameters = (

site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { autoCreateWorkspace, createWorkspace } from "api/queries/workspaces";
99
import type {
1010
DynamicParametersRequest,
1111
DynamicParametersResponse,
12-
Template,
1312
Workspace,
1413
} from "api/typesGenerated";
1514
import { Loader } from "components/Loader/Loader";
@@ -32,6 +31,7 @@ import type { AutofillBuildParameter } from "utils/richParameters";
3231
import { CreateWorkspacePageViewExperimental } from "./CreateWorkspacePageViewExperimental";
3332
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
3433
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
34+
import { API } from "api/api";
3535
import {
3636
type CreateWorkspacePermissions,
3737
createWorkspaceChecks,
@@ -47,8 +47,9 @@ const CreateWorkspacePageExperimental: FC = () => {
4747

4848
const [currentResponse, setCurrentResponse] =
4949
useState<DynamicParametersResponse | null>(null);
50-
const [wsResponseId, setWSResponseId] = useState<number>(0);
51-
const sendMessage = (message: DynamicParametersRequest) => {};
50+
const [wsResponseId, setWSResponseId] = useState<number>(-1);
51+
const ws = useRef<WebSocket | null>(null);
52+
const [wsError, setWsError] = useState<Error | null>(null);
5253

5354
const customVersionId = searchParams.get("version") ?? undefined;
5455
const defaultName = searchParams.get("name");
@@ -80,6 +81,49 @@ const CreateWorkspacePageExperimental: FC = () => {
8081
const realizedVersionId =
8182
customVersionId ?? templateQuery.data?.active_version_id;
8283

84+
const onMessage = useCallback((response: DynamicParametersResponse) => {
85+
setCurrentResponse((prev) => {
86+
if (prev?.id === response.id) {
87+
return prev;
88+
}
89+
return response;
90+
});
91+
}, []);
92+
93+
// Initialize the WebSocket connection when there is a valid template version ID
94+
useEffect(() => {
95+
if (!realizedVersionId) {
96+
return;
97+
}
98+
99+
const socket = API.templateVersionDynamicParameters(realizedVersionId, {
100+
onMessage,
101+
onError: (error) => {
102+
setWsError(error);
103+
},
104+
});
105+
106+
ws.current = socket;
107+
108+
return () => {
109+
socket.close();
110+
};
111+
}, [realizedVersionId, onMessage]);
112+
113+
const sendMessage = useCallback((formValues: Record<string, string>) => {
114+
setWSResponseId((prevId) => {
115+
const request: DynamicParametersRequest = {
116+
id: prevId + 1,
117+
inputs: formValues,
118+
};
119+
if (ws.current && ws.current.readyState === WebSocket.OPEN) {
120+
ws.current.send(JSON.stringify(request));
121+
return prevId + 1;
122+
}
123+
return prevId;
124+
});
125+
}, []);
126+
83127
const organizationId = templateQuery.data?.organization_id;
84128

85129
const {
@@ -90,7 +134,9 @@ const CreateWorkspacePageExperimental: FC = () => {
90134
} = useExternalAuth(realizedVersionId);
91135

92136
const isLoadingFormData =
93-
templateQuery.isLoading || permissionsQuery.isLoading;
137+
ws.current?.readyState !== WebSocket.OPEN ||
138+
templateQuery.isLoading ||
139+
permissionsQuery.isLoading;
94140
const loadFormDataError = templateQuery.error ?? permissionsQuery.error;
95141

96142
const title = autoCreateWorkspaceMutation.isLoading
@@ -189,11 +235,12 @@ const CreateWorkspacePageExperimental: FC = () => {
189235
<CreateWorkspacePageViewExperimental
190236
mode={mode}
191237
defaultName={defaultName}
192-
diagnostics={currentResponse.diagnostics}
238+
diagnostics={currentResponse?.diagnostics ?? []}
193239
disabledParams={disabledParams}
194240
defaultOwner={me}
195241
autofillParameters={autofillParameters}
196242
error={
243+
wsError ||
197244
createWorkspaceMutation.error ||
198245
autoCreateError ||
199246
loadFormDataError ||
@@ -210,7 +257,6 @@ const CreateWorkspacePageExperimental: FC = () => {
210257
parameters={sortedParams}
211258
presets={templateVersionPresetsQuery.data ?? []}
212259
creatingWorkspace={createWorkspaceMutation.isLoading}
213-
setWSResponseId={setWSResponseId}
214260
sendMessage={sendMessage}
215261
onCancel={() => {
216262
navigate(-1);

site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ export interface CreateWorkspacePageViewExperimentalProps {
6767
owner: TypesGen.User,
6868
) => void;
6969
resetMutation: () => void;
70-
sendMessage: (message: DynamicParametersRequest) => void;
71-
setWSResponseId: (value: React.SetStateAction<number>) => void;
70+
sendMessage: (message: Record<string, string>) => void;
7271
startPollingExternalAuth: () => void;
7372
}
7473

@@ -95,7 +94,6 @@ export const CreateWorkspacePageViewExperimental: FC<
9594
onCancel,
9695
resetMutation,
9796
sendMessage,
98-
setWSResponseId,
9997
startPollingExternalAuth,
10098
}) => {
10199
const [owner, setOwner] = useState(defaultOwner);
@@ -222,15 +220,7 @@ export const CreateWorkspacePageViewExperimental: FC<
222220
// Update the input for the changed parameter
223221
formInputs[parameter.name] = value;
224222

225-
setWSResponseId((prevId) => {
226-
const newId = prevId + 1;
227-
const request: DynamicParametersRequest = {
228-
id: newId,
229-
inputs: formInputs,
230-
};
231-
sendMessage(request);
232-
return newId;
233-
});
223+
sendMessage(formInputs);
234224
};
235225

236226
const { debounced: handleChangeDebounced } = useDebouncedFunction(
@@ -240,7 +230,7 @@ export const CreateWorkspacePageViewExperimental: FC<
240230
value: string,
241231
) => {
242232
await form.setFieldValue(parameterField, {
243-
name: parameter.form_type,
233+
name: parameter.name,
244234
value,
245235
});
246236
sendDynamicParamsRequest(parameter, value);
@@ -257,7 +247,7 @@ export const CreateWorkspacePageViewExperimental: FC<
257247
handleChangeDebounced(parameter, parameterField, value);
258248
} else {
259249
await form.setFieldValue(parameterField, {
260-
name: parameter.form_type,
250+
name: parameter.name,
261251
value,
262252
});
263253
sendDynamicParamsRequest(parameter, value);

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