diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx
index e4eafb8df..2248835a2 100644
--- a/web/src/components/filter/ReviewFilterGroup.tsx
+++ b/web/src/components/filter/ReviewFilterGroup.tsx
@@ -593,40 +593,26 @@ export function GeneralFilterContent({
{allLabels.map((item) => (
-
-
- {
- if (isChecked) {
- const updatedLabels = currentLabels
- ? [...currentLabels]
- : [];
+ {
+ if (isChecked) {
+ const updatedLabels = currentLabels ? [...currentLabels] : [];
- updatedLabels.push(item);
+ updatedLabels.push(item);
+ setCurrentLabels(updatedLabels);
+ } else {
+ const updatedLabels = currentLabels ? [...currentLabels] : [];
+
+ // can not deselect the last item
+ if (updatedLabels.length > 1) {
+ updatedLabels.splice(updatedLabels.indexOf(item), 1);
setCurrentLabels(updatedLabels);
- } else {
- const updatedLabels = currentLabels
- ? [...currentLabels]
- : [];
-
- // can not deselect the last item
- if (updatedLabels.length > 1) {
- updatedLabels.splice(updatedLabels.indexOf(item), 1);
- setCurrentLabels(updatedLabels);
- }
}
- }}
- />
-
+ }
+ }}
+ />
))}
diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx
index a7968075d..0767933b2 100644
--- a/web/src/components/player/PreviewThumbnailPlayer.tsx
+++ b/web/src/components/player/PreviewThumbnailPlayer.tsx
@@ -520,6 +520,7 @@ export function VideoPreview({
const onStopManualSeek = useCallback(() => {
setTimeout(() => {
setIgnoreClick(false);
+ setHoverTimeout(undefined);
if (isSafari || (isFirefox && isMobile)) {
setManualPlayback(true);
@@ -565,7 +566,7 @@ export function VideoPreview({
{showProgress && (
void;
private setFocusedItem: (timeline: Timeline) => void;
private playerMode: PlayerMode = "playback";
// playback
private recordings: Recording[] = [];
+ private timeRange: TimeRange = { after: 0, before: 0 };
private annotationOffset: number;
private timeToStart: number | undefined = undefined;
@@ -24,6 +26,7 @@ export class DynamicVideoController {
previewController: PreviewController,
annotationOffset: number,
defaultMode: PlayerMode,
+ setNoRecording: (noRecs: boolean) => void,
setFocusedItem: (timeline: Timeline) => void,
) {
this.camera = camera;
@@ -31,11 +34,13 @@ export class DynamicVideoController {
this.previewController = previewController;
this.annotationOffset = annotationOffset;
this.playerMode = defaultMode;
+ this.setNoRecording = setNoRecording;
this.setFocusedItem = setFocusedItem;
}
newPlayback(newPlayback: DynamicPlayback) {
this.recordings = newPlayback.recordings;
+ this.timeRange = newPlayback.timeRange;
if (this.timeToStart) {
this.seekToTimestamp(this.timeToStart);
@@ -52,12 +57,17 @@ export class DynamicVideoController {
}
seekToTimestamp(time: number, play: boolean = false) {
+ if (time < this.timeRange.after || time > this.timeRange.before) {
+ this.timeToStart = time;
+ return;
+ }
+
if (
this.recordings.length == 0 ||
time < this.recordings[0].start_time ||
time > this.recordings[this.recordings.length - 1].end_time
) {
- this.timeToStart = time;
+ this.setNoRecording(true);
return;
}
@@ -90,6 +100,8 @@ export class DynamicVideoController {
} else {
this.playerController.pause();
}
+ } else {
+ console.log(`seek time is 0`);
}
}
diff --git a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx
index f923fbd43..15216b749 100644
--- a/web/src/components/player/dynamic/DynamicVideoPlayer.tsx
+++ b/web/src/components/player/dynamic/DynamicVideoPlayer.tsx
@@ -45,6 +45,7 @@ export default function DynamicVideoPlayer({
const playerRef = useRef(null);
const [previewController, setPreviewController] =
useState(null);
+ const [noRecording, setNoRecording] = useState(false);
const controller = useMemo(() => {
if (!config || !playerRef.current || !previewController) {
return undefined;
@@ -56,6 +57,7 @@ export default function DynamicVideoPlayer({
previewController,
(config.cameras[camera]?.detect?.annotation_offset || 0) / 1000,
isScrubbing ? "scrubbing" : "playback",
+ setNoRecording,
() => {},
);
// we only want to fire once when players are ready
@@ -92,9 +94,11 @@ export default function DynamicVideoPlayer({
return () => {
if (loadingTimeout) {
- clearTimeout(loadingTimeout)
+ clearTimeout(loadingTimeout);
}
- }
+ };
+ // we only want trigger when scrubbing state changes
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [camera, isScrubbing]);
const onPlayerLoaded = useCallback(() => {
@@ -149,6 +153,7 @@ export default function DynamicVideoPlayer({
controller.newPlayback({
recordings: recordings ?? [],
+ timeRange,
});
// we only want this to change when recordings update
@@ -175,6 +180,7 @@ export default function DynamicVideoPlayer({
}
setIsLoading(false);
+ setNoRecording(false);
}}
/>
- {isLoading && (
+ {isLoading && !noRecording && (
)}
+ {!isScrubbing && noRecording && (
+
+ No recordings found for this time
+
+ )}
>
);
}
diff --git a/web/src/components/ui/slider.tsx b/web/src/components/ui/slider.tsx
index 8a3e93747..1dde1df67 100644
--- a/web/src/components/ui/slider.tsx
+++ b/web/src/components/ui/slider.tsx
@@ -55,7 +55,7 @@ const NoThumbSlider = React.forwardRef<
)}
{...props}
>
-
+
diff --git a/web/src/types/playback.ts b/web/src/types/playback.ts
index 6c4202304..ae45d43d7 100644
--- a/web/src/types/playback.ts
+++ b/web/src/types/playback.ts
@@ -4,6 +4,7 @@ import { TimeRange } from "./timeline";
export type DynamicPlayback = {
recordings: Recording[];
+ timeRange: TimeRange;
};
export type PreviewPlayback = {
diff --git a/web/src/views/events/EventView.tsx b/web/src/views/events/EventView.tsx
index 2540efc79..6c6bd2dec 100644
--- a/web/src/views/events/EventView.tsx
+++ b/web/src/views/events/EventView.tsx
@@ -591,7 +591,9 @@ function DetectionReview({
})
: Array(itemsToReview)
.fill(0)
- .map(() => )}
+ .map((_, idx) => (
+
+ ))}
{!loading &&
(currentItems?.length ?? 0) > 0 &&
(itemsToReview ?? 0) > 0 && (
@@ -953,7 +955,7 @@ function MotionReview({
{!scrubbing && (
-
-
-
- sendDetect(detectState == "ON" ? "OFF" : "ON")
- }
- />
-
-
-
-
- sendRecord(recordState == "ON" ? "OFF" : "ON")
- }
- />
-
-
-
-
- sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")
- }
- />
-
+ sendDetect(detectState == "ON" ? "OFF" : "ON")}
+ />
+ sendRecord(recordState == "ON" ? "OFF" : "ON")}
+ />
+
+ sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")
+ }
+ />
{audioDetectEnabled && (
-
-
-
- sendAudio(audioState == "ON" ? "OFF" : "ON")
- }
- />
-
+ sendAudio(audioState == "ON" ? "OFF" : "ON")}
+ />
)}