mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-09-26 19:41:29 +08:00
Fixes (#18552)
* Ensure config editor recalculates layout on error * ensure empty lists are returned when lpr recognition model fails * Add docs section for session_length * clarify Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * clarify Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Catch missing file * Improve graph axis colors * Ensure playback rate controls are portaled to the video container in history view On larger tablets in landscape view, the playback rate dropdown disappeared underneath the bottom bar. This small change ensures we use the correct container on the DropdownMenuContent so that the div is portaled correctly. The VideoControls are also used in motion review which does not pass in a container ref, so we can just fall back to the existing controlsContainer ref when it's undefined. --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
@@ -106,6 +106,9 @@ export function CameraLineGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@@ -118,6 +121,9 @@ export function CameraLineGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
@@ -138,7 +144,7 @@ export function CameraLineGraph({
|
||||
className="size-2"
|
||||
style={{ color: GRAPH_COLORS[labelIdx] }}
|
||||
/>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<div className="text-xs text-secondary-foreground">
|
||||
{t("cameras.label." + label)}
|
||||
</div>
|
||||
<div className="text-xs text-primary">
|
||||
@@ -243,6 +249,9 @@ export function EventsPerSecondsLineGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@@ -255,6 +264,9 @@ export function EventsPerSecondsLineGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
@@ -268,7 +280,7 @@ export function EventsPerSecondsLineGraph({
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="text-xs text-muted-foreground">{name}</div>
|
||||
<div className="text-xs text-secondary-foreground">{name}</div>
|
||||
<div className="text-xs text-primary">
|
||||
{lastValue}
|
||||
{unit}
|
||||
|
@@ -138,6 +138,9 @@ export function ThresholdBarGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@@ -150,6 +153,9 @@ export function ThresholdBarGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
max: yMax,
|
||||
@@ -180,7 +186,7 @@ export function ThresholdBarGraph({
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="text-xs text-muted-foreground">{name}</div>
|
||||
<div className="text-xs text-secondary-foreground">{name}</div>
|
||||
<div className="text-xs text-primary">
|
||||
{lastValue}
|
||||
{unit}
|
||||
|
@@ -250,7 +250,9 @@ export default function VideoControls({
|
||||
>
|
||||
<DropdownMenuTrigger>{`${playbackRate}x`}</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
portalProps={{ container: controlsContainerRef.current }}
|
||||
portalProps={{
|
||||
container: containerRef?.current ?? controlsContainerRef.current,
|
||||
}}
|
||||
>
|
||||
<DropdownMenuRadioGroup
|
||||
onValueChange={(rate) => onSetPlaybackRate(parseFloat(rate))}
|
||||
|
@@ -209,13 +209,24 @@ function ConfigEditor() {
|
||||
};
|
||||
}, [hasChanges, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (editorRef.current) {
|
||||
// Small delay to ensure DOM has updated
|
||||
const timeoutId = setTimeout(() => {
|
||||
editorRef.current?.layout();
|
||||
}, 0);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
if (!config) {
|
||||
return <ActivityIndicator />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-2 left-0 right-0 top-2 md:left-2">
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<div className="relative flex h-full flex-col overflow-hidden">
|
||||
<div className="mr-1 flex items-center justify-between">
|
||||
<Heading as="h2" className="mb-0 ml-1 md:ml-0">
|
||||
{t("configEditor")}
|
||||
@@ -254,13 +265,14 @@ function ConfigEditor() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-2 max-h-[30%] overflow-auto whitespace-pre-wrap border-2 border-muted bg-background_alt p-4 text-sm text-danger md:max-h-[40%]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div ref={configRef} className="mt-2 h-[calc(100%-2.75rem)]" />
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
{error && (
|
||||
<div className="mt-2 max-h-[30%] min-h-[2.5rem] overflow-auto whitespace-pre-wrap border-2 border-muted bg-background_alt p-4 text-sm text-danger md:max-h-[40%]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
<div ref={configRef} className="flex-1 overflow-hidden" />
|
||||
</div>
|
||||
</div>
|
||||
<Toaster closeButton={true} />
|
||||
<RestartDialog
|
||||
|
Reference in New Issue
Block a user