mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Clean up selected data for recording (#10537)
This commit is contained in:
parent
f835e86df1
commit
ab6bac1d2c
@ -26,7 +26,7 @@ type PreviewPlayerProps = {
|
||||
scrollLock?: boolean;
|
||||
onTimeUpdate?: (time: number | undefined) => void;
|
||||
setReviewed: (review: ReviewSegment) => void;
|
||||
onClick: (reviewId: string, ctrl: boolean) => void;
|
||||
onClick: (review: ReviewSegment, ctrl: boolean) => void;
|
||||
};
|
||||
|
||||
type Preview = {
|
||||
@ -55,7 +55,7 @@ export default function PreviewThumbnailPlayer({
|
||||
const handleOnClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!ignoreClick) {
|
||||
onClick(review.id, e.metaKey);
|
||||
onClick(review, e.metaKey);
|
||||
}
|
||||
},
|
||||
[ignoreClick, review, onClick],
|
||||
@ -165,7 +165,7 @@ export default function PreviewThumbnailPlayer({
|
||||
onMouseLeave={isMobile ? undefined : () => setIsHovered(false)}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
onClick(review.id, true);
|
||||
onClick(review, true);
|
||||
}}
|
||||
onClick={handleOnClick}
|
||||
{...swipeHandlers}
|
||||
|
@ -2,7 +2,7 @@ import { useCallback, useMemo } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { usePersistence } from "./use-persistence";
|
||||
|
||||
export function useOverlayState<S extends string>(
|
||||
export function useOverlayState<S>(
|
||||
key: string,
|
||||
defaultValue: S | undefined = undefined,
|
||||
): [S | undefined, (value: S, replace?: boolean) => void] {
|
||||
|
@ -4,6 +4,7 @@ import { useTimezone } from "@/hooks/use-date-utils";
|
||||
import { useOverlayState } from "@/hooks/use-overlay-state";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { Preview } from "@/types/preview";
|
||||
import { RecordingStartingPoint } from "@/types/record";
|
||||
import {
|
||||
ReviewFilter,
|
||||
ReviewSegment,
|
||||
@ -26,7 +27,8 @@ export default function Events() {
|
||||
"severity",
|
||||
"alert",
|
||||
);
|
||||
const [selectedReviewId, setSelectedReviewId] = useOverlayState("review");
|
||||
const [recording, setRecording] =
|
||||
useOverlayState<RecordingStartingPoint>("recording");
|
||||
const [startTime, setStartTime] = useState<number>();
|
||||
|
||||
// review filter
|
||||
@ -257,6 +259,10 @@ export default function Events() {
|
||||
// selected items
|
||||
|
||||
const selectedReviewData = useMemo(() => {
|
||||
if (!recording) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
return undefined;
|
||||
}
|
||||
@ -265,50 +271,20 @@ export default function Events() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!selectedReviewId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
setStartTime(recording.startTime);
|
||||
const allCameras = reviewFilter?.cameras ?? Object.keys(config.cameras);
|
||||
|
||||
if (selectedReviewId.startsWith("motion")) {
|
||||
const motionData = selectedReviewId.split(",");
|
||||
const motionStart = parseFloat(motionData[2]);
|
||||
setStartTime(motionStart);
|
||||
// format is motion,camera,start_time
|
||||
return {
|
||||
camera: motionData[1],
|
||||
severity: "significant_motion" as ReviewSeverity,
|
||||
start_time: motionStart,
|
||||
allCameras: allCameras,
|
||||
cameraSegments: reviews.filter((seg) =>
|
||||
allCameras.includes(seg.camera),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const selectedReview = reviews.find((item) => item.id == selectedReviewId);
|
||||
|
||||
if (!selectedReview) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// mark item as reviewed since it has been opened
|
||||
if (!selectedReview?.has_been_reviewed) {
|
||||
markItemAsReviewed(selectedReview);
|
||||
}
|
||||
|
||||
return {
|
||||
camera: selectedReview.camera,
|
||||
severity: selectedReview.severity,
|
||||
start_time: selectedReview.start_time,
|
||||
camera: recording.camera,
|
||||
severity: recording.severity,
|
||||
start_time: recording.startTime,
|
||||
allCameras: allCameras,
|
||||
cameraSegments: reviews.filter((seg) => allCameras.includes(seg.camera)),
|
||||
};
|
||||
|
||||
// previews will not update after item is selected
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedReviewId, reviews]);
|
||||
}, [recording, reviews]);
|
||||
|
||||
if (!timezone) {
|
||||
return <ActivityIndicator />;
|
||||
@ -338,7 +314,7 @@ export default function Events() {
|
||||
setSeverity={setSeverity}
|
||||
markItemAsReviewed={markItemAsReviewed}
|
||||
markAllItemsAsReviewed={markAllItemsAsReviewed}
|
||||
onOpenReview={setSelectedReviewId}
|
||||
onOpenRecording={setRecording}
|
||||
pullLatestData={reloadData}
|
||||
updateFilter={onUpdateFilter}
|
||||
/>
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { ReviewSeverity } from "./review";
|
||||
|
||||
export type Recording = {
|
||||
id: string;
|
||||
camera: string;
|
||||
@ -30,3 +32,9 @@ type RecordingSegmentActivity = {
|
||||
count: number;
|
||||
hasObjects: boolean;
|
||||
};
|
||||
|
||||
export type RecordingStartingPoint = {
|
||||
camera: string;
|
||||
startTime: number;
|
||||
severity: ReviewSeverity;
|
||||
};
|
||||
|
@ -36,6 +36,7 @@ import { Button } from "@/components/ui/button";
|
||||
import PreviewPlayer, {
|
||||
PreviewController,
|
||||
} from "@/components/player/PreviewPlayer";
|
||||
import { RecordingStartingPoint } from "@/types/record";
|
||||
|
||||
type EventViewProps = {
|
||||
reviews?: ReviewSegment[];
|
||||
@ -48,7 +49,7 @@ type EventViewProps = {
|
||||
setSeverity: (severity: ReviewSeverity) => void;
|
||||
markItemAsReviewed: (review: ReviewSegment) => void;
|
||||
markAllItemsAsReviewed: (currentItems: ReviewSegment[]) => void;
|
||||
onOpenReview: (reviewId: string) => void;
|
||||
onOpenRecording: (recordingInfo: RecordingStartingPoint) => void;
|
||||
pullLatestData: () => void;
|
||||
updateFilter: (filter: ReviewFilter) => void;
|
||||
};
|
||||
@ -63,7 +64,7 @@ export default function EventView({
|
||||
setSeverity,
|
||||
markItemAsReviewed,
|
||||
markAllItemsAsReviewed,
|
||||
onOpenReview,
|
||||
onOpenRecording,
|
||||
pullLatestData,
|
||||
updateFilter,
|
||||
}: EventViewProps) {
|
||||
@ -145,9 +146,9 @@ export default function EventView({
|
||||
|
||||
const [selectedReviews, setSelectedReviews] = useState<string[]>([]);
|
||||
const onSelectReview = useCallback(
|
||||
(reviewId: string, ctrl: boolean) => {
|
||||
(review: ReviewSegment, ctrl: boolean) => {
|
||||
if (selectedReviews.length > 0 || ctrl) {
|
||||
const index = selectedReviews.indexOf(reviewId);
|
||||
const index = selectedReviews.indexOf(review.id);
|
||||
|
||||
if (index != -1) {
|
||||
if (selectedReviews.length == 1) {
|
||||
@ -161,14 +162,20 @@ export default function EventView({
|
||||
}
|
||||
} else {
|
||||
const copy = [...selectedReviews];
|
||||
copy.push(reviewId);
|
||||
copy.push(review.id);
|
||||
setSelectedReviews(copy);
|
||||
}
|
||||
} else {
|
||||
onOpenReview(reviewId);
|
||||
onOpenRecording({
|
||||
camera: review.camera,
|
||||
startTime: review.start_time,
|
||||
severity: review.severity,
|
||||
});
|
||||
|
||||
markItemAsReviewed(review);
|
||||
}
|
||||
},
|
||||
[selectedReviews, setSelectedReviews, onOpenReview],
|
||||
[selectedReviews, setSelectedReviews, onOpenRecording, markItemAsReviewed],
|
||||
);
|
||||
|
||||
const exportReview = useCallback(
|
||||
@ -281,7 +288,7 @@ export default function EventView({
|
||||
timeRange={timeRange}
|
||||
startTime={startTime}
|
||||
filter={filter}
|
||||
onSelectReview={onSelectReview}
|
||||
onOpenRecording={onOpenRecording}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@ -305,7 +312,7 @@ type DetectionReviewProps = {
|
||||
timeRange: { before: number; after: number };
|
||||
markItemAsReviewed: (review: ReviewSegment) => void;
|
||||
markAllItemsAsReviewed: (currentItems: ReviewSegment[]) => void;
|
||||
onSelectReview: (id: string, ctrl: boolean) => void;
|
||||
onSelectReview: (review: ReviewSegment, ctrl: boolean) => void;
|
||||
pullLatestData: () => void;
|
||||
};
|
||||
function DetectionReview({
|
||||
@ -552,7 +559,7 @@ type MotionReviewProps = {
|
||||
timeRange: { before: number; after: number };
|
||||
startTime?: number;
|
||||
filter?: ReviewFilter;
|
||||
onSelectReview: (data: string, ctrl: boolean) => void;
|
||||
onOpenRecording: (data: RecordingStartingPoint) => void;
|
||||
};
|
||||
function MotionReview({
|
||||
contentRef,
|
||||
@ -561,7 +568,7 @@ function MotionReview({
|
||||
timeRange,
|
||||
startTime,
|
||||
filter,
|
||||
onSelectReview,
|
||||
onOpenRecording,
|
||||
}: MotionReviewProps) {
|
||||
const segmentDuration = 30;
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
@ -688,7 +695,11 @@ function MotionReview({
|
||||
videoPlayersRef.current[camera.name] = controller;
|
||||
}}
|
||||
onClick={() =>
|
||||
onSelectReview(`motion,${camera.name},${currentTime}`, false)
|
||||
onOpenRecording({
|
||||
camera: camera.name,
|
||||
startTime: currentTime,
|
||||
severity: "significant_motion",
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user