import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Switch } from "@/components/ui/switch"; import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import axios from "axios"; import useSWR from "swr"; const EVENTS = "events"; const CONTINUOUS = "continuous"; const MODES = [EVENTS, CONTINUOUS] as const; type SetupRecordingProps = { cameraNames: string[]; onNext: () => void; onBack: () => void; onSkip: () => void; }; export default function SetupRecording({ cameraNames, onNext, onBack, onSkip, }: SetupRecordingProps) { const { t } = useTranslation(["views/setup"]); const [enabled, setEnabled] = useState(true); const [mode, setMode] = useState(EVENTS); const [retentionDays, setRetentionDays] = useState(10); const [saving, setSaving] = useState(false); const { data: stats } = useSWR("stats", { revalidateOnFocus: false }); const storageInfo = stats?.service?.storage?.["/tmp/frigate/recordings"]; const freeGb = storageInfo ? Math.round(storageInfo.free / 1024) : null; const cameraCount = cameraNames.length; // Rough estimate: ~2 Mbps per camera continuous recording const estimatedDays = freeGb && cameraCount > 0 ? Math.round((freeGb * 1024) / ((2 * 0.125 * 86400) / 1024) / cameraCount) : null; const handleSave = useCallback(async () => { setSaving(true); try { const record: Record = { enabled }; if (enabled) { record.alerts = { retain: { days: retentionDays } }; record.detections = { retain: { days: retentionDays } }; // written even when off, so switching modes back turns it off again record.continuous = { days: mode === CONTINUOUS ? retentionDays : 0 }; } await axios.put("config/set", { config_data: { record }, requires_restart: 1, }); onNext(); } catch { toast.error(t("setupWizard.errors.saveFailed")); } finally { setSaving(false); } }, [enabled, mode, retentionDays, onNext, t]); return (

{t("setupWizard.recording.title")}

{t("setupWizard.recording.description")}

{cameraCount === 0 && (

{t("setupWizard.recording.noCameras")}

)}
{enabled && ( <>
{MODES.map((option) => (

{t(`setupWizard.recording.modes.${option}.description`)}

))}
setRetentionDays(Math.max(1, parseInt(e.target.value) || 1)) } />

{t(`setupWizard.recording.retentionHint.${mode}`)}

{mode === CONTINUOUS && freeGb !== null && estimatedDays !== null && cameraCount > 0 && (

{t("setupWizard.recording.storageEstimate", { free: freeGb, days: estimatedDays, cameras: cameraCount, })}

)} )}
); }