* 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:
Josh Hawkins
2025-06-04 20:48:26 -05:00
committed by GitHub
parent dba9206898
commit ed43df9c13
7 changed files with 63 additions and 13 deletions

View File

@@ -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}

View File

@@ -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}

View File

@@ -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))}

View File

@@ -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