'use client'; import { useEffect, useState } from 'react'; import { getPeers, listPins, checkHealth, getRepoStats, getBWStats } from '@/lib/api'; import type { RepoStats, BWStats } from '@/lib/api'; import PortalLayout from '@/app/layout-portal'; import Link from 'next/link'; import { HardDrive, Globe, Wifi, Database, Server, ArrowUpRight, ArrowDownLeft, BarChart3, Fingerprint, } from 'lucide-react'; interface PeerData { id: string; addr: string; latency: string } interface PinData { cid: string; name: string; size: number } export default function DashboardPage() { const [peers, setPeers] = useState([]); const [pins, setPins] = useState([]); const [health, setHealth] = useState<{ status: string; node: string } | null>(null); const [repo, setRepo] = useState(null); const [bw, setBW] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { async function load() { try { const [h, p, pinList, r, b] = await Promise.all([ checkHealth().catch(() => null), getPeers().catch(() => [] as PeerData[]), listPins().catch(() => [] as PinData[]), getRepoStats().catch(() => null), getBWStats().catch(() => null), ]); setHealth(h); setPeers(p); setPins(pinList); setRepo(r); setBW(b); } finally { setLoading(false); } } load(); const iv = setInterval(load, 15000); return () => clearInterval(iv); }, []); const repoSizeGb = repo ? (repo.repoSize / 1e9).toFixed(2) : '—'; const bwIn = bw ? (bw.totalIn / 1e6).toFixed(1) : '—'; const bwOut = bw ? (bw.totalOut / 1e6).toFixed(1) : '—'; const stats = [ { label: 'Peers', value: peers.length, icon: Wifi, color: 'text-accent-cyan', bg: 'bg-accent-cyan/10' }, { label: 'Pins', value: pins.length, icon: HardDrive, color: 'text-accent-purple', bg: 'bg-accent-purple/10' }, { label: 'Node', value: health?.status ?? '—', icon: Server, color: 'text-accent-green', bg: 'bg-accent-green/10' }, { label: 'Repo', value: `${repoSizeGb} GB`, icon: Database, color: 'text-accent-amber', bg: 'bg-accent-amber/10' }, ]; return ( {/* Page header */}

Dashboard

IPFS node overview, storage, and bandwidth

{loading && (
refreshing…
)}
{/* Stat cards */}
{stats.map((s) => (
{s.value}
{s.label}
))}
{/* Row 2: Peer + Bandwidth */}
{/* Peers list */}

Connected Peers {peers.length} peer{peers.length !== 1 ? 's' : ''}

{peers.length === 0 ? (

No peers connected

) : (
{peers.slice(0, 20).map((p) => (
{p.id.slice(0, 20)}…
{p.latency}
))}
)}
View all peers →
{/* Bandwidth */}

Bandwidth

In
{bwIn} MB
Out
{bwOut} MB
Total since node start
{/* IPNS quick */}

IPNS Names

Publish CIDs to human-readable IPNS names, or resolve existing names.

Manage IPNS Keys Browse Explorer
{/* Row 3: Pins + Repo details */}
{/* Pins */}

Recent Pins {pins.length} total

{pins.length === 0 ? (

No pins yet — upload or add content to get started.

) : (
{pins.slice(0, 8).map((pin) => (
{pin.name || pin.cid.slice(0, 24) + '…'}
{(pin.size / 1024).toFixed(1)} KB
))}
)}
Manage pins → Upload new →
{/* Repo Details */}

Repository

{repo ? (
Size {repoSizeGb} GB
Objects {repo.numObjects.toLocaleString()}
Storage Max {(repo.storageMax / 1e9).toFixed(1)} GB
Version {repo.version || health?.node || '—'}
Path {repo.repoPath}
) : (

Repo stats unavailable (Kubo may not expose /api/v0/repo/stat via gateway).

)}
); }