diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index 3216dd409..e0e27a321 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -3,7 +3,7 @@ import { Button } from "../ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import useSWR from "swr"; import { FrigateConfig } from "@/types/frigateConfig"; -import { useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { DropdownMenu, DropdownMenuContent, @@ -13,7 +13,11 @@ import { } from "../ui/dropdown-menu"; import { Calendar } from "../ui/calendar"; import { ReviewFilter } from "@/types/review"; -import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; +import { + formatUnixTimestampToDateTime, + getEndOfDayTimestamp, +} from "@/utils/dateUtil"; +import { useFormattedTimestamp } from "@/hooks/use-date-utils"; const ATTRIBUTES = ["amazon", "face", "fedex", "license_plate", "ups"]; @@ -55,6 +59,19 @@ export default function ReviewFilterGroup({ [config, allLabels] ); + // handle updating filters + + const onUpdateSelectedDay = useCallback( + (day?: Date) => { + onUpdateFilter({ + ...filter, + after: day == undefined ? undefined : day.getTime() / 1000, + before: day == undefined ? undefined : getEndOfDayTimestamp(day), + }); + }, + [onUpdateFilter] + ); + return (
- + setOpen(open)}> - - - - -
- - - - - - - Filter Labels - - { - if (isChecked) { - setSelectedFilters({ - ...selectedFilters, - labels: ["all"], - }); - } - }} - /> - - {filterValues.labels.map((item) => ( - { - if (isChecked) { - const selectedLabels = allItems.labels - ? [] - : [...selectedFilters.labels]; - selectedLabels.push(item); - setSelectedFilters({ - ...selectedFilters, - labels: selectedLabels, - }); - } else { - const selectedLabelList = [...selectedFilters.labels]; - - // can not deselect the last item - if (selectedLabelList.length > 1) { - selectedLabelList.splice( - selectedLabelList.indexOf(item), - 1 - ); - setSelectedFilters({ - ...selectedFilters, - labels: selectedLabelList, - }); - } - } - }} - /> - ))} - - - - - - - - Detail Level - - { - setSelectedFilters({ - ...selectedFilters, - // @ts-ignore we know that value is one of the detailLevel - detailLevel: value, - }); - }} - > - - Normal - - - Extra - - Full - - -
void; }; -function CalendarFilterButton({ before, after }: CalendarFilterButtonProps) { +function CalendarFilterButton({ + day, + updateSelectedDay, +}: CalendarFilterButtonProps) { + const [selectedDay, setSelectedDay] = useState(day); const disabledDates = useMemo(() => { const tomorrow = new Date(); tomorrow.setHours(tomorrow.getHours() + 24, -1, 0, 0); @@ -308,28 +233,34 @@ function CalendarFilterButton({ before, after }: CalendarFilterButtonProps) { future.setFullYear(tomorrow.getFullYear() + 10); return { from: tomorrow, to: future }; }, []); - // @ts-ignore - const dateRange = useMemo(() => { - return before == undefined || after == undefined - ? undefined - : { - from: new Date(after * 1000), - to: new Date(before * 1000), - }; - }, [before, after]); + const selectedDate = useFormattedTimestamp( + day == undefined ? 0 : day?.getTime() / 1000, + "%b %-d" + ); return ( - + { + if (!open) { + updateSelectedDay(selectedDay); + } + }} + > - + { + setSelectedDay(day); + }} + /> ); @@ -364,11 +295,18 @@ function GeneralFilterButton({ selectedLabels={selectedLabels} updateLabelFilter={updateLabelFilter} /> - setShowReviewed(isChecked)} - /> +
diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index 598aa234b..5884f2c0b 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -18,6 +18,7 @@ import { } from "../ui/context-menu"; import { LuCheckSquare, LuFileUp, LuTrash } from "react-icons/lu"; import axios from "axios"; +import { useFormattedTimestamp } from "@/hooks/use-date-utils"; type PreviewPlayerProps = { review: ReviewSegment; @@ -92,6 +93,13 @@ export default function PreviewThumbnailPlayer({ [hoverTimeout, review] ); + // date + + const formattedDate = useFormattedTimestamp( + review.start_time, + config?.ui.time_format == "24hour" ? "%b %-d, %H:%M" : "%b %-d, %I:%M %p" + ); + return ( @@ -137,13 +145,7 @@ export default function PreviewThumbnailPlayer({ {!playingBack && (
- {config && - formatUnixTimestampToDateTime(review.start_time, { - strftime_fmt: - config.ui.time_format == "24hour" - ? "%b %-d, %H:%M" - : "%b %-d, %I:%M %p", - })} + {formattedDate}
)}
diff --git a/web/src/hooks/use-date-utils.ts b/web/src/hooks/use-date-utils.ts new file mode 100644 index 000000000..99ee55f59 --- /dev/null +++ b/web/src/hooks/use-date-utils.ts @@ -0,0 +1,12 @@ +import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; +import { useMemo } from "react"; + +export function useFormattedTimestamp(timestamp: number, format: string) { + const formattedTimestamp = useMemo(() => { + return formatUnixTimestampToDateTime(timestamp, { + strftime_fmt: format, + }); + }, [format, timestamp]); + + return formattedTimestamp; +} diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index dcc549386..2d1cb66bc 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -21,6 +21,11 @@ export default function Events() { const [reviewFilter, setReviewFilter, reviewSearchParams] = useApiFilter(); + const onUpdateFilter = useCallback((newFilter: ReviewFilter) => { + setSize(1); + setReviewFilter(newFilter); + }, []) + // review paging const timeRange = useMemo(() => { @@ -34,7 +39,6 @@ export default function Events() { const getKey = useCallback( (index: number, prevData: ReviewSegment[]) => { - console.log("The params are " + JSON.stringify(reviewSearchParams)) if (index > 0) { const lastDate = prevData[prevData.length - 1].start_time; reviewSearchParams; @@ -137,7 +141,7 @@ export default function Events() { return newData; }, - { revalidate: false } + { revalidate: false, populateCache: true } ); } }, @@ -209,7 +213,7 @@ export default function Events() { markItemAsReviewed={markItemAsReviewed} onSelectReview={setSelectedReviewId} pullLatestData={updateSegments} - updateFilter={setReviewFilter} + updateFilter={onUpdateFilter} /> ); } diff --git a/web/src/utils/dateUtil.ts b/web/src/utils/dateUtil.ts index f17a261fc..244dcb586 100644 --- a/web/src/utils/dateUtil.ts +++ b/web/src/utils/dateUtil.ts @@ -293,6 +293,11 @@ export function endOfHourOrCurrentTime(timestamp: number) { return Math.min(timestamp, now.getTime() / 1000); } +export function getEndOfDayTimestamp(date: Date) { + date.setHours(23, 59, 59, 999); + return date.getTime() / 1000; +} + export function isCurrentHour(timestamp: number) { const now = new Date(); now.setMinutes(0, 0, 0); diff --git a/web/vite.config.ts b/web/vite.config.ts index a97dbd014..5d5bf8207 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -12,24 +12,24 @@ export default defineConfig({ server: { proxy: { '/api': { - target: 'http://localhost:5000', + target: 'http://192.168.50.106:5000', ws: true, }, '/vod': { - target: 'http://localhost:5000' + target: 'http://192.168.50.106:5000' }, '/clips': { - target: 'http://localhost:5000' + target: 'http://192.168.50.106:5000' }, '/exports': { - target: 'http://localhost:5000' + target: 'http://192.168.50.106:5000' }, '/ws': { - target: 'ws://localhost:5000', + target: 'ws://192.168.50.106:5000', ws: true, }, '/live': { - target: 'ws://localhost:5000', + target: 'ws://192.168.50.106:5000', changeOrigin: true, ws: true, },