mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-10 10:33:11 +03:00
frontend
This commit is contained in:
parent
5e36dd0776
commit
fdf704fffd
@ -40,7 +40,8 @@ import UsersView from "@/views/settings/UsersView";
|
||||
import RolesView from "@/views/settings/RolesView";
|
||||
import UiSettingsView from "@/views/settings/UiSettingsView";
|
||||
import FrigatePlusSettingsView from "@/views/settings/FrigatePlusSettingsView";
|
||||
import MaintenanceSettingsView from "@/views/settings/MaintenanceSettingsView";
|
||||
import MediaSyncSettingsView from "@/views/settings/MediaSyncSettingsView";
|
||||
import RegionGridSettingsView from "@/views/settings/RegionGridSettingsView";
|
||||
import SystemDetectionModelSettingsView from "@/views/settings/SystemDetectionModelSettingsView";
|
||||
import {
|
||||
SingleSectionPage,
|
||||
@ -154,7 +155,8 @@ const allSettingsViews = [
|
||||
"roles",
|
||||
"notifications",
|
||||
"frigateplus",
|
||||
"maintenance",
|
||||
"mediaSync",
|
||||
"regionGrid",
|
||||
] as const;
|
||||
type SettingsType = (typeof allSettingsViews)[number];
|
||||
|
||||
@ -444,7 +446,10 @@ const settingsGroups = [
|
||||
},
|
||||
{
|
||||
label: "maintenance",
|
||||
items: [{ key: "maintenance", component: MaintenanceSettingsView }],
|
||||
items: [
|
||||
{ key: "mediaSync", component: MediaSyncSettingsView },
|
||||
{ key: "regionGrid", component: RegionGridSettingsView },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -471,15 +476,12 @@ const CAMERA_SELECT_BUTTON_PAGES = [
|
||||
"masksAndZones",
|
||||
"motionTuner",
|
||||
"triggers",
|
||||
"regionGrid",
|
||||
];
|
||||
|
||||
const ALLOWED_VIEWS_FOR_VIEWER = ["ui", "debug", "notifications"];
|
||||
|
||||
const LARGE_BOTTOM_MARGIN_PAGES = [
|
||||
"masksAndZones",
|
||||
"motionTuner",
|
||||
"maintenance",
|
||||
];
|
||||
const LARGE_BOTTOM_MARGIN_PAGES = ["masksAndZones", "motionTuner", "mediaSync"];
|
||||
|
||||
// keys for camera sections
|
||||
const CAMERA_SECTION_MAPPING: Record<string, SettingsType> = {
|
||||
|
||||
@ -15,7 +15,7 @@ import { cn } from "@/lib/utils";
|
||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||
import { MediaSyncStats } from "@/types/ws";
|
||||
|
||||
export default function MaintenanceSettingsView() {
|
||||
export default function MediaSyncSettingsView() {
|
||||
const { t } = useTranslation("views/settings");
|
||||
const [selectedMediaTypes, setSelectedMediaTypes] = useState<string[]>([
|
||||
"all",
|
||||
@ -103,7 +103,7 @@ export default function MaintenanceSettingsView() {
|
||||
<div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto px-2 md:order-none">
|
||||
<div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div className="col-span-1">
|
||||
<Heading as="h4" className="mb-2">
|
||||
<Heading as="h4" className="mb-2 hidden md:block">
|
||||
{t("maintenance.sync.title")}
|
||||
</Heading>
|
||||
|
||||
124
web/src/views/settings/RegionGridSettingsView.tsx
Normal file
124
web/src/views/settings/RegionGridSettingsView.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import Heading from "@/components/ui/heading";
|
||||
import { Button, buttonVariants } from "@/components/ui/button";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { useCallback, useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import axios from "axios";
|
||||
import { toast } from "sonner";
|
||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type RegionGridSettingsViewProps = {
|
||||
selectedCamera: string;
|
||||
};
|
||||
|
||||
export default function RegionGridSettingsView({
|
||||
selectedCamera,
|
||||
}: RegionGridSettingsViewProps) {
|
||||
const { t } = useTranslation("views/settings");
|
||||
const { addMessage } = useContext(StatusBarMessagesContext)!;
|
||||
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
||||
const [isClearing, setIsClearing] = useState(false);
|
||||
const [imageKey, setImageKey] = useState(0);
|
||||
|
||||
const handleClear = useCallback(async () => {
|
||||
setIsClearing(true);
|
||||
|
||||
try {
|
||||
await axios.delete(`${selectedCamera}/region_grid`);
|
||||
toast.success(t("maintenance.regionGrid.clearSuccess"), {
|
||||
position: "top-center",
|
||||
});
|
||||
setImageKey((prev) => prev + 1);
|
||||
addMessage(
|
||||
"region_grid_restart",
|
||||
t("maintenance.regionGrid.restartRequired"),
|
||||
undefined,
|
||||
"region_grid_settings",
|
||||
);
|
||||
} catch {
|
||||
toast.error(t("maintenance.regionGrid.clearError"), {
|
||||
position: "top-center",
|
||||
});
|
||||
} finally {
|
||||
setIsClearing(false);
|
||||
setIsConfirmOpen(false);
|
||||
}
|
||||
}, [selectedCamera, t, addMessage]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex size-full flex-col pb-12 md:flex-row">
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto px-2 md:order-none">
|
||||
<Heading as="h4" className="mb-2 hidden md:block">
|
||||
{t("maintenance.regionGrid.title")}
|
||||
</Heading>
|
||||
|
||||
<div className="max-w-6xl">
|
||||
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-muted-foreground">
|
||||
<p>{t("maintenance.regionGrid.desc")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 max-w-5xl rounded-lg border border-secondary">
|
||||
<img
|
||||
key={imageKey}
|
||||
src={`api/${selectedCamera}/grid.jpg?cache=${imageKey}`}
|
||||
alt={t("maintenance.regionGrid.title")}
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[50%]">
|
||||
<Button
|
||||
onClick={() => setIsConfirmOpen(true)}
|
||||
disabled={isClearing}
|
||||
variant="destructive"
|
||||
className="flex flex-1 text-white md:max-w-sm"
|
||||
>
|
||||
{t("maintenance.regionGrid.clear")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AlertDialog open={isConfirmOpen} onOpenChange={setIsConfirmOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{t("maintenance.regionGrid.clearConfirmTitle")}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{t("maintenance.regionGrid.clearConfirmDesc")}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={cn(
|
||||
buttonVariants({ variant: "destructive" }),
|
||||
"text-white",
|
||||
)}
|
||||
onClick={handleClear}
|
||||
>
|
||||
{t("maintenance.regionGrid.clear")}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user