From 53a57543dd116ccc81e93f1c786332ef9228f6a6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 28 May 2025 12:22:24 -0500 Subject: [PATCH 1/3] chore: autofill previous values from build on workspace settings --- .../WorkspaceParametersPageExperimental.tsx | 7 +++++++ .../WorkspaceParametersPageViewExperimental.tsx | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx index 781f8b12e8c67..51061862f33ed 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx @@ -39,6 +39,11 @@ const WorkspaceParametersPageExperimental: FC = () => { const navigate = useNavigate(); const experimentalFormContext = useContext(ExperimentalFormContext); + const { data: originalParameters, isLoading: originalParametersLoading } = useQuery({ + queryKey: ["workspace", "build", workspace.id, "parameters"], + queryFn: () => API.getWorkspaceBuildParameters(workspace.latest_build.id), + }); + const [latestResponse, setLatestResponse] = useState(null); const wsResponseId = useRef(-1); @@ -149,6 +154,7 @@ const WorkspaceParametersPageExperimental: FC = () => { const error = wsError || updateParameters.error; if ( + originalParametersLoading || !latestResponse || (ws.current && ws.current.readyState === WebSocket.CONNECTING) ) { @@ -203,6 +209,7 @@ const WorkspaceParametersPageExperimental: FC = () => { = ({ workspace, + originalParameters, parameters, diagnostics, canChangeVersions, @@ -45,7 +47,10 @@ export const WorkspaceParametersPageViewExperimental: FC< const form = useFormik({ onSubmit, initialValues: { - rich_parameter_values: getInitialParameterValues(parameters), + rich_parameter_values: getInitialParameterValues(parameters, originalParameters!.map((p) => ({ + ...p, + source: "active_build", + }))), }, validationSchema: useValidationSchemaForDynamicParameters(parameters), enableReinitialize: false, From 296219601c16fb1e4d9622e909e8c86b9ab61283 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 28 May 2025 12:29:36 -0500 Subject: [PATCH 2/3] add initialTouched --- ...orkspaceParametersPageViewExperimental.tsx | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageViewExperimental.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageViewExperimental.tsx index d2c8f7207fd86..a3b4480ac4c67 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageViewExperimental.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageViewExperimental.tsx @@ -16,6 +16,7 @@ import { } from "modules/workspaces/DynamicParameter/DynamicParameter"; import type { FC } from "react"; import { docs } from "utils/docs"; +import { AutofillBuildParameter } from "utils/richParameters"; type WorkspaceParametersPageViewExperimentalProps = { workspace: Workspace; @@ -44,14 +45,32 @@ export const WorkspaceParametersPageViewExperimental: FC< sendMessage, onCancel, }) => { + + const autoFillValues: AutofillBuildParameter[] = originalParameters!.map((p) => ({ + ...p, + source: "active_build", + })) + const autofillByName = Object.fromEntries( + autoFillValues.map((param) => [param.name, param]), + ); + + + const initialTouched = parameters.reduce( + (touched, parameter) => { + if (autofillByName[parameter.name] !== undefined) { + touched[parameter.name] = true; + } + return touched; + }, + {} as Record, + ); + const form = useFormik({ onSubmit, initialValues: { - rich_parameter_values: getInitialParameterValues(parameters, originalParameters!.map((p) => ({ - ...p, - source: "active_build", - }))), + rich_parameter_values: getInitialParameterValues(parameters, autoFillValues), }, + initialTouched, validationSchema: useValidationSchemaForDynamicParameters(parameters), enableReinitialize: false, validateOnChange: true, From 9e678449ad6705e7cd8d436749cc106131450900 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Wed, 28 May 2025 21:58:56 +0000 Subject: [PATCH 3/3] fix: set initial autofill parameters from latest workspace build parameters --- .../DynamicParameter/DynamicParameter.tsx | 20 +++++++-- .../WorkspaceParametersPageExperimental.tsx | 43 +++++++++++++++++-- ...orkspaceParametersPageViewExperimental.tsx | 22 ++++------ 3 files changed, 63 insertions(+), 22 deletions(-) diff --git a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx index 72113ce8f504b..35c5763c23d25 100644 --- a/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx +++ b/site/src/modules/workspaces/DynamicParameter/DynamicParameter.tsx @@ -84,6 +84,7 @@ export const DynamicParameter: FC = ({ value={value} onChange={onChange} disabled={disabled} + isPreset={isPreset} /> ) : ( void; disabled?: boolean; id: string; + isPreset?: boolean; } const DebouncedParameterField: FC = ({ @@ -239,6 +241,7 @@ const DebouncedParameterField: FC = ({ onChange, disabled, id, + isPreset, }) => { const [localValue, setLocalValue] = useState( value !== undefined ? value : validValue(parameter.value), @@ -251,19 +254,26 @@ const DebouncedParameterField: FC = ({ // This is necessary in the case of fields being set by preset parameters useEffect(() => { - if (value !== undefined && value !== prevValueRef.current) { + if (isPreset && value !== undefined && value !== prevValueRef.current) { setLocalValue(value); prevValueRef.current = value; } - }, [value]); + }, [value, isPreset]); useEffect(() => { - if (prevDebouncedValueRef.current !== undefined) { + // Only call onChangeEvent if debouncedLocalValue is different from the previously committed value + // and it's not the initial undefined state. + if ( + prevDebouncedValueRef.current !== undefined && + prevDebouncedValueRef.current !== debouncedLocalValue + ) { onChangeEvent(debouncedLocalValue); } + // Update the ref to the current debounced value for the next comparison prevDebouncedValueRef.current = debouncedLocalValue; }, [debouncedLocalValue, onChangeEvent]); + const textareaRef = useRef(null); const resizeTextarea = useEffectEvent(() => { @@ -513,7 +523,9 @@ const ParameterField: FC = ({ max={parameter.validations[0]?.validation_max ?? 100} disabled={disabled} /> - {parameter.value.value} + + {Number.isFinite(Number(value)) ? value : "0"} + ); case "error": diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx index 51061862f33ed..e80542f3144da 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceParametersPage/WorkspaceParametersPageExperimental.tsx @@ -26,6 +26,7 @@ import { useMutation, useQuery } from "react-query"; import { useNavigate } from "react-router-dom"; import { docs } from "utils/docs"; import { pageTitle } from "utils/page"; +import type { AutofillBuildParameter } from "utils/richParameters"; import { type WorkspacePermissions, workspaceChecks, @@ -39,8 +40,12 @@ const WorkspaceParametersPageExperimental: FC = () => { const navigate = useNavigate(); const experimentalFormContext = useContext(ExperimentalFormContext); - const { data: originalParameters, isLoading: originalParametersLoading } = useQuery({ - queryKey: ["workspace", "build", workspace.id, "parameters"], + // autofill the form with the workspace build parameters from the latest build + const { + data: latestBuildParameters, + isLoading: latestBuildParametersLoading, + } = useQuery({ + queryKey: ["workspaceBuilds", workspace.latest_build.id, "parameters"], queryFn: () => API.getWorkspaceBuildParameters(workspace.latest_build.id), }); @@ -49,6 +54,13 @@ const WorkspaceParametersPageExperimental: FC = () => { const wsResponseId = useRef(-1); const ws = useRef(null); const [wsError, setWsError] = useState(null); + const initialParamsSentRef = useRef(false); + + const autofillParameters: AutofillBuildParameter[] = + latestBuildParameters?.map((p) => ({ + ...p, + source: "active_build", + })) ?? []; const sendMessage = useEffectEvent((formValues: Record) => { const request: DynamicParametersRequest = { @@ -62,11 +74,34 @@ const WorkspaceParametersPageExperimental: FC = () => { } }); + // On page load, sends initial workspace build parameters to the websocket. + // This ensures the backend has the form's complete initial state, + // vital for rendering dynamic UI elements dependent on initial parameter values. + const sendInitialParameters = useEffectEvent(() => { + if (initialParamsSentRef.current) return; + if (autofillParameters.length === 0) return; + + const initialParamsToSend: Record = {}; + for (const param of autofillParameters) { + if (param.name && param.value) { + initialParamsToSend[param.name] = param.value; + } + } + if (Object.keys(initialParamsToSend).length === 0) return; + + sendMessage(initialParamsToSend); + initialParamsSentRef.current = true; + }); + const onMessage = useEffectEvent((response: DynamicParametersResponse) => { if (latestResponse && latestResponse?.id >= response.id) { return; } + if (!initialParamsSentRef.current && response.parameters?.length > 0) { + sendInitialParameters(); + } + setLatestResponse(response); }); @@ -154,7 +189,7 @@ const WorkspaceParametersPageExperimental: FC = () => { const error = wsError || updateParameters.error; if ( - originalParametersLoading || + latestBuildParametersLoading || !latestResponse || (ws.current && ws.current.readyState === WebSocket.CONNECTING) ) { @@ -208,8 +243,8 @@ const WorkspaceParametersPageExperimental: FC = () => { {sortedParams.length > 0 ? ( = ({ workspace, - originalParameters, + autofillParameters, parameters, diagnostics, canChangeVersions, @@ -45,16 +45,9 @@ export const WorkspaceParametersPageViewExperimental: FC< sendMessage, onCancel, }) => { - - const autoFillValues: AutofillBuildParameter[] = originalParameters!.map((p) => ({ - ...p, - source: "active_build", - })) const autofillByName = Object.fromEntries( - autoFillValues.map((param) => [param.name, param]), + autofillParameters.map((param) => [param.name, param]), ); - - const initialTouched = parameters.reduce( (touched, parameter) => { if (autofillByName[parameter.name] !== undefined) { @@ -64,11 +57,13 @@ export const WorkspaceParametersPageViewExperimental: FC< }, {} as Record, ); - const form = useFormik({ onSubmit, initialValues: { - rich_parameter_values: getInitialParameterValues(parameters, autoFillValues), + rich_parameter_values: getInitialParameterValues( + parameters, + autofillParameters, + ), }, initialTouched, validationSchema: useValidationSchemaForDynamicParameters(parameters), @@ -76,7 +71,6 @@ export const WorkspaceParametersPageViewExperimental: FC< validateOnChange: true, validateOnBlur: true, }); - // Group parameters by ephemeral status const ephemeralParameters = parameters.filter((p) => p.ephemeral); const standardParameters = parameters.filter((p) => !p.ephemeral); 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