Files
LaunchPad/apps/frontend/src/routes/admin/DashboardPage.tsx

85 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useServices } from "../../hooks/useServices.js";
import { useDevices } from "../../hooks/useDevices.js";
import { useCategories } from "../../hooks/useCategories.js";
import { AdminPageHeader } from "./AdminPageHeader.js";
function StatCard({ label, value }: { label: string; value: number | string }) {
return (
<div className="rounded-2xl border border-black/10 bg-white p-5 dark:border-white/10 dark:bg-white/5">
<div className="text-3xl font-semibold text-black dark:text-white">{value}</div>
<div className="mt-1 text-sm text-black/50 dark:text-white/50">{label}</div>
</div>
);
}
export function DashboardPage() {
const { data: services } = useServices();
const { data: devices } = useDevices();
const { data: categories } = useCategories();
const onlineDevices = devices?.filter((d) => d.online).length ?? 0;
const favoriteServices = services?.filter((s) => s.favorite).length ?? 0;
const recentlyScanned = [...(devices ?? [])]
.filter((d) => d.lastScan)
.sort((a, b) => (b.lastScan ?? "").localeCompare(a.lastScan ?? ""))
.slice(0, 5);
return (
<div>
<AdminPageHeader
title="Dashboard"
description="Überblick über dein Homelab."
/>
<div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
<StatCard label="Geräte" value={devices?.length ?? 0} />
<StatCard label="davon online" value={onlineDevices} />
<StatCard label="Dienste" value={services?.length ?? 0} />
<StatCard label="Favoriten" value={favoriteServices} />
</div>
<div className="mt-8">
<h2 className="mb-3 text-sm font-semibold text-black/60 dark:text-white/60">
Zuletzt gescannte Geräte
</h2>
{recentlyScanned.length === 0 ? (
<p className="text-sm text-black/40 dark:text-white/40">
Noch keine Scans durchgeführt. Starte einen Scan unter Geräte oder Scanner.
</p>
) : (
<div className="overflow-hidden rounded-2xl border border-black/10 dark:border-white/10">
<table className="w-full text-sm">
<tbody>
{recentlyScanned.map((device) => (
<tr
key={device.id}
className="border-b border-black/5 last:border-0 dark:border-white/5"
>
<td className="px-4 py-3 font-medium text-black dark:text-white">
{device.hostname}
</td>
<td className="px-4 py-3 text-black/40 dark:text-white/40">{device.ip}</td>
<td className="px-4 py-3 text-black/40 dark:text-white/40">
{device.lastScan ? new Date(device.lastScan).toLocaleString("de-DE") : ""}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
<div className="mt-8">
<h2 className="mb-3 text-sm font-semibold text-black/60 dark:text-white/60">
Kategorien
</h2>
<p className="text-sm text-black/40 dark:text-white/40">
{categories?.length ?? 0} Kategorie(n) angelegt.
</p>
</div>
</div>
);
}