* Move openai specific workaround so it doesn't apply to other providers
* Fix gemini tool calling
* Improve efficiency of frame listing for previews
* debug replay fixes
- initial selection without changing the radio button in the dialog would select 1 hour (rather than 1 minute)
- use CLIPS_DIR instead of CACHE_DIR so that longer replay clips don't cause tmpfs cache overflows
* don't re-render the tracking details overlay on every video time tick
* change pinned to planned
---------
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* ensure embeddings process restarts after maintainer thread crash
* add docs link to media sync settings
* fix color
Co-authored-by: Copilot <copilot@github.com>
* match link color with other sections
* ensure recording staleness threshold scales with segment_time
* docs tweak
* Fix llama.cpp media marker
* Fix gemini tools call
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* Reduce max frames per second to 1
* Use pydantic but don't fail if some constraints are not met.
* Adjust limits
* Adjust limits
* Cleanup
* add unsaved changes icon/popover to individual settings section
* allow changing camera friendly_name from camera management pane
---------
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* use ffmpeg to probe rtsp urls instead of cv2
cv2 is faster (no subprocess launch) and will continue to be used for recording segments
* tweak faq
* change unsaved color to orange
avoids confusion with validation errors (red)
* don't use any variant of orange as a profile color
avoids confusion with unsaved changes
* more unsaved color tweaks
* Bump radix-ui packages to align react-dismissable-layer version and fix nested overlay pointer-events bug
* remove workarounds for radix pointer events issues on dropdown and context menus
* remove disablePortal from popover
* remove modal on popovers
* remove workarounds in restart dialog
* keep onCloseAutoFocus for face, classification, and ptz
these are necessary to prevent tooltips from re-showing and from the arrow keys from reopening the ptz presets menu
* add tests
* apply annotation offset to frigate+ submission frame time
* fix broken docs links with hash fragments that resolve wrong on reload
* undo
* use recording snapshot for frigate+ frame submission from VideoControls
rather than a canvas grab/paint, which may not always align with an ffmpeg snapshot due to keyframes
* add more docs links
- display docs link for main sections on collapsible fields
* dialog button consistency
* Initial copy timestamp url implementation
* revise url format
* Implement share timestamp dialog
* Use translations
* Add comments
* Add validations to shared link
* Switch to searchEffect implementation
* Add missing accessibility related dialog description
* Change URL format to unix timestamps
* Remove unnecessary useEffect
* Remove duplicated dialog title
* Fixes/improvements based off PR review comments
* Add missing cancel button & separators to dialog
* Make share description clearer
* Bugfix: guard against showing toasts twice
Because this effect ends up running multiple times
* Clamp future timestamps to now
* Revert "Bugfix: guard against showing toasts twice"
This reverts commit 99fa5e1dee.
* Use normal separator
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* Fixes based off PR review comments
* Bugfix: Share dialog was not receiving the player timestamp after removing key that triggered remounts
* Defer `setRecording` and return true from hook for cleanup
* Remove timeout defer hack in favor of refactored hook
* Attempt to replay video muted on NotAllowedError
* Use separate persistent mute and temporary forced mute states
* Align cancel button with other dialogs
* Prevent wrapping on dialog title
* Remove extra "back" button on mobile drawer
* Fix back navigation when coming from direct shared timestamp links
* Use new timeformat hook
* Simplify dialog radio buttons
* Apply suggestions from code review
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
---------
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* backend
* frontend + i18n
* tests + api spec
* tweak backend to use Job infrastructure for exports
* frontend tweaks and Job infrastructure
* tests
* tweaks
- add ability to remove from case
- change location of counts in case card
* add stale export reaper on startup
* fix toaster close button color
* improve add dialog
* formatting
* hide max_concurrent from camera config export settings
* remove border
* refactor batch endpoint for multiple review items
* frontend
* tests and fastapi spec
* fix deletion of in-progress exports in a case
* tweaks
- hide cases when filtering cameras that have no exports from those cameras
- remove description from case card
- use textarea instead of input for case description in add new case dialog
* add auth exceptions for exports
* add e2e test for deleting cases with exports
* refactor delete and case endpoints
allow bulk deleting and reassigning
* frontend
- bulk selection like Review
- gate admin-only actions
- consolidate dialogs
- spacing/padding tweaks
* i18n and tests
* update openapi spec
* tweaks
- add None to case selection list
- allow new case creation from single cam export dialog
* fix codeql
* fix i18n
* remove unused
* fix frontend tests
* display area as proper percentage in debug view
* match replay objects list with debug view
* motion search fixes
- tweak progress bar to exclude heatmap and inactive segments
- show metrics immediately on search start
- fix preview frame loading race
- fix polygon missing after dialog remount
- don't try to drag the image when dragging vertex of polygon
* add activity indicator to storage metrics
* make sub label query for events API endpoints case insensitive
* add guards to reject missing sub commands
* mask/zone bugfixes
- fix websocket crash when creating a new mask or zone before a name is assigned
- fix deleted masks and zones not disappearing from the list until navigating away
- fix deleting profile override not reverting to the base mask in the list
- fix inertia defaulting to nan
* disable save button on invalid form state
* fix validation for speed estimation
* ensure polygon is closed before allowing save
* require all masks and zones to be on the base config
* clarify dialog message and tooltip when removing an override
* clarify docs
* implement hook to return resolved "24hour" | "12hour" string
delegate to existing use24HourTime(), which correctly detects the browser's locale preference via Intl.DateTimeFormat
* update frontend to use use24HourTime(config) or useTimeFormat(config) instead of directly comparing config.ui.time_format
* embed cpu/mem stats into detectors, cameras, and processes
so history consumers don't need the full cpu_usages dict
* support dot-notation for nested keys
to avoid returning large objects when only specific subfields are needed
* fix setLastUpdated being called inside useMemo
this triggered a setState-during-render warning, so moved to a useEffect
* frontend types
* frontend
hide instead of unmount all graphs - re-rendering is much more expensive and disruptive than the amount of dom memory required
keep track of visited tabs to keep them mounted rather than re-mounting or mounting all tabs
add isActive prop to all charts to re-trigger animation when switching metrics tabs
fix chart data padding bug where the loop used number of series rather than number of data points
fix bug where only a shallow copy of the array was used for mutation
fix missing key prop causing console logs
* add isactive after rebase
* formatting
* skip None values in filtered output for dot notation
* tweak language
* show validation errors in json response
* fix export hwaccel args field in UI
* increase annotation offset consts
* fix save button race conditions, add reset spinner, and fix enrichments profile leak
- Disable both Save and SaveAll buttons while either operation is in progress so users cannot trigger concurrent saves
- Show activity indicator on Reset to Default/Global button during the API call
- Enrichments panes (semantic search, genai, face recognition) now always show base config fields regardless of profile selection in the header dropdown
* fix genai additional_concerns validation error with textarea array widget
The additional_concerns field is list[str] in the backend but was using the textarea widget which produces a string value, causing validation errors.
Created a TextareaArrayWidget that converts between array (one item per line) and textarea display, and switched additional_concerns to use it
* populate and sort global audio filters for all audio labels
* add column labels in profiles view
* enforce a minimum value of 2 for min_initialized
* reuse widget and refactor for multiline
* fix
* change record copy preset to transcode audio to aac
* Mark items as reviewed as a group with keyboard
* Improve handling of half model regions
* update viewport meta tag to prevent user scaling
fixes https://github.com/blakeblackshear/frigate/issues/22017
* add small animation to collapsible shadcn elements
* add proxy auth env var tests
* Improve search effect
* Fix mobile back navigation losing overlay state on classification page
* undo historyBack changes
* fix classification history navigation
---------
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* add randomness to object classification
also ensure train_dir is fresh if user has regenerated examples
* frontend refresh button
* fix radix dropdown issue
* i18n
* mobile button spacing
* prevent console warning about div being descendant of p
* ensure consistent spacing
* add missing i18n keys
* i18n fixes
- add missing translations
- fix dot notation keys
* use plain string
* add missing key
* add i18next-cli commands for extraction and status
also add false positives removal for several keys
* add i18n key check step to PR workflow
* formatting
* fix genai settings ui
- add roles widget to select roles for genai providers
- add dropdown in semantic search to allow selection of embeddings genai provider
* tweak grouping to prioritize fieldOrder before groups
previously, groups were always rendered first. now fieldOrder is respected, and any fields in a group will cause the group and all the fields in that group to be rendered in order. this allows moving the enabled switches to the top of the section
* mobile tweaks
stack buttons, add more space on profiles pane, and move the overridden badge beneath the description
* language consistency
* prevent camera config sections from being regenerated for profiles
* conditionally import axengine module
to match other detectors
* i18n
* update vscode launch.json for new integrated browser
* formatting
* Add go2rtc settings section
- create separate settings section for all go2rtc streams
- extract credentials mask code into util
- create ffmpeg module utility
- i18n
* add camera config updater topic for live section
to support adding go2rtc streams after configuring a new one via the UI
* clean up
* tweak delete button color for consistency
* tweaks
* add CameraProfileConfig model for named config overrides
* add profiles field to CameraConfig
* add active_profile field to FrigateConfig
Runtime-only field excluded from YAML serialization, tracks which
profile is currently active.
* add ProfileManager for profile activation and persistence
Handles snapshotting base configs, applying profile overrides via
deep_merge + apply_section_update, publishing ZMQ updates, and
persisting active profile to /config/.active_profile.
* add profile API endpoints (GET /profiles, GET/PUT /profile)
* add MQTT and dispatcher integration for profiles
- Subscribe to frigate/profile/set MQTT topic
- Publish profile/state and profiles/available on connect
- Add _on_profile_command handler to dispatcher
- Broadcast active profile state on WebSocket connect
* wire ProfileManager into app startup and FastAPI
- Create ProfileManager after dispatcher init
- Restore persisted profile on startup
- Pass dispatcher and profile_manager to FastAPI app
* add tests for invalid profile values and keys
Tests that Pydantic rejects: invalid field values (fps: "not_a_number"),
unknown section keys (ffmpeg in profile), invalid nested values, and
invalid profiles in full config parsing.
* formatting
* fix CameraLiveConfig JSON serialization error on profile activation
refactor _publish_updates to only publish ZMQ updates for
sections that actually changed, not all sections on affected cameras.
* consolidate
* add enabled field to camera profiles for enabling/disabling cameras
* add zones support to camera profiles
* add frontend profile types, color utility, and config save support
* add profile state management and save preview support
* add profileName prop to BaseSection for profile-aware config editing
* add profile section dropdown and wire into camera settings pages
* add per-profile camera enable/disable to Camera Management view
* add profiles summary page with card-based layout and fix backend zone comparison bug
* add active profile badge to settings toolbar
* i18n
* add red dot for any pending changes including profiles
* profile support for mask and zone editor
* fix hidden field validation errors caused by lodash wildcard and schema gaps
lodash unset does not support wildcard (*) segments, so hidden fields like
filters.*.mask were never stripped from form data, leaving null raw_coordinates
that fail RJSF anyOf validation. Add unsetWithWildcard helper and also strip
hidden fields from the JSON schema itself as defense-in-depth.
* add face_recognition and lpr to profile-eligible sections
* move profile dropdown from section panes to settings header
* add profiles enable toggle and improve empty state
* formatting
* tweaks
* tweak colors and switch
* fix profile save diff, masksAndZones delete, and config sync
* ui tweaks
* ensure profile manager gets updated config
* rename profile settings to ui settings
* refactor profilesview and add dots/border colors when overridden
* implement an update_config method for profile manager
* fix mask deletion
* more unique colors
* add top-level profiles config section with friendly names
* implement profile friendly names and improve profile UI
- Add ProfileDefinitionConfig type and profiles field to FrigateConfig
- Use ProfilesApiResponse type with friendly_name support throughout
- Replace Record<string, unknown> with proper JsonObject/JsonValue types
- Add profile creation form matching zone pattern (Zod + NameAndIdFields)
- Add pencil icon for renaming profile friendly names in ProfilesView
- Move Profiles menu item to first under Camera Configuration
- Add activity indicators on save/rename/delete buttons
- Display friendly names in CameraManagementView profile selector
- Fix duplicate colored dots in management profile dropdown
- Fix i18n namespace for overridden base config tooltips
- Move profile override deletion from dropdown trash icon to footer
button with confirmation dialog, matching Reset to Global pattern
- Remove Add Profile from section header dropdown to prevent saving
camera overrides before top-level profile definition exists
- Clean up newProfiles state after API profile deletion
- Refresh profiles SWR cache after saving profile definitions
* remove profile badge in settings and add profiles to main menu
* use icon only on mobile
* change color order
* docs
* show activity indicator on trash icon while deleting a profile
* tweak language
* immediately create profiles on backend instead of deferring to Save All
* hide restart-required fields when editing a profile section
fields that require a restart cannot take effect via profile switching,
so they are merged into hiddenFields when profileName is set
* show active profile indicator in desktop status bar
* fix profile config inheritance bug where Pydantic defaults override base values
The /config API was dumping profile overrides with model_dump() which included
all Pydantic defaults. When the frontend merged these over
the camera's base config, explicitly-set base values were
lost. Now profile overrides are re-dumped with exclude_unset=True so only
user-specified fields are returned.
Also fixes the Save All path generating spurious deletion markers for
restart-required fields that are hidden during profile
editing but not excluded from the raw data sanitization in
prepareSectionSavePayload.
* docs tweaks
* docs tweak
* formatting
* formatting
* fix typing
* fix test pollution
test_maintainer was injecting MagicMock() into sys.modules["frigate.config.camera.updater"] at module load time and never restoring it. When the profile tests later imported CameraConfigUpdateEnum and CameraConfigUpdateTopic from that module, they got mock objects instead of the real dataclass/enum, so equality comparisons always failed
* remove
* fix settings showing profile-merged values when editing base config
When a profile is active, the in-memory config contains effective
(profile-merged) values. The settings UI was displaying these merged
values even when the "Base Config" view was selected.
Backend: snapshot pre-profile base configs in ProfileManager and expose
them via a `base_config` key in the /api/config camera response when a
profile is active. The top-level sections continue to reflect the
effective running config.
Frontend: read from `base_config` when available in BaseSection,
useConfigOverride, useAllCameraOverrides, and prepareSectionSavePayload.
Include formData labels in Object/Audio switches widgets so that labels
added only by a profile override remain visible when editing that profile.
* use rasterized_mask as field
makes it easier to exclude from the schema with exclude=True
prevents leaking of the field when using model_dump for profiles
* fix zones
- Fix zone colors not matching across profiles by falling back to base zone color when profile zone data lacks a color field
- Use base_config for base-layer values in masks/zones view so profile-merged values don't pollute the base config editing view
- Handle zones separately in profile manager snapshot/restore since ZoneConfig requires special serialization (color as private attr, contour generation)
- Inherit base zone color and generate contours for profile zone overrides in profile manager
* formatting
* don't require restart for camera enabled change for profiles
* publish camera state when changing profiles
* formatting
* remove available profiles from mqtt
* improve typing
setVolumeStates was replacing the entire state object instead of
merging, so changing one camera's volume reset all others to default.
Uses the functional update pattern to preserve existing state, matching
how toggleAudio already works.
* fix double scrollbar in debug replay
* always hide ffmpeg cpu warnings for replay cameras
* add slovenian
* fix motion previews on safari and ios
match the logic used in ScrubbablePreview for manually stepping currentTime at the correct rate
* prevent motion recalibration when opening motion tuner
* add shm frame lifetime calculation and update UI for shared memory metrics
* consistent sizing on activity indicator in save buttons
* fix offline overlay overflowing on mobile when in grid mode
* add optional field widget
adds a switch to enable nullable fields like skip_motion_threshold
* config field updates
add skip_motion_threshold optional switch
add fps back to detect restart required
* don't use ternary operator when displaying motion previews
the main previews were being unnecessarily unmounted
* lazy mount motion preview clips to reduce DOM overhead
* face recognition dynamic config
* lpr dynamic config
* safe changes for birdseye dynamic config
* bird classification dynamic config
* always assign new config to stats emitter to make telemetry fields dynamic
* add wildcard support for camera config updates in config_set
* update restart required fields for global sections
* add test
* fix rebase issue
* collapsible settings sidebar
use the preexisting control available with shadcn's sidebar (cmd/ctrl-B) to give users more space to set masks/zones on smaller screens
* dynamic ffmpeg
* ensure previews dir exists
when ffmpeg processes restart, there's a brief window where the preview frame generation pipeline is torn down and restarted. before these changes, ffmpeg only restarted on crash/stall recovery or full Frigate restart. Now that ffmpeg restarts happen on-demand via config changes, there's a higher chance a frontend request hits the preview_mp4 or preview_gif endpoints during that brief restart window when the directory might not exist yet. The existing os.listdir() call would throw FileNotFoundError without a directory existence check. this fix just checks if the directory exists and returns 404 if not, exactly how preview_thumbnail already handles the same scenario a few lines below
* global ffmpeg section
* clean up
* tweak
* fix test
* fix useImageLoaded hook running on every render
* fix volume not applying for all cameras
* Fix maximum update depth exceeded errors on Review page
- use-overlay-state: use refs for location to keep setter identity
stable across renders, preventing cascading re-render loops when
effects depend on the setter. Add Object.is bail-out guard to skip
redundant navigate calls. Move setPersistedValue after bail-out to
avoid unnecessary IndexedDB writes.
* don't try to fetch previews when motion search dialog is open
* revert unneeded changes
re-rendering was caused by the overlay state hook, not this one
* filter dicts to only use id field in sync recordings
* remove unused RecoilRoot and fix implicit ref callback
Remove the vestigial recoil dependency (zero consumers) and convert
the implicit-return ref callback in SearchView to block form to
prevent React 19 interpreting it as a cleanup function.
* replace react-transition-group with framer-motion in Chip
Replace CSSTransition with framer-motion AnimatePresence + motion.div
for React 19 compatibility (react-transition-group uses findDOMNode).
framer-motion is already a project dependency.
* migrate react-grid-layout v1 to v2
- Replace WidthProvider(Responsive) HOC with useContainerWidth hook
- Update types: Layout (single item) → LayoutItem, Layout[] → Layout
- Replace isDraggable/isResizable/resizeHandles with dragConfig/resizeConfig
- Update EventCallback signature for v2 API
- Remove @types/react-grid-layout (v2 includes its own types)
* upgrade vaul, next-themes, framer-motion, react-zoom-pan-pinch
- vaul: ^0.9.1 → ^1.1.2
- next-themes: ^0.3.0 → ^0.4.6
- framer-motion: ^11.5.4 → ^12.35.0 (React 19 native support)
- react-zoom-pan-pinch: 3.4.4 → latest
* upgrade to React 19, react-konva v19, eslint-plugin-react-hooks v5
Core React 19 upgrade with all necessary type fixes:
- Update RefObject types to accept T | null (React 19 refs always nullable)
- Add JSX namespace imports (no longer global in React 19)
- Add initial values to useRef calls (required in React 19)
- Fix ReactElement.props unknown type in config-form components
- Fix IconWrapper interface to use HTMLAttributes instead of index signature
- Add monaco-editor as dev dependency for type declarations
- Upgrade react-konva to v19, eslint-plugin-react-hooks to v5
* upgrade typescript to 5.9.3
* modernize Context.Provider to React 19 shorthand
Replace <Context.Provider value={...}> with <Context value={...}>
across all project-owned context providers. External library contexts
(react-icons IconContext, radix TooltipPrimitive) left unchanged.
* add runtime patches for React 19 compatibility
- Patch @radix-ui/react-compose-refs@1.1.2: stabilize useComposedRefs
to prevent infinite render loops from unstable ref callbacks
https://github.com/radix-ui/primitives/issues/3799
- Patch @radix-ui/react-slot@1.2.4: use useComposedRefs hook in
SlotClone instead of inline composeRefs to prevent re-render cycles
https://github.com/radix-ui/primitives/pull/3804
- Patch react-use-websocket@4.8.1: remove flushSync wrappers that
cause "Maximum update depth exceeded" with React 19 auto-batching
https://github.com/facebook/react/issues/27613
- Add npm overrides to ensure single hoisted copies of compose-refs
and react-slot across all Radix packages
- Add postinstall script for patch-package
- Remove leftover react-transition-group dependency
* formatting
* use availableWidth instead of useContainerWidth for grid layout
The useContainerWidth hook from react-grid-layout v2 returns raw
container width without accounting for scrollbar width, causing the
grid to not fill the full available space. Use the existing
availableWidth value from useResizeObserver which already compensates
for scrollbar width, matching the working implementation.
* remove unused carousel component and fix React 19 peer deps
Remove embla-carousel-react and its unused Carousel UI component.
Upgrade sonner v1 → v2 for native React 19 support. Remove
@types/react-icons stub (react-icons bundles its own types).
These changes eliminate all peer dependency conflicts, so
npm install works without --legacy-peer-deps.
* fix React 19 infinite re-render loop on live dashboard
The "Maximum update depth exceeded" error was caused by two issues:
1. useDeferredStreamMetadata returned a new `{}` default on every render
when SWR data was undefined, creating an unstable reference that
triggered the useEffect in useCameraLiveMode on every render cycle.
Fixed by using a stable module-level EMPTY_METADATA constant.
2. useResizeObserver's rest parameter `...refs` created a new array on
every render, causing its useEffect to re-run and re-observe elements
continuously. Fixed by stabilizing refs with useRef and only
reconnecting the observer when actual DOM elements change.
* debug replay implementation
* fix masks after dev rebase
* fix squash merge issues
* fix
* fix
* fix
* no need to write debug replay camera to config
* camera and filter button and dropdown
* add filters
* add ability to edit motion and object config for debug replay
* add debug draw overlay to debug replay
* add guard to prevent crash when camera is no longer in camera_states
* fix overflow due to radix absolutely positioned elements
* increase number of messages
* ensure deep_merge replaces existing list values when override is true
* add back button
* add debug replay to explore and review menus
* clean up
* clean up
* update instructions to prevent exposing exception info
* fix typing
* refactor output logic
* refactor with helper function
* move init to function for consistency