mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-11 05:35:25 +03:00
Get storage graph formatted
This commit is contained in:
parent
b93031649f
commit
76b805eba1
@ -125,6 +125,108 @@ export function ThresholdBarGraph({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StorageGraph() {
|
const getUnitSize = (MB: number) => {
|
||||||
|
if (isNaN(MB) || MB < 0) return "Invalid number";
|
||||||
|
if (MB < 1024) return `${MB} MiB`;
|
||||||
|
if (MB < 1048576) return `${(MB / 1024).toFixed(2)} GiB`;
|
||||||
|
|
||||||
|
return `${(MB / 1048576).toFixed(2)} TiB`;
|
||||||
|
};
|
||||||
|
|
||||||
|
type StorageGraphProps = {
|
||||||
|
graphId: string;
|
||||||
|
used: number;
|
||||||
|
total: number;
|
||||||
|
data: ApexAxisChartSeries;
|
||||||
|
};
|
||||||
|
export function StorageGraph({
|
||||||
|
graphId,
|
||||||
|
used,
|
||||||
|
total,
|
||||||
|
data,
|
||||||
|
}: StorageGraphProps) {
|
||||||
|
const { theme, systemTheme } = useTheme();
|
||||||
|
|
||||||
|
const options = useMemo(() => {
|
||||||
|
return {
|
||||||
|
chart: {
|
||||||
|
id: graphId,
|
||||||
|
background: (systemTheme || theme) == "dark" ? "#404040" : "#E5E5E5",
|
||||||
|
selection: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
show: false,
|
||||||
|
padding: {
|
||||||
|
bottom: -40,
|
||||||
|
top: -60,
|
||||||
|
left: -20,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
horizontal: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
theme: systemTheme || theme,
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
axisBorder: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
axisTicks: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
show: false,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, [graphId, systemTheme, theme]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ApexCharts.exec(graphId, "updateOptions", options, true, true);
|
||||||
|
}, [graphId, options]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full flex flex-col gap-2.5">
|
||||||
|
<div className="w-full flex justify-between items-center gap-1">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<div className="text-xs text-primary-foreground">
|
||||||
|
{getUnitSize(used)}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-primary-foreground">/</div>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
{getUnitSize(total)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-primary-foreground">
|
||||||
|
{Math.round((used / total) * 100)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="h-5 rounded-md overflow-hidden">
|
||||||
|
<Chart type="bar" options={options} series={data} height="100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import TimeAgo from "@/components/dynamic/TimeAgo";
|
|||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
import { isDesktop } from "react-device-detect";
|
import { isDesktop } from "react-device-detect";
|
||||||
import GeneralMetrics from "@/views/system/GeneralMetrics";
|
import GeneralMetrics from "@/views/system/GeneralMetrics";
|
||||||
|
import StorageMetrics from "@/views/system/StorageMetrics";
|
||||||
|
|
||||||
const metrics = ["general", "storage", "cameras"] as const;
|
const metrics = ["general", "storage", "cameras"] as const;
|
||||||
type SystemMetric = (typeof metrics)[number];
|
type SystemMetric = (typeof metrics)[number];
|
||||||
@ -70,6 +71,12 @@ function System() {
|
|||||||
setLastUpdated={setLastUpdated}
|
setLastUpdated={setLastUpdated}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{page == "storage" && (
|
||||||
|
<StorageMetrics
|
||||||
|
lastUpdated={lastUpdated}
|
||||||
|
setLastUpdated={setLastUpdated}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
59
web/src/views/system/StorageMetrics.tsx
Normal file
59
web/src/views/system/StorageMetrics.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { StorageGraph } from "@/components/graph/SystemGraph";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
type CameraStorage = {
|
||||||
|
[key: string]: {
|
||||||
|
bandwidth: number;
|
||||||
|
usage: number;
|
||||||
|
usage_percent: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type StorageMetricsProps = {
|
||||||
|
lastUpdated: number;
|
||||||
|
setLastUpdated: (last: number) => void;
|
||||||
|
};
|
||||||
|
export default function StorageMetrics({
|
||||||
|
lastUpdated,
|
||||||
|
setLastUpdated,
|
||||||
|
}: StorageMetricsProps) {
|
||||||
|
const { data: storage } = useSWR<CameraStorage>("recordings/storage");
|
||||||
|
|
||||||
|
const totalStorage = useMemo(() => {
|
||||||
|
if (!storage) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalStorage = {
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.values(storage).forEach((cam) => (totalStorage.total += cam.usage));
|
||||||
|
|
||||||
|
return totalStorage;
|
||||||
|
}, [storage]);
|
||||||
|
|
||||||
|
if (!totalStorage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="size-full mt-4 flex flex-col overflow-y-auto">
|
||||||
|
<div className="text-muted-foreground text-sm font-medium">
|
||||||
|
General Storage
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 grid grid-cols-1 sm:grid-cols-3 gap-2">
|
||||||
|
<div className="p-2.5 bg-primary rounded-2xl flex-col">
|
||||||
|
<div className="mb-5">Recordings</div>
|
||||||
|
<StorageGraph
|
||||||
|
graphId="general-recordings"
|
||||||
|
used={1000000}
|
||||||
|
total={5000000}
|
||||||
|
data={[{ name: "Recordings", data: [{ x: "Recordings", y: 25 }] }]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user