/** * dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx — rename/merge/split. * * Controlled dialogs for the three curation mutations. Non-destructive: on * success the parent refetches and paints the returned CurationResult; on * failure the pre-mutation snapshot stays (no local partial apply). * * Styling: Tailwind + shadcn (Button). No legacy CSS classes. */ import type React from "react"; import { useState } from "react"; import { renameTopic, mergeTopics, splitTopic } from "../../api/client"; import type { MemoryProvenance } from "@contracts"; import { Button } from "../../components/ui/button"; interface ControlsProps { topicId: string; others: Array<{ id: string; label: string }>; members: MemoryProvenance[]; onMutated: () => void; } type Mode = "rename" | "merge" | "split" | null; function memberSnippet(id: string, method: string): string { const base = id.length > 14 ? id.slice(0, 14) + "…" : id; return method ? `${base} (${method})` : base; } export default function WikiPageControls({ topicId, others, members, onMutated, }: ControlsProps): React.ReactElement { const [mode, setMode] = useState(null); const [label, setLabel] = useState(""); const [target, setTarget] = useState(""); const [picked, setPicked] = useState([]); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); function open(m: Exclude): void { setMode(m); setError(null); setLabel(""); setTarget(""); setPicked([]); } async function submit(): Promise { setBusy(true); setError(null); try { if (mode === "rename") { await renameTopic(topicId, label); } else if (mode === "merge") { if (!target) { setError("Pick a target topic."); setBusy(false); return; } await mergeTopics(topicId, target); } else if (mode === "split") { if (picked.length === 0) { setError("Pick at least one memory."); setBusy(false); return; } await splitTopic(topicId, picked); } setMode(null); onMutated(); } catch (e) { setError(e instanceof Error ? e.message : String(e)); } finally { setBusy(false); } } return ( <>
{mode && (
setMode(null)} >
e.stopPropagation()} >

{mode === "rename" ? "Rename topic" : mode === "merge" ? "Merge into…" : "Split topic"}

{mode === "rename" && ( setLabel(e.target.value)} className="w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary" /> )} {mode === "merge" && ( )} {mode === "split" && (
{members.map((m) => ( ))}
)} {error && (

{error}

)}
)} ); }