From 0e56a1ee1c403875762d94aaf5c9833a3e625624 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 26 May 2026 09:52:16 -0500 Subject: [PATCH] add to camera management pane --- .../views/settings/CameraManagementView.tsx | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/web/src/views/settings/CameraManagementView.tsx b/web/src/views/settings/CameraManagementView.tsx index f18b8f94b4..d28b621dc8 100644 --- a/web/src/views/settings/CameraManagementView.tsx +++ b/web/src/views/settings/CameraManagementView.tsx @@ -15,6 +15,7 @@ import CameraWizardDialog from "@/components/settings/CameraWizardDialog"; import DeleteCameraDialog from "@/components/overlay/dialog/DeleteCameraDialog"; import { LuCheck, + LuCopy, LuExternalLink, LuGripVertical, LuPencil, @@ -22,6 +23,7 @@ import { LuRefreshCcw, LuTrash2, } from "react-icons/lu"; +import CloneCameraDialog from "@/components/settings/CloneCameraDialog"; import { Reorder, useDragControls } from "framer-motion"; import { Link } from "react-router-dom"; import { useDocDomain } from "@/hooks/use-doc-domain"; @@ -88,6 +90,9 @@ export default function CameraManagementView({ const [showWizard, setShowWizard] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [cloneSourceCamera, setCloneSourceCamera] = useState( + null, + ); // State for restart dialog when enabling a disabled camera const [restartDialogOpen, setRestartDialogOpen] = useState(false); @@ -288,6 +293,7 @@ export default function CameraManagementView({ onConfigChanged={updateConfig} onDragEnd={handleReorderDragEnd} setRestartDialogOpen={setRestartDialogOpen} + onClone={setCloneSourceCamera} /> ))} @@ -307,6 +313,7 @@ export default function CameraManagementView({ camera={camera} onConfigChanged={updateConfig} setRestartDialogOpen={setRestartDialogOpen} + onClone={setCloneSourceCamera} /> ))} @@ -364,6 +371,11 @@ export default function CameraManagementView({ onClose={() => setRestartDialogOpen(false)} onRestart={() => sendRestart("restart")} /> + setCloneSourceCamera(null)} + sourceCamera={cloneSourceCamera ?? ""} + /> ); } @@ -404,6 +416,7 @@ type ActiveCameraRowProps = { onConfigChanged: () => Promise; onDragEnd: () => void; setRestartDialogOpen: React.Dispatch>; + onClone: (camera: string) => void; }; function ActiveCameraRow({ @@ -411,6 +424,7 @@ function ActiveCameraRow({ onConfigChanged, onDragEnd, setRestartDialogOpen, + onClone, }: ActiveCameraRowProps) { const { t } = useTranslation(["views/settings"]); const controls = useDragControls(); @@ -438,6 +452,22 @@ function ActiveCameraRow({ cameraName={camera} onConfigChanged={onConfigChanged} /> + + + + + {t("cameraManagement.clone.trigger")} + Promise; setRestartDialogOpen: React.Dispatch>; + onClone: (camera: string) => void; }; function DisabledCameraRow({ camera, onConfigChanged, setRestartDialogOpen, + onClone, }: DisabledCameraRowProps) { + const { t } = useTranslation(["views/settings"]); + return (
@@ -468,6 +502,22 @@ function DisabledCameraRow({ cameraName={camera} onConfigChanged={onConfigChanged} /> + + + + + {t("cameraManagement.clone.trigger")} +