diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index 7926a6292..1e3c8db92 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -140,14 +140,17 @@ export default function PreviewThumbnailPlayer({ /> {!hover && (review.severity == "alert" || review.severity == "detection") && ( -
+
{review.data.objects.map((object) => { - return getIconForLabel(object); + return getIconForLabel(object, "w-3 h-3 text-white"); + })} + {review.data.audio.map((audio) => { + return getIconForLabel(audio, "w-3 h-3 text-white"); })}
)} {!hover && ( -
+
{config && formatUnixTimestampToDateTime(review.start_time, { diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index 453ab196b..ea72b5efd 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -18,7 +18,7 @@ import { MdCircle } from "react-icons/md"; import useSWR from "swr"; import useSWRInfinite from "swr/infinite"; -const API_LIMIT = 20; +const API_LIMIT = 100; export default function Events() { const { data: config } = useSWR("config"); @@ -37,7 +37,7 @@ export default function Events() { if (index > 0) { const lastDate = prevData[prevData.length - 1].start_time; const pagedParams = reviewSearchParams - ? { before: lastDate, limit: API_LIMIT, severity: severity } + ? { before: lastDate, limit: API_LIMIT } : { ...reviewSearchParams, before: lastDate, @@ -47,7 +47,7 @@ export default function Events() { } const params = reviewSearchParams - ? { limit: API_LIMIT, severity: severity } + ? { limit: API_LIMIT } : { ...reviewSearchParams, limit: API_LIMIT }; return ["review", params]; }, @@ -62,6 +62,30 @@ export default function Events() { isValidating, } = useSWRInfinite(getKey, reviewSegmentFetcher); + const reviewItems = useMemo(() => { + const alerts: ReviewSegment[] = []; + const detections: ReviewSegment[] = []; + const motion: ReviewSegment[] = []; + + reviewPages?.forEach((page) => { + page.forEach((segment) => { + switch (segment.severity) { + case "alert": + alerts.push(segment); + break; + case "detection": + detections.push(segment); + break; + default: + motion.push(segment); + break; + } + }); + }); + + return { alert: alerts, detection: detections, significant_motion: motion }; + }, [reviewPages]); + const isDone = useMemo( () => (reviewPages?.at(-1)?.length ?? 0) < API_LIMIT, [reviewPages] @@ -185,38 +209,35 @@ export default function Events() {
- {reviewPages?.map((reviewSegments, pageIdx) => { - return reviewSegments.map((value, segIdx) => { - const lastRow = - pageIdx == size - 1 && segIdx == reviewSegments.length - 1; - const detectConfig = config.cameras[value.camera].detect; - const relevantPreview = Object.values(allPreviews || []).find( - (preview) => - preview.camera == value.camera && - preview.start < value.start_time && - preview.end > value.end_time - ); + {reviewItems[severity]?.map((value, segIdx) => { + const lastRow = segIdx == reviewItems[severity].length - 1; + const detectConfig = config.cameras[value.camera].detect; + const relevantPreview = Object.values(allPreviews || []).find( + (preview) => + preview.camera == value.camera && + preview.start < value.start_time && + preview.end > value.end_time + ); - return ( -
-
- setReviewed(value.id)} - /> -
- {lastRow && !isDone && } + return ( +
+
+ setReviewed(value.id)} + />
- ); - }); + {lastRow && !isDone && } +
+ ); })}