Phase 5: secondary screens (diagnostics, skills, training)
Port the remaining read views from the vanilla UI to Next.js:
- /diagnostics — system health snapshot (DB connected, table counts,
active tasks, failed and stuck documents). Uses the existing
/api/system/diagnostics payload with a 10s refetchInterval so the
page self-updates while the user watches.
- /skills — Paperclip skill inventory with sync status (DB-only,
disk-only, synced, not-synced) as a card grid driven by
/api/admin/skills.
- /training — Dafna's style portrait as three tabs on one page:
* Report: corpus KPIs + CSS conic-gradient subject donut
(SubjectDonut ported from index.html renderHero) + horizontal
anatomy bars + top-12 signature phrases.
* Corpus: TanStack Table of style_corpus rows with an inline
delete mutation (useDeleteCorpusEntry invalidates both the
corpus list and the style report so KPIs update).
* Compare: two-decision selector backed by /api/training/compare,
side-by-side panels plus shared / only-A / only-B pattern
lists.
New API modules: lib/api/system.ts, lib/api/skills.ts,
lib/api/training.ts. All three use TanStack Query with staleTime
profiles tuned per endpoint (10s for diagnostics, 30s for skills,
60s for training reports).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
42
web-ui/src/lib/api/system.ts
Normal file
42
web-ui/src/lib/api/system.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* System-level hooks: diagnostics + active task snapshot.
|
||||
*
|
||||
* The vanilla UI polled /api/system/diagnostics and /api/system/tasks on
|
||||
* an interval. We replace the polling with TanStack Query's refetchInterval
|
||||
* — same effect, but participates in the shared cache and survives route
|
||||
* transitions without setting up its own setInterval bookkeeping.
|
||||
*/
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { apiRequest } from "./client";
|
||||
|
||||
export type DiagDoc = {
|
||||
id: string;
|
||||
title: string;
|
||||
status: string;
|
||||
case_number: string;
|
||||
created_at: string | null;
|
||||
};
|
||||
|
||||
export type Diagnostics = {
|
||||
db_ok: boolean;
|
||||
tables: Record<string, number | null>;
|
||||
failed_documents: DiagDoc[];
|
||||
stuck_documents: DiagDoc[];
|
||||
active_tasks: Array<{
|
||||
task_id: string;
|
||||
filename: string;
|
||||
status: string;
|
||||
step: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export function useDiagnostics() {
|
||||
return useQuery({
|
||||
queryKey: ["system", "diagnostics"] as const,
|
||||
queryFn: ({ signal }) =>
|
||||
apiRequest<Diagnostics>("/api/system/diagnostics", { signal }),
|
||||
refetchInterval: 10_000,
|
||||
staleTime: 5_000,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user