Skip to content

Commit 9673441

Browse files
committed
feat: connect to dynamic parameters websocket
1 parent 25c7d3c commit 9673441

File tree

3 files changed

+70
-40
lines changed

3 files changed

+70
-40
lines changed

site/src/api/api.ts

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

1012+
templateVersionDynamicParameters = (versionId: string): WebSocket => {
1013+
const socket = createWebSocket(
1014+
`/api/v2/templateversions/${versionId}/dynamic-parameters`,
1015+
);
1016+
return socket;
1017+
};
1018+
10121019
/**
10131020
* @param organization Can be the organization's ID or name
10141021
*/

site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
} from "api/queries/templates";
88
import { autoCreateWorkspace, createWorkspace } from "api/queries/workspaces";
99
import type {
10+
DynamicParametersRequest,
1011
DynamicParametersResponse,
1112
Template,
1213
Workspace,
@@ -31,17 +32,13 @@ import type { AutofillBuildParameter } from "utils/richParameters";
3132
import { CreateWorkspacePageViewExperimental } from "./CreateWorkspacePageViewExperimental";
3233
export const createWorkspaceModes = ["form", "auto", "duplicate"] as const;
3334
export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
34-
import { useWebSocket } from "hooks/useWebsocket";
35+
import { API } from "api/api";
3536
import {
3637
type CreateWorkspacePermissions,
3738
createWorkspaceChecks,
3839
} from "./permissions";
3940
export type ExternalAuthPollingState = "idle" | "polling" | "abandoned";
4041

41-
const serverAddress = "localhost:8100";
42-
const urlTestdata = "demo";
43-
const wsUrl = `ws://${serverAddress}/ws/${encodeURIComponent(urlTestdata)}`;
44-
4542
const CreateWorkspacePageExperimental: FC = () => {
4643
const { organization: organizationName = "default", template: templateName } =
4744
useParams() as { organization?: string; template: string };
@@ -51,20 +48,8 @@ const CreateWorkspacePageExperimental: FC = () => {
5148

5249
const [currentResponse, setCurrentResponse] =
5350
useState<DynamicParametersResponse | null>(null);
54-
const [wsResponseId, setWSResponseId] = useState<number>(0);
55-
const { message: webSocketResponse, sendMessage } =
56-
useWebSocket<DynamicParametersResponse>(wsUrl, urlTestdata, "", "");
57-
58-
useEffect(() => {
59-
if (webSocketResponse && webSocketResponse.id >= wsResponseId) {
60-
setCurrentResponse((prev) => {
61-
if (prev?.id === webSocketResponse.id) {
62-
return prev;
63-
}
64-
return webSocketResponse;
65-
});
66-
}
67-
}, [webSocketResponse, wsResponseId]);
51+
const [wsResponseId, setWSResponseId] = useState<number>(-1);
52+
const webSocket = useRef<WebSocket | null>(null);
6853

6954
const customVersionId = searchParams.get("version") ?? undefined;
7055
const defaultName = searchParams.get("name");
@@ -96,6 +81,59 @@ const CreateWorkspacePageExperimental: FC = () => {
9681
const realizedVersionId =
9782
customVersionId ?? templateQuery.data?.active_version_id;
9883

84+
// Initialize the WebSocket connection when there is a valid template version ID
85+
useEffect(() => {
86+
if (!realizedVersionId) {
87+
return;
88+
}
89+
90+
if (webSocket.current) {
91+
webSocket.current.close();
92+
}
93+
94+
const socket = API.templateVersionDynamicParameters(realizedVersionId);
95+
96+
socket.addEventListener("message", (event) => {
97+
try {
98+
const response = JSON.parse(event.data) as DynamicParametersResponse;
99+
100+
if (response && response.id >= wsResponseId) {
101+
setCurrentResponse((prev) => {
102+
if (prev?.id === response.id) {
103+
return prev;
104+
}
105+
return response;
106+
});
107+
}
108+
} catch (error) {
109+
console.error("Failed to parse WebSocket message:", error);
110+
}
111+
});
112+
113+
webSocket.current = socket;
114+
115+
return () => {
116+
if (webSocket.current) {
117+
webSocket.current.close();
118+
}
119+
};
120+
}, [realizedVersionId]);
121+
122+
const sendMessage =
123+
(formValues: Record<string, string>) => {
124+
setWSResponseId(prevId => {
125+
const request: DynamicParametersRequest = {
126+
id: prevId + 1,
127+
inputs: formValues,
128+
};
129+
if (webSocket.current && webSocket.current.readyState === WebSocket.OPEN) {
130+
webSocket.current.send(JSON.stringify(request));
131+
return prevId + 1;
132+
}
133+
return prevId;
134+
})
135+
};
136+
99137
const organizationId = templateQuery.data?.organization_id;
100138

101139
const {
@@ -225,7 +263,6 @@ const CreateWorkspacePageExperimental: FC = () => {
225263
parameters={sortedParams}
226264
presets={templateVersionPresetsQuery.data ?? []}
227265
creatingWorkspace={createWorkspaceMutation.isLoading}
228-
setWSResponseId={setWSResponseId}
229266
sendMessage={sendMessage}
230267
onCancel={() => {
231268
navigate(-1);

site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type * as TypesGen from "api/typesGenerated";
22
import type {
3-
DynamicParametersRequest,
43
PreviewDiagnostics,
54
PreviewParameter,
65
} from "api/typesGenerated";
@@ -66,8 +65,7 @@ export interface CreateWorkspacePageViewExperimentalProps {
6665
owner: TypesGen.User,
6766
) => void;
6867
resetMutation: () => void;
69-
sendMessage: (message: DynamicParametersRequest) => void;
70-
setWSResponseId: (value: React.SetStateAction<number>) => void;
68+
sendMessage: (message: Record<string, string>) => void;
7169
startPollingExternalAuth: () => void;
7270
}
7371

@@ -94,7 +92,6 @@ export const CreateWorkspacePageViewExperimental: FC<
9492
onCancel,
9593
resetMutation,
9694
sendMessage,
97-
setWSResponseId,
9895
startPollingExternalAuth,
9996
}) => {
10097
const [owner, setOwner] = useState(defaultOwner);
@@ -218,35 +215,24 @@ export const CreateWorkspacePageViewExperimental: FC<
218215
parameterField: string,
219216
parameter: PreviewParameter,
220217
) => {
221-
// Update form value immediately for all types
222218
await form.setFieldValue(parameterField, {
223-
name: parameter.form_type,
219+
name: parameter.name,
224220
value,
225221
});
226222

227-
// Create the request object
228223
const createRequest = () => {
229224
// Convert the rich_parameter_values array to a key-value object
230-
const newInputs = (form.values.rich_parameter_values ?? []).reduce(
225+
const formValues = (form.values.rich_parameter_values ?? []).reduce(
231226
(acc, param) => {
232227
acc[param.name] = param.value;
233228
return acc;
234229
},
235230
{} as Record<string, string>,
236231
);
237232

238-
// Update the input for the changed parameter
239-
newInputs[parameter.name] = value;
240-
241-
setWSResponseId((prevId) => {
242-
const newId = prevId + 1;
243-
const request: DynamicParametersRequest = {
244-
id: newId,
245-
inputs: newInputs,
246-
};
247-
sendMessage(request);
248-
return newId;
249-
});
233+
formValues[parameter.name] = value;
234+
235+
sendMessage(formValues);
250236
};
251237

252238
// Clear any existing timer

0 commit comments

Comments
 (0)