// Global Configuration View // Main view for configuring global Frigate settings import { useMemo, useCallback, useState } from "react"; import useSWR from "swr"; import axios from "axios"; import { toast } from "sonner"; import { useTranslation } from "react-i18next"; import { ConfigForm } from "@/components/config-form/ConfigForm"; import { DetectSection, RecordSection, SnapshotsSection, MotionSection, ObjectsSection, ReviewSection, AudioSection, NotificationsSection, LiveSection, TimestampSection, } from "@/components/config-form/sections"; import type { RJSFSchema } from "@rjsf/utils"; import type { FrigateConfig } from "@/types/frigateConfig"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ScrollArea } from "@/components/ui/scroll-area"; import { extractSchemaSection } from "@/lib/config-schema"; import ActivityIndicator from "@/components/indicators/activity-indicator"; // Section configurations for global-only settings const globalSectionConfigs: Record< string, { fieldOrder?: string[]; hiddenFields?: string[]; advancedFields?: string[] } > = { mqtt: { fieldOrder: [ "enabled", "host", "port", "user", "password", "topic_prefix", "client_id", "stats_interval", "tls_ca_certs", "tls_client_cert", "tls_client_key", "tls_insecure", ], advancedFields: [ "stats_interval", "tls_ca_certs", "tls_client_cert", "tls_client_key", "tls_insecure", ], }, database: { fieldOrder: ["path"], advancedFields: [], }, auth: { fieldOrder: [ "enabled", "reset_admin_password", "native_oauth_url", "failed_login_rate_limit", "trusted_proxies", ], advancedFields: ["failed_login_rate_limit", "trusted_proxies"], }, tls: { fieldOrder: ["enabled", "cert", "key"], advancedFields: [], }, telemetry: { fieldOrder: ["network_interfaces", "stats", "version_check"], advancedFields: ["stats"], }, birdseye: { fieldOrder: [ "enabled", "restream", "width", "height", "quality", "mode", "layout", "inactivity_threshold", ], advancedFields: ["width", "height", "quality", "inactivity_threshold"], }, semantic_search: { fieldOrder: ["enabled", "reindex", "model_size"], advancedFields: ["reindex"], }, face_recognition: { fieldOrder: ["enabled", "threshold", "min_area", "model_size"], advancedFields: ["threshold", "min_area"], }, lpr: { fieldOrder: [ "enabled", "threshold", "min_area", "min_ratio", "max_ratio", "model_size", ], advancedFields: ["threshold", "min_area", "min_ratio", "max_ratio"], }, }; interface GlobalConfigSectionProps { sectionKey: string; schema: RJSFSchema | null; config: FrigateConfig | undefined; onSave: () => void; } function GlobalConfigSection({ sectionKey, schema, config, onSave, }: GlobalConfigSectionProps) { const { t } = useTranslation(["views/settings"]); const formData = useMemo((): Record => { if (!config) return {} as Record; const value = (config as unknown as Record)[sectionKey]; return ( (value as Record) || ({} as Record) ); }, [config, sectionKey]); const handleSubmit = useCallback( async (data: Record) => { try { await axios.put("config/set", { requires_restart: 1, config_data: { [sectionKey]: data, }, }); toast.success( t(`configForm.${sectionKey}.toast.success`, { defaultValue: "Settings saved successfully", }), ); onSave(); } catch (error) { toast.error( t(`configForm.${sectionKey}.toast.error`, { defaultValue: "Failed to save settings", }), ); } }, [sectionKey, t, onSave], ); if (!schema) { return null; } const sectionConfig = globalSectionConfigs[sectionKey] || {}; return ( {t(`configForm.${sectionKey}.title`, { defaultValue: sectionKey.charAt(0).toUpperCase() + sectionKey.slice(1), })} ); } export default function GlobalConfigView() { const { t } = useTranslation(["views/settings"]); const [activeTab, setActiveTab] = useState("shared"); const { data: config, mutate: refreshConfig } = useSWR("config"); const { data: schema } = useSWR("config/schema.json"); const handleSave = useCallback(() => { refreshConfig(); }, [refreshConfig]); if (!config || !schema) { return (
); } return (

{t("configForm.global.title", { defaultValue: "Global Configuration", })}

{t("configForm.global.description", { defaultValue: "Configure global settings that apply to all cameras by default.", })}

{t("configForm.global.tabs.shared", { defaultValue: "Shared Defaults", })} {t("configForm.global.tabs.system", { defaultValue: "System" })} {t("configForm.global.tabs.integrations", { defaultValue: "Integrations", })} {/* Shared config sections - these can be overridden per camera */} {/* System configuration sections */} {/* Integration configuration sections */}
); }