mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-28 22:59:02 +03:00
Clone camera settings (#23339)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add clone dialog * i18n * tweaks * add to camera management pane * add e2e test * optional disable portal prop * radio and checkbox tweaks * tweak i18n * add select all/select none * fixes * reset form only on open transition * unselect all targets for existing camera * fix test * reorder sections for save and collapse to single put for new camera * change source and allow cloning to multiple cameras * tweak language * fix overflowing text in save all popover * tweaks * fix per label object masks * use grid for source and target * language tweak
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
import Heading from "@/components/ui/heading";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
CONTROL_COLUMN_CLASS_NAME,
|
||||
SettingsGroupCard,
|
||||
SPLIT_ROW_CLASS_NAME,
|
||||
} from "@/components/card/SettingsGroupCard";
|
||||
import { toast } from "sonner";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
@@ -15,6 +21,7 @@ import CameraWizardDialog from "@/components/settings/CameraWizardDialog";
|
||||
import DeleteCameraDialog from "@/components/overlay/dialog/DeleteCameraDialog";
|
||||
import {
|
||||
LuCheck,
|
||||
LuCopy,
|
||||
LuExternalLink,
|
||||
LuGripVertical,
|
||||
LuPencil,
|
||||
@@ -22,6 +29,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";
|
||||
@@ -50,6 +58,7 @@ import {
|
||||
import type { ProfileState } from "@/types/profile";
|
||||
import { getProfileColor } from "@/utils/profileColors";
|
||||
import { isReplayCamera } from "@/utils/cameraUtil";
|
||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Select,
|
||||
@@ -88,6 +97,7 @@ export default function CameraManagementView({
|
||||
|
||||
const [showWizard, setShowWizard] = useState(false);
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const [showCloneDialog, setShowCloneDialog] = useState(false);
|
||||
|
||||
// State for restart dialog when enabling a disabled camera
|
||||
const [restartDialogOpen, setRestartDialogOpen] = useState(false);
|
||||
@@ -217,12 +227,6 @@ export default function CameraManagementView({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toaster
|
||||
richColors
|
||||
className="z-[1000]"
|
||||
position="top-center"
|
||||
closeButton
|
||||
/>
|
||||
<div className="flex size-full space-y-6">
|
||||
<div className="scrollbar-container flex-1 overflow-y-auto pb-2">
|
||||
<Heading as="h4" className="mb-2">
|
||||
@@ -254,6 +258,27 @@ export default function CameraManagementView({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{enabledCameras.length + disabledCameras.length > 0 && (
|
||||
<div className="mb-5 space-y-3">
|
||||
<div className="space-y-0.5">
|
||||
<div className="text-md font-medium">
|
||||
{t("cameraManagement.clone.sectionTitle")}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("cameraManagement.clone.sectionDescription")}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="select"
|
||||
onClick={() => setShowCloneDialog(true)}
|
||||
className="flex max-w-48 items-center gap-2"
|
||||
>
|
||||
<LuCopy className="h-4 w-4" />
|
||||
{t("cameraManagement.clone.button")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(enabledCameras.length > 0 || disabledCameras.length > 0) && (
|
||||
<SettingsGroupCard
|
||||
title={
|
||||
@@ -364,6 +389,10 @@ export default function CameraManagementView({
|
||||
onClose={() => setRestartDialogOpen(false)}
|
||||
onRestart={() => sendRestart("restart")}
|
||||
/>
|
||||
<CloneCameraDialog
|
||||
open={showCloneDialog}
|
||||
onClose={() => setShowCloneDialog(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -501,6 +530,7 @@ function CameraStatusSelect({
|
||||
]);
|
||||
const { payload: enabledState, send: sendEnabled } =
|
||||
useEnabledState(cameraName);
|
||||
const statusBar = useContext(StatusBarMessagesContext);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const currentStatus: CameraStatus = isDisabledInConfig
|
||||
@@ -586,6 +616,12 @@ function CameraStatusSelect({
|
||||
},
|
||||
});
|
||||
await onConfigChanged();
|
||||
statusBar?.addMessage(
|
||||
"config_restart_required",
|
||||
t("configForm.restartRequiredFooter", { ns: "views/settings" }),
|
||||
undefined,
|
||||
"config_restart_required",
|
||||
);
|
||||
toast.success(
|
||||
t("cameraManagement.streams.disableSuccess", {
|
||||
ns: "views/settings",
|
||||
@@ -617,6 +653,7 @@ function CameraStatusSelect({
|
||||
onConfigChanged,
|
||||
sendEnabled,
|
||||
setRestartDialogOpen,
|
||||
statusBar,
|
||||
t,
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user