From 7997dbb3f31efcdc72bda764ca898442545c4684 Mon Sep 17 00:00:00 2001 From: jules Date: Sat, 11 Jul 2026 09:03:35 +1000 Subject: [PATCH] feat(kb-ui): humanise provenance "Added by" via an injected resolver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProvenancePanel/ObjectViewer gain an optional resolvePrincipal(p) prop so the consumer can turn a {type,id} principal ref into a human label — the lib can't know who "you" is. Falls back to the raw type·id when the resolver returns undefined, so existing callers are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/components-object.tsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components-object.tsx b/src/components-object.tsx index d0e179a..47deda5 100644 --- a/src/components-object.tsx +++ b/src/components-object.tsx @@ -16,7 +16,7 @@ import { Tag, Trash2, } from "lucide-react"; -import type { ObjectOutline, ObjectSummary, OutlineSection, TextSlice } from "./types"; +import type { ObjectOutline, ObjectSummary, OutlineSection, PrincipalRef, TextSlice } from "./types"; import { Badge, SensitivityBadge, @@ -160,11 +160,20 @@ export const CatalogCard: FC<{ outline: ObjectOutline; className?: string }> = ( // ---- ProvenancePanel ------------------------------------------------------ -export const ProvenancePanel: FC<{ outline: ObjectOutline; className?: string }> = ({ outline, className }) => { +export const ProvenancePanel: FC<{ + outline: ObjectOutline; + /** Turn a principal ref into a human label ("You", an agent's name, …). The + * lib can't know who "you" is, so the app supplies this; falls back to the + * raw type·id when it returns undefined. */ + resolvePrincipal?: (p: string | PrincipalRef) => string | undefined; + className?: string; +}> = ({ outline, resolvePrincipal, className }) => { const p = outline.provenance; + const addedBy = + (p.created_by != null ? resolvePrincipal?.(p.created_by) : undefined) ?? formatPrincipal(p.created_by) ?? "—"; const rows: [string, ReactNode][] = [ ["Source", p.source_ref ? `${p.source_type} · ${p.source_ref}` : p.source_type], - ["Added by", formatPrincipal(p.created_by) ?? "—"], + ["Added by", addedBy], ["Added", formatDate(p.inserted_at)], ["Effective", p.effective_at ? formatDate(p.effective_at) : "—"], ["Last verified", p.verified_at ? formatDate(p.verified_at) : "Not confirmed"], @@ -499,6 +508,8 @@ export interface ObjectViewerProps { readText: TextReaderProps["readText"]; /** Resolve a browser-openable blob URL (for images + download). */ resolveBlobUrl?: () => Promise; + /** Humanise the "Added by" principal (see ProvenancePanel). */ + resolvePrincipal?: (p: string | PrincipalRef) => string | undefined; highlight?: { start: number; end: number }; onOpenObject?: (objectId: string, span?: { start: number; end: number }) => void; actions?: ObjectActions; @@ -509,6 +520,7 @@ export const ObjectViewer: FC = ({ outline, readText, resolveBlobUrl, + resolvePrincipal, highlight, onOpenObject, actions, @@ -602,7 +614,7 @@ export const ObjectViewer: FC = ({ setActiveSection(s.id)} /> )} - +