import { useI18n } from "../i18n"; import { useState } from "react"; import { Copy } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; import { apiFetch, apiErrorMessage } from "../api/client"; import { listEvidence, getEvidence, type EvidencePage, type EvidenceUnit } from "../api/evidence"; 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"]; const states: Record = { new: "New file", modified: "Modified", active: "Active locally", removed: "Removed file", review_required: "Needs review", legacy: "Conversion required", invalid: "Invalid file" }; const templates: Record = { domain: "## Rule\n\nDescribe the approved domain rule.", glossary: "## Definition\n\nDefine the concept.\n\n## Synonyms\n\n- Alternative name\n\n## Variants\n", enum: '## Column\n\nsales.orders.status\n\n## Values\n\n### "A"\n\nActive', example: "## Question\n\nHow many orders?\n\n## Interpretation\n\nCount distinct orders.", mapping: "## Concept\n\nOrders\n\n## Tables\n\n- sales.orders\n\n## Columns\n\n- sales.orders.id", normalization: "## Input\n\nA\n\n## Output\n\nActive\n\n## Rule\n\nExpand the status abbreviation.", formula: "## Concept\n\nTotal amount\n\n## Columns\n\n- sales.lines.amount\n\n## SQL\n\n```sql\nsum(amount)\n```", reference: "## URL\n\nhttps://example.org/policy\n\n## Label\n\nPolicy\n\n## Description\n\nDescribe the reference.", }; function CopyText({ text, label, showText = true }: { text: string; label: string; showText?: boolean }) { const { t } = useI18n(); const [notice, setNotice] = useState(""); return
{showText && {text}} {notice && {t(notice)}}
; } export function EvidenceManagementPage({ canManage, initialWorkspaceId }: { canManage: boolean; initialWorkspaceId?: string }) { const { t } = useI18n(); const context = useWorkingContextScope(); const generation = useAuthGeneration(); const [workspace, setWorkspace] = useState(initialWorkspaceId ?? ""); const workspaces = useQuery({ queryKey: ["evidence-workspaces", generation], queryFn: () => apiFetch>("/workspaces"), enabled: canManage }); if (!canManage) return
{t("Evidence administration is not permitted.")}
; return
{t("Workspace")} } /> {workspaces.isError &&

{t(apiErrorMessage(workspaces.error))}

} {workspace ? :

{t("Choose a workspace to browse its Evidence and locate the files to edit.")}

}
; } function WorkspaceEvidence({ workspace, generation }: { workspace: string; generation: number }) { const { t } = useI18n(); const [filters, setFilters] = useState>({ q: "", kind: "", purpose: "", status: "", sort: "title", direction: "asc" }); const [page, setPage] = useState(1); const [selected, setSelected] = useState(""); const list = useQuery({ queryKey: ["evidence", generation, workspace, filters, page], queryFn: () => listEvidence(workspace, { ...filters, page, page_size: 25 }) }); const detail = useQuery({ queryKey: ["evidence-detail", generation, workspace, selected], queryFn: () => getEvidence(workspace, selected), enabled: Boolean(selected) }); function filter(key: string, value: string) { setFilters(old => ({ ...old, [key]: value })); setPage(1); } return
{list.data && }
filter("purpose", v)} /> filter(key, e.target.value)} />)} filter("direction", v)} all={false} />
{list.isError &&

{t(apiErrorMessage(list.error))}

} {list.isPending &&

{t("Loading Evidence files…")}

} {list.data?.errors.map(error =>
{error.file}

{t(error.message)}

{t("Correct this file before consolidation.")}

)}

{t("Evidence library")}

{list.data?.total ?? 0} {t("Evidence units")}

{list.data?.items.map(item => )}
{t("Evidence")}{t("Kind")}{t("Status")}
{item.id}
{t(item.kind)}{t(states[item.status])}
{list.data?.total === 0 &&

{t("No Evidence matches these filters. Clear the filters or use the file instructions to create a unit.")}

}
{detail.isError ?

{t(apiErrorMessage(detail.error))}

: selected && detail.isPending ?

{t("Loading Evidence…")}

: detail.data?.item ? :

{t("Select an Evidence unit to read its complete content and provenance.")}

}
; } function Select({ label, value, values, labels = {}, onChange, all = true }: { label: string; value: string; values: string[]; labels?: Record; onChange: (value: string) => void; all?: boolean }) { const { t } = useI18n(); return ; } function Instructions({ data }: { data: EvidencePage }) { const { t } = useI18n(); const [kind, setKind] = useState("domain"); const example = `---\nschema_version: 4\nid: evidence:my-unit\nkind: ${kind}\nlanguage: en\npurposes: [sql_generation]\n---\n\n# My Evidence\n\n${templates[kind]}\n`; return

{data.pending_revision ? t("Consolidation is incomplete. The previous active content remains available.") : data.active_revision ? t("The core uses the last successfully consolidated version.") : t("Run the first consolidation to convert and activate the local archive.")}

{t("Edit files, consolidate and commit")} {data.location.workspace ?

{t("Workspace on the installation host")}

:

{t("A host file path is unavailable for this installation. Configure a persistent workspace-registry bind mount before editing files from the host.")}

}
  1. {t("Edit the files under")} evidence/curated/<kind>/ {t("with your preferred editor. Keep existing IDs. Remove a unit's file to delete it; keep the curated directory.")}
  2. {t("Check Git status and the diff. Saving a file does not update recall.")}{data.location.git_commands.slice(0, 2).map(command =>
    )}
  3. {t("From the installation directory, run this command. It validates and activates Evidence without a full preprocessing run. If needed, add")} --installation /absolute/path/thothii-installation.yaml {t("immediately after")} tht.
  4. {t("After success, review the generated metadata and complete Git commit/push manually. These commands use a POSIX shell on the installation host. A remote host's path is not a file on this browser's computer.")}{data.location.git_commands.slice(2).map(command =>
    )}

{t("Source drafts are preserved under evidence/source/. Maintain the refined files under evidence/curated/. New source acquisition and refresh are not part of consolidation.")}

{t("Create a manual Evidence file")}