"use client"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { AlertTriangle, CheckCircle2, Clock, Layers, Loader2, RefreshCw, Star, } from "lucide-react"; import { formatKnowledgeTimestamp, kbCanReindex, kbNeedsReindex, resolveKbStatus, resolveProgressPercent, type IndexVersion, type KnowledgeBase, } from "@/lib/knowledge-helpers"; import type { TaskState } from "@/hooks/useKnowledgeProgress"; import ProcessLogs from "@/components/common/ProcessLogs"; interface KbIndexVersionsSectionProps { kb: KnowledgeBase; task?: TaskState; onReindex: () => Promise; } export default function KbIndexVersionsSection({ kb, task, onReindex, }: KbIndexVersionsSectionProps) { const { t } = useTranslation(); const [submitting, setSubmitting] = useState(false); const versions = kb.statistics?.index_versions ?? []; const activeSig = kb.statistics?.active_signature ?? null; const needsReindex = kbNeedsReindex(kb); const isError = resolveKbStatus(kb) === "error"; const mismatch = Boolean(kb.metadata?.embedding_mismatch); const isReindexingHere = (task?.kind === "reindex" || task?.kind === "retry") && task.executing; const percent = resolveProgressPercent(kb.progress); const lastIndexed = formatKnowledgeTimestamp(kb.metadata?.last_indexed_at); const lastIndexedCount = kb.metadata?.last_indexed_count; const handleReindex = async () => { setSubmitting(true); try { await onReindex(); } finally { setSubmitting(false); } }; const showReindexCta = kbCanReindex(kb); return (
{t("Index versions")} {versions.length}

{t( "Each embedding configuration gets its own stored vector index.", )}

{showReindexCta && ( )}
{(isError || needsReindex || mismatch) && (
{isError ? t( "Previous indexing failed. Retry will rebuild the index from the existing source documents.", ) : t( "The active embedding configuration doesn't match any ready index version. Re-index to rebuild against the current embedding model.", )}
)}
{t("Last indexed")}:{" "} {lastIndexed || t("Not recorded yet")} {typeof lastIndexedCount === "number" && ( ·{" "} {t( lastIndexedCount === 1 ? "{{count}} indexed doc" : "{{count}} indexed docs", { count: lastIndexedCount }, )} )}
{versions.length > 0 ? ( ) : (
{t("No index versions yet.")}
)} {(task?.kind === "reindex" || task?.kind === "retry") && (task.taskId || task.logs.length > 0 || task.executing) && (
{task.label} {task.taskId ? ` · ${task.taskId}` : ""} {task.executing && percent > 0 && ( {percent}% )}
{task.executing && (
)} {task.error && (
                  {task.error}
                
)}
)}
); } function IndexVersionRow({ version, activeSignature, }: { version: IndexVersion; activeSignature: string | null; }) { const { t } = useTranslation(); const matchesActive = !!version.signature && version.signature === activeSignature; const isActive = matchesActive && version.ready === true; const isPhantom = matchesActive && version.ready !== true; const isLegacy = !!version.legacy; const title = isLegacy ? t("Legacy index") : version.model ? version.model : (version.signature ?? t("Unknown")); const created = formatKnowledgeTimestamp(version.created_at); return (
  • {isActive ? ( ) : isPhantom ? ( ) : isLegacy ? ( ) : ( )}
    {title} {isActive && ( {t("Active")} )} {isPhantom && ( {t("Stale")} )} {isLegacy && !isActive && ( {t("Legacy")} )}
    {typeof version.dimension === "number" && ( {version.dimension} {t("d")} )} {version.binding && {version.binding}} {created && {created}} {version.signature && ( {version.signature.slice(0, 10)} )}
  • ); }