mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-06 05:27:44 +03:00
add frigate+ page in settings
This commit is contained in:
parent
3539e50ed4
commit
543ff91cfe
@ -7,7 +7,8 @@
|
|||||||
"masksAndZones": "Mask and Zone Editor - Frigate",
|
"masksAndZones": "Mask and Zone Editor - Frigate",
|
||||||
"motionTuner": "Motion Tuner - Frigate",
|
"motionTuner": "Motion Tuner - Frigate",
|
||||||
"object": "Object Settings - Frigate",
|
"object": "Object Settings - Frigate",
|
||||||
"general": "General Settings - Frigate"
|
"general": "General Settings - Frigate",
|
||||||
|
"frigatePlus": "Frigate+ Settings - Frigate"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"uiSettings": "UI Settings",
|
"uiSettings": "UI Settings",
|
||||||
@ -17,7 +18,8 @@
|
|||||||
"motionTuner": "Motion Tuner",
|
"motionTuner": "Motion Tuner",
|
||||||
"debug": "Debug",
|
"debug": "Debug",
|
||||||
"users": "Users",
|
"users": "Users",
|
||||||
"notifications": "Notifications"
|
"notifications": "Notifications",
|
||||||
|
"frigateplus": "Frigate+"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"unsavedChanges": {
|
"unsavedChanges": {
|
||||||
@ -515,5 +517,36 @@
|
|||||||
"registerFailed": "Failed to save notification registration."
|
"registerFailed": "Failed to save notification registration."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"frigatePlus": {
|
||||||
|
"title": "Frigate+ Settings",
|
||||||
|
"apiKey": {
|
||||||
|
"title": "Frigate+ API Key",
|
||||||
|
"validated": "Frigate+ API key is detected and validated",
|
||||||
|
"notValidated": "Frigate+ API key is not detected or not validated",
|
||||||
|
"desc": "The Frigate+ API key enables integration with the Frigate+ service.",
|
||||||
|
"plusLink": "Read more about Frigate+"
|
||||||
|
},
|
||||||
|
"snapshotConfig": {
|
||||||
|
"title": "Snapshot Configuration",
|
||||||
|
"desc": "Submitting to Frigate+ requires both snapshots and <code>clean_copy</code> snapshots to be enabled in your config.",
|
||||||
|
"documentation": "Read the documentation",
|
||||||
|
"cleanCopyWarning": "Some cameras have snapshots enabled but have the clean copy disabled. You need to enable <code>clean_copy</code> in your snapshot config to be able to submit images from these cameras to Frigate+.",
|
||||||
|
"table": {
|
||||||
|
"camera": "Camera",
|
||||||
|
"snapshots": "Snapshots",
|
||||||
|
"cleanCopySnapshots": "<code>clean_copy</code> Snapshots"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modelInfo": {
|
||||||
|
"title": "Model Information",
|
||||||
|
"modelType": "Model Type",
|
||||||
|
"trainDate": "Train Date",
|
||||||
|
"baseModel": "Base Model",
|
||||||
|
"supportedDetectors": "Supported Detectors",
|
||||||
|
"cameras": "Cameras",
|
||||||
|
"loading": "Loading model information...",
|
||||||
|
"error": "Failed to load model information"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import AuthenticationView from "@/views/settings/AuthenticationView";
|
|||||||
import NotificationView from "@/views/settings/NotificationsSettingsView";
|
import NotificationView from "@/views/settings/NotificationsSettingsView";
|
||||||
import ClassificationSettingsView from "@/views/settings/ClassificationSettingsView";
|
import ClassificationSettingsView from "@/views/settings/ClassificationSettingsView";
|
||||||
import UiSettingsView from "@/views/settings/UiSettingsView";
|
import UiSettingsView from "@/views/settings/UiSettingsView";
|
||||||
|
import FrigatePlusSettingsView from "@/views/settings/FrigatePlusSettingsView";
|
||||||
import { useSearchEffect } from "@/hooks/use-overlay-state";
|
import { useSearchEffect } from "@/hooks/use-overlay-state";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import { useInitialCameraState } from "@/api/ws";
|
import { useInitialCameraState } from "@/api/ws";
|
||||||
@ -54,6 +55,7 @@ const allSettingsViews = [
|
|||||||
"debug",
|
"debug",
|
||||||
"users",
|
"users",
|
||||||
"notifications",
|
"notifications",
|
||||||
|
"frigateplus",
|
||||||
] as const;
|
] as const;
|
||||||
type SettingsType = (typeof allSettingsViews)[number];
|
type SettingsType = (typeof allSettingsViews)[number];
|
||||||
|
|
||||||
@ -279,6 +281,7 @@ export default function Settings() {
|
|||||||
{page == "notifications" && (
|
{page == "notifications" && (
|
||||||
<NotificationView setUnsavedChanges={setUnsavedChanges} />
|
<NotificationView setUnsavedChanges={setUnsavedChanges} />
|
||||||
)}
|
)}
|
||||||
|
{page == "frigateplus" && <FrigatePlusSettingsView />}
|
||||||
</div>
|
</div>
|
||||||
{confirmationDialogOpen && (
|
{confirmationDialogOpen && (
|
||||||
<AlertDialog
|
<AlertDialog
|
||||||
|
|||||||
229
web/src/views/settings/FrigatePlusSettingsView.tsx
Normal file
229
web/src/views/settings/FrigatePlusSettingsView.tsx
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
import Heading from "@/components/ui/heading";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { Toaster } from "sonner";
|
||||||
|
import { Separator } from "../../components/ui/separator";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
|
import { CheckCircle2, XCircle } from "lucide-react";
|
||||||
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import { IoIosWarning } from "react-icons/io";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { LuExternalLink } from "react-icons/lu";
|
||||||
|
|
||||||
|
export default function FrigatePlusSettingsView() {
|
||||||
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
|
const { t } = useTranslation("views/settings");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = t("documentTitle.frigatePlus");
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
const needCleanSnapshots = () => {
|
||||||
|
if (!config) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Object.values(config.cameras).some(
|
||||||
|
(camera) => camera.snapshots.enabled && !camera.snapshots.clean_copy,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex size-full flex-col md:flex-row">
|
||||||
|
<Toaster position="top-center" closeButton={true} />
|
||||||
|
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||||
|
<Heading as="h3" className="my-2">
|
||||||
|
{t("frigatePlus.title")}
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Separator className="my-2 flex bg-secondary" />
|
||||||
|
|
||||||
|
<Heading as="h4" className="my-2">
|
||||||
|
{t("frigatePlus.apiKey.title")}
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<div className="mt-2 space-y-6">
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{config?.plus?.enabled ? (
|
||||||
|
<CheckCircle2 className="h-5 w-5 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<XCircle className="h-5 w-5 text-red-500" />
|
||||||
|
)}
|
||||||
|
<Label>
|
||||||
|
{config?.plus?.enabled
|
||||||
|
? t("frigatePlus.apiKey.validated")
|
||||||
|
: t("frigatePlus.apiKey.notValidated")}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<div className="my-2 max-w-5xl text-sm text-muted-foreground">
|
||||||
|
<p>{t("frigatePlus.apiKey.desc")}</p>
|
||||||
|
{!config?.model.plus && (
|
||||||
|
<>
|
||||||
|
<div className="mt-2 flex items-center text-primary-variant">
|
||||||
|
<Link
|
||||||
|
to="https://frigate.video/plus"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline"
|
||||||
|
>
|
||||||
|
{t("frigatePlus.apiKey.plusLink")}
|
||||||
|
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{config?.model.plus && (
|
||||||
|
<>
|
||||||
|
<Separator className="my-2 flex bg-secondary" />
|
||||||
|
<div className="mt-2 max-w-2xl">
|
||||||
|
<Heading as="h4" className="my-2">
|
||||||
|
{t("frigatePlus.modelInfo.title")}
|
||||||
|
</Heading>
|
||||||
|
<div className="mt-2 space-y-3">
|
||||||
|
{!config?.model?.plus && (
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
{t("frigatePlus.modelInfo.loading")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{config?.model?.plus === null && (
|
||||||
|
<p className="text-danger">
|
||||||
|
{t("frigatePlus.modelInfo.error")}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{config?.model?.plus && (
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<Label className="text-muted-foreground">
|
||||||
|
{t("frigatePlus.modelInfo.modelType")}
|
||||||
|
</Label>
|
||||||
|
<p>{config.model.plus.name}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label className="text-muted-foreground">
|
||||||
|
{t("frigatePlus.modelInfo.trainDate")}
|
||||||
|
</Label>
|
||||||
|
<p>
|
||||||
|
{new Date(
|
||||||
|
config.model.plus.trainDate,
|
||||||
|
).toLocaleString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label className="text-muted-foreground">
|
||||||
|
{t("frigatePlus.modelInfo.baseModel")}
|
||||||
|
</Label>
|
||||||
|
<p>{config.model.plus.baseModel}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Label className="text-muted-foreground">
|
||||||
|
{t("frigatePlus.modelInfo.supportedDetectors")}
|
||||||
|
</Label>
|
||||||
|
<p>
|
||||||
|
{config.model.plus.supportedDetectors.join(", ")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Separator className="my-2 flex bg-secondary" />
|
||||||
|
|
||||||
|
<div className="mt-2 max-w-5xl">
|
||||||
|
<Heading as="h4" className="my-2">
|
||||||
|
{t("frigatePlus.snapshotConfig.title")}
|
||||||
|
</Heading>
|
||||||
|
<div className="mt-2 space-y-3">
|
||||||
|
<div className="my-2 text-sm text-muted-foreground">
|
||||||
|
<p>
|
||||||
|
<Trans ns="views/settings">
|
||||||
|
frigatePlus.snapshotConfig.desc
|
||||||
|
</Trans>
|
||||||
|
</p>
|
||||||
|
<div className="mt-2 flex items-center text-primary-variant">
|
||||||
|
<Link
|
||||||
|
to="https://docs.frigate.video/configuration/plus/faq"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline"
|
||||||
|
>
|
||||||
|
{t("frigatePlus.snapshotConfig.documentation")}
|
||||||
|
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{config && (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="max-w-2xl text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-secondary">
|
||||||
|
<th className="px-4 py-2 text-left">
|
||||||
|
{t("frigatePlus.snapshotConfig.table.camera")}
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-center">
|
||||||
|
{t("frigatePlus.snapshotConfig.table.snapshots")}
|
||||||
|
</th>
|
||||||
|
<th className="px-4 py-2 text-center">
|
||||||
|
<Trans ns="views/settings">
|
||||||
|
frigatePlus.snapshotConfig.table.cleanCopySnapshots
|
||||||
|
</Trans>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{Object.entries(config.cameras).map(
|
||||||
|
([name, camera]) => (
|
||||||
|
<tr
|
||||||
|
key={name}
|
||||||
|
className="border-b border-secondary"
|
||||||
|
>
|
||||||
|
<td className="px-4 py-2">{name}</td>
|
||||||
|
<td className="px-4 py-2 text-center">
|
||||||
|
{camera.snapshots.enabled ? (
|
||||||
|
<CheckCircle2 className="mx-auto size-5 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<XCircle className="mx-auto size-5 text-danger" />
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2 text-center">
|
||||||
|
{camera.snapshots?.enabled &&
|
||||||
|
camera.snapshots?.clean_copy ? (
|
||||||
|
<CheckCircle2 className="mx-auto size-5 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<XCircle className="mx-auto size-5 text-danger" />
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{needCleanSnapshots() && (
|
||||||
|
<div className="mt-2 max-w-xl rounded-lg border border-secondary-foreground bg-secondary p-4 text-sm text-danger">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<IoIosWarning className="mr-2 size-5 text-danger" />
|
||||||
|
<div className="max-w-[85%] text-sm">
|
||||||
|
<Trans ns="views/settings">
|
||||||
|
frigatePlus.snapshotConfig.cleanCopyWarning
|
||||||
|
</Trans>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user