Improve graph using pandas (#9234)

* Ensure viewport is always full screen

* Protect against hour with no cards and ensure data is consistent

* Reduce grouped up image refreshes

* Include current hour and fix scrubbing bugginess

* Scroll initially selected timeline in to view

* Expand timelne class type

* Use poster image for preview on video player instead of using separate image view

* Fix available streaming modes

* Incrase timing for grouping timline items

* Fix audio activity listener

* Fix player not switching views correctly

* Use player time to convert to timeline time

* Update sub labels for previous timeline items

* Show mini timeline bar for non selected items

* Rewrite desktop timeline to use separate dynamic video player component

* Extend improvements to mobile as well

* Improve time formatting

* Fix scroll

* Fix no preview case

* Mobile fixes

* Audio toggle fixes

* More fixes for mobile

* Improve scaling of graph motion activity

* Add keyboard shortcut hook and support shortcuts for playback page

* Fix sizing of dialog

* Improve height scaling of dialog

* simplify and fix layout system for timeline

* Fix timeilne items not working

* Implement basic Frigate+ submitting from timeline
This commit is contained in:
Nicolas Mowen
2024-01-31 05:29:18 -07:00
committed by Blake Blackshear
parent 9c4b69191b
commit af3f6dadcb
28 changed files with 1379 additions and 852 deletions

View File

@@ -6,6 +6,20 @@ import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import VideoPlayer from "../player/VideoPlayer";
import { Card } from "../ui/card";
import { useApiHost } from "@/api";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "../ui/alert-dialog";
import { useCallback } from "react";
import axios from "axios";
type TimelineItemCardProps = {
timeline: Timeline;
@@ -18,37 +32,55 @@ export default function TimelineItemCard({
onSelect,
}: TimelineItemCardProps) {
const { data: config } = useSWR<FrigateConfig>("config");
const apiHost = useApiHost();
const onSubmitToPlus = useCallback(
async (falsePositive: boolean) => {
falsePositive
? await axios.put(`events/${timeline.source_id}/false_positive`)
: await axios.post(`events/${timeline.source_id}/plus`, {
include_annotation: 1,
});
},
[timeline]
);
return (
<Card className="relative m-2 flex w-full h-32 cursor-pointer" onClick={onSelect}>
<div className="w-1/2 p-2">
{relevantPreview && (
<VideoPlayer
options={{
preload: "auto",
height: "114",
width: "202",
autoplay: true,
controls: false,
fluid: false,
muted: true,
loadingSpinner: false,
sources: [
{
src: `${relevantPreview.src}`,
type: "video/mp4",
},
],
}}
seekOptions={{}}
onReady={(player) => {
<Card
className="relative m-2 flex w-full h-20 xl:h-24 3xl:h-28 4xl:h-36 cursor-pointer"
onClick={onSelect}
>
<div className="w-32 xl:w-40 3xl:w-44 4xl:w-60 p-2">
<VideoPlayer
options={{
preload: "auto",
autoplay: true,
controls: false,
aspectRatio: "16:9",
muted: true,
loadingSpinner: false,
poster: relevantPreview
? ""
: `${apiHost}api/preview/${timeline.camera}/${timeline.timestamp}/thumbnail.jpg`,
sources: relevantPreview
? [
{
src: `${relevantPreview.src}`,
type: "video/mp4",
},
]
: [],
}}
seekOptions={{}}
onReady={(player) => {
if (relevantPreview) {
player.pause(); // autoplay + pause is required for iOS
player.currentTime(timeline.timestamp - relevantPreview.start);
}}
/>
)}
}
}}
/>
</div>
<div className="px-2 py-1 w-1/2">
<div className="py-1">
<div className="capitalize font-semibold text-sm">
{getTimelineItemDescription(timeline)}
</div>
@@ -60,16 +92,52 @@ export default function TimelineItemCard({
date_style: "medium",
})}
</div>
<Button
className="absolute bottom-1 right-1"
size="sm"
variant="secondary"
>
<div className="w-8 h-8">
<Logo />
</div>
+
</Button>
{timeline.source == "tracked_object" && (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
className="absolute bottom-1 right-1 hidden xl:flex"
size="sm"
variant="secondary"
>
<div className="w-8 h-8">
<Logo />
</div>
+
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Submit To Frigate+</AlertDialogTitle>
<AlertDialogDescription>
Objects in locations you want to avoid are not false
positives. Submitting them as false positives will confuse the
model.
</AlertDialogDescription>
</AlertDialogHeader>
<img
className="flex-grow-0"
src={`${apiHost}api/events/${timeline.source_id}/snapshot.jpg`}
alt={`${timeline.data.label}`}
/>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
className="bg-success"
onClick={() => onSubmitToPlus(false)}
>
This is a {timeline.data.label}
</AlertDialogAction>
<AlertDialogAction
className="bg-danger"
onClick={() => onSubmitToPlus(true)}
>
This is not a {timeline.data.label}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
</div>
</Card>
);