feat: establish unified administration and model context baseline
This commit is contained in:
@@ -6,6 +6,8 @@ import { useAuthGeneration } from "../auth/authState";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { MarkdownView } from "../viewers/MarkdownView";
|
||||
import { EvidenceSources } from "./EvidenceSourceReview";
|
||||
import { AdministrationHeader } from "./administration/AdministrationPage";
|
||||
import { useWorkingContextScope } from "../workspaces/WorkingContext";
|
||||
|
||||
const control = "rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:ring-3 focus-visible:ring-ring/50";
|
||||
const kinds = ["domain", "glossary", "enum", "example", "mapping", "normalization", "formula", "reference"];
|
||||
@@ -32,22 +34,21 @@ function CopyText({ text, label, showText = true }: { text: string; label: strin
|
||||
</div>;
|
||||
}
|
||||
|
||||
export function EvidenceManagementPage({ canManage }: { canManage: boolean }) {
|
||||
export function EvidenceManagementPage({ canManage, initialWorkspaceId }: { canManage: boolean; initialWorkspaceId?: string }) {
|
||||
const context = useWorkingContextScope();
|
||||
const generation = useAuthGeneration();
|
||||
const [workspace, setWorkspace] = useState("");
|
||||
const [workspace, setWorkspace] = useState(initialWorkspaceId ?? "");
|
||||
const workspaces = useQuery({ queryKey: ["evidence-workspaces", generation],
|
||||
queryFn: () => apiFetch<Array<{ id: string; displayName?: string }>>("/workspaces"), enabled: canManage });
|
||||
if (!canManage) return <main className="p-6">Evidence administration is not permitted.</main>;
|
||||
return <main aria-label="Evidence management" className="flex min-h-0 flex-1 flex-col overflow-auto bg-background">
|
||||
<header className="flex flex-wrap items-end justify-between gap-4 border-b px-6 py-5">
|
||||
<div><h1 className="font-serif text-2xl font-semibold">Evidence management</h1>
|
||||
<p className="mt-1 text-sm text-muted-foreground">Review workspace knowledge and maintain its Markdown files.</p></div>
|
||||
return <main aria-label="Evidence management" className="thot-administration-page">
|
||||
<AdministrationHeader title="Evidence management" description="Review workspace knowledge and maintain its Markdown files." actions={!context &&
|
||||
<label className="grid min-w-52 gap-1 text-sm">Workspace
|
||||
<select className={control} value={workspace} onChange={event => setWorkspace(event.target.value)}>
|
||||
<option value="">Choose a workspace</option>
|
||||
{workspaces.data?.map(w => <option key={w.id} value={w.id}>{w.displayName ?? w.id}</option>)}
|
||||
</select></label>
|
||||
</header>
|
||||
} />
|
||||
{workspaces.isError && <p role="alert" className="p-6">{apiErrorMessage(workspaces.error)}</p>}
|
||||
{workspace ? <WorkspaceEvidence key={`${generation}:${workspace}`} workspace={workspace} generation={generation} />
|
||||
: <p className="p-8 text-muted-foreground">Choose a workspace to browse its Evidence and locate the files to edit.</p>}
|
||||
@@ -79,8 +80,9 @@ function WorkspaceEvidence({ workspace, generation }: { workspace: string; gener
|
||||
{list.isError && <p role="alert">{apiErrorMessage(list.error)}</p>}
|
||||
{list.isPending && <p role="status">Loading Evidence files…</p>}
|
||||
{list.data?.errors.map(error => <div key={error.file} role="alert" className="rounded-md border border-destructive/40 p-3 text-sm"><strong>{error.file}</strong><p>{error.message}</p><p>Correct this file before consolidation.</p></div>)}
|
||||
<div className="grid min-h-0 gap-6 xl:grid-cols-[minmax(20rem,2fr)_minmax(25rem,3fr)]">
|
||||
<section aria-label="Evidence list" className="min-w-0">
|
||||
<div className="thot-administration-split" style={{ margin: 0 }}>
|
||||
<section aria-label="Evidence list" className="thot-administration-index p-4">
|
||||
<h2 className="thot-administration-eyebrow mb-3">Evidence library</h2>
|
||||
<p className="mb-2 text-sm text-muted-foreground">{list.data?.total ?? 0} Evidence units</p>
|
||||
<div className="overflow-auto"><table className="w-full text-left text-sm"><thead><tr className="border-b text-muted-foreground"><th className="py-2 pr-3 font-medium">Evidence</th><th className="pr-3 font-medium">Kind</th><th className="font-medium">Status</th></tr></thead>
|
||||
<tbody>{list.data?.items.map(item => <tr key={item.id} className={`border-b ${selected === item.id ? "bg-muted" : ""}`}><td className="py-3 pr-3"><button className="text-left font-medium underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-ring" onClick={() => setSelected(item.id)}>{item.title}</button><div className="mt-1 break-all text-xs text-muted-foreground">{item.id}</div></td><td className="pr-3 align-top pt-3">{item.kind}</td><td className="align-top pt-3">{states[item.status]}</td></tr>)}</tbody>
|
||||
@@ -88,7 +90,7 @@ function WorkspaceEvidence({ workspace, generation }: { workspace: string; gener
|
||||
{list.data?.total === 0 && <p className="py-6 text-sm text-muted-foreground">No Evidence matches these filters. Clear the filters or use the file instructions to create a unit.</p>}
|
||||
<nav aria-label="Evidence pages" className="mt-4 flex items-center gap-3"><Button variant="outline" size="sm" disabled={page === 1 || list.isFetching} onClick={() => setPage(p => p-1)}>Previous</Button><span className="text-sm">Page {page}</span><Button variant="outline" size="sm" disabled={!list.data || page*25 >= list.data.total || list.isFetching} onClick={() => setPage(p => p+1)}>Next</Button></nav>
|
||||
</section>
|
||||
<section aria-label="Evidence detail" className="min-w-0">
|
||||
<section aria-label="Evidence detail" className="thot-administration-detail">
|
||||
{detail.isError ? <p role="alert">{apiErrorMessage(detail.error)}</p> : selected && detail.isPending ? <p role="status">Loading Evidence…</p> : detail.data?.item ? <UnitDetail item={detail.data.item} location={detail.data.location} /> : <p className="py-10 text-sm text-muted-foreground">Select an Evidence unit to read its complete content and provenance.</p>}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user