mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-13 11:57:36 +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 RolesView from "@/views/settings/RolesView";
|
||||||
import UiSettingsView from "@/views/settings/UiSettingsView";
|
import UiSettingsView from "@/views/settings/UiSettingsView";
|
||||||
import FrigatePlusSettingsView from "@/views/settings/FrigatePlusSettingsView";
|
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 SystemDetectionModelSettingsView from "@/views/settings/SystemDetectionModelSettingsView";
|
||||||
import {
|
import {
|
||||||
SingleSectionPage,
|
SingleSectionPage,
|
||||||
@ -154,7 +155,8 @@ const allSettingsViews = [
|
|||||||
"roles",
|
"roles",
|
||||||
"notifications",
|
"notifications",
|
||||||
"frigateplus",
|
"frigateplus",
|
||||||
"maintenance",
|
"mediaSync",
|
||||||
|
"regionGrid",
|
||||||
] as const;
|
] as const;
|
||||||
type SettingsType = (typeof allSettingsViews)[number];
|
type SettingsType = (typeof allSettingsViews)[number];
|
||||||
|
|
||||||
@ -444,7 +446,10 @@ const settingsGroups = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "maintenance",
|
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",
|
"masksAndZones",
|
||||||
"motionTuner",
|
"motionTuner",
|
||||||
"triggers",
|
"triggers",
|
||||||
|
"regionGrid",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ALLOWED_VIEWS_FOR_VIEWER = ["ui", "debug", "notifications"];
|
const ALLOWED_VIEWS_FOR_VIEWER = ["ui", "debug", "notifications"];
|
||||||
|
|
||||||
const LARGE_BOTTOM_MARGIN_PAGES = [
|
const LARGE_BOTTOM_MARGIN_PAGES = ["masksAndZones", "motionTuner", "mediaSync"];
|
||||||
"masksAndZones",
|
|
||||||
"motionTuner",
|
|
||||||
"maintenance",
|
|
||||||
];
|
|
||||||
|
|
||||||
// keys for camera sections
|
// keys for camera sections
|
||||||
const CAMERA_SECTION_MAPPING: Record<string, SettingsType> = {
|
const CAMERA_SECTION_MAPPING: Record<string, SettingsType> = {
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
|
||||||
import { MediaSyncStats } from "@/types/ws";
|
import { MediaSyncStats } from "@/types/ws";
|
||||||
|
|
||||||
export default function MaintenanceSettingsView() {
|
export default function MediaSyncSettingsView() {
|
||||||
const { t } = useTranslation("views/settings");
|
const { t } = useTranslation("views/settings");
|
||||||
const [selectedMediaTypes, setSelectedMediaTypes] = useState<string[]>([
|
const [selectedMediaTypes, setSelectedMediaTypes] = useState<string[]>([
|
||||||
"all",
|
"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="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="grid w-full grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
<Heading as="h4" className="mb-2">
|
<Heading as="h4" className="mb-2 hidden md:block">
|
||||||
{t("maintenance.sync.title")}
|
{t("maintenance.sync.title")}
|
||||||
</Heading>
|
</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