fix: statfs when volume is not mounted

This commit is contained in:
Nicolas Meienberger
2025-09-25 21:28:36 +02:00
parent 6b386d28d6
commit 9b57dd8a1c
4 changed files with 52 additions and 5 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { HardDrive } from "lucide-react";
import { HardDrive, Unplug } from "lucide-react";
import * as React from "react";
import { Label, Pie, PieChart } from "recharts";
import { ByteSize } from "~/components/bytes-size";
@@ -47,6 +47,25 @@ export function StorageChart({ statfs }: Props) {
return Math.round((statfs.used / statfs.total) * 100);
}, [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 (
<Card className="flex flex-col h-full text-sm">
<CardHeader className="items-center pb-0">

View File

@@ -1,4 +1,4 @@
import { Database, HardDrive } from "lucide-react";
import { Database, HardDrive, Unplug } from "lucide-react";
import { ByteSize } from "~/components/bytes-size";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import type { StatFs } from "~/lib/types";
@@ -8,6 +8,25 @@ type 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 (
<Card className="h-full text-sm">
<CardHeader>

View File

@@ -10,7 +10,7 @@ import { db } from "../../db/db";
import { volumesTable } from "../../db/schema";
import { createVolumeBackend } from "../backends/backend";
import { toMessage } from "../../utils/errors";
import { getStatFs } from "../../utils/mountinfo";
import { getStatFs, type StatFs } from "../../utils/mountinfo";
import { VOLUME_MOUNT_BASE } from "../../core/constants";
const listVolumes = async () => {
@@ -101,12 +101,15 @@ const getVolume = async (name: string) => {
where: eq(volumesTable.name, name),
});
const statfs = await getStatFs(`${VOLUME_MOUNT_BASE}/${name}/_data`).catch(() => {});
if (!volume) {
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 };
};

View File

@@ -6,6 +6,12 @@ type MountInfo = {
fstype: string;
};
export type StatFs = {
total: number;
used: number;
free: number;
};
function isPathWithin(base: string, target: string): boolean {
const rel = path.posix.relative(base, target);
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));