import { useState, useEffect } from 'react'; import { Topbar } from '../../components/layout/Topbar'; import { Upload, Search } from 'lucide-react'; import { UploadModal } from './UploadModal'; interface Doc { id: string; name: string; status: 'ok' | 'warn' | 'risk' | 'info'; uploadedAt: string; chunks: number; type: string; } const STATUS_FILTERS = ['All', 'Ready', 'Embedding', 'Failed', 'Pending']; const TYPE_OPTS = ['All types', 'EU Regulation', 'ISO Standard', 'National Draft', 'Internal Policy']; const MOCK_DOCS: Doc[] = [ { id: '1', name: 'EU AI Act — Full text (EN)', status: 'ok', uploadedAt: '2025-11-10', chunks: 842, type: 'EU Regulation' }, { id: '2', name: 'MIIT Draft 2025-08 (ZH)', status: 'ok', uploadedAt: '2025-11-01', chunks: 320, type: 'National Draft' }, { id: '3', name: 'ISO/SAE 21434:2021', status: 'ok', uploadedAt: '2025-10-15', chunks: 614, type: 'ISO Standard' }, { id: '4', name: 'Vehicle AI Safety Manual v3.2', status: 'ok', uploadedAt: '2025-10-08', chunks: 198, type: 'Internal Policy' }, { id: '5', name: 'ADAS System Requirements', status: 'warn', uploadedAt: '2025-09-22', chunks: 0, type: 'Internal Policy' }, { id: '6', name: 'UNECE R155 Corrigendum', status: 'info', uploadedAt: '2025-09-12', chunks: 87, type: 'EU Regulation' }, { id: '7', name: 'GB/T 42118-2022', status: 'risk', uploadedAt: '2025-08-30', chunks: 0, type: 'National Draft' }, ]; const STATUS_LABEL: Record = { ok: 'Ready', warn: 'Processing', risk: 'Failed', info: 'Pending' }; const STATUS_MAP: Record = { All: 'All', Ready: 'ok', Embedding: 'warn', Failed: 'risk', Pending: 'info' }; // Map backend DocumentStatus enum values to frontend display status function backendStatus(s: string): Doc['status'] { if (s === 'indexed') return 'ok'; if (s === 'failed') return 'risk'; if (s === 'parsed') return 'warn'; // chunked, awaiting embedding return 'info'; // pending / stored } export function DocsPage() { const [search, setSearch] = useState(''); const [statusF, setStatusF] = useState('All'); const [typeF, setTypeF] = useState('All types'); const [selected, setSelected] = useState>(new Set()); const [docs, setDocs] = useState(MOCK_DOCS); const [showUpload, setShowUpload] = useState(false); useEffect(() => { fetch('/api/v1/documents/management-list') .then(r => r.json()) .then(d => { if (!Array.isArray(d?.documents)) return; setDocs(d.documents.map((item: Record) => ({ id: item.doc_id as string, name: item.doc_name as string, status: backendStatus(item.status as string), uploadedAt: ((item.updated_at as string) ?? '').slice(0, 10), chunks: (item.chunk_count as number) ?? 0, type: (item.regulation_type as string) || '—', }))); }) .catch(() => {}); }, []); const filtered = docs.filter(d => { const matchSearch = !search || d.name.toLowerCase().includes(search.toLowerCase()); const matchStatus = statusF === 'All' || d.status === STATUS_MAP[statusF]; const matchType = typeF === 'All types' || d.type === typeF; return matchSearch && matchStatus && matchType; }); function toggleAll() { if (selected.size === filtered.length) setSelected(new Set()); else setSelected(new Set(filtered.map(d => d.id))); } function toggleOne(id: string) { const s = new Set(selected); s.has(id) ? s.delete(id) : s.add(id); setSelected(s); } return (
setSearch(e.target.value)} />
} />
{STATUS_FILTERS.map(f => ( ))}
{selected.size > 0 && (
{selected.size} document{selected.size > 1 ? 's' : ''} selected
)}
0} onChange={toggleAll} /> Document name Status Uploaded Chunks Type Actions
{filtered.map(d => (
toggleOne(d.id)} /> {d.name} {STATUS_LABEL[d.status]} {d.uploadedAt} {d.chunks || '—'} {d.type} {d.status === 'risk' && }
))}
{showUpload && setShowUpload(false)} />}
); }