Commit Graph

608 Commits

Author SHA1 Message Date
Claude
5e40dbbcd2
fix: reliably init grid width on page refresh using useLayoutEffect
useResizeObserver reads ref.current at render time; on page refresh with
fast SWR cache, no re-render occurs after mount so ref.current remains null
in the effect, observation never starts, and containerWidth stays 0 forever.

Add a useLayoutEffect that measures offsetWidth synchronously before paint
as a seed value (effectiveWidth = containerWidth || initialWidth). Once
ResizeObserver fires normally, containerWidth takes over. The Responsive
grid is gated on effectiveWidth > 0 so it always renders correctly on both
first load and refresh.

https://claude.ai/code/session_01H1sqbcFmtwwsdNTJcJHJWd
2026-03-15 11:32:13 +00:00
Claude
d39590604f
fix: prevent grid right-edge overflow by gating Responsive on containerWidth
Gate <Responsive> rendering on containerWidth > 0 so it only mounts after
ResizeObserver has measured the container. Use availableWidth directly as
the width prop (no window.innerWidth fallback) since the component now only
renders when containerWidth is known. This prevents the grid from rendering
wider than its container (which caused the rightmost column to overflow the
right edge).

https://claude.ai/code/session_01H1sqbcFmtwwsdNTJcJHJWd
2026-03-15 11:03:26 +00:00
Claude
84f3b16461
Fix DraggableGridLayout initial height collapse due to nullish coalescing bug
availableWidth starts at 0 (not null/undefined) before ResizeObserver fires.
The ?? operator passes 0 through instead of falling back to window.innerWidth,
making cellHeight negative and causing react-grid-layout to render a ~10px
container. The overflow-x-hidden div then becomes an implicit scroll container,
producing the 'cards squeezed in a small rectangle' symptom.

Changing ?? to || makes 0 trigger the window.innerWidth fallback, giving a
reasonable initial rowHeight until the real container width is measured.

https://claude.ai/code/session_01H1sqbcFmtwwsdNTJcJHJWd
2026-03-15 10:15:52 +00:00
ibs0d
a0ca322129
revert Update RecordingView.tsx 2026-03-15 14:31:11 +11:00
ibs0d
86de033f74
Merge branch 'blakeblackshear:dev' into dev 2026-03-15 13:55:05 +11:00
ibs0d
0c78103e56
Revert "Claude/fix video stretch history ans qf" 2026-03-15 13:38:11 +11:00
ibs0d
14709511f0
Revert "Claude/fix video stretch history ans qf" 2026-03-15 13:37:31 +11:00
ibs0d
b6b3c970c2
Revert "Add config useSWR to DetectionReview component" 2026-03-15 13:36:49 +11:00
ibs0d
f35a257844
Update RecordingView.tsx 2026-03-14 16:34:48 +11:00
Claude
128f016b5a
Add config useSWR to DetectionReview component
config was referenced but not available in DetectionReview scope.

https://claude.ai/code/session_01EwdaKGsrRLZ74smmCQ1MgW
2026-03-14 04:08:12 +00:00
Claude
0dd59b1409
Fix review card aspect ratio using camera's actual detect dimensions
Hard-coded aspect-video (16:9) caused stretching for non-16:9 cameras.
Now uses camera detect.width/detect.height from config, falling back to 16:9.

https://claude.ai/code/session_01EwdaKGsrRLZ74smmCQ1MgW
2026-03-13 21:13:55 +00:00
Claude
93a5f2691c
Use fill object-fit in draggable grid, contain elsewhere
Grid tiles explicitly set --frigate-mse-object-fit:fill so video stretches
to fill the card without preserving aspect ratio. The MsePlayer default
is contain, so History preview and all other contexts keep correct proportions.

https://claude.ai/code/session_01EwdaKGsrRLZ74smmCQ1MgW
2026-03-13 11:24:08 +00:00
Josh Hawkins
324953d3a5
UI tweaks (#22405)
Some checks failed
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
* 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
2026-03-12 16:57:42 -06:00
Josh Hawkins
9cbd80d981
Add motion previews filter (#22347)
* add ability to filter motion previews via heatmap grid

* i18n

* use dialog on mobile
2026-03-09 14:14:13 -06:00
ibs0d
1e238d2fe2
Revert "Expose mediaContentStyle on LivePlayer and pass through to MSEPlayer and still image" 2026-03-09 15:34:41 +11:00
ibs0d
078b6f62a7 Revert non-MSE style props from live players 2026-03-09 15:07:43 +11:00
ibs0d
626c05179e Restore live grid card zoom at grid layout layer 2026-03-09 14:15:46 +11:00
ibs0d
171688445d Revert LivePlayer transform wrapper regression 2026-03-09 13:57:16 +11:00
ibs0d
534b6ced19 Fix passive wheel listener for live grid card zoom 2026-03-09 12:47:39 +11:00
ibs0d
6940713054 Fix grid live zoom so overlays stay anchored 2026-03-09 12:14:05 +11:00
ibs0d
7969930d21 Persist per-camera live grid zoom state 2026-03-09 11:37:28 +11:00
ibs0d
bf622d5ff7 Add independent shift+wheel zoom for draggable live cards 2026-03-09 10:48:58 +11:00
ibs0d
1820f222ef
Revert "Add live zoom config and helpers for player/debug modes" 2026-03-09 10:16:46 +11:00
ibs0d
6ddfbf3d46
Revert "refactor(live): use shared live-zoom helpers in LiveCameraView" 2026-03-09 10:16:17 +11:00
ibs0d
71327cd94a
Revert "Add cursor-relative shift-wheel zoom and refactor live zoom utilities" 2026-03-09 10:15:43 +11:00
Josh Hawkins
dd9497baf2
Add ability to delete cameras (#22336)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* refactor camera cleanup code to generic util

* add api endpoint for deleting a camera

* frontend

* i18n

* clean up
2026-03-08 16:23:48 -06:00
Josh Hawkins
df27e04c0f
Frontend updates (#22327)
* 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
2026-03-08 12:27:53 -05:00
ibs0d
de9878f5fd Clamp live zoom scale and align wheel coordinates to transform viewport 2026-03-08 23:48:37 +11:00
ibs0d
c9283f5990 refactor: use shared live zoom helpers in camera view 2026-03-08 23:31:00 +11:00
ibs0d
36e9c63e91 refactor(web): trim live zoom module to shared primitives only 2026-03-08 23:21:42 +11:00
ibs0d
e398ec5f03 Fix rotated MSE sizing in draggable live grid 2026-03-08 22:18:25 +11:00
ibs0d
3a0d71c47b
Update DraggableGridLayout.tsx 2026-03-08 21:25:46 +11:00
ibs0d
5ee023f5a4 Add grid-only MSE rotation for cameras with ui.rotate 2026-03-08 21:24:02 +11:00
ibs0d
52b14cabf3
Update DraggableGridLayout.tsx 2026-03-08 20:24:07 +11:00
ibs0d
937460abd0 Make draggable live grid MSE video use cover fit 2026-03-08 19:27:11 +11:00
ibs0d
3bc6f59e5e Simplify live grid camera tile sizing 2026-03-08 18:06:07 +11:00
ibs0d
20c060ed8f
Revert "Add per-camera dashboard rotation and cover-fit support for live views" 2026-03-08 16:51:34 +11:00
ibs0d
85ade0a615 Harden dashboard transform behavior and add LivePlayer gating test 2026-03-08 15:12:41 +11:00
ibs0d
9f05a677e2 Apply requested live view/player tuning changes 2026-03-08 13:57:38 +11:00
ibs0d
22910292aa Update storage overview totals and section order 2026-03-07 22:58:20 +11:00
ibs0d
9f5d93e723 Fix recordings root attribution to use DB paths 2026-03-07 12:17:17 +11:00
Josh Hawkins
c2e667c0dd
Add dynamic configuration for more fields (#22295)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* 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
2026-03-06 13:45:39 -07:00
Josh Hawkins
c9bd907721
Frontend fixes (#22294)
* 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
2026-03-06 13:41:15 -07:00
Josh Hawkins
2babfd2ec9
Improve motion review and add motion search (#22253)
* implement motion search and motion previews

* tweaks

* fix merge issue

* fix copilot instructions
2026-03-05 17:53:48 -06:00
Josh Hawkins
229436c94a
Add ability to clear region grids from the frontend (#22277)
* backend

* frontend

* i18n

* tweaks
2026-03-05 16:19:30 -07:00
Josh Hawkins
2782931c72
Update frontend to React 19 (#22275)
* 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.
2026-03-05 07:42:38 -07:00
Josh Hawkins
95956a690b
Debug replay (#22212)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* 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
2026-03-04 10:07:34 -06:00
Michal Srb
c3c27d036f
Hide hidden camera alerts (#22226)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
Cameras that have `ui.dashboard = false` config are hidden from
the All Cameras "default" group, but their alerts still appear in the
top row. This hides the alerts as well.

One can still view the hidden cameras and their alerts by making a
custom camera group.
2026-03-03 06:29:57 -07:00
Josh Hawkins
1f1d546326
fix masks and zones layout issues at high browser zoom levels (#22181)
Some checks failed
CI / AMD64 Build (push) Has been cancelled
CI / ARM Build (push) Has been cancelled
CI / Jetson Jetpack 6 (push) Has been cancelled
CI / AMD64 Extra Build (push) Has been cancelled
CI / ARM Extra Build (push) Has been cancelled
CI / Synaptics Build (push) Has been cancelled
CI / Assemble and push default build (push) Has been cancelled
2026-03-01 13:41:33 -07:00
Josh Hawkins
6a21b2952d
Masks and zones improvements (#22163)
* migrator and runtime config changes

* component changes to use rasterized_mask

* frontend

* convert none to empty string for config save

* i18n

* update tests

* add enabled config to zones

* zones frontend

* i18n

* docs

* tweaks

* use dashed stroke to indicate disabled

* allow toggle from icon

* use filelock to ensure atomic config updates from endpoint

* enforce atomic config update in the frontend

* toggle via mqtt

* fix global object masks

* correctly handle global object masks in dispatcher

* ws hooks

* render masks and zones based on ws enabled state

* use enabled_in_config for zones and masks

* frontend for enabled_in_config

* tweaks

* i18n

* publish websocket on config save

* i18n tweaks

* pydantic title and description

* i18n generation

* tweaks

* fix typing
2026-02-28 07:04:43 -07:00