/** Data source (add / edit / test connection) and password dialogs. */ import { Fragment, useState } from "react"; import { call, commands, type DataSource } from "@/platform/ipc"; import { Checkbox, Dialog, Input, lazyComponent, T } from "@/ui"; import { sshLabel } from "./model"; import { SourceDialog } from "./SourceDialog"; import { closeDialog, useDatabase } from "./store"; import styles from "./Database.module.css"; import { isImeKey } from "@/platform/ime"; import { tx } from "@/platform/i18n"; const ObjectDialogs = lazyComponent(() => import("./ObjectDialogs").then((m) => m.ObjectDialogs)); const ExportDialog = lazyComponent(() => import("./ExportDialog").then((m) => m.ExportDialog)); const HistoryDialog = lazyComponent(() => import("./DataDialogs").then((m) => m.HistoryDialog)); const ImportDialog = lazyComponent(() => import("./DataDialogs").then((m) => m.ImportDialog)); function PasswordDialog({ source, resolve }: { source: DataSource; resolve: (ok: boolean) => void }) { const [password, setPassword] = useState(""); const [save, setSave] = useState(!!source.savePassword); const done = (ok: boolean) => { closeDialog(); resolve(ok); }; const submit = async () => { await call(commands.dbSetPassword(source.id ?? "", password, save)); done(true); }; return ( done(false)} title={tx`Connect to ${source.name}`} width={400} buttons={[ { label: "Cancel", role: "cancel" }, { label: "Connect", role: "default", onClick: () => void submit() }, ]} >
User: {source.user || "(default)"} setPassword(e.target.value)} />
); } /** SSH password / key passphrase asked on connect. */ function SshSecretDialog({ source, prompt, resolve, }: { source: DataSource; prompt: string; resolve: (ok: boolean) => void; }) { const [secret, setSecret] = useState(""); const [save, setSave] = useState(!!source.ssh?.saveSecret); const password = source.ssh?.auth === "password" || /password required/.test(prompt); const done = (ok: boolean) => { closeDialog(); resolve(ok); }; const submit = async () => { await call(commands.dbSetSshSecret(source.id ?? "", secret, save)); done(true); }; return ( done(false)} title={tx`SSH: ${sshLabel(source) || source.name}`} width={440} buttons={[ { label: "Cancel", role: "cancel" }, { label: "Connect", role: "default", onClick: () => void submit() }, ]} >
{prompt} setSecret(e.target.value)} />
); } /** IDEA's parameter dialog: one SQL value per query parameter, remembered for the next run. */ function ParamsDialog({ names, resolve, }: { names: string[]; resolve: (values: Record | null) => void; }) { const [values, setValues] = useState>(() => { const last = useDatabase.getState().paramValues; return Object.fromEntries(names.map((n) => [n, last[n] ?? ""])); }); const done = (v: Record | null) => { closeDialog(); resolve(v); }; return ( done(null)} title="Parameters" width={480} buttons={[ { label: "Cancel", role: "cancel" }, { label: "Execute", role: "default", onClick: () => done(values) }, ]} >
{ if (e.key !== "Enter" || isImeKey(e.nativeEvent)) return; e.preventDefault(); done(values); }} > {names.map((n, i) => ( setValues((v) => ({ ...v, [n]: e.target.value }))} /> ))} Values are inserted as SQL: quote strings, e.g. 'abc'.
); } /** Overlay host: whichever dialog the store asks for. */ export function DatabaseDialogs() { const dialog = useDatabase((s) => s.dialog); if (!dialog) return null; if (dialog.kind === "source") return ( ); if (dialog.kind === "params") return ; if (dialog.kind === "export") return ; if (dialog.kind === "history") return ; if (dialog.kind === "import") return ( ); if (dialog.kind === "sshSecret") return ( ); if (dialog.kind === "password") return ; return ; }