diff --git a/web/src/components/config-form/theme/fields/CameraInputsField.tsx b/web/src/components/config-form/theme/fields/CameraInputsField.tsx index 205e888c9e..6d42de613d 100644 --- a/web/src/components/config-form/theme/fields/CameraInputsField.tsx +++ b/web/src/components/config-form/theme/fields/CameraInputsField.tsx @@ -170,6 +170,12 @@ export function CameraInputsField(props: FieldProps) { [go2rtcStreamNames], ); + useEffect(() => { + setSourceModeByIndex((previous) => + Object.keys(previous).length > 0 ? {} : previous, + ); + }, [formContext?.cameraName]); + useEffect(() => { setOpenByIndex((previous) => { const next: Record = {}; @@ -222,18 +228,12 @@ export function CameraInputsField(props: FieldProps) { const handleSourceModeChange = useCallback( (index: number, nextMode: StreamSourceMode) => { const input = inputs[index]; - const currentPath = - typeof input?.path === "string" ? input.path : undefined; - if (nextMode === "manual") { - // Only revert the preset we set ourselves; never clobber custom args. - if (input?.input_args === RESTREAM_PRESET) { - handleFieldValuesChange(index, { input_args: undefined }); - } - } else if (!parseRestreamStreamName(currentPath)) { - // Entering restream with a non-restream path: clear it so the dropdown - // shows its placeholder until a stream is chosen. - handleFieldValuesChange(index, { path: undefined }); + // Only revert the preset we set ourselves; never clobber custom args. + // The path is left alone until a stream is picked, so switching modes + // never discards a typed URL or empties a required field. + if (nextMode === "manual" && input?.input_args === RESTREAM_PRESET) { + handleFieldValuesChange(index, { input_args: undefined }); } setSourceModeByIndex((previous) => ({ ...previous, [index]: nextMode }));