mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-06-21 20:01:54 +03:00
* hide camera overrides badge from system sections * show empty card on camera metrics page when no cameras are defined * fix enabled camera state switch after adding via wizard Cameras added mid-session have no WS state until the dispatcher publishes camera_activity (which only happens on a fresh onConnect). Fall back to the config's enabled value so the switch reflects reality immediately after the wizard closes. * guard camera enabled access console would throw errors after adding via camera wizard * fix useOptimisticState dropping debounced setState under StrictMode * use openvino on cpu as default model - faster than tflite on cpu - add to default generated config * use an enum for model_size the frontend will then render this as a select dropdown because of the changes in the json schema * i18n * sync object filter entries with tracked labels in camera config form Filter sub-collapsibles in the camera Objects section are driven by `filters` dict keys, but profile merges and live track-switch edits don't add matching entries, so newly tracked labels (like from a profile override) had no collapsible. Synthesize default filter entries from `track` in the form data so every tracked label renders a collapsible; baseline data also gets the synthesized entries, so save payloads are unchanged. * revalidate raw paths cache after config save so CameraPathWidget shows fresh credentials * fix test * restore masked ffmpeg credentials when persisting camera config * formatting * rebuild ffmpeg commands when enabling recording for the first time Toggling record.enabled from the config UI updated the in-memory config but left ffmpeg running with its original command, so the record output args were never wired in and nothing landed in the cache for the maintainer to move. The record config update now rebuilds ffmpeg_cmds when enabled_in_config transitions, and the camera watchdog restarts ffmpeg on a false to true transition so the record output gets wired in. MQTT toggles, which only flip record.enabled at runtime, are unaffected and continue to work via the maintainer's drop/keep gate. * keep record toggle switch in single camera view disabled until enabled in config * fix override detection for sections unset in the global config Override badges and the blue dot now compare against schema defaults for sections like motion that the API serializes as null when omitted from the global YAML, instead of treating any populated camera config as an override * add support for config-aware patterns in section hiddenFields Section configs can now declare dynamic hidden-field entries as functions of the loaded config; objects.ts uses this to hide auto-populated attribute filters (DHL, face, license_plate, etc.) from the form, save flow, and override popover when those labels aren't user-settable * siimplify object filters handling live updating was getting very messy. users will just need to save once they enable a new object in order to see filters for that object * tweaks * update docs for new detector default * make genai provider required and add special case for UI prevent validation errors from appearing on initial creation of genai provider by setting the first option in the select dropdown as default
49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
import { useState, useEffect, useCallback } from "react";
|
|
|
|
type OptimisticStateResult<T> = [T, (newValue: T) => void];
|
|
|
|
const useOptimisticState = <T>(
|
|
currentState: T,
|
|
setState: (newValue: T) => void,
|
|
delay: number = 20,
|
|
): OptimisticStateResult<T> => {
|
|
const [optimisticValue, setOptimisticValue] = useState<T>(currentState);
|
|
|
|
const handleValueChange = useCallback((newValue: T) => {
|
|
// Update the optimistic value immediately
|
|
setOptimisticValue(newValue);
|
|
}, []);
|
|
|
|
// Push the optimistic value to the real setter after the delay. Scoping
|
|
// this to an effect keyed on optimisticValue ensures the cleanup only
|
|
// cancels the timer for the value it scheduled — so StrictMode's
|
|
// effect-rerun (and future re-running mechanisms) reschedules cleanly
|
|
// instead of dropping the pending update on the floor.
|
|
useEffect(() => {
|
|
if (Object.is(optimisticValue, currentState)) {
|
|
return;
|
|
}
|
|
const id = setTimeout(() => setState(optimisticValue), delay);
|
|
return () => clearTimeout(id);
|
|
}, [optimisticValue, currentState, delay, setState]);
|
|
|
|
// External updates to currentState should win over a stale optimistic value.
|
|
// The guard matters under StrictMode: this effect's re-run captures the
|
|
// *old* currentState in its closure, so without the equality check it
|
|
// would clobber an optimistic update that another effect (e.g. a search
|
|
// param sync) made earlier in the same commit.
|
|
useEffect(() => {
|
|
if (!Object.is(currentState, optimisticValue)) {
|
|
setOptimisticValue(currentState);
|
|
}
|
|
// sometimes an external action will cause the currentState to change
|
|
// without handleValueChange being called. In this case
|
|
// we need to update the optimistic value so the UI reflects the change
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [currentState]);
|
|
|
|
return [optimisticValue, handleValueChange];
|
|
};
|
|
|
|
export default useOptimisticState;
|