This commit is contained in:
wangwei
2026-06-04 15:43:44 +08:00
parent ac490d851a
commit 746513cc54
11 changed files with 955 additions and 131 deletions
+44 -16
View File
@@ -1,8 +1,11 @@
import { useState, useEffect } from 'react';
import { Topbar } from '../../components/layout/Topbar';
import { Search, Upload, Download } from 'lucide-react';
import { Search, Upload, Download, RefreshCw } from 'lucide-react';
import { UploadModal } from '../Docs/UploadModal';
interface Stats { total_documents: number; vector_chunks: number; high_impact: number; last_90_days: number; }
// Backend /api/v1/status/stats returns:
// { documents_total, documents_indexed, documents_failed, chunks_total }
interface Stats { documents_total: number; documents_indexed: number; documents_failed: number; chunks_total: number; }
const TASKS = [
{ name: 'EU AI Act — Article 13 check', status: 'ok', progress: 88, cta: 'View report' },
@@ -40,13 +43,20 @@ const STATUS_LABEL: Record<string, string> = { ok: 'Complete', warn: 'In progres
export function StatusPage() {
const [stats, setStats] = useState<Stats | null>(null);
const [loading, setLoading] = useState(true);
const [refreshKey, setRefreshKey] = useState(0);
const [showUpload, setShowUpload] = useState(false);
useEffect(() => {
fetch('/api/v1/perception/stats')
setLoading(true);
fetch('/api/v1/status/stats')
.then(r => r.json())
.then(d => setStats(d))
.catch(() => setStats({ total_documents: 42, vector_chunks: 3841, high_impact: 7, last_90_days: 14 }));
}, []);
.then(d => { setStats(d); setLoading(false); })
.catch(() => {
setStats({ documents_total: 42, documents_indexed: 38, documents_failed: 1, chunks_total: 3841 });
setLoading(false);
});
}, [refreshKey]);
return (
<div className="status-page">
@@ -58,28 +68,44 @@ export function StatusPage() {
<Search size={13} />
<input placeholder="Search..." />
</div>
<button className="btn sm"><Download size={13} />Export status</button>
<button className="btn sm primary"><Upload size={13} />New upload</button>
<button
className="btn sm"
onClick={() => {
const blob = new Blob([JSON.stringify(stats, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = 'regulation-hub-status.json'; a.click();
URL.revokeObjectURL(url);
}}
>
<Download size={13} />Export status
</button>
<button className="btn sm" onClick={() => setRefreshKey(k => k + 1)}>
<RefreshCw size={13} />Refresh
</button>
<button className="btn sm primary" onClick={() => setShowUpload(true)}>
<Upload size={13} />New upload
</button>
</>
}
/>
<div className="page-content">
<div className="stats-grid">
<div className="stat-cell">
<div className="stat-value">{stats?.total_documents ?? '—'}</div>
<div className="stat-label">Documents indexed</div>
{loading ? <span className="loading-shimmer stat-value-loading" /> : <div className="stat-value">{stats?.documents_total ?? '—'}</div>}
<div className="stat-label">Documents total</div>
</div>
<div className="stat-cell">
<div className="stat-value">{stats?.vector_chunks?.toLocaleString() ?? '—'}</div>
<div className="stat-label">Vector chunks</div>
{loading ? <span className="loading-shimmer stat-value-loading" /> : <div className="stat-value">{stats?.documents_indexed ?? '—'}</div>}
<div className="stat-label">Indexed</div>
</div>
<div className="stat-cell danger">
<div className="stat-value">{stats?.high_impact ?? '—'}</div>
<div className="stat-label">High-impact signals</div>
{loading ? <span className="loading-shimmer stat-value-loading" /> : <div className="stat-value">{stats?.documents_failed ?? '—'}</div>}
<div className="stat-label">Failed</div>
</div>
<div className="stat-cell">
<div className="stat-value">{stats?.last_90_days ?? '—'}</div>
<div className="stat-label">Last 90 days</div>
{loading ? <span className="loading-shimmer stat-value-loading" /> : <div className="stat-value">{stats?.chunks_total?.toLocaleString() ?? '—'}</div>}
<div className="stat-label">Vector chunks</div>
</div>
</div>
@@ -150,6 +176,8 @@ export function StatusPage() {
<div className="live-dot" />
<span>Regulation Hub · T-Systems AI · Online</span>
</footer>
{showUpload && <UploadModal onClose={() => setShowUpload(false)} />}
</div>
);
}