diff --git a/web/src/routes/Events.jsx b/web/src/routes/Events.jsx index b0afff971..912293b69 100644 --- a/web/src/routes/Events.jsx +++ b/web/src/routes/Events.jsx @@ -31,6 +31,9 @@ import Timepicker from '../components/TimePicker'; import TimelineSummary from '../components/TimelineSummary'; import TimelineEventOverlay from '../components/TimelineEventOverlay'; import { Score } from '../icons/Score'; +import { About } from '../icons/About'; +import MenuIcon from '../icons/Menu'; +import { MenuOpen } from '../icons/MenuOpen'; const API_LIMIT = 25; @@ -91,13 +94,15 @@ export default function Events({ path, ...props }) { showDeleteFavorite: false, }); + const [showInProgress, setShowInProgress] = useState(true); + const eventsFetcher = useCallback( (path, params) => { if (searchParams.event) { path = `${path}/${searchParams.event}`; return axios.get(path).then((res) => [res.data]); } - params = { ...params, include_thumbnails: 0, limit: API_LIMIT }; + params = { ...params, in_progress: 0, include_thumbnails: 0, limit: API_LIMIT }; return axios.get(path, { params }).then((res) => res.data); }, [searchParams] @@ -116,6 +121,7 @@ export default function Events({ path, ...props }) { [searchParams] ); + const { data: ongoingEvents } = useSWR(['events', { in_progress: 1, include_thumbnails: 0 }]); const { data: eventPages, mutate, size, setSize, isValidating } = useSWRInfinite(getKey, eventsFetcher); const { data: allLabels } = useSWR(['labels']); @@ -604,6 +610,217 @@ export default function Events({ path, ...props }) { )}
+ {ongoingEvents ? ( +
+
+ + Ongoing Events + + + +
+ {showInProgress && ongoingEvents.map((event, _) => { + return ( + +
(viewEvent === event.id ? setViewEvent(null) : setViewEvent(event.id))} + > +
+ onSave(e, event.id, !event.retain_indefinitely)} + fill={event.retain_indefinitely ? 'currentColor' : 'none'} + /> + {event.end_time ? null : ( +
+ In progress +
+ )} +
+
+
+
+ {event.label.replaceAll('_', ' ')} + {event.sub_label ? `: ${event.sub_label.replaceAll('_', ' ')}` : null} +
+ +
+ + {formatUnixTimestampToDateTime(event.start_time, { ...config.ui })} +
+ - + +
+
+ ( {getDurationFromTimestamps(event.start_time, event.end_time)} ) +
+
+
+ + {event.camera.replaceAll('_', ' ')} +
+ {event.zones.length ? ( +
+ + {event.zones.join(', ').replaceAll('_', ' ')} +
+ ) : null} +
+ + {(event?.data?.top_score || event.top_score || 0) == 0 + ? null + : `${event.label}: ${((event?.data?.top_score || event.top_score) * 100).toFixed(0)}%`} + {(event?.data?.sub_label_score || 0) == 0 + ? null + : `, ${event.sub_label}: ${(event?.data?.sub_label_score * 100).toFixed(0)}%`} +
+
+ +
+ onDelete(e, event.id, event.retain_indefinitely)} + /> + + onDownloadClick(e, event)} + /> +
+
+
+ {viewEvent !== event.id ? null : ( +
+
+
+ + + + +
+ +
+ {eventDetailType == 'clip' && event.has_clip ? ( +
+ + onEventFrameSelected(event, frame, seekSeconds) + } + /> +
+ { + this.player = player; + this.player.on('playing', () => { + setEventOverlay(undefined); + }); + }} + onDispose={() => { + this.player = null; + }} + > + {eventOverlay ? ( + + ) : null} + +
+
+ ) : null} + + {eventDetailType == 'image' || !event.has_clip ? ( +
+ {`${event.label} +
+ ) : null} +
+
+
+ )} +
+ ); + })} +
+ ) : null} + + Past Events + {eventPages ? ( eventPages.map((page, i) => { const lastPage = eventPages.length === i + 1;