import React, { useEffect, useMemo, useState } from "react";
import {
Alert,
Box,
Button,
Chip,
Paper,
Stack,
Typography,
} from "@mui/material";
import { api } from "../api";
type SummarizerMetrics = {
healthy: boolean;
model?: string | null;
device?: string | null;
gpuAvailable?: boolean;
gpuName?: string | null;
healthLatencyMs?: number | null;
probeLatencyMs?: number | null;
lastProbeAt?: string | null;
lastProbeSuccessAt?: string | null;
lastProbeFailureAt?: string | null;
probeFailures: number;
requests: number;
cacheHits: number;
cacheMisses: number;
failures: number;
averageLatencyMs?: number | null;
lastSuccessAt?: string | null;
lastFailureAt?: string | null;
lastError?: string | null;
};
type SystemStatus = {
environment: string;
contentRoot: string;
version: string;
commitSha?: string | null;
buildStamp?: string | null;
storage: {
dataRoot: string;
dbPath: string;
dbExists: boolean;
dbSizeBytes?: number | null;
companyCount: number;
jobCount: number;
deletedCount: number;
};
email: {
enabled: boolean;
host?: string | null;
port: number;
enableSsl: boolean;
from?: string | null;
fromName?: string | null;
};
database: {
provider: string;
looksConfigured: boolean;
canConnect: boolean;
target?: string | null;
usesFileStorage: boolean;
warning?: string | null;
};
runtime: {
framework: string;
osDescription: string;
processArchitecture: string;
machineName?: string | null;
};
auth: {
required: boolean;
hasJwtKey: boolean;
googleConfigured: boolean;
gmailConfigured: boolean;
};
summarizer: SummarizerMetrics;
};
function formatBytes(bytes?: number | null) {
if (bytes == null) return "-";
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
function displayMetadata(value?: string | null) {
return value && value.trim().length > 0 ? value : "-";
}
function formatDate(value?: string | null) {
return value ? new Date(value).toLocaleString() : "-";
}
function SummaryCard({ title, value, subtitle, tone = "default" }: { title: string; value: string; subtitle?: string; tone?: "default" | "success" | "warning" | "error" }) {
const color = tone === "success" ? "success.main" : tone === "warning" ? "warning.main" : tone === "error" ? "error.main" : "text.primary";
return (
{title}
{value}
{subtitle || "-"}
);
}
function DetailRow({ label, value }: { label: string; value: React.ReactNode }) {
return {label}: {value};
}
export default function AdminSystemPage() {
const [status, setStatus] = useState(null);
const [loading, setLoading] = useState(false);
const [runningProbe, setRunningProbe] = useState(false);
const [error, setError] = useState(null);
const load = async () => {
setLoading(true);
setError(null);
try {
const res = await api.get("/admin/system");
setStatus(res.data);
} catch (e: any) {
setError(e?.response?.data || e?.message || "Failed to load system status.");
setStatus(null);
} finally {
setLoading(false);
}
};
useEffect(() => {
void load();
}, []);
const dbTone = useMemo(() => {
if (!status) return "default" as const;
if (!status.database.looksConfigured || !status.database.canConnect) return "error" as const;
if (status.database.warning) return "warning" as const;
return "success" as const;
}, [status]);
const summarizerTone = useMemo(() => {
if (!status) return "default" as const;
if (!status.summarizer.healthy) return "error" as const;
if (status.summarizer.probeFailures > 0 || status.summarizer.failures > 0) return "warning" as const;
return "success" as const;
}, [status]);
return (
System status
Production diagnostics for runtime, database, auth, email, and summarizer health.
{error ? {error} : null}
{status?.database.warning ? {status.database.warning} : null}
{status?.summarizer.lastError ? {status.summarizer.lastError} : null}
Database and storage
Runtime and auth
Email configuration
Summarizer runtime
Summarizer telemetry
Requests{status?.summarizer.requests ?? 0}
Cache hits{status?.summarizer.cacheHits ?? 0}
Cache misses{status?.summarizer.cacheMisses ?? 0}
Failures{status?.summarizer.failures ?? 0}
Probe failures{status?.summarizer.probeFailures ?? 0}
Avg latency{status?.summarizer.averageLatencyMs != null ? `${status.summarizer.averageLatencyMs} ms` : "-"}
);
}