import { useState, useRef, useEffect } from "react"; import { Plus, MoreVertical } from "lucide-react"; import * as cmd from "../../lib/commands"; import type { DependencyInfo } from "../../lib/types"; import { AnimatedModal } from "../ui/AnimatedModal"; import { Button } from "../ui/Button"; import { DependencyDialog } from "./DependencyDialog"; interface SchemaMenuProps { connectionId: string; schema?: string; onRefresh: () => void; } export function SchemaMenu({ connectionId, schema, onRefresh }: SchemaMenuProps) { const [menuOpen, setMenuOpen] = useState(false); const [creating, setCreating] = useState(false); const [name, setName] = useState(""); const [renaming, setRenaming] = useState(false); const [newName, setNewName] = useState(""); const [dropOpen, setDropOpen] = useState(false); const [deps, setDeps] = useState([]); const [typed, setTyped] = useState(""); const [err, setErr] = useState(null); const menuRef = useRef(null); useEffect(() => { if (!menuOpen) return; const handleClick = (e: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { setMenuOpen(false); } }; document.addEventListener("mousedown", handleClick); return () => document.removeEventListener("mousedown", handleClick); }, [menuOpen]); const resetErrors = () => setErr(null); const create = async () => { resetErrors(); try { await cmd.createSchema(connectionId, name); setCreating(false); setName(""); onRefresh(); } catch (e) { setErr((e as Error)?.message ?? String(e)); } }; const rename = async () => { resetErrors(); if (!schema) return; try { await cmd.renameSchema(connectionId, schema, newName); setRenaming(false); setNewName(""); onRefresh(); } catch (e) { setErr((e as Error)?.message ?? String(e)); } }; const startDrop = async () => { setMenuOpen(false); if (!schema) return; try { const d = await cmd.getObjectDependencies(connectionId, schema, "schema", schema); setDeps(d); setDropOpen(true); setTyped(""); setErr(null); } catch (e) { setErr((e as Error)?.message ?? String(e)); } }; const confirmDrop = async (cascade: boolean) => { if (!schema) return; try { await cmd.dropSchema(connectionId, schema, cascade); setDropOpen(false); setTyped(""); setDeps([]); onRefresh(); } catch (e) { setErr((e as Error)?.message ?? String(e)); } }; const hasDeps = deps.length > 0; const inputClass = "w-full bg-surface border border-border rounded-md px-3 py-2 text-sm text-text placeholder:text-text-muted outline-none focus:border-accent/50 transition-colors"; return (
{schema && ( )} {menuOpen && (
)} {/* New Schema */} setCreating(false)}>

New Schema

Create a new schema in the current database.

setName(e.target.value)} className={inputClass} /> {err &&

{err}

}
{/* Rename Schema */} setRenaming(false)}>

Rename {schema}

Enter the new name for this schema.

setNewName(e.target.value)} className={inputClass} /> {err &&

{err}

}
{/* Dependency warning */} {dropOpen && ( { setDropOpen(false); setTyped(""); setDeps([]); setErr(null); }} onProceed={() => {}} /> )} {/* Typed-name confirmation for CASCADE drop */} {dropOpen && hasDeps && ( { setDropOpen(false); setTyped(""); setErr(null); }} >

Drop Schema: {schema}

Type the schema name to confirm the CASCADE drop.

{ setTyped(e.target.value); if (err) setErr(null); }} className={inputClass} /> {err &&

{err}

}
)} {/* Empty-schema confirmation (no deps) */} {dropOpen && !hasDeps && ( { setDropOpen(false); setErr(null); }} >

Drop Schema: {schema}

No dependencies — drop this empty schema?

{err &&

{err}

}
)}
); }