diff --git a/web-new/src/components/ui/table.tsx b/web-new/src/components/ui/table.tsx new file mode 100644 index 000000000..7f3502f8b --- /dev/null +++ b/web-new/src/components/ui/table.tsx @@ -0,0 +1,117 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/web-new/src/pages/Storage.tsx b/web-new/src/pages/Storage.tsx index 00886c004..96a86369c 100644 --- a/web-new/src/pages/Storage.tsx +++ b/web-new/src/pages/Storage.tsx @@ -1,9 +1,150 @@ +import { useWs } from "@/api/ws"; +import ActivityIndicator from "@/components/ui/activity-indicator"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import Heading from "@/components/ui/heading"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { useMemo } from "react"; +import useSWR from "swr"; + +type CameraStorage = { + [key: string]: { + bandwidth: number; + usage: number; + usage_percent: number; + }; +}; + +const emptyObject = Object.freeze({}); function Storage() { + const { data: storage } = useSWR("recordings/storage"); + + const { + value: { payload: stats }, + } = useWs("stats", ""); + const { data: initialStats } = useSWR("stats"); + + const { service } = stats || initialStats || emptyObject; + + const hasSeparateMedia = useMemo(() => { + return ( + service && + service["storage"]["/media/frigate/recordings"]["total"] != + service["storage"]["/media/frigate/clips"]["total"] + ); + }, service); + + 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`; + }; + + if (!service || !storage) { + return ; + } + return ( <> Storage + + Overview +
+ + + Data + + + + + + Location + Used + Total + + + + + + {hasSeparateMedia ? "Recordings" : "Recordings & Snapshots"} + + + {getUnitSize( + service["storage"]["/media/frigate/recordings"]["used"] + )} + + + {getUnitSize( + service["storage"]["/media/frigate/recordings"]["total"] + )} + + + {hasSeparateMedia && ( + + Snapshots + + {getUnitSize( + service["storage"]["/media/frigate/clips"]["used"] + )} + + + {getUnitSize( + service["storage"]["/media/frigate/clips"]["total"] + )} + + + )} + +
+
+
+ + + + Memory + + + + + + Location + Used + Total + + + + + /dev/shm + + {getUnitSize(service["storage"]["/dev/shm"]["used"])} + + + {getUnitSize(service["storage"]["/dev/shm"]["total"])} + + + + /tmp/cache + + {getUnitSize(service["storage"]["/tmp/cache"]["used"])} + + + {getUnitSize(service["storage"]["/tmp/cache"]["total"])} + + + +
+
+
+
); } diff --git a/web-new/vite.config.ts b/web-new/vite.config.ts index a97dbd014..2ed74b4c7 100644 --- a/web-new/vite.config.ts +++ b/web-new/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' }, '/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, },