mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
fix: statfs when volume is not mounted
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { HardDrive } from "lucide-react";
|
import { HardDrive, Unplug } from "lucide-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Label, Pie, PieChart } from "recharts";
|
import { Label, Pie, PieChart } from "recharts";
|
||||||
import { ByteSize } from "~/components/bytes-size";
|
import { ByteSize } from "~/components/bytes-size";
|
||||||
@@ -47,6 +47,25 @@ export function StorageChart({ statfs }: Props) {
|
|||||||
return Math.round((statfs.used / statfs.total) * 100);
|
return Math.round((statfs.used / statfs.total) * 100);
|
||||||
}, [statfs]);
|
}, [statfs]);
|
||||||
|
|
||||||
|
const isEmpty = !statfs.total;
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
return (
|
||||||
|
<Card className="flex flex-col h-full text-sm">
|
||||||
|
<CardHeader className="items-center pb-0">
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<HardDrive className="h-4 w-4" />
|
||||||
|
Storage Usage
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="flex-1 pb-10 flex flex-col items-center justify-center text-center">
|
||||||
|
<Unplug className="mb-4 h-5 w-5 text-muted-foreground" />
|
||||||
|
<p className="text-muted-foreground">No storage data available. Mount the volume to see usage statistics.</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="flex flex-col h-full text-sm">
|
<Card className="flex flex-col h-full text-sm">
|
||||||
<CardHeader className="items-center pb-0">
|
<CardHeader className="items-center pb-0">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Database, HardDrive } from "lucide-react";
|
import { Database, HardDrive, Unplug } from "lucide-react";
|
||||||
import { ByteSize } from "~/components/bytes-size";
|
import { ByteSize } from "~/components/bytes-size";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||||
import type { StatFs } from "~/lib/types";
|
import type { StatFs } from "~/lib/types";
|
||||||
@@ -8,6 +8,25 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function StorageInfoCard({ statfs }: Props) {
|
export function StorageInfoCard({ statfs }: Props) {
|
||||||
|
const isEmpty = !statfs.total;
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
return (
|
||||||
|
<Card className="flex flex-col h-full text-sm">
|
||||||
|
<CardHeader className="items-center pb-0">
|
||||||
|
<CardTitle className="flex items-center gap-2">
|
||||||
|
<Database className="h-4 w-4" />
|
||||||
|
Storage Usage
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="flex-1 pb-10 flex flex-col items-center justify-center text-center">
|
||||||
|
<Unplug className="mb-4 h-5 w-5 text-muted-foreground" />
|
||||||
|
<p className="text-muted-foreground">No storage data available. Mount the volume to see usage statistics.</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="h-full text-sm">
|
<Card className="h-full text-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { db } from "../../db/db";
|
|||||||
import { volumesTable } from "../../db/schema";
|
import { volumesTable } from "../../db/schema";
|
||||||
import { createVolumeBackend } from "../backends/backend";
|
import { createVolumeBackend } from "../backends/backend";
|
||||||
import { toMessage } from "../../utils/errors";
|
import { toMessage } from "../../utils/errors";
|
||||||
import { getStatFs } from "../../utils/mountinfo";
|
import { getStatFs, type StatFs } from "../../utils/mountinfo";
|
||||||
import { VOLUME_MOUNT_BASE } from "../../core/constants";
|
import { VOLUME_MOUNT_BASE } from "../../core/constants";
|
||||||
|
|
||||||
const listVolumes = async () => {
|
const listVolumes = async () => {
|
||||||
@@ -101,12 +101,15 @@ const getVolume = async (name: string) => {
|
|||||||
where: eq(volumesTable.name, name),
|
where: eq(volumesTable.name, name),
|
||||||
});
|
});
|
||||||
|
|
||||||
const statfs = await getStatFs(`${VOLUME_MOUNT_BASE}/${name}/_data`).catch(() => {});
|
|
||||||
|
|
||||||
if (!volume) {
|
if (!volume) {
|
||||||
throw new NotFoundError("Volume not found");
|
throw new NotFoundError("Volume not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let statfs: Partial<StatFs> = {};
|
||||||
|
if (volume.status === "mounted") {
|
||||||
|
statfs = (await getStatFs(`${VOLUME_MOUNT_BASE}/${name}/_data`).catch(() => {})) ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
return { volume, statfs };
|
return { volume, statfs };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ type MountInfo = {
|
|||||||
fstype: string;
|
fstype: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type StatFs = {
|
||||||
|
total: number;
|
||||||
|
used: number;
|
||||||
|
free: number;
|
||||||
|
};
|
||||||
|
|
||||||
function isPathWithin(base: string, target: string): boolean {
|
function isPathWithin(base: string, target: string): boolean {
|
||||||
const rel = path.posix.relative(base, target);
|
const rel = path.posix.relative(base, target);
|
||||||
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
||||||
|
|||||||
Reference in New Issue
Block a user