import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks"; import { useT } from "@agent-native/core/client/i18n"; import { IconBook, IconCheck, IconFilter, IconSearch, IconTable, IconX, } from "@tabler/icons-react"; import { useMemo, useState } from "react"; import { useSearchParams } from "react-router"; import { type CanonicalPreviewData, CanonicalPreviewSheet, } from "@/components/brain/CanonicalPreviewSheet"; import { EmptyActionState, LoadingRows, PageHeader, StatusBadge, } from "@/components/brain/Surface"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { type KnowledgeResponse, type KnowledgeRow, formatPercent, statusLabel, } from "@/lib/brain"; const statusOptions = [ "all", "published", "approved", "needs_review", "draft", "stale", "redacted", "archived", ]; const typeOptions = [ "all", "manual", "generic", "slack", "granola", "Docs", "Notion", "GitHub", "Drive", ]; export default function KnowledgeRoute() { const t = useT(); const [params, setParams] = useSearchParams(); const query = params.get("q") ?? ""; const status = params.get("status") ?? "all"; const type = params.get("type") ?? "all"; const [previewOpen, setPreviewOpen] = useState(false); const [canonicalPreview, setCanonicalPreview] = useState(null); const [previewRow, setPreviewRow] = useState(null); const [previewOperation, setPreviewOperation] = useState< "publish" | "unpublish" >("publish"); const knowledgeQuery = useActionQuery( "search-knowledge" as any, { query: query || undefined, status: status === "all" ? undefined : status, sourceType: type === "all" ? undefined : type, } as any, ); const setCanonical = useActionMutation< unknown, { knowledgeId: string; published: boolean } >("set-knowledge-canonical" as any); const previewCanonical = useActionMutation< { preview: CanonicalPreviewData }, { knowledgeId: string; operation: "publish" | "unpublish" } >("preview-canonical-resource" as any); const actionRows = knowledgeQuery.data?.rows ?? knowledgeQuery.data?.knowledge; const rows = actionRows ?? []; const hasActiveFilters = Boolean(query) || status !== "all" || type !== "all"; const filteredRows = useMemo(() => { return rows.filter((row) => { const matchesQuery = query ? `${row.title} ${row.summary ?? row.body ?? ""} ${row.sourceName ?? row.sourceId ?? ""} ${row.topic ?? ""}` .toLowerCase() .includes(query.toLowerCase()) : true; const matchesStatus = status === "all" ? true : row.status === status; const matchesType = type === "all" ? true : row.sourceType === type; return matchesQuery && matchesStatus && matchesType; }); }, [query, rows, status, type]); function updateParam(key: string, value: string) { const next = new URLSearchParams(params); if (!value || value === "all") next.delete(key); else next.set(key, value); setParams(next, { replace: true }); } async function openCanonicalPreview(row: KnowledgeRow) { const operation = row.publishedResourcePath ? "unpublish" : "publish"; const result = await previewCanonical.mutateAsync({ knowledgeId: row.id, operation, }); setCanonicalPreview(result.preview); setPreviewRow(row); setPreviewOperation(operation); setPreviewOpen(true); } async function confirmCanonicalChange() { if (!previewRow) return; await setCanonical.mutateAsync({ knowledgeId: previewRow.id, published: previewOperation === "publish", }); setPreviewOpen(false); setCanonicalPreview(null); setPreviewRow(null); } return (
{t("knowledge.rows", { count: filteredRows.length.toLocaleString(), })} } />
updateParam("q", event.target.value)} placeholder={t("knowledge.searchPlaceholder")} className="ps-9" />
{knowledgeQuery.isLoading ? ( ) : filteredRows.length ? ( {t("navigation.knowledge")} {t("searchPage.source")} {t("searchPage.status")} {t("knowledge.companyContext")} {t("searchPage.confidence")} {t("knowledge.cites")} {filteredRows.map((row) => (

{row.title}

{row.topic ? ( {row.topic} ) : null}

{row.summary ?? row.body ?? t("knowledge.noSummary")}

{row.owner ? (

{t("knowledge.owner", { owner: row.owner })}

) : null}
{row.sourceName ?? row.sourceId ?? t("searchPage.source")}
{row.sourceType ?? t("knowledge.source")}
void openCanonicalPreview(row)} /> {typeof row.confidence === "number" ? formatPercent(row.confidence) : t("knowledge.notApplicable")} {row.citations ?? 0}
))}
) : ( )} {setCanonical.isError || previewCanonical.isError ? ( ) : null} {knowledgeQuery.isError ? ( ) : null}
{t("knowledge.viewStateMirrored")}
void confirmCanonicalChange()} />
); } function CanonicalControl({ row, pending, onPreview, }: { row: KnowledgeRow; pending: boolean; onPreview: () => void; }) { const t = useT(); const isPublished = Boolean(row.publishedResourcePath); const canPublish = row.status === "published"; if (!canPublish && !isPublished) { return ( {t("knowledge.notEligible")} ); } return ( ); }