Added 'force-dynamic' export to admin orders and status pages for dynamic rendering. Updated next.config.mjs to modularize imports for better tree-shaking and switched to Turbopack for optimal bundle sizes. Upgraded Next.js and related dependencies in package.json and package-lock.json.
183 lines
6.9 KiB
TypeScript
183 lines
6.9 KiB
TypeScript
import React from "react";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Server, Database, Cpu, HardDrive, Activity } from "lucide-react";
|
|
import { fetchServer } from "@/lib/api";
|
|
import SystemStatusCard from "@/components/admin/SystemStatusCard";
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
interface SystemStatus {
|
|
uptimeSeconds: number;
|
|
memory: {
|
|
rss: number;
|
|
heapTotal: number;
|
|
heapUsed: number;
|
|
external: number;
|
|
arrayBuffers: number;
|
|
};
|
|
versions: Record<string, string>;
|
|
counts: {
|
|
vendors: number;
|
|
orders: number;
|
|
products: number;
|
|
chats: number;
|
|
};
|
|
}
|
|
|
|
export default async function AdminStatusPage() {
|
|
let systemStatus: SystemStatus | null = null;
|
|
let error: string | null = null;
|
|
|
|
try {
|
|
systemStatus = await fetchServer<SystemStatus>("/admin/system-status");
|
|
} catch (err) {
|
|
console.error("Failed to fetch system status:", err);
|
|
error = "Failed to load system status";
|
|
}
|
|
if (error) {
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h1 className="text-2xl font-semibold tracking-tight">System Status</h1>
|
|
<p className="text-sm text-muted-foreground mt-1">Monitor system health and performance metrics</p>
|
|
</div>
|
|
<Card>
|
|
<CardContent className="pt-6">
|
|
<div className="text-center text-red-500">
|
|
<p>{error}</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const formatUptime = (seconds: number) => {
|
|
const days = Math.floor(seconds / 86400);
|
|
const hours = Math.floor((seconds % 86400) / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
return `${days}d ${hours}h ${minutes}m`;
|
|
};
|
|
|
|
const formatBytes = (bytes: number) => {
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
if (bytes === 0) return '0 Bytes';
|
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
|
|
};
|
|
|
|
const memoryUsagePercent = systemStatus ?
|
|
Math.round((systemStatus.memory.heapUsed / systemStatus.memory.heapTotal) * 100) : 0;
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h1 className="text-2xl font-semibold tracking-tight">System Status</h1>
|
|
<p className="text-sm text-muted-foreground mt-1">Monitor system health and performance metrics</p>
|
|
</div>
|
|
|
|
<SystemStatusCard />
|
|
|
|
<div className="grid gap-4 lg:gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
{/* Server Status */}
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Server Status</CardTitle>
|
|
<Server className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge variant="default" className="bg-green-500">Online</Badge>
|
|
<span className="text-sm text-muted-foreground">
|
|
{systemStatus ? formatUptime(systemStatus.uptimeSeconds) : 'N/A'}
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mt-2">
|
|
Last checked: {new Date().toLocaleTimeString()}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Database Status */}
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Database</CardTitle>
|
|
<Database className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge variant="default" className="bg-green-500">Connected</Badge>
|
|
<span className="text-sm text-muted-foreground">
|
|
{systemStatus ? `${systemStatus.counts.vendors + systemStatus.counts.orders + systemStatus.counts.products} records` : 'N/A'}
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mt-2">
|
|
Total collections: 4
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Memory Usage */}
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Memory</CardTitle>
|
|
<HardDrive className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge variant={memoryUsagePercent > 80 ? "destructive" : memoryUsagePercent > 60 ? "secondary" : "outline"}>
|
|
{memoryUsagePercent}%
|
|
</Badge>
|
|
<span className="text-sm text-muted-foreground">
|
|
{systemStatus ? formatBytes(systemStatus.memory.heapUsed) : 'N/A'}
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mt-2">
|
|
Total: {systemStatus ? formatBytes(systemStatus.memory.heapTotal) : 'N/A'}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Platform Stats */}
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Platform Stats</CardTitle>
|
|
<Activity className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge variant="default" className="bg-green-500">Active</Badge>
|
|
<span className="text-sm text-muted-foreground">
|
|
{systemStatus ? `${systemStatus.counts.vendors} vendors` : 'N/A'}
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mt-2">
|
|
{systemStatus ? `${systemStatus.counts.orders} orders, ${systemStatus.counts.products} products` : 'N/A'}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Node.js Version */}
|
|
<Card>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">Runtime</CardTitle>
|
|
<Activity className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center space-x-2">
|
|
<Badge variant="outline">
|
|
{systemStatus ? `Node ${systemStatus.versions.node}` : 'N/A'}
|
|
</Badge>
|
|
<span className="text-sm text-muted-foreground">Runtime</span>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mt-2">
|
|
{systemStatus ? `V8: ${systemStatus.versions.v8}` : 'N/A'}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|