Improve display of recordings data (#16436)

* backend

* frontend

* add earliest recording available to storage metrics page
This commit is contained in:
Josh Hawkins
2025-02-09 16:02:36 -07:00
committed by GitHub
parent bc96db8612
commit d5b60237a2
11 changed files with 217 additions and 39 deletions
+4
View File
@@ -12,6 +12,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
import { Preview } from "@/types/preview";
import {
MotionData,
RecordingsSummary,
REVIEW_PADDING,
ReviewFilter,
ReviewSegment,
@@ -59,6 +60,7 @@ type EventViewProps = {
reviewItems?: SegmentedReviewData;
currentReviewItems: ReviewSegment[] | null;
reviewSummary?: ReviewSummary;
recordingsSummary?: RecordingsSummary;
relevantPreviews?: Preview[];
timeRange: TimeRange;
filter?: ReviewFilter;
@@ -77,6 +79,7 @@ export default function EventView({
reviewItems,
currentReviewItems,
reviewSummary,
recordingsSummary,
relevantPreviews,
timeRange,
filter,
@@ -359,6 +362,7 @@ export default function EventView({
}
currentSeverity={severityToggle}
reviewSummary={reviewSummary}
recordingsSummary={recordingsSummary}
filter={filter}
motionOnly={motionOnly}
filterList={reviewFilterList}
+16
View File
@@ -15,6 +15,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
import { Preview } from "@/types/preview";
import {
MotionData,
RecordingsSummary,
REVIEW_PADDING,
ReviewFilter,
ReviewSegment,
@@ -46,6 +47,7 @@ import { ASPECT_VERTICAL_LAYOUT, ASPECT_WIDE_LAYOUT } from "@/types/record";
import { useResizeObserver } from "@/hooks/resize-observer";
import { cn } from "@/lib/utils";
import { useFullscreen } from "@/hooks/use-fullscreen";
import { useTimezone } from "@/hooks/use-date-utils";
import { useTimelineZoom } from "@/hooks/use-timeline-zoom";
type RecordingViewProps = {
@@ -74,6 +76,18 @@ export function RecordingView({
const navigate = useNavigate();
const contentRef = useRef<HTMLDivElement | null>(null);
// recordings summary
const timezone = useTimezone(config);
const { data: recordingsSummary } = useSWR<RecordingsSummary>([
"recordings/summary",
{
timezone: timezone,
cameras: allCameras ?? null,
},
]);
// controller state
const [mainCamera, setMainCamera] = useState(startCamera);
@@ -430,6 +444,7 @@ export function RecordingView({
<ReviewFilterGroup
filters={["date", "general"]}
reviewSummary={reviewSummary}
recordingsSummary={recordingsSummary}
filter={filter}
motionOnly={false}
filterList={reviewFilterList}
@@ -475,6 +490,7 @@ export function RecordingView({
filter={filter}
currentTime={currentTime}
latestTime={timeRange.before}
recordingsSummary={recordingsSummary}
mode={exportMode}
range={exportRange}
showExportPreview={showExportPreview}
+36 -1
View File
@@ -9,6 +9,10 @@ import {
} from "@/components/ui/popover";
import useSWR from "swr";
import { LuAlertCircle } from "react-icons/lu";
import { FrigateConfig } from "@/types/frigateConfig";
import { useTimezone } from "@/hooks/use-date-utils";
import { RecordingsSummary } from "@/types/review";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
type CameraStorage = {
[key: string]: {
@@ -26,6 +30,11 @@ export default function StorageMetrics({
}: StorageMetricsProps) {
const { data: cameraStorage } = useSWR<CameraStorage>("recordings/storage");
const { data: stats } = useSWR<FrigateStats>("stats");
const { data: config } = useSWR<FrigateConfig>("config", {
revalidateOnFocus: false,
});
const timezone = useTimezone(config);
const totalStorage = useMemo(() => {
if (!cameraStorage || !stats) {
@@ -44,7 +53,23 @@ export default function StorageMetrics({
return totalStorage;
}, [cameraStorage, stats, setLastUpdated]);
if (!cameraStorage || !stats || !totalStorage) {
// recordings summary
const { data: recordingsSummary } = useSWR<RecordingsSummary>([
"recordings/summary",
{
timezone: timezone,
},
]);
const earliestDate = useMemo(() => {
const keys = Object.keys(recordingsSummary || {});
return keys.length
? new Date(keys[keys.length - 1]).getTime() / 1000
: null;
}, [recordingsSummary]);
if (!cameraStorage || !stats || !totalStorage || !config) {
return;
}
@@ -81,6 +106,16 @@ export default function StorageMetrics({
used={totalStorage.used}
total={totalStorage.total}
/>
{earliestDate && (
<div className="mt-2 text-xs text-primary-variant">
<span className="font-medium">Earliest recording available:</span>{" "}
{formatUnixTimestampToDateTime(earliestDate, {
timezone: timezone,
strftime_fmt:
config.ui.time_format == "24hour" ? "%d %b %Y" : "%B %d, %Y",
})}
</div>
)}
</div>
<div className="flex-col rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
<div className="mb-5">/tmp/cache</div>