diff --git a/web/package-lock.json b/web/package-lock.json index e4d53d791..f896f7c8a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -58,7 +58,6 @@ "vaul": "^0.8.0", "video.js": "^8.6.1", "videojs-playlist": "^5.1.0", - "vis-timeline": "^7.7.3", "vite-plugin-monaco-editor": "^1.1.0", "zod": "^3.22.4" }, @@ -218,18 +217,6 @@ "resolved": "https://registry.npmjs.org/@cycjimmy/jsmpeg-player/-/jsmpeg-player-6.0.5.tgz", "integrity": "sha512-bVNHQ7VN9ecKT5AI/6RC7zpW/y4ca68a9txeR5Wiin+jKpUn/7buMe+5NPub89A8NNeNnKPQfrD2+c76ch36mA==" }, - "node_modules/@egjs/hammerjs": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", - "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", - "peer": true, - "dependencies": { - "@types/hammerjs": "^2.0.36" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/@esbuild/android-arm": { "version": "0.19.8", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.8.tgz", @@ -2556,12 +2543,6 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true }, - "node_modules/@types/hammerjs": { - "version": "2.0.45", - "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.45.tgz", - "integrity": "sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==", - "peer": true - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -3714,15 +3695,6 @@ "node": ">= 6" } }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3782,12 +3754,6 @@ "node": ">=4" } }, - "node_modules/cssfilter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", - "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==", - "peer": true - }, "node_modules/cssstyle": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", @@ -5374,12 +5340,6 @@ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, - "node_modules/keycharm": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz", - "integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==", - "peer": true - }, "node_modules/keycode": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", @@ -5680,15 +5640,6 @@ "node": ">= 8" } }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/monaco-editor": { "version": "0.44.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", @@ -6547,15 +6498,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/propagating-hammerjs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz", - "integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==", - "peer": true, - "peerDependencies": { - "@egjs/hammerjs": "^2.0.17" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -8010,19 +7952,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "peer": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", @@ -8110,57 +8039,6 @@ "global": "^4.3.1" } }, - "node_modules/vis-data": { - "version": "7.1.9", - "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.9.tgz", - "integrity": "sha512-COQsxlVrmcRIbZMMTYwD+C2bxYCFDNQ2EHESklPiInbD/Pk3JZ6qNL84Bp9wWjYjAzXfSlsNaFtRk+hO9yBPWA==", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/visjs" - }, - "peerDependencies": { - "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "vis-util": "^5.0.1" - } - }, - "node_modules/vis-timeline": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.7.3.tgz", - "integrity": "sha512-hGMzTttdOFWaw1PPlJuCXU2/4UjnsIxT684Thg9fV6YU1JuKZJs3s3BrJgZ4hO3gu5i1hsMe1YIi96o+eNT0jg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/visjs" - }, - "peerDependencies": { - "@egjs/hammerjs": "^2.0.0", - "component-emitter": "^1.3.0", - "keycharm": "^0.2.0 || ^0.3.0 || ^0.4.0", - "moment": "^2.24.0", - "propagating-hammerjs": "^1.4.0 || ^2.0.0", - "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "vis-data": "^6.3.0 || ^7.0.0", - "vis-util": "^5.0.1", - "xss": "^1.0.0" - } - }, - "node_modules/vis-util": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.7.tgz", - "integrity": "sha512-E3L03G3+trvc/X4LXvBfih3YIHcKS2WrP0XTdZefr6W6Qi/2nNCqZfe4JFfJU6DcQLm6Gxqj2Pfl+02859oL5A==", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/visjs" - }, - "peerDependencies": { - "@egjs/hammerjs": "^2.0.0", - "component-emitter": "^1.3.0 || ^2.0.0" - } - }, "node_modules/vite": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", @@ -8497,28 +8375,6 @@ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true }, - "node_modules/xss": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz", - "integrity": "sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==", - "peer": true, - "dependencies": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" - }, - "bin": { - "xss": "bin/xss" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/xss/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "peer": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/web/package.json b/web/package.json index 19f20bf73..5250d3740 100644 --- a/web/package.json +++ b/web/package.json @@ -63,7 +63,6 @@ "vaul": "^0.8.0", "video.js": "^8.6.1", "videojs-playlist": "^5.1.0", - "vis-timeline": "^7.7.3", "vite-plugin-monaco-editor": "^1.1.0", "zod": "^3.22.4" }, diff --git a/web/src/components/playground/TimelineScrubber.tsx b/web/src/components/playground/TimelineScrubber.tsx deleted file mode 100644 index 44bd17eac..000000000 --- a/web/src/components/playground/TimelineScrubber.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import useSWR from "swr"; -import ActivityScrubber, { ScrubberItem } from "../scrubber/ActivityScrubber"; - -type TimelineScrubberProps = { - eventID: string; -}; - -function timelineEventsToScrubberItems(events: Timeline[]): ScrubberItem[] { - return events.map((event: Timeline, index: number) => ({ - id: index, - content: event.class_type, - start: event.timestamp * 1000, - type: "box", - })); -} - -function generateScrubberOptions(events: Timeline[]) { - const startTime = events[0].timestamp * 1000 - 10; - const endTime = events[events.length - 1].timestamp * 1000 + 10; - - return { start: startTime, end: endTime }; -} - -function TimelineScrubber({ eventID }: TimelineScrubberProps) { - const { data: eventTimeline } = useSWR([ - "timeline", - { - source_id: eventID, - }, - ]); - - return ( - <> - {eventTimeline && ( - <> - - - )} - - ); -} - -export default TimelineScrubber; diff --git a/web/src/components/scrubber/ActivityScrubber.tsx b/web/src/components/scrubber/ActivityScrubber.tsx deleted file mode 100644 index 64debc320..000000000 --- a/web/src/components/scrubber/ActivityScrubber.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { - Timeline as VisTimeline, - TimelineGroup, - TimelineItem, - TimelineOptions, - DateType, - IdType, -} from "vis-timeline"; -import type { DataGroup, DataItem, TimelineEvents } from "vis-timeline/types"; -import "./scrubber.css"; -import useSWR from "swr"; -import { FrigateConfig } from "@/types/frigateConfig"; - -export type TimelineEventsWithMissing = - | TimelineEvents - | "dragover" - | "markerchange" - | "markerchanged"; - -export type TimelineEventHandler = - | "currentTimeTickHandler" - | "clickHandler" - | "contextmenuHandler" - | "doubleClickHandler" - | "dragoverHandler" - | "dropHandler" - | "mouseOverHandler" - | "mouseDownHandler" - | "mouseUpHandler" - | "mouseMoveHandler" - | "groupDraggedHandler" - | "changedHandler" - | "rangechangeHandler" - | "rangechangedHandler" - | "selectHandler" - | "itemoverHandler" - | "itemoutHandler" - | "timechangeHandler" - | "timechangedHandler" - | "markerchangeHandler" - | "markerchangedHandler"; - -type EventHandler = { - (properties: any): void; -}; - -export type TimelineEventsHandlers = Partial< - Record ->; - -export type ScrubberItem = TimelineItem; - -const domEvents: TimelineEventsWithMissing[] = [ - "currentTimeTick", - "click", - "contextmenu", - "doubleClick", - "dragover", - "drop", - "mouseOver", - "mouseDown", - "mouseUp", - "mouseMove", - "groupDragged", - "changed", - "rangechange", - "rangechanged", - "select", - "itemover", - "itemout", - "timechange", - "timechanged", - "markerchange", - "markerchanged", -]; - -type ActivityScrubberProps = { - className?: string; - items?: TimelineItem[]; - timeBars?: { time: DateType; id: IdType }[]; - groups?: TimelineGroup[]; - options?: TimelineOptions; -} & TimelineEventsHandlers; - -function ActivityScrubber({ - className, - items, - timeBars, - groups, - options, - ...eventHandlers -}: ActivityScrubberProps) { - const { data: config } = useSWR("config"); - const containerRef = useRef(null); - const timelineRef = useRef<{ timeline: VisTimeline | null }>({ - timeline: null, - }); - const [currentTime, setCurrentTime] = useState(Date.now()); - const [_, setCustomTimes] = useState<{ id: IdType; time: DateType }[]>([]); - - const defaultOptions: TimelineOptions = { - width: "100%", - maxHeight: "350px", - stack: true, - showMajorLabels: true, - showCurrentTime: false, - zoomMin: 10 * 1000, // 10 seconds - // start: new Date(currentTime - 60 * 1 * 60 * 1000), // 1 hour ago - end: currentTime, - max: currentTime, - format: { - minorLabels: { - minute: config?.ui.time_format == "24hour" ? "HH:mm" : "hh:mma", - }, - majorLabels: { - minute: - config?.ui.time_format == "24hour" ? "MM/DD HH:mm" : "MM/DD hh:mma", - }, - }, - }; - - useEffect(() => { - const intervalId = setInterval(() => { - setCurrentTime(Date.now()); - }, 60000); // Update every minute - - return () => { - clearInterval(intervalId); - }; - }, []); - - useEffect(() => { - const divElement = containerRef.current; - if (!divElement) { - return; - } - - const timelineOptions: TimelineOptions = { - ...defaultOptions, - ...options, - }; - - const timelineInstance = new VisTimeline( - divElement, - (items || []) as DataItem[], - (groups || []) as DataGroup[], - timelineOptions - ); - - if (timeBars) { - timeBars.forEach((bar) => { - timelineInstance.addCustomTime(bar.time, bar.id); - }); - } - - domEvents.forEach((event) => { - const eventHandler = eventHandlers[`${event}Handler`]; - if (typeof eventHandler === "function") { - timelineInstance.on(event, eventHandler); - } - }); - - timelineRef.current.timeline = timelineInstance; - - return () => { - timelineInstance.destroy(); - }; - }, [containerRef]); - - // need to keep custom times in sync - useEffect(() => { - if (!timelineRef.current.timeline || timeBars == undefined) { - return; - } - - setCustomTimes((prevTimes) => { - if (prevTimes.length == 0 && timeBars.length == 0) { - return []; - } - - prevTimes - .filter((x) => timeBars.find((y) => x.id == y.id) == undefined) - .forEach((time) => { - try { - timelineRef.current.timeline?.removeCustomTime(time.id); - } catch {} - }); - - timeBars.forEach((time) => { - try { - const existing = timelineRef.current.timeline?.getCustomTime(time.id); - - if (existing != time.time) { - timelineRef.current.timeline?.setCustomTime(time.time, time.id); - } - } catch { - timelineRef.current.timeline?.addCustomTime(time.time, time.id); - } - }); - - return timeBars; - }); - }, [timeBars, timelineRef]); - - return ( -
-
-
- ); -} - -export default ActivityScrubber; diff --git a/web/src/components/scrubber/scrubber.css b/web/src/components/scrubber/scrubber.css deleted file mode 100644 index 9a97ac8fa..000000000 --- a/web/src/components/scrubber/scrubber.css +++ /dev/null @@ -1,670 +0,0 @@ -.vis-time-axis { - @apply overflow-hidden relative; -} -.vis-time-axis.vis-foreground { - @apply w-full left-0 top-0; -} -.vis-time-axis.vis-background { - @apply h-full absolute w-full left-0 top-0; -} -.vis-time-axis .vis-text { - @apply box-border text-muted-foreground overflow-hidden absolute whitespace-nowrap p-[3px]; -} -.vis-time-axis .vis-text.vis-measure { - @apply absolute invisible mx-0 px-0; -} -.vis-time-axis .vis-grid.vis-vertical { - @apply absolute border-l border-dashed border-muted-foreground; -} -.vis-time-axis .vis-grid.vis-vertical-rtl { - @apply absolute border-r border-dashed border-muted-foreground; -} -.vis-time-axis .vis-grid.vis-minor { - @apply border-foreground; -} -.vis-time-axis .vis-grid.vis-major { - @apply border-muted-foreground; -} -.vis .overlay { - @apply h-full absolute w-full z-10 left-0 top-0; -} -.vis-active { - @apply shadow-[0_0_10px_#86d5f8]; -} -.vis-custom-time { - @apply bg-[#6e94ff] cursor-move w-0.5 z-[1]; -} -.vis-custom-time > .vis-custom-time-marker { - @apply bg-inherit text-white cursor-auto text-xs whitespace-nowrap z-[inherit] px-[5px] py-[3px] top-0; -} -.vis-current-time { - @apply bg-[#ff7f6e] pointer-events-none w-0.5 z-[1]; -} -.vis-rolling-mode-btn { - @apply text-white cursor-pointer text-[28px] font-bold h-10 opacity-80 absolute text-center w-10 rounded-[50%] right-5 top-[7px] before:content-["\26F6"] hover:opacity-100; - background: #3876c2; -} -.vis-panel { - @apply box-border absolute m-0 p-0; -} -.vis-panel.vis-bottom, -.vis-panel.vis-center, -.vis-panel.vis-left, -.vis-panel.vis-right, -.vis-panel.vis-top { - @apply border; -} -.vis-panel.vis-center, -.vis-panel.vis-left, -.vis-panel.vis-right { - @apply overflow-hidden; - border-bottom-style: solid; - border-top-style: solid; -} -.vis-left.vis-panel.vis-vertical-scroll, -.vis-right.vis-panel.vis-vertical-scroll { - @apply h-full overflow-x-hidden overflow-y-scroll; -} -.vis-left.vis-panel.vis-vertical-scroll { - direction: rtl; -} -.vis-left.vis-panel.vis-vertical-scroll .vis-content, -.vis-right.vis-panel.vis-vertical-scroll { - direction: ltr; -} -.vis-right.vis-panel.vis-vertical-scroll .vis-content { - direction: rtl; -} -.vis-panel.vis-bottom, -.vis-panel.vis-center, -.vis-panel.vis-top { - border-left-style: solid; - border-right-style: solid; -} -.vis-background { - @apply overflow-hidden; -} -.vis-panel > .vis-content { - @apply relative; -} -.vis-panel .vis-shadow { - @apply shadow-[0_0_10px_rgba(0,0,0,0.8)] h-px absolute w-full; -} -.vis-panel .vis-shadow.vis-top { - @apply left-0 -top-px; -} -.vis-panel .vis-shadow.vis-bottom { - @apply left-0 -bottom-px; -} -.vis-graph-group0 { - @apply fill-[#4f81bd] stroke-[2px] stroke-[#4f81bd]; - fill-opacity: 0; -} -.vis-graph-group1 { - @apply fill-[#f79646] stroke-[2px] stroke-[#f79646]; - fill-opacity: 0; -} -.vis-graph-group2 { - @apply fill-[#8c51cf] stroke-[2px] stroke-[#8c51cf]; - fill-opacity: 0; -} -.vis-graph-group3 { - @apply fill-[#75c841] stroke-[2px] stroke-[#75c841]; - fill-opacity: 0; -} -.vis-graph-group4 { - @apply fill-[#ff0100] stroke-[2px] stroke-[#ff0100]; - fill-opacity: 0; -} -.vis-graph-group5 { - @apply fill-[#37d8e6] stroke-[2px] stroke-[#37d8e6]; - fill-opacity: 0; -} -.vis-graph-group6 { - @apply fill-[#042662] stroke-[2px] stroke-[#042662]; - fill-opacity: 0; -} -.vis-graph-group7 { - @apply fill-[#00ff26] stroke-[2px] stroke-[#00ff26]; - fill-opacity: 0; -} -.vis-graph-group8 { - @apply fill-[#f0f] stroke-[2px] stroke-[#f0f]; - fill-opacity: 0; -} -.vis-graph-group9 { - @apply fill-[#8f3938] stroke-[2px] stroke-[#8f3938]; - fill-opacity: 0; -} -.vis-timeline .vis-fill { - @apply stroke-none; - fill-opacity: 0.1; -} -.vis-timeline .vis-bar { - @apply stroke-[1px]; - fill-opacity: 0.5; -} -.vis-timeline .vis-point { - @apply stroke-[2px]; - fill-opacity: 1; -} -.vis-timeline .vis-legend-background { - @apply stroke-[1px] fill-white stroke-[#c2c2c2]; - fill-opacity: 0.9; -} -.vis-timeline .vis-outline { - @apply stroke-[1px] fill-white stroke-neutral-200; - fill-opacity: 1; -} -.vis-timeline .vis-icon-fill { - @apply stroke-none; - fill-opacity: 0.3; -} -.vis-timeline { - @apply border box-border overflow-hidden relative m-0 p-0 border-solid border-[#bfbfbf]; -} -.vis-loading-screen { - @apply h-full absolute w-full left-0 top-0; -} -.vis [class*="span"] { - @apply min-h-0 w-auto; -} -.vis-item { - @apply bg-accent border text-foreground inline-block absolute z-[1] border-border; -} -.vis-item.vis-selected { - @apply bg-muted-foreground z-[2] border-muted text-muted; -} -.vis-editable.vis-selected { - @apply cursor-move; -} -.vis-item.vis-point.vis-selected { - @apply bg-muted-foreground; -} -.vis-item.vis-box { - @apply text-center rounded-sm border-solid; -} -.vis-item.vis-point { - background: none; -} -.vis-item.vis-dot { - @apply rounded absolute p-0 border-solid border-4; -} -.vis-item.vis-range { - @apply box-border rounded-sm border-solid; -} -.vis-item.vis-background { - @apply bg-[rgba(213,221,246,0.4)] box-border m-0 p-0 border-[none]; -} -.vis-item .vis-item-overflow { - @apply h-full overflow-hidden relative w-full m-0 p-0; -} -.vis-item-visible-frame { - @apply whitespace-nowrap; -} -.vis-item.vis-range .vis-item-content { - @apply inline-block relative; -} -.vis-item.vis-background .vis-item-content { - @apply inline-block absolute; -} -.vis-item.vis-line { - @apply absolute w-0 p-0 border-l border-solid text-muted; -} -.vis-item .vis-item-content { - @apply box-border whitespace-nowrap p-[5px]; -} -.vis-item .vis-onUpdateTime-tooltip { - @apply text-white absolute text-center transition-[0.4s] whitespace-nowrap w-[200px] p-[5px] rounded-[1px]; - background: #4f81bd; - -o-transition: 0.4s; - -moz-transition: 0.4s; - -webkit-transition: 0.4s; -} -.vis-item .vis-delete, -.vis-item .vis-delete-rtl { - @apply box-border cursor-pointer h-6 absolute transition-[background] duration-200 ease-linear w-6 px-[5px] py-0 top-0; - -webkit-transition: background 0.2s linear; - -moz-transition: background 0.2s linear; - -ms-transition: background 0.2s linear; - -o-transition: background 0.2s linear; -} -.vis-item .vis-delete { - @apply -right-6; -} -.vis-item .vis-delete-rtl { - @apply -left-6; -} -.vis-item .vis-delete-rtl:after, -.vis-item .vis-delete:after { - @apply text-[red] content-["\00D7"] text-[22px] font-bold transition-[color] duration-200 ease-linear; - font-family: arial, sans-serif; - -webkit-transition: color 0.2s linear; - -moz-transition: color 0.2s linear; - -ms-transition: color 0.2s linear; - -o-transition: color 0.2s linear; -} -.vis-item .vis-delete-rtl:hover, -.vis-item .vis-delete:hover { - background: red; -} -.vis-item .vis-delete-rtl:hover:after, -.vis-item .vis-delete:hover:after { - @apply text-white; -} -.vis-item .vis-drag-center { - @apply cursor-move h-full absolute w-full left-0 top-0; -} -.vis-item.vis-range .vis-drag-left { - @apply cursor-w-resize -left-1; -} -.vis-item.vis-range .vis-drag-left, -.vis-item.vis-range .vis-drag-right { - @apply h-full max-w-[20%] min-w-[2px] absolute w-6 top-0; -} -.vis-item.vis-range .vis-drag-right { - @apply cursor-e-resize -right-1; -} -.vis-range.vis-item.vis-readonly .vis-drag-left, -.vis-range.vis-item.vis-readonly .vis-drag-right { - @apply cursor-auto; -} -.vis-item.vis-cluster { - @apply text-center rounded-sm border-solid; - vertical-align: center; -} -.vis-item.vis-cluster-line { - @apply absolute w-0 p-0 border-l; - border-left-style: solid; -} -.vis-item.vis-cluster-dot { - @apply rounded absolute p-0 border-solid border-4; -} -div.vis-tooltip { - @apply bg-[#f5f4ed] border shadow-[3px_3px_10px_rgba(0,0,0,0.2)] text-black text-sm pointer-events-none absolute invisible whitespace-nowrap z-[5] p-[5px] rounded-[3px] border-solid border-[#808074]; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - font-family: verdana; -} -.vis-itemset { - @apply box-border relative m-0 p-0; -} -.vis-itemset .vis-background, -.vis-itemset .vis-foreground { - @apply h-full overflow-visible absolute w-full; -} -.vis-axis { - @apply h-0 absolute w-full z-[1] left-0; -} -.vis-foreground .vis-group { - @apply box-border relative border-b-[#bfbfbf] border-b border-solid last:border-b-[none]; -} -.vis-nesting-group { - @apply cursor-pointer; -} -.vis-label.vis-nested-group.vis-group-level-unknown-but-gte1 { - background: #f5f5f5; -} -.vis-label.vis-nested-group.vis-group-level-0 { - @apply bg-white; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-0 .vis-inner { - @apply pl-0; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-0 .vis-inner { - @apply pr-0; -} -.vis-label.vis-nested-group.vis-group-level-1 { - @apply bg-[rgba(0,0,0,0.05)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-1 .vis-inner { - @apply pl-[15px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-1 .vis-inner { - @apply pr-[15px]; -} -.vis-label.vis-nested-group.vis-group-level-2 { - @apply bg-[rgba(0,0,0,0.1)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-2 .vis-inner { - @apply pl-[30px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-2 .vis-inner { - @apply pr-[30px]; -} -.vis-label.vis-nested-group.vis-group-level-3 { - @apply bg-[rgba(0,0,0,0.15)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-3 .vis-inner { - @apply pl-[45px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-3 .vis-inner { - @apply pr-[45px]; -} -.vis-label.vis-nested-group.vis-group-level-4 { - @apply bg-[rgba(0,0,0,0.2)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-4 .vis-inner { - @apply pl-[60px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-4 .vis-inner { - @apply pr-[60px]; -} -.vis-label.vis-nested-group.vis-group-level-5 { - @apply bg-[rgba(0,0,0,0.25)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-5 .vis-inner { - @apply pl-[75px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-5 .vis-inner { - @apply pr-[75px]; -} -.vis-label.vis-nested-group.vis-group-level-6 { - @apply bg-[rgba(0,0,0,0.3)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-6 .vis-inner { - @apply pl-[90px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-6 .vis-inner { - @apply pr-[90px]; -} -.vis-label.vis-nested-group.vis-group-level-7 { - @apply bg-[rgba(0,0,0,0.35)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-7 .vis-inner { - @apply pl-[105px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-7 .vis-inner { - @apply pr-[105px]; -} -.vis-label.vis-nested-group.vis-group-level-8 { - @apply bg-[rgba(0,0,0,0.4)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-8 .vis-inner { - @apply pl-[120px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-8 .vis-inner { - @apply pr-[120px]; -} -.vis-label.vis-nested-group.vis-group-level-9 { - @apply bg-[rgba(0,0,0,0.45)]; -} -.vis-ltr .vis-label.vis-nested-group.vis-group-level-9 .vis-inner { - @apply pl-[135px]; -} -.vis-rtl .vis-label.vis-nested-group.vis-group-level-9 .vis-inner { - @apply pr-[135px]; -} -.vis-label.vis-nested-group { - @apply bg-[rgba(0,0,0,0.5)]; -} -.vis-ltr .vis-label.vis-nested-group .vis-inner { - @apply pl-[150px]; -} -.vis-rtl .vis-label.vis-nested-group .vis-inner { - @apply pr-[150px]; -} -.vis-group-level-unknown-but-gte1 { - @apply border border-solid border-[red]; -} -.vis-label.vis-nesting-group:before { - @apply inline-block w-[15px]; -} -.vis-label.vis-nesting-group.expanded:before { - @apply content-["\25BC"]; -} -.vis-label.vis-nesting-group.collapsed:before { - @apply content-["\25B6"]; -} -.vis-rtl .vis-label.vis-nesting-group.collapsed:before { - @apply content-["\25C0"]; -} -.vis-ltr .vis-label:not(.vis-nesting-group):not(.vis-group-level-0) { - @apply pl-[15px]; -} -.vis-rtl .vis-label:not(.vis-nesting-group):not(.vis-group-level-0) { - @apply pr-[15px]; -} -.vis-overlay { - @apply h-full absolute w-full z-10 left-0 top-0; -} -.vis-labelset { - @apply overflow-hidden; -} -.vis-labelset, -.vis-labelset .vis-label { - @apply box-border relative; -} -.vis-labelset .vis-label { - @apply text-[#4d4d4d] w-full border-b-[#bfbfbf] border-b border-solid left-0 top-0 last:border-b-[none]; -} -.vis-labelset .vis-label.draggable { - @apply cursor-pointer; -} -.vis-group-is-dragging { - background: rgba(0, 0, 0, 0.1); -} -.vis-labelset .vis-label .vis-inner { - @apply inline-block p-[5px]; -} -.vis-labelset .vis-label .vis-inner.vis-hidden { - @apply p-0; -} -div.vis-configuration { - @apply block float-left text-xs relative; -} -div.vis-configuration-wrapper { - @apply block w-[700px] after:clear-both after:content-[""] after:block; -} -div.vis-configuration.vis-config-option-container { - @apply bg-white rounded block w-[495px] mt-5 pl-[5px] border-2 border-solid border-[#f7f8fa] left-2.5; -} -div.vis-configuration.vis-config-button { - @apply bg-[#f7f8fa] rounded cursor-pointer block h-[25px] leading-[25px] align-middle w-[495px] mt-5 mb-[30px] pl-[5px] border-2 border-solid border-[#ceced0] left-2.5; -} -div.vis-configuration.vis-config-button.hover { - @apply bg-[#4588e6] text-white border-2 border-solid border-[#214373]; -} -div.vis-configuration.vis-config-item { - @apply block float-left h-[25px] leading-[25px] align-middle w-[495px]; -} -div.vis-configuration.vis-config-item.vis-config-s2 { - @apply bg-[#f7f8fa] pl-[5px] rounded-[3px] left-2.5; -} -div.vis-configuration.vis-config-item.vis-config-s3 { - @apply bg-[#e4e9f0] pl-[5px] rounded-[3px] left-5; -} -div.vis-configuration.vis-config-item.vis-config-s4 { - @apply bg-[#cfd8e6] pl-[5px] rounded-[3px] left-[30px]; -} -div.vis-configuration.vis-config-header { - @apply text-lg font-bold; -} -div.vis-configuration.vis-config-label { - @apply h-[25px] leading-[25px] w-[120px]; -} -div.vis-configuration.vis-config-label.vis-config-s3 { - @apply w-[110px]; -} -div.vis-configuration.vis-config-label.vis-config-s4 { - @apply w-[100px]; -} -div.vis-configuration.vis-config-colorBlock { - @apply border cursor-pointer h-[19px] w-[30px] m-0 p-0 rounded-sm border-solid border-[#444] top-px; -} -input.vis-configuration.vis-config-checkbox { - @apply left-[-5px]; -} -input.vis-configuration.vis-config-rangeinput { - @apply pointer-events-none relative top-[-5px] w-[60px] m-0 p-px; -} -input.vis-configuration.vis-config-range { - @apply bg-transparent h-5 w-[300px] border-0 border-solid border-white; - -webkit-appearance: none; -} -input.vis-configuration.vis-config-range::-webkit-slider-runnable-track { - @apply border shadow-[0_0_3px_0_#aaa] h-[5px] w-[300px] rounded-[3px] border-solid border-[#999]; - background: #dedede; - background: -moz-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, #dedede), - color-stop(99%, #c8c8c8) - ); - background: -webkit-linear-gradient(top, #dedede, #c8c8c8 99%); - background: -o-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: -ms-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: linear-gradient(180deg, #dedede 0, #c8c8c8 99%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#dedede",endColorstr="#c8c8c8",GradientType=0); -} -input.vis-configuration.vis-config-range::-webkit-slider-thumb { - @apply border shadow-[0_0_1px_0_#111927] h-[17px] mt-[-7px] w-[17px] rounded-[50%] border-solid border-[#14334b]; - -webkit-appearance: none; - background: #3876c2; - background: -moz-linear-gradient(top, #3876c2 0, #385380 100%); - background: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, #3876c2), - color-stop(100%, #385380) - ); - background: -webkit-linear-gradient(top, #3876c2, #385380); - background: -o-linear-gradient(top, #3876c2 0, #385380 100%); - background: -ms-linear-gradient(top, #3876c2 0, #385380 100%); - background: linear-gradient(180deg, #3876c2 0, #385380); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#3876c2",endColorstr="#385380",GradientType=0); -} -input.vis-configuration.vis-config-range:focus { - outline: none; -} -input.vis-configuration.vis-config-range:focus::-webkit-slider-runnable-track { - background: #9d9d9d; - background: -moz-linear-gradient(top, #9d9d9d 0, #c8c8c8 99%); - background: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, #9d9d9d), - color-stop(99%, #c8c8c8) - ); - background: -webkit-linear-gradient(top, #9d9d9d, #c8c8c8 99%); - background: -o-linear-gradient(top, #9d9d9d 0, #c8c8c8 99%); - background: -ms-linear-gradient(top, #9d9d9d 0, #c8c8c8 99%); - background: linear-gradient(180deg, #9d9d9d 0, #c8c8c8 99%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#9d9d9d",endColorstr="#c8c8c8",GradientType=0); -} -input.vis-configuration.vis-config-range::-moz-range-track { - @apply border shadow-[0_0_3px_0_#aaa] h-2.5 w-[300px] rounded-[3px] border-solid border-[#999]; - background: #dedede; - background: -moz-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, #dedede), - color-stop(99%, #c8c8c8) - ); - background: -webkit-linear-gradient(top, #dedede, #c8c8c8 99%); - background: -o-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: -ms-linear-gradient(top, #dedede 0, #c8c8c8 99%); - background: linear-gradient(180deg, #dedede 0, #c8c8c8 99%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#dedede",endColorstr="#c8c8c8",GradientType=0); -} -input.vis-configuration.vis-config-range::-moz-range-thumb { - @apply h-4 w-4 rounded-[50%] border-[none]; - background: #385380; -} -input.vis-configuration.vis-config-range:-moz-focusring { - @apply -outline-offset-1; - outline: 1px solid #fff; -} -input.vis-configuration.vis-config-range::-ms-track { - @apply text-transparent h-[5px] w-[300px] border-[6px_0]; - background: transparent; -} -input.vis-configuration.vis-config-range::-ms-fill-lower { - @apply rounded-[10px]; - background: #777; -} -input.vis-configuration.vis-config-range::-ms-fill-upper { - @apply rounded-[10px]; - background: #ddd; -} -input.vis-configuration.vis-config-range::-ms-thumb { - @apply h-4 w-4 rounded-[50%] border-[none]; - background: #385380; -} -input.vis-configuration.vis-config-range:focus::-ms-fill-lower { - background: #888; -} -input.vis-configuration.vis-config-range:focus::-ms-fill-upper { - background: #ccc; -} -.vis-configuration-popup { - @apply rounded text-white text-sm h-[30px] leading-[30px] absolute text-center transition-opacity duration-300 ease-in-out w-[150px] border-2 border-solid border-[#f2faff] after:-mt-2 after:border-[rgba(136,183,213,0)_rgba(136,183,213,0)_rgba(136,183,213,0)_rgba(57,76,89,0.85)] after:border-8 before:-mt-3 before:border-[rgba(194,225,245,0)_rgba(194,225,245,0)_rgba(194,225,245,0)_#f2faff] before:border-[12px]; - background: rgba(57, 76, 89, 0.85); - -webkit-transition: opacity 0.3s ease-in-out; - -moz-transition: opacity 0.3s ease-in-out; -} -.vis-configuration-popup:after, -.vis-configuration-popup:before { - @apply content-["_"] h-0 pointer-events-none absolute w-0 border-[solid] left-full top-2/4; -} -.vis-panel.vis-background.vis-horizontal .vis-grid.vis-horizontal { - @apply h-0 absolute w-full border-b border-solid; -} -.vis-panel.vis-background.vis-horizontal .vis-grid.vis-minor { - @apply border-neutral-200; -} -.vis-panel.vis-background.vis-horizontal .vis-grid.vis-major { - @apply border-[#bfbfbf]; -} -.vis-data-axis .vis-y-axis.vis-major { - @apply text-[#4d4d4d] absolute whitespace-nowrap w-full; -} -.vis-data-axis .vis-y-axis.vis-major.vis-measure { - @apply invisible w-auto m-0 p-0 border-0; -} -.vis-data-axis .vis-y-axis.vis-minor { - @apply text-[#bebebe] absolute whitespace-nowrap w-full; -} -.vis-data-axis .vis-y-axis.vis-minor.vis-measure { - @apply invisible w-auto m-0 p-0 border-0; -} -.vis-data-axis .vis-y-axis.vis-title { - @apply text-[#4d4d4d] absolute text-center whitespace-nowrap bottom-5; -} -.vis-data-axis .vis-y-axis.vis-title.vis-measure { - @apply invisible w-auto m-0 p-0; -} -.vis-data-axis .vis-y-axis.vis-title.vis-left { - @apply -rotate-90 origin-[left_bottom] bottom-0; - -webkit-transform: rotate(-90deg); - -moz-transform: rotate(-90deg); - -ms-transform: rotate(-90deg); - -o-transform: rotate(-90deg); - -webkit-transform-origin: left top; - -moz-transform-origin: left top; - -ms-transform-origin: left top; - -o-transform-origin: left top; -} -.vis-data-axis .vis-y-axis.vis-title.vis-right { - @apply rotate-90 origin-[right_bottom] bottom-0; - -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); - -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); - -webkit-transform-origin: right bottom; - -moz-transform-origin: right bottom; - -ms-transform-origin: right bottom; - -o-transform-origin: right bottom; -} -.vis-legend { - @apply bg-[rgba(247,252,255,0.65)] border shadow-[2px_2px_10px_hsla(0,0%,60%,0.55)] p-[5px] border-solid border-[#b3b3b3]; -} -.vis-legend-text { - @apply inline-block whitespace-nowrap; -} diff --git a/web/src/pages/UIPlayground.tsx b/web/src/pages/UIPlayground.tsx index d37a0a01a..3fc94ac56 100644 --- a/web/src/pages/UIPlayground.tsx +++ b/web/src/pages/UIPlayground.tsx @@ -1,14 +1,9 @@ -import { useCallback, useMemo, useRef, useState } from "react"; +import { useMemo, useRef, useState } from "react"; import Heading from "@/components/ui/heading"; -import ActivityScrubber, { - ScrubberItem, -} from "@/components/scrubber/ActivityScrubber"; import useSWR from "swr"; import { FrigateConfig } from "@/types/frigateConfig"; import { Event } from "@/types/event"; import ActivityIndicator from "@/components/ui/activity-indicator"; -import { useApiHost } from "@/api"; -import TimelineScrubber from "@/components/playground/TimelineScrubber"; import EventReviewTimeline from "@/components/timeline/EventReviewTimeline"; import { ReviewData, ReviewSegment, ReviewSeverity } from "@/types/review"; import { Button } from "@/components/ui/button"; @@ -48,18 +43,6 @@ function ColorSwatch({ name, value }: { name: string; value: string }) { ); } -function eventsToScrubberItems(events: Event[]): ScrubberItem[] { - const apiHost = useApiHost(); - - return events.map((event: Event) => ({ - id: event.id, - content: `
${event.label}
`, - start: new Date(event.start_time * 1000), - end: event.end_time ? new Date(event.end_time * 1000) : undefined, - type: "box", - })); -} - const generateRandomEvent = (): ReviewSegment => { const start_time = Math.floor(Date.now() / 1000) - 10800 - Math.random() * 60 * 60; @@ -98,17 +81,12 @@ const generateRandomEvent = (): ReviewSegment => { function UIPlayground() { const { data: config } = useSWR("config"); - const [timeline, setTimeline] = useState(undefined); const contentRef = useRef(null); const [mockEvents, setMockEvents] = useState([]); const [handlebarTime, setHandlebarTime] = useState( Math.floor(Date.now() / 1000) - 15 * 60 ); - const onSelect = useCallback(({ items }: { items: string[] }) => { - setTimeline(items[0]); - }, []); - const recentTimestamp = useMemo(() => { const now = new Date(); now.setMinutes(now.getMinutes() - 240); @@ -190,29 +168,6 @@ function UIPlayground() { {!config && } - {config && ( -
- {events && events.length > 0 && ( - <> - - - )} -
- )} - - {config && ( -
- {timeline && ( - <> - - - )} -
- )} -
Timeline