From a09c4fdffb4e4363c4a2efe9ff82526d0ffcb0c9 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 10 Nov 2025 07:32:41 -0600 Subject: [PATCH] form description and field change --- web/public/locales/en/views/settings.json | 3 +- .../settings/wizard/Step1NameCamera.tsx | 54 +++++++++++-------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index 23716648c..f00fe5b00 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -172,7 +172,7 @@ "testFailed": "Stream test failed: {{error}}" }, "step1": { - "description": "Enter your camera details and test the connection.", + "description": "Enter your camera details and choose to probe the camera or manually select the brand.", "cameraName": "Camera Name", "cameraNamePlaceholder": "e.g., front_door or Back Yard Overview", "host": "Host/IP Address", @@ -201,6 +201,7 @@ "probingMetadata": "Probing camera metadata...", "fetchingSnapshot": "Fetching camera snapshot..." }, + "detectionMethodDescription": "Probe the camera with ONVIF to find camera stream URLs, or manually select the camera brand to use pre-defined URLs. To enter a custom RTSP URL, choose the manual method and select \"Other\".", "probingDevice": "Probing device...", "probeError": "Probe Error", "probeNoSuccess": "Probe unsuccessful", diff --git a/web/src/components/settings/wizard/Step1NameCamera.tsx b/web/src/components/settings/wizard/Step1NameCamera.tsx index cc2bd3887..e770b2ec7 100644 --- a/web/src/components/settings/wizard/Step1NameCamera.tsx +++ b/web/src/components/settings/wizard/Step1NameCamera.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, + FormDescription, FormField, FormItem, FormLabel, @@ -73,7 +74,6 @@ export default function Step1NameCamera({ const [testStatus, setTestStatus] = useState(""); const [testResult, setTestResult] = useState(null); const [probeMode, setProbeMode] = useState(true); - const [onvifPort, setOnvifPort] = useState(80); const [isProbing, setIsProbing] = useState(false); const [probeError, setProbeError] = useState(null); const [probeResult, setProbeResult] = useState( @@ -111,6 +111,7 @@ export default function Step1NameCamera({ username: z.string().optional(), password: z.string().optional(), brandTemplate: z.enum(CAMERA_BRAND_VALUES).optional(), + onvifPort: z.coerce.number().int().min(1).max(65535).optional(), customUrl: z .string() .optional() @@ -147,6 +148,7 @@ export default function Step1NameCamera({ ? (wizardData.brandTemplate as CameraBrand) : "dahua", customUrl: wizardData.customUrl || "", + onvifPort: wizardData.onvifPort ?? 80, }, mode: "onChange", }); @@ -246,7 +248,7 @@ export default function Step1NameCamera({ const response = await axios.get("/onvif/probe", { params: { host: data.host, - port: onvifPort, + port: data.onvifPort ?? 80, username: data.username || "", password: data.password || "", test: false, @@ -276,7 +278,7 @@ export default function Step1NameCamera({ } finally { setIsProbing(false); } - }, [form, onvifPort, t]); + }, [form, t]); const handleSelectCandidate = useCallback((uri: string) => { // toggle selection: add or remove from selectedCandidateUris @@ -737,27 +739,34 @@ export default function Step1NameCamera({ + + {t("cameraWizard.step1.detectionMethodDescription")} + {probeMode && ( - - - {t("cameraWizard.step1.onvifPort")} - - - - setOnvifPort(parseInt(e.target.value, 10) || 80) - } - placeholder="80" - /> - - + ( + + + {t("cameraWizard.step1.onvifPort")} + + + + + + {fieldState.error ? fieldState.error.message : null} + + + )} + /> )} {!probeMode && ( @@ -954,6 +963,9 @@ export default function Step1NameCamera({ variant="select" className="flex items-center justify-center gap-2 sm:flex-1" > + {(isProbing || isTesting) && ( + + )} {probeMode ? t("cameraWizard.step1.probeMode") : t("cameraWizard.step1.testConnection")}