1
+ import { API } from "api/api" ;
1
2
import { type ApiErrorResponse , DetailedError } from "api/errors" ;
2
3
import { checkAuthorization } from "api/queries/authCheck" ;
3
4
import {
@@ -9,11 +10,13 @@ import { autoCreateWorkspace, createWorkspace } from "api/queries/workspaces";
9
10
import type {
10
11
DynamicParametersRequest ,
11
12
DynamicParametersResponse ,
13
+ PreviewParameter ,
12
14
Workspace ,
13
15
} from "api/typesGenerated" ;
14
16
import { Loader } from "components/Loader/Loader" ;
15
17
import { useAuthenticated } from "hooks" ;
16
18
import { useEffectEvent } from "hooks/hookPolyfills" ;
19
+ import { getInitialParameterValues } from "modules/workspaces/DynamicParameter/DynamicParameter" ;
17
20
import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName" ;
18
21
import {
19
22
type FC ,
@@ -29,13 +32,13 @@ import { useNavigate, useParams, useSearchParams } from "react-router-dom";
29
32
import { pageTitle } from "utils/page" ;
30
33
import type { AutofillBuildParameter } from "utils/richParameters" ;
31
34
import { CreateWorkspacePageViewExperimental } from "./CreateWorkspacePageViewExperimental" ;
32
- const createWorkspaceModes = [ "form" , "auto" , "duplicate" ] as const ;
33
- export type CreateWorkspaceMode = ( typeof createWorkspaceModes ) [ number ] ;
34
- import { API } from "api/api" ;
35
35
import {
36
36
type CreateWorkspacePermissions ,
37
37
createWorkspaceChecks ,
38
38
} from "./permissions" ;
39
+
40
+ const createWorkspaceModes = [ "form" , "auto" , "duplicate" ] as const ;
41
+ export type CreateWorkspaceMode = ( typeof createWorkspaceModes ) [ number ] ;
39
42
export type ExternalAuthPollingState = "idle" | "polling" | "abandoned" ;
40
43
41
44
const CreateWorkspacePageExperimental : FC = ( ) => {
@@ -50,6 +53,7 @@ const CreateWorkspacePageExperimental: FC = () => {
50
53
const [ wsResponseId , setWSResponseId ] = useState < number > ( - 1 ) ;
51
54
const ws = useRef < WebSocket | null > ( null ) ;
52
55
const [ wsError , setWsError ] = useState < Error | null > ( null ) ;
56
+ const initialParamsSentRef = useRef ( false ) ;
53
57
54
58
const customVersionId = searchParams . get ( "version" ) ?? undefined ;
55
59
const defaultName = searchParams . get ( "name" ) ;
@@ -84,15 +88,72 @@ const CreateWorkspacePageExperimental: FC = () => {
84
88
const realizedVersionId =
85
89
customVersionId ?? templateQuery . data ?. active_version_id ;
86
90
87
- const onMessage = useCallback ( ( response : DynamicParametersResponse ) => {
88
- setCurrentResponse ( ( prev ) => {
89
- if ( prev ?. id === response . id ) {
90
- return prev ;
91
+ const autofillParameters = useMemo (
92
+ ( ) => getAutofillParameters ( searchParams ) ,
93
+ [ searchParams ] ,
94
+ ) ;
95
+
96
+ const sendMessage = useCallback ( ( formValues : Record < string , string > ) => {
97
+ setWSResponseId ( ( prevId ) => {
98
+ const request : DynamicParametersRequest = {
99
+ id : prevId + 1 ,
100
+ inputs : formValues ,
101
+ } ;
102
+ if ( ws . current && ws . current . readyState === WebSocket . OPEN ) {
103
+ ws . current . send ( JSON . stringify ( request ) ) ;
104
+ return prevId + 1 ;
91
105
}
92
- return response ;
106
+ return prevId ;
93
107
} ) ;
94
108
} , [ ] ) ;
95
109
110
+ // On sends all initial parameter values to the websocket
111
+ // (including defaults and autofilled from the url)
112
+ // This ensures the backend has the complete initial state of the form,
113
+ // which is vital for correctly rendering dynamic UI elements where parameter visibility
114
+ // or options might depend on the initial values of other parameters.
115
+ const sendInitialParameters = useEffectEvent (
116
+ ( parameters : PreviewParameter [ ] ) => {
117
+ if ( initialParamsSentRef . current ) return ;
118
+ if ( parameters . length === 0 ) return ;
119
+
120
+ const initialFormValues = getInitialParameterValues (
121
+ parameters ,
122
+ autofillParameters ,
123
+ ) ;
124
+ if ( initialFormValues . length === 0 ) return ;
125
+
126
+ const initialParamsToSend : Record < string , string > = { } ;
127
+ for ( const param of initialFormValues ) {
128
+ if ( param . name && param . value ) {
129
+ initialParamsToSend [ param . name ] = param . value ;
130
+ }
131
+ }
132
+
133
+ if ( Object . keys ( initialParamsToSend ) . length === 0 ) return ;
134
+
135
+ sendMessage ( initialParamsToSend ) ;
136
+ initialParamsSentRef . current = true ;
137
+ } ,
138
+ ) ;
139
+
140
+ const onMessage = useCallback (
141
+ ( response : DynamicParametersResponse ) => {
142
+ setCurrentResponse ( ( prev ) => {
143
+ if ( prev ?. id === response . id ) {
144
+ return prev ;
145
+ }
146
+
147
+ if ( ! initialParamsSentRef . current && response . parameters . length > 0 ) {
148
+ sendInitialParameters ( [ ...response . parameters ] ) ;
149
+ }
150
+
151
+ return response ;
152
+ } ) ;
153
+ } ,
154
+ [ sendInitialParameters ] ,
155
+ ) ;
156
+
96
157
// Initialize the WebSocket connection when there is a valid template version ID
97
158
useEffect ( ( ) => {
98
159
if ( ! realizedVersionId ) return ;
@@ -127,20 +188,6 @@ const CreateWorkspacePageExperimental: FC = () => {
127
188
} ;
128
189
} , [ owner . id , realizedVersionId , onMessage ] ) ;
129
190
130
- const sendMessage = useCallback ( ( formValues : Record < string , string > ) => {
131
- setWSResponseId ( ( prevId ) => {
132
- const request : DynamicParametersRequest = {
133
- id : prevId + 1 ,
134
- inputs : formValues ,
135
- } ;
136
- if ( ws . current && ws . current . readyState === WebSocket . OPEN ) {
137
- ws . current . send ( JSON . stringify ( request ) ) ;
138
- return prevId + 1 ;
139
- }
140
- return prevId ;
141
- } ) ;
142
- } , [ ] ) ;
143
-
144
191
const organizationId = templateQuery . data ?. organization_id ;
145
192
146
193
const {
@@ -167,9 +214,6 @@ const CreateWorkspacePageExperimental: FC = () => {
167
214
[ navigate ] ,
168
215
) ;
169
216
170
- // Auto fill parameters
171
- const autofillParameters = getAutofillParameters ( searchParams ) ;
172
-
173
217
const autoCreationStartedRef = useRef ( false ) ;
174
218
const automateWorkspaceCreation = useEffectEvent ( async ( ) => {
175
219
if ( autoCreationStartedRef . current || ! organizationId ) {
0 commit comments