From 1d97fb54e73971f38b7c5a5cd5b1f8afd2da2d46 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 18 Jun 2024 07:33:24 -0600 Subject: [PATCH] Add ability to select all review items --- web/src/hooks/use-keyboard-listener.tsx | 9 ++++++--- web/src/views/events/EventView.tsx | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/web/src/hooks/use-keyboard-listener.tsx b/web/src/hooks/use-keyboard-listener.tsx index b3143db0a..6bbcaa2e0 100644 --- a/web/src/hooks/use-keyboard-listener.tsx +++ b/web/src/hooks/use-keyboard-listener.tsx @@ -2,7 +2,10 @@ import { useCallback, useEffect } from "react"; export default function useKeyboardListener( keys: string[], - listener: (key: string, down: boolean, repeat: boolean) => void, + listener: ( + key: string, + modifiers: { down: boolean; repeat: boolean; ctrl: boolean }, + ) => void, ) { const keyDownListener = useCallback( (e: KeyboardEvent) => { @@ -12,7 +15,7 @@ export default function useKeyboardListener( if (keys.includes(e.key)) { e.preventDefault(); - listener(e.key, true, e.repeat); + listener(e.key, { down: true, repeat: e.repeat, ctrl: e.ctrlKey }); } }, [keys, listener], @@ -26,7 +29,7 @@ export default function useKeyboardListener( if (keys.includes(e.key)) { e.preventDefault(); - listener(e.key, false, false); + listener(e.key, { down: false, repeat: false, ctrl: false }); } }, [keys, listener], diff --git a/web/src/views/events/EventView.tsx b/web/src/views/events/EventView.tsx index dfcf0344d..090de1866 100644 --- a/web/src/views/events/EventView.tsx +++ b/web/src/views/events/EventView.tsx @@ -51,6 +51,7 @@ import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { FilterList, LAST_24_HOURS_KEY } from "@/types/filter"; import { GiSoundWaves } from "react-icons/gi"; +import useKeyboardListener from "@/hooks/use-keyboard-listener"; type EventViewProps = { reviewItems?: SegmentedReviewData; @@ -158,6 +159,17 @@ export default function EventView({ }, [selectedReviews, setSelectedReviews, onOpenRecording, markItemAsReviewed], ); + const onSelectAllReviews = useCallback(() => { + if (!currentReviewItems || currentReviewItems.length == 0) { + return; + } + + if (selectedReviews.length < currentReviewItems.length) { + setSelectedReviews(currentReviewItems.map((seg) => seg.id)); + } else { + setSelectedReviews([]); + } + }, [currentReviewItems, selectedReviews]); const exportReview = useCallback( (id: string) => { @@ -376,6 +388,7 @@ export default function EventView({ markItemAsReviewed={markItemAsReviewed} markAllItemsAsReviewed={markAllItemsAsReviewed} onSelectReview={onSelectReview} + onSelectAllReviews={onSelectAllReviews} pullLatestData={pullLatestData} /> )} @@ -417,6 +430,7 @@ type DetectionReviewProps = { markItemAsReviewed: (review: ReviewSegment) => void; markAllItemsAsReviewed: (currentItems: ReviewSegment[]) => void; onSelectReview: (review: ReviewSegment, ctrl: boolean) => void; + onSelectAllReviews: () => void; pullLatestData: () => void; }; function DetectionReview({ @@ -434,6 +448,7 @@ function DetectionReview({ markItemAsReviewed, markAllItemsAsReviewed, onSelectReview, + onSelectAllReviews, pullLatestData, }: DetectionReviewProps) { const reviewTimelineRef = useRef(null); @@ -580,6 +595,14 @@ function DetectionReview({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [startTime]); + // keyboard + + useKeyboardListener(["a"], (key, modifiers) => { + if (key == "a" && modifiers.down && modifiers.ctrl) { + onSelectAllReviews(); + } + }); + return ( <>