mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-09 04:35:25 +03:00
reorganize components
This commit is contained in:
parent
920f76c97c
commit
24291a2bc2
@ -11,7 +11,7 @@ import EventSegment from "./EventSegment";
|
|||||||
import { useEventUtils } from "@/hooks/use-event-utils";
|
import { useEventUtils } from "@/hooks/use-event-utils";
|
||||||
import { Event } from "@/types/event";
|
import { Event } from "@/types/event";
|
||||||
|
|
||||||
export type ReviewTimelineProps = {
|
export type EventReviewTimelineProps = {
|
||||||
segmentDuration: number;
|
segmentDuration: number;
|
||||||
timestampSpread: number;
|
timestampSpread: number;
|
||||||
timelineStart: number;
|
timelineStart: number;
|
||||||
@ -26,7 +26,7 @@ export type ReviewTimelineProps = {
|
|||||||
contentRef: RefObject<HTMLDivElement>;
|
contentRef: RefObject<HTMLDivElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ReviewTimeline({
|
export function EventReviewTimeline({
|
||||||
segmentDuration,
|
segmentDuration,
|
||||||
timestampSpread,
|
timestampSpread,
|
||||||
timelineStart,
|
timelineStart,
|
||||||
@ -39,7 +39,7 @@ export function ReviewTimeline({
|
|||||||
events,
|
events,
|
||||||
severityType,
|
severityType,
|
||||||
contentRef,
|
contentRef,
|
||||||
}: ReviewTimelineProps) {
|
}: EventReviewTimelineProps) {
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const [currentTimeSegment, setCurrentTimeSegment] = useState<number>(0);
|
const [currentTimeSegment, setCurrentTimeSegment] = useState<number>(0);
|
||||||
const scrollTimeRef = useRef<HTMLDivElement>(null);
|
const scrollTimeRef = useRef<HTMLDivElement>(null);
|
||||||
@ -203,7 +203,7 @@ export function ReviewTimeline({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={timelineRef}
|
ref={timelineRef}
|
||||||
className={`relative w-[100px] h-screen overflow-y-scroll no-scrollbar ${
|
className={`relative md:w-[100px] h-screen overflow-y-scroll no-scrollbar ${
|
||||||
isDragging && showHandlebar ? "cursor-grabbing" : "cursor-auto"
|
isDragging && showHandlebar ? "cursor-grabbing" : "cursor-auto"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@ -237,4 +237,4 @@ export function ReviewTimeline({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ReviewTimeline;
|
export default EventReviewTimeline;
|
||||||
@ -14,6 +14,109 @@ type EventSegmentProps = {
|
|||||||
severityType: string;
|
severityType: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type MinimapSegmentProps = {
|
||||||
|
isFirstSegmentInMinimap: boolean;
|
||||||
|
isLastSegmentInMinimap: boolean;
|
||||||
|
alignedMinimapStartTime: number;
|
||||||
|
alignedMinimapEndTime: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TickSegmentProps = {
|
||||||
|
isFirstSegmentInMinimap: boolean;
|
||||||
|
isLastSegmentInMinimap: boolean;
|
||||||
|
timestamp: Date;
|
||||||
|
timestampSpread: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TimestampSegmentProps = {
|
||||||
|
isFirstSegmentInMinimap: boolean;
|
||||||
|
isLastSegmentInMinimap: boolean;
|
||||||
|
timestamp: Date;
|
||||||
|
timestampSpread: number;
|
||||||
|
segmentKey: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function MinimapBounds({
|
||||||
|
isFirstSegmentInMinimap,
|
||||||
|
isLastSegmentInMinimap,
|
||||||
|
alignedMinimapStartTime,
|
||||||
|
alignedMinimapEndTime,
|
||||||
|
}: MinimapSegmentProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isFirstSegmentInMinimap && (
|
||||||
|
<div className="absolute inset-0 -bottom-5 w-full flex items-center justify-center text-xs text-primary font-medium z-20 text-center text-[9px]">
|
||||||
|
{new Date(alignedMinimapStartTime).toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
day: "2-digit",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isLastSegmentInMinimap && (
|
||||||
|
<div className="absolute inset-0 -top-1 w-full flex items-center justify-center text-xs text-primary font-medium z-20 text-center text-[9px]">
|
||||||
|
{new Date(alignedMinimapEndTime).toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
day: "2-digit",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tick({
|
||||||
|
isFirstSegmentInMinimap,
|
||||||
|
isLastSegmentInMinimap,
|
||||||
|
timestamp,
|
||||||
|
timestampSpread,
|
||||||
|
}: TickSegmentProps) {
|
||||||
|
return (
|
||||||
|
<div className="w-5 h-2 flex justify-left items-end">
|
||||||
|
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && (
|
||||||
|
<div
|
||||||
|
className={`h-0.5 ${
|
||||||
|
timestamp.getMinutes() % timestampSpread === 0 &&
|
||||||
|
timestamp.getSeconds() === 0
|
||||||
|
? "w-4 bg-gray-400"
|
||||||
|
: "w-2 bg-gray-600"
|
||||||
|
}`}
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Timestamp({
|
||||||
|
isFirstSegmentInMinimap,
|
||||||
|
isLastSegmentInMinimap,
|
||||||
|
timestamp,
|
||||||
|
timestampSpread,
|
||||||
|
segmentKey,
|
||||||
|
}: TimestampSegmentProps) {
|
||||||
|
return (
|
||||||
|
<div className="w-10 h-2 flex justify-left items-top z-10">
|
||||||
|
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && (
|
||||||
|
<div
|
||||||
|
key={`${segmentKey}_timestamp`}
|
||||||
|
className="text-[8px] text-gray-400"
|
||||||
|
>
|
||||||
|
{timestamp.getMinutes() % timestampSpread === 0 &&
|
||||||
|
timestamp.getSeconds() === 0 &&
|
||||||
|
timestamp.toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function EventSegment({
|
export function EventSegment({
|
||||||
events,
|
events,
|
||||||
segmentTime,
|
segmentTime,
|
||||||
@ -97,56 +200,39 @@ export function EventSegment({
|
|||||||
: ""
|
: ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const severityColors: { [key: number]: string } = {
|
||||||
|
1: reviewed
|
||||||
|
? "from-yellow-200/30 to-yellow-400/30"
|
||||||
|
: "from-yellow-200 to-yellow-400",
|
||||||
|
2: reviewed
|
||||||
|
? "from-orange-400/30 to-orange-600/30"
|
||||||
|
: "from-orange-400 to-orange-600",
|
||||||
|
3: reviewed ? "from-red-500/30 to-red-800/30" : "from-red-500 to-red-800",
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={segmentKey} className={segmentClasses}>
|
<div key={segmentKey} className={segmentClasses}>
|
||||||
{isFirstSegmentInMinimap && (
|
<MinimapBounds
|
||||||
<div className="absolute inset-0 -bottom-5 w-full flex items-center justify-center text-xs text-primary font-medium z-20 text-center text-[9px]">
|
isFirstSegmentInMinimap={isFirstSegmentInMinimap}
|
||||||
{new Date(alignedMinimapStartTime).toLocaleTimeString([], {
|
isLastSegmentInMinimap={isLastSegmentInMinimap}
|
||||||
hour: "2-digit",
|
alignedMinimapStartTime={alignedMinimapStartTime}
|
||||||
minute: "2-digit",
|
alignedMinimapEndTime={alignedMinimapEndTime}
|
||||||
month: "short",
|
/>
|
||||||
day: "2-digit",
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isLastSegmentInMinimap && (
|
<Tick
|
||||||
<div className="absolute inset-0 -top-1 w-full flex items-center justify-center text-xs text-primary font-medium z-20 text-center text-[9px]">
|
isFirstSegmentInMinimap={isFirstSegmentInMinimap}
|
||||||
{new Date(alignedMinimapEndTime).toLocaleTimeString([], {
|
isLastSegmentInMinimap={isLastSegmentInMinimap}
|
||||||
hour: "2-digit",
|
timestamp={timestamp}
|
||||||
minute: "2-digit",
|
timestampSpread={timestampSpread}
|
||||||
month: "short",
|
/>
|
||||||
day: "2-digit",
|
|
||||||
})}
|
<Timestamp
|
||||||
</div>
|
isFirstSegmentInMinimap={isFirstSegmentInMinimap}
|
||||||
)}
|
isLastSegmentInMinimap={isLastSegmentInMinimap}
|
||||||
<div className="w-5 h-2 flex justify-left items-end">
|
timestamp={timestamp}
|
||||||
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && (
|
timestampSpread={timestampSpread}
|
||||||
<div
|
segmentKey={segmentKey}
|
||||||
className={`h-0.5 ${
|
/>
|
||||||
timestamp.getMinutes() % timestampSpread === 0 &&
|
|
||||||
timestamp.getSeconds() === 0
|
|
||||||
? "w-4 bg-gray-400"
|
|
||||||
: "w-2 bg-gray-600"
|
|
||||||
}`}
|
|
||||||
></div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="w-10 h-2 flex justify-left items-top z-10">
|
|
||||||
{!isFirstSegmentInMinimap && !isLastSegmentInMinimap && (
|
|
||||||
<div
|
|
||||||
key={`${segmentKey}_timestamp`}
|
|
||||||
className="text-[8px] text-gray-400"
|
|
||||||
>
|
|
||||||
{timestamp.getMinutes() % timestampSpread === 0 &&
|
|
||||||
timestamp.getSeconds() === 0 &&
|
|
||||||
timestamp.toLocaleTimeString([], {
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{severity == displaySeverityType && (
|
{severity == displaySeverityType && (
|
||||||
<div className="mr-3 w-2 h-2 flex justify-left items-end">
|
<div className="mr-3 w-2 h-2 flex justify-left items-end">
|
||||||
@ -164,23 +250,7 @@ export function EventSegment({
|
|||||||
? "rounded-tl-full rounded-tr-full"
|
? "rounded-tl-full rounded-tr-full"
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${severityColors[severity]}
|
||||||
reviewed
|
|
||||||
? severity === 1
|
|
||||||
? "from-yellow-200/30 to-yellow-400/30"
|
|
||||||
: severity === 2
|
|
||||||
? "from-orange-400/30 to-orange-600/30"
|
|
||||||
: severity === 3
|
|
||||||
? "from-red-500/30 to-red-800/30"
|
|
||||||
: ""
|
|
||||||
: severity === 1
|
|
||||||
? "from-yellow-200 to-yellow-400"
|
|
||||||
: severity === 2
|
|
||||||
? "from-orange-400 to-orange-600"
|
|
||||||
: severity === 3
|
|
||||||
? "from-red-500 to-red-800"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
`}
|
`}
|
||||||
></div>
|
></div>
|
||||||
@ -203,23 +273,7 @@ export function EventSegment({
|
|||||||
? "rounded-tl-full rounded-tr-full"
|
? "rounded-tl-full rounded-tr-full"
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
${
|
${severityColors[severity]}
|
||||||
reviewed
|
|
||||||
? severity === 1
|
|
||||||
? "from-yellow-200/30 to-yellow-400/30"
|
|
||||||
: severity === 2
|
|
||||||
? "from-orange-400/30 to-orange-600/30"
|
|
||||||
: severity === 3
|
|
||||||
? "from-red-500/30 to-red-800/30"
|
|
||||||
: ""
|
|
||||||
: severity === 1
|
|
||||||
? "from-yellow-200 to-yellow-400"
|
|
||||||
: severity === 2
|
|
||||||
? "from-orange-400 to-orange-600"
|
|
||||||
: severity === 3
|
|
||||||
? "from-red-500 to-red-800"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
`}
|
`}
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { Event } from "@/types/event";
|
|||||||
import ActivityIndicator from "@/components/ui/activity-indicator";
|
import ActivityIndicator from "@/components/ui/activity-indicator";
|
||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import TimelineScrubber from "@/components/playground/TimelineScrubber";
|
import TimelineScrubber from "@/components/playground/TimelineScrubber";
|
||||||
import { ReviewTimeline } from "@/components/timeline/ReviewTimeline";
|
import EventReviewTimeline from "@/components/timeline/EventReviewTimeline";
|
||||||
|
|
||||||
// Color data
|
// Color data
|
||||||
const colors = [
|
const colors = [
|
||||||
@ -60,7 +60,7 @@ function eventsToScrubberItems(events: Event[]): ScrubberItem[] {
|
|||||||
|
|
||||||
const generateRandomEvent = (): Event => {
|
const generateRandomEvent = (): Event => {
|
||||||
const start_time = Date.now() - Math.random() * 3600000 * 3;
|
const start_time = Date.now() - Math.random() * 3600000 * 3;
|
||||||
const end_time = start_time + Math.random() * 36000;
|
const end_time = start_time + Math.random() * 360000;
|
||||||
const severities = ["motion", "detection", "alert"];
|
const severities = ["motion", "detection", "alert"];
|
||||||
const severity = severities[Math.floor(Math.random() * severities.length)];
|
const severity = severities[Math.floor(Math.random() * severities.length)];
|
||||||
const has_been_reviewed = Math.random() < 0.2;
|
const has_been_reviewed = Math.random() < 0.2;
|
||||||
@ -158,7 +158,7 @@ function UIPlayground() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-none">
|
<div className="flex-none">
|
||||||
<ReviewTimeline
|
<EventReviewTimeline
|
||||||
segmentDuration={60} // seconds per segment
|
segmentDuration={60} // seconds per segment
|
||||||
timestampSpread={15} // minutes between each major timestamp
|
timestampSpread={15} // minutes between each major timestamp
|
||||||
timelineStart={Date.now()} // start of the timeline - all times are numeric, not Date objects
|
timelineStart={Date.now()} // start of the timeline - all times are numeric, not Date objects
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user