mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-01 00:22:19 +03:00
Improve display of recordings data (#16436)
* backend * frontend * add earliest recording available to storage metrics page
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user