mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +03:00
Add Detail stream in History view (#20525)
* new type * activity stream panel * use context provider for activity stream * new activity stream panel in history view * overlay for object tracking details in history view * use overlay in video player * don't refetch timeline * fix activity stream group from being highlighted prematurely * use annotation offset * fix scrolling and use custom hook for interaction * memoize to prevent unnecessary renders * i18n and timestamp formatting * add annotation offset slider * bg color * add collapsible component * refactor * rename activity to detail * fix merge conflicts * i18n * more i18n
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { Slider } from "@/components/ui/slider";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useDetailStream } from "@/context/detail-stream-context";
|
||||
import axios from "axios";
|
||||
import { useSWRConfig } from "swr";
|
||||
import { toast } from "sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export default function AnnotationOffsetSlider({ className }: Props) {
|
||||
const { annotationOffset, setAnnotationOffset, camera } = useDetailStream();
|
||||
const { mutate } = useSWRConfig();
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(values: number[]) => {
|
||||
if (!values || values.length === 0) return;
|
||||
const valueMs = values[0];
|
||||
setAnnotationOffset(valueMs);
|
||||
},
|
||||
[setAnnotationOffset],
|
||||
);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setAnnotationOffset(0);
|
||||
}, [setAnnotationOffset]);
|
||||
|
||||
const save = useCallback(async () => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
// save value in milliseconds to config
|
||||
await axios.put(
|
||||
`config/set?cameras.${camera}.detect.annotation_offset=${annotationOffset}`,
|
||||
{ requires_restart: 0 },
|
||||
);
|
||||
|
||||
toast.success(
|
||||
t("objectLifecycle.annotationSettings.offset.toast.success", {
|
||||
camera,
|
||||
}),
|
||||
{ position: "top-center" },
|
||||
);
|
||||
|
||||
// refresh config
|
||||
await mutate("config");
|
||||
} catch (e: unknown) {
|
||||
const err = e as {
|
||||
response?: { data?: { message?: string } };
|
||||
message?: string;
|
||||
};
|
||||
const errorMessage =
|
||||
err?.response?.data?.message || err?.message || "Unknown error";
|
||||
toast.error(t("toast.save.error.title", { errorMessage, ns: "common" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, [annotationOffset, camera, mutate, t]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`absolute bottom-0 left-0 right-0 z-30 flex items-center gap-3 bg-background p-3 ${className ?? ""}`}
|
||||
style={{ pointerEvents: "auto" }}
|
||||
>
|
||||
<div className="w-56 text-sm">
|
||||
Annotation offset (ms): {annotationOffset}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<Slider
|
||||
value={[annotationOffset]}
|
||||
min={-1500}
|
||||
max={1500}
|
||||
step={50}
|
||||
onValueChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="ghost" onClick={reset}>
|
||||
Reset
|
||||
</Button>
|
||||
<Button size="sm" onClick={save} disabled={isSaving}>
|
||||
{isSaving
|
||||
? t("button.saving", { ns: "common" })
|
||||
: t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -174,7 +174,7 @@ export function AnnotationSettingsPane({
|
||||
{t("objectLifecycle.annotationSettings.offset.label")}
|
||||
</FormLabel>
|
||||
<div className="flex flex-col gap-3 md:flex-row-reverse md:gap-8">
|
||||
<div className="flex flex-row items-center gap-3 rounded-lg bg-destructive/50 p-3 text-sm text-primary-variant md:my-0 md:my-5">
|
||||
<div className="flex flex-row items-center gap-3 rounded-lg bg-destructive/50 p-3 text-sm text-primary-variant md:my-5">
|
||||
<PiWarningCircle className="size-24" />
|
||||
<div>
|
||||
<Trans ns="views/explore">
|
||||
|
||||
Reference in New Issue
Block a user