import Heading from "@/components/ui/heading"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Event } from "@/types/event"; import { FrigateConfig } from "@/types/frigateConfig"; import { zodResolver } from "@hookform/resolvers/zod"; import axios from "axios"; import { useCallback, useState } from "react"; import { useForm } from "react-hook-form"; import { LuExternalLink } from "react-icons/lu"; import { PiWarningCircle } from "react-icons/pi"; import { Link } from "react-router-dom"; import { toast } from "sonner"; import useSWR from "swr"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { z } from "zod"; import { Button } from "@/components/ui/button"; import ActivityIndicator from "@/components/indicators/activity-indicator"; import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import { Trans, useTranslation } from "react-i18next"; type AnnotationSettingsPaneProps = { event: Event; showZones: boolean; setShowZones: React.Dispatch>; annotationOffset: number; setAnnotationOffset: React.Dispatch>; }; export function AnnotationSettingsPane({ event, showZones, setShowZones, annotationOffset, setAnnotationOffset, }: AnnotationSettingsPaneProps) { const { t } = useTranslation(["views/explore"]); const { data: config, mutate: updateConfig } = useSWR("config"); const [isLoading, setIsLoading] = useState(false); const formSchema = z.object({ annotationOffset: z.coerce.number().optional().or(z.literal("")), }); const form = useForm>({ resolver: zodResolver(formSchema), mode: "onChange", defaultValues: { annotationOffset: annotationOffset, }, }); const saveToConfig = useCallback( async (annotation_offset: number | string) => { if (!config || !event) { return; } axios .put( `config/set?cameras.${event?.camera}.detect.annotation_offset=${annotation_offset}`, { requires_restart: 0, }, ) .then((res) => { if (res.status === 200) { toast.success( `Annotation offset for ${event?.camera} has been saved to the config file. Restart Frigate to apply your changes.`, { position: "top-center", }, ); updateConfig(); } else { toast.error( t("toast.save.error.title", { errorMessage: res.statusText, ns: "common", }), { position: "top-center", }, ); } }) .catch((error) => { const errorMessage = error.response?.data?.message || error.response?.data?.detail || "Unknown error"; toast.error( t("toast.save.error.title", { errorMessage, ns: "common" }), { position: "top-center", }, ); }) .finally(() => { setIsLoading(false); }); }, [updateConfig, config, event, t], ); function onSubmit(values: z.infer) { if (!values || values.annotationOffset == null || !config) { return; } setIsLoading(true); saveToConfig(values.annotationOffset); } function onApply(values: z.infer) { if ( !values || values.annotationOffset === null || values.annotationOffset === "" || !config ) { return; } setAnnotationOffset(values.annotationOffset ?? 0); } return (
{t("objectLifecycle.annotationSettings.title")}
{t("objectLifecycle.annotationSettings.showAllZones.desc")}
( {t("objectLifecycle.annotationSettings.offset.label")}
objectLifecycle.annotationSettings.offset.desc
{t( "objectLifecycle.annotationSettings.offset.documentation", )}
objectLifecycle.annotationSettings.offset.millisecondsToOffset
{t("objectLifecycle.annotationSettings.offset.tips")}
)} />
); }