diff --git a/web/src/components/TimelineSummary.jsx b/web/src/components/TimelineSummary.jsx
new file mode 100644
index 000000000..cf966c6ba
--- /dev/null
+++ b/web/src/components/TimelineSummary.jsx
@@ -0,0 +1,37 @@
+import { h } from 'preact';
+import useSWR from 'swr';
+import Heading from './Heading';
+import ActivityIndicator from './ActivityIndicator';
+import { formatUnixTimestampToDateTime } from '../utils/dateUtil';
+
+export default function TimelineSummary({ event }) {
+ const { data: eventTimeline } = useSWR([
+ 'timeline',
+ {
+ source_id: event.id,
+ },
+ ]);
+
+ if (!eventTimeline) {
+ return ;
+ }
+
+ return (
+
+
Timeline:
+ {eventTimeline.map((item, index) => (
+
{getTimelineItemDescription(item, event, index)}
+ ))}
+
+ );
+}
+
+function getTimelineItemDescription(timelineItem, event, index) {
+ if (timelineItem.class_type == 'visible') {
+ return `${index}. ${event.label} detected at ${formatUnixTimestampToDateTime(event.start_time, { date_style: "short", time_style: "medium" })}`;
+ } else if (timelineItem.class_type == 'entered_zone') {
+ return `${index}. ${event.label} entered ${timelineItem.data.zones} at ${formatUnixTimestampToDateTime(event.start_time, { date_style: "short", time_style: "medium" })}`;
+ }
+
+ return `${index}. ${event.label} left at ${formatUnixTimestampToDateTime(event.start_time, { date_style: "short", time_style: "medium" })}`;
+}
diff --git a/web/src/routes/Events.jsx b/web/src/routes/Events.jsx
index 25036f505..b0696a6b1 100644
--- a/web/src/routes/Events.jsx
+++ b/web/src/routes/Events.jsx
@@ -26,6 +26,7 @@ import Dialog from '../components/Dialog';
import MultiSelect from '../components/MultiSelect';
import { formatUnixTimestampToDateTime, getDurationFromTimestamps } from '../utils/dateUtil';
import TimeAgo from '../components/TimeAgo';
+import TimelineSummary from '../components/TimelineSummary';
const API_LIMIT = 25;
@@ -560,6 +561,9 @@ export default function Events({ path, ...props }) {
{viewEvent !== event.id ? null : (