fix(ui): improve knowledge reading and add isolated formatting examples

This commit is contained in:
Codex
2026-09-13 16:52:53 +02:00
parent 2953f6b608
commit 3535fda958
14 changed files with 362 additions and 19 deletions
@@ -1,5 +1,6 @@
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";
@@ -28,11 +29,11 @@ function CopyText({ text, label, showText = true }: { text: string; label: strin
const { t } = useI18n();
const [notice, setNotice] = useState("");
return <div className="flex min-w-0 flex-wrap items-start gap-2">
{showText && <code className="min-w-0 flex-1 break-all text-xs select-text">{text}</code>}
<Button size="sm" variant="outline" aria-label={t("Copy {label}", { label: label })} onClick={async () => {
{showText && <code className="min-w-0 flex-1 [overflow-wrap:anywhere] text-xs select-text">{text}</code>}
<Button size="icon" variant="ghost" title={t("Copy {label}", { label })} aria-label={t("Copy {label}", { label })} onClick={async () => {
try { await navigator.clipboard.writeText(text); setNotice("Copied"); }
catch { setNotice("Select the text and copy it manually."); }
}}>{t("Copy")}</Button><span role="status" className="text-xs text-muted-foreground">{t(notice)}</span>
}}><Copy aria-hidden="true" /></Button>{notice && <span role="status" className="basis-full text-xs text-muted-foreground">{t(notice)}</span>}
</div>;
}
@@ -113,7 +114,7 @@ function Instructions({ data }: { data: EvidencePage }) {
<p className="mb-2 text-sm font-medium">{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.")}</p>
<details className="mt-3"><summary className="cursor-pointer text-sm font-medium">{t("Edit files, consolidate and commit")}</summary>
{data.location.workspace ? <div className="mt-3"><p className="mb-1 text-xs text-muted-foreground">{t("Workspace on the installation host")}</p><CopyText text={data.location.workspace} label={t("workspace path")} /></div> : <p role="alert" className="mt-3 text-sm">{t("A host file path is unavailable for this installation. Configure a persistent workspace-registry bind mount before editing files from the host.")}</p>}
<ol className="mt-3 max-w-[75ch] list-decimal space-y-3 pl-5 text-sm">
<ol className="mt-3 list-decimal space-y-3 pl-5 text-sm">
<li>{t("Edit the files under")} <code>evidence/curated/&lt;kind&gt;/</code> {t("with your preferred editor. Keep existing IDs. Remove a unit's file to delete it; keep the curated directory.")}</li>
<li>{t("Check Git status and the diff. Saving a file does not update recall.")}{data.location.git_commands.slice(0, 2).map(command => <div className="mt-2" key={command}><CopyText text={command} label={t("Git inspection command")} /></div>)}</li>
<li>{t("From the installation directory, run this command. It validates and activates Evidence without a full preprocessing run. If needed, add")} <code>--installation /absolute/path/thothii-installation.yaml</code> {t("immediately after")} <code>tht</code>.
@@ -130,14 +131,14 @@ function UnitDetail({ item, location }: { item: EvidenceUnit; location: Evidence
const { t } = useI18n();
const source = item.provenance.kind === "manual" ? item.provenance.original : item.provenance;
const file = location.workspace ? `${location.workspace.replace(/\\/g, "/")}/evidence/${item.file}` : null;
return <article className="max-w-[75ch] space-y-5 pb-8">
return <article className="min-w-0 w-full space-y-5 pb-8 [overflow-wrap:anywhere]">
<header><p className="text-xs text-muted-foreground">{t(states[item.status])} · {item.purposes.map(purpose => t(purpose.replaceAll("_", " "))).join(", ")}</p><h2 className="mt-1 font-sans text-xl font-semibold">{item.title}</h2></header>
{file && <CopyText text={file} label={t("Evidence file path")} />}
{item.status !== "active" && <p className="text-sm text-muted-foreground">{["invalid", "removed"].includes(item.status) ? t("The file is invalid or removed. Its last active content is shown here.") : t("This is the file version awaiting consolidation.")} {t("The core continues to use its last active version.")}</p>}
{Object.entries(item.applies_to).some(([, values]) => values.length > 0) && <section><h3 className="font-medium">{t("Scope")}</h3>{Object.entries(item.applies_to).map(([name, values]) => values.length > 0 && <p className="mt-2 break-words text-sm" key={name}><span className="capitalize">{t(name)}</span>: {values.join(", ")}</p>)}</section>}
{Object.entries(item.payload).map(([field, value]) => <section key={field}><h3 className="mb-2 text-sm font-semibold capitalize">{t(field.replaceAll("_", " "))}</h3>{typeof value === "string" ? field === "sql" ? <pre className="overflow-auto rounded-md bg-muted p-3 text-sm">{value}</pre> : <MarkdownView source={value} /> : Array.isArray(value) ? <ul className="list-inside list-disc text-sm">{value.map(v => <li key={v}>{v}</li>)}</ul> : <dl className="space-y-2 text-sm">{Object.entries(value).map(([key, text]) => <div key={key}><dt className="font-mono font-medium">{key || t("(empty value)")}</dt><dd>{text}</dd></div>)}</dl>}</section>)}
{Object.entries(item.payload).map(([field, value]) => <section key={field}><h3 className="mb-2 text-sm font-semibold capitalize">{t(field.replaceAll("_", " "))}</h3>{typeof value === "string" ? field === "sql" ? <pre className="overflow-auto whitespace-pre-wrap [overflow-wrap:anywhere] rounded-md bg-muted p-3 text-sm">{value}</pre> : <MarkdownView source={value} readable /> : Array.isArray(value) ? <ul className="list-inside list-disc space-y-2 text-sm">{value.map(v => <li key={v}>{v}</li>)}</ul> : <dl className="space-y-2 text-sm">{Object.entries(value).map(([key, text]) => <div key={key}><dt className="font-mono font-medium">{key || t("(empty value)")}</dt><dd><MarkdownView source={text} readable /></dd></div>)}</dl>}</section>)}
<section className="border-t pt-4"><h3 className="font-medium">{t("Provenance")}</h3><p className="mt-2 text-sm">{item.provenance.kind === "manual" ? t("Manual declaration by {author}.", { author: item.provenance.declared_by ?? "" }) : t("Derived from a source document.")}</p>
{source?.source_file && <><p className="mt-2 break-all text-xs">{item.provenance.kind === "manual" ? t("Original document (lineage): ") : t("Source: ")}{source.source_file}</p>{source.supporting_excerpts?.map((text, i) => <p key={i} className="mt-2 whitespace-pre-wrap text-sm text-muted-foreground">“{text}”</p>)}</>}
{source?.source_file && <><p className="mt-2 [overflow-wrap:anywhere] text-xs">{item.provenance.kind === "manual" ? t("Original document (lineage): ") : t("Source: ")}{source.source_file}</p>{source.supporting_excerpts?.map((text, i) => <div key={i} className="mt-4"><MarkdownView source={text} readable /></div>)}</>}
</section>
{item.review_items.length > 0 && <section><h3 className="font-medium">{t("Review required")}</h3>{item.review_items.map((review, i) => <p key={i} className="mt-2 text-sm">{t(review.message)}</p>)}</section>}
</article>;