Enable safe multi-connection cleanup from the sidebar (#816)
The sidebar already supports multi-select, so deletion now resolves the context-clicked selected connection set before confirming. Connection removal gained a batched path to persist once while pruning sidebar layout, pins, active state, connection errors, and stale selection for every removed connection. Constraint: No new dependencies and existing single-connection delete behavior must remain available.\nRejected: Delete every selected tree item regardless of type | mixed tree selections could unexpectedly remove connections while table/object deletion has separate SQL confirmation behavior.\nConfidence: high\nScope-risk: narrow\nTested: pnpm fmt; pnpm test; pnpm typecheck; pnpm lint; pnpm build\nNot-tested: Manual desktop UI interaction against a running Tauri window Co-authored-by: caisin <caisin@caisins-Mac-mini.local>
This commit is contained in:
1 parent
74e19ec6a3
commit
13363b9094
10 files changed
+137
-19
No files matched your search
@@ -131,6 +131,7 @@ import {
|
||||
treeSelectionRangeIdsByIndex,
|
||||
treeSelectionRangeIds,
|
||||
} from "@/lib/sidebarTreeSelection";
|
||||
import { selectedConnectionDeleteTargets } from "@/lib/sidebarConnectionSelection";
|
||||
import { sidebarTreeContextKey } from "@/lib/sidebarTreeContext";
|
||||
import DangerConfirmDialog from "@/components/editor/DangerConfirmDialog.vue";
|
||||
import ProcedureExecutionDialog from "@/components/objects/ProcedureExecutionDialog.vue";
|
||||
@@ -904,20 +905,41 @@ async function refresh() {
|
||||
|
||||
const showDeleteConfirm = ref(false);
|
||||
|
||||
function connectionDeleteTargets() {
|
||||
return selectedConnectionDeleteTargets(props.node, selectedTreeNodesInVisibleOrder());
|
||||
}
|
||||
|
||||
function connectionDeleteMenuLabel(): string {
|
||||
const count = connectionDeleteTargets().length;
|
||||
return count > 1 ? t("contextMenu.deleteSelectedConnections", { count }) : t("contextMenu.deleteConnection");
|
||||
}
|
||||
|
||||
function connectionDeleteConfirmMessage(): string {
|
||||
const targets = connectionDeleteTargets();
|
||||
return targets.length > 1
|
||||
? t("contextMenu.confirmDeleteSelectedMessage", { count: targets.length })
|
||||
: t("contextMenu.confirmDeleteMessage", { name: props.node.label });
|
||||
}
|
||||
|
||||
function deleteConnection() {
|
||||
if (!connectionDeleteTargets().length) return;
|
||||
showDeleteConfirm.value = true;
|
||||
}
|
||||
|
||||
async function confirmDelete() {
|
||||
const node = props.node;
|
||||
if (node.connectionId) {
|
||||
try {
|
||||
await connectionStore.disconnect(node.connectionId);
|
||||
await connectionStore.removeConnection(node.connectionId);
|
||||
toast(t("connection.deleted"), 2000);
|
||||
} catch (e: any) {
|
||||
toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000);
|
||||
const targets = connectionDeleteTargets();
|
||||
if (!targets.length) return;
|
||||
try {
|
||||
for (const target of targets) {
|
||||
await connectionStore.disconnect(target.connectionId);
|
||||
}
|
||||
await connectionStore.removeConnections(targets.map((target) => target.connectionId));
|
||||
toast(
|
||||
targets.length > 1 ? t("connection.deletedSelected", { count: targets.length }) : t("connection.deleted"),
|
||||
2000,
|
||||
);
|
||||
} catch (e: any) {
|
||||
toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2913,7 +2935,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
items.push({ label: t("contextMenu.duplicateConnection"), action: duplicateConnection, icon: CopyPlus });
|
||||
items.push({ label: "", separator: true });
|
||||
items.push({
|
||||
label: t("contextMenu.deleteConnection"),
|
||||
label: connectionDeleteMenuLabel(),
|
||||
action: deleteConnection,
|
||||
icon: Trash2,
|
||||
shortcut: shortcutDelete,
|
||||
@@ -3383,7 +3405,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
<DialogTitle>{{ t("contextMenu.confirmDeleteTitle") }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ t("contextMenu.confirmDeleteMessage", { name: node.label }) }}
|
||||
{{ connectionDeleteConfirmMessage() }}
|
||||
</p>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="showDeleteConfirm = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
@@ -3393,7 +3415,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
||||
showDeleteConfirm = false;
|
||||
confirmDelete();
|
||||
"
|
||||
>{{ t("contextMenu.deleteConnection") }}</Button
|
||||
>{{ connectionDeleteMenuLabel() }}</Button
|
||||
>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
Reference in new issue
Block a user