feat(sidebar): support bulk connection group deletion
This commit is contained in:
29 files changed
+864
-79
No files matched your search
@@ -30,6 +30,7 @@ import { copyNameForTreeNode, objectSourceTargetForTreeNode } from "@/lib/sideba
|
||||
import { supportsTypeObjectSource } from "@/lib/database/databaseObjectCapabilities";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { connectionPasteTargetGroupId, copySelectedConnectionsToClipboards, selectedConnectionEditTarget } from "@/lib/sidebar/sidebarConnectionSelection";
|
||||
import { pruneTreeSelectionToVisibleNodes } from "@/lib/sidebar/sidebarTreeSelection";
|
||||
import { isEditableSidebarTypeSearchTarget, sidebarTypeSearchNextQuery } from "@/lib/sidebar/sidebarTypeSearch";
|
||||
import { isInternalDorisCatalog, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
|
||||
import { connectionObjectTreeNodeSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
@@ -807,6 +808,24 @@ const selectableVisibleNodeIndexById = computed(() => flatTreeIndex.value.select
|
||||
const useVirtualTree = computed(() => shouldVirtualizeFlatTree(flatNodes.value.length));
|
||||
const activeTab = computed(() => queryStore.tabs.find((tab) => tab.id === queryStore.activeTabId));
|
||||
|
||||
watch(
|
||||
visibleNodes,
|
||||
(nodes) => {
|
||||
const next = pruneTreeSelectionToVisibleNodes(nodes, {
|
||||
nodeIds: store.selectedTreeNodeIds,
|
||||
activeNodeId: store.selectedTreeNodeId,
|
||||
anchorNodeId: store.treeSelectionAnchorId,
|
||||
});
|
||||
const selectionChanged = next.nodeIds.length !== store.selectedTreeNodeIds.length || next.nodeIds.some((id, index) => id !== store.selectedTreeNodeIds[index]);
|
||||
if (!selectionChanged && next.activeNodeId === store.selectedTreeNodeId && next.anchorNodeId === store.treeSelectionAnchorId) return;
|
||||
store.selectedTreeNodeIds = [...next.nodeIds];
|
||||
store.selectedTreeNodeId = next.activeNodeId;
|
||||
store.treeSelectionAnchorId = next.anchorNodeId;
|
||||
if (!next.nodeIds.length) store.connectionMultiSelectActive = false;
|
||||
},
|
||||
{ flush: "sync" },
|
||||
);
|
||||
|
||||
// --- Sticky database header ---
|
||||
// RecycleScroller positions each row absolutely, so CSS `position: sticky` on
|
||||
// a database row can't work. Instead we overlay a pinned row from this parent
|
||||
|
||||
@@ -23,6 +23,10 @@ const {
|
||||
moveToNewGroupName,
|
||||
confirmMoveToNewGroup,
|
||||
showDeleteGroupConfirm,
|
||||
deleteConnectionsWithGroup,
|
||||
connectionGroupDeleteConfirmMessage,
|
||||
connectionGroupDeleteMenuLabel,
|
||||
deletingConnectionGroups,
|
||||
confirmDeleteGroup,
|
||||
showRenameObjectDialog,
|
||||
renameObjectName,
|
||||
@@ -159,6 +163,15 @@ function closeCreateDatabaseResult() {
|
||||
showCreateDatabasePreviewDialog.value = false;
|
||||
}
|
||||
|
||||
function updateDeleteGroupDialogOpen(open: boolean) {
|
||||
if (!open && deletingConnectionGroups.value) return;
|
||||
showDeleteGroupConfirm.value = open;
|
||||
}
|
||||
|
||||
function preventDeleteGroupDialogDismiss(event: Event) {
|
||||
if (deletingConnectionGroups.value) event.preventDefault();
|
||||
}
|
||||
|
||||
const mongoIndexCollectionName = computed(() => node.value.tableName || node.value.label);
|
||||
|
||||
function mongoIndexTypeLabel(type: string): string {
|
||||
@@ -232,17 +245,24 @@ watch(
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model:open="showDeleteGroupConfirm">
|
||||
<DialogContent class="sm:max-w-[400px]">
|
||||
<Dialog :open="showDeleteGroupConfirm" @update:open="updateDeleteGroupDialogOpen">
|
||||
<DialogContent class="sm:max-w-[400px]" :show-close-button="!deletingConnectionGroups" @escape-key-down="preventDeleteGroupDialogDismiss" @interact-outside="preventDeleteGroupDialogDismiss">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t("connectionGroup.deleteGroupConfirmTitle") }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ t("connectionGroup.deleteGroupConfirmMessage", { name: node.label }) }}
|
||||
{{ connectionGroupDeleteConfirmMessage() }}
|
||||
</p>
|
||||
<label class="flex items-start gap-2 rounded-md border border-border/70 px-3 py-2 text-sm" :class="deletingConnectionGroups ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'">
|
||||
<input v-model="deleteConnectionsWithGroup" type="checkbox" class="mt-0.5 h-4 w-4 shrink-0 accent-primary" :disabled="deletingConnectionGroups" />
|
||||
<span>{{ t("connectionGroup.deleteConnectionsWithGroup") }}</span>
|
||||
</label>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="showDeleteGroupConfirm = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
<Button variant="destructive" @click="confirmDeleteGroup">{{ t("connectionGroup.deleteGroup") }}</Button>
|
||||
<Button variant="outline" :disabled="deletingConnectionGroups" @click="showDeleteGroupConfirm = false">{{ t("dangerDialog.cancel") }}</Button>
|
||||
<Button variant="destructive" :disabled="deletingConnectionGroups" @click="confirmDeleteGroup">
|
||||
<Loader2 v-if="deletingConnectionGroups" class="mr-2 h-4 w-4 animate-spin" />
|
||||
{{ connectionGroupDeleteMenuLabel() }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
@@ -280,6 +280,7 @@ import {
|
||||
schemaCommentLoading,
|
||||
schemaCommentPreviewSql,
|
||||
showDeleteGroupConfirm,
|
||||
deleteConnectionsWithGroup,
|
||||
showMoveToNewGroupDialog,
|
||||
moveToNewGroupName,
|
||||
type DuplicateStructureSource,
|
||||
@@ -354,7 +355,6 @@ const { openAllDatabasesExport, openDataCompare, openDatabaseExport, openDatabas
|
||||
|
||||
const emit = defineEmits<{
|
||||
"rename-started": [];
|
||||
"group-created": [groupId: string];
|
||||
"request-group-rename": [groupId: string];
|
||||
"request-saved-sql-rename": [nodeId: string];
|
||||
"node-toggled": [node: TreeNode, expanded: boolean];
|
||||
@@ -412,10 +412,13 @@ const {
|
||||
openVisibleDatabasesDialog,
|
||||
openVisibleSchemasDialog,
|
||||
startRenameGroup,
|
||||
connectionGroupDeleteMenuLabel,
|
||||
connectionGroupDeleteConfirmMessage,
|
||||
deleteConnectionGroup,
|
||||
newConnectionInGroup,
|
||||
newSubgroup,
|
||||
confirmDeleteGroup,
|
||||
deletingConnectionGroups,
|
||||
moveToGroup,
|
||||
createGroupAndMoveConnection,
|
||||
} = useSidebarConnectionMutationRuntime({
|
||||
@@ -425,7 +428,6 @@ const {
|
||||
connectionStore,
|
||||
queryStore,
|
||||
requestGroupRename: (groupId) => emit("request-group-rename", groupId),
|
||||
groupCreated: (groupId) => emit("group-created", groupId),
|
||||
openVisibleDatabases: (node) => emit("open-visible-databases", node),
|
||||
openVisibleSchemas: (node) => emit("open-visible-schemas", node),
|
||||
});
|
||||
@@ -4164,6 +4166,10 @@ function connectionDialogCapabilities() {
|
||||
moveToNewGroupName,
|
||||
confirmMoveToNewGroup,
|
||||
showDeleteGroupConfirm,
|
||||
deleteConnectionsWithGroup,
|
||||
connectionGroupDeleteConfirmMessage,
|
||||
connectionGroupDeleteMenuLabel,
|
||||
deletingConnectionGroups,
|
||||
confirmDeleteGroup,
|
||||
};
|
||||
}
|
||||
@@ -4624,7 +4630,7 @@ function buildConnectionSidebarMenu(context: SidebarMenuFactoryContext): boolean
|
||||
});
|
||||
items.push({ label: "", separator: true });
|
||||
items.push({
|
||||
label: t("connectionGroup.deleteGroup"),
|
||||
label: connectionGroupDeleteMenuLabel(),
|
||||
action: deleteConnectionGroup,
|
||||
icon: Trash2,
|
||||
shortcut: shortcutDelete,
|
||||
|
||||
@@ -530,6 +530,14 @@ function visibleTreeNodes(): TreeNode[] {
|
||||
return flattenTree(connectionStore.treeNodes).map((item) => item.node);
|
||||
}
|
||||
|
||||
function connectionIdsForSelection(): Set<string> {
|
||||
return new Set(connectionStore.connections.map((connection) => connection.id));
|
||||
}
|
||||
|
||||
function connectionGroupIdsForSelection(): Set<string> {
|
||||
return new Set(connectionStore.sidebarLayout.groups.map((group) => group.id));
|
||||
}
|
||||
|
||||
function selectSingleTreeNode(node: TreeNode) {
|
||||
// Re-clicking the selected row should not replace the selection array and
|
||||
// force visible tree rows to recompute.
|
||||
@@ -558,7 +566,8 @@ function toggleTreeNodeSelection(node: TreeNode) {
|
||||
activeNodeId: node.id,
|
||||
anchorNodeId: node.id,
|
||||
},
|
||||
new Set(connectionStore.connections.map((connection) => connection.id)),
|
||||
connectionIdsForSelection(),
|
||||
connectionGroupIdsForSelection(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -580,7 +589,8 @@ function selectTreeNodeRange(node: TreeNode) {
|
||||
activeNodeId: node.id,
|
||||
anchorNodeId: anchorId,
|
||||
},
|
||||
new Set(connectionStore.connections.map((connection) => connection.id)),
|
||||
connectionIdsForSelection(),
|
||||
connectionGroupIdsForSelection(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -598,7 +608,8 @@ function selectTreeNodeRange(node: TreeNode) {
|
||||
activeNodeId: node.id,
|
||||
anchorNodeId: anchorId,
|
||||
},
|
||||
new Set(connectionStore.connections.map((connection) => connection.id)),
|
||||
connectionIdsForSelection(),
|
||||
connectionGroupIdsForSelection(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -608,10 +619,20 @@ function selectedConnectionIdsForAction(): string[] {
|
||||
}
|
||||
|
||||
const isConnectionSelectionChecked = computed(() => {
|
||||
if (!connectionStore.connectionMultiSelectActive || activeNode.value.type !== "connection" || !activeNode.value.connectionId) return false;
|
||||
if (!isConnectionMultiSelectActive() || activeNode.value.type !== "connection" || !activeNode.value.connectionId) return false;
|
||||
return connectionStore.selectedTreeNodeIds.includes(activeNode.value.connectionId);
|
||||
});
|
||||
|
||||
function isConnectionGroupMultiSelectActive(): boolean {
|
||||
if (!connectionStore.connectionMultiSelectActive) return false;
|
||||
const firstSelectedId = connectionStore.selectedTreeNodeIds[0];
|
||||
return !!firstSelectedId && connectionStore.sidebarLayout.groups.some((group) => group.id === firstSelectedId);
|
||||
}
|
||||
|
||||
function isConnectionMultiSelectActive(): boolean {
|
||||
return connectionStore.connectionMultiSelectActive && !isConnectionGroupMultiSelectActive();
|
||||
}
|
||||
|
||||
function toggleConnectionMultiSelection(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -624,6 +645,40 @@ function toggleConnectionMultiSelection(event: MouseEvent) {
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
function selectedConnectionGroupIdsForAction(): string[] {
|
||||
const groupIds = connectionGroupIdsForSelection();
|
||||
return connectionStore.selectedTreeNodeIds.filter((id) => groupIds.has(id));
|
||||
}
|
||||
|
||||
function isConnectionGroupSelectionChecked(): boolean {
|
||||
if (!isConnectionGroupMultiSelectActive() || activeNode.value.type !== "connection-group") return false;
|
||||
return connectionStore.selectedTreeNodeIds.includes(activeNode.value.id);
|
||||
}
|
||||
|
||||
function toggleConnectionGroupMultiSelection(event: MouseEvent) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (activeNode.value.type !== "connection-group") return;
|
||||
|
||||
const selectedGroupIds = connectionStore.connectionMultiSelectActive ? selectedConnectionGroupIdsForAction() : [];
|
||||
const nextGroupIds = new Set(selectedGroupIds);
|
||||
if (nextGroupIds.has(activeNode.value.id)) nextGroupIds.delete(activeNode.value.id);
|
||||
else nextGroupIds.add(activeNode.value.id);
|
||||
const nodeIds = [...nextGroupIds];
|
||||
const activeNodeId = nextGroupIds.has(activeNode.value.id) ? activeNode.value.id : (nodeIds[0] ?? null);
|
||||
applyTreeNodeSelection(
|
||||
connectionStore,
|
||||
{
|
||||
nodeIds,
|
||||
activeNodeId,
|
||||
anchorNodeId: activeNodeId,
|
||||
},
|
||||
connectionIdsForSelection(),
|
||||
connectionGroupIdsForSelection(),
|
||||
);
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
async function cancelConnectionAttempt() {
|
||||
if (!activeNode.value.connectionId) return;
|
||||
try {
|
||||
@@ -1387,7 +1442,7 @@ function onKeydown(event: KeyboardEvent) {
|
||||
v-if="node.type === 'connection'"
|
||||
type="button"
|
||||
class="flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground/55 opacity-0 transition-colors transition-opacity hover:bg-secondary/45 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover/sidebar-row:opacity-100"
|
||||
:class="[{ 'opacity-100': isConnectionSelectionChecked || connectionStore.connectionMultiSelectActive }, isConnecting ? '' : 'ml-auto']"
|
||||
:class="[{ 'opacity-100': isConnectionSelectionChecked || isConnectionMultiSelectActive() }, isConnecting ? '' : 'ml-auto']"
|
||||
:aria-label="isConnectionSelectionChecked ? t('connectionGroup.deselectConnection') : t('connectionGroup.selectConnection')"
|
||||
@mousedown.stop
|
||||
@click="toggleConnectionMultiSelection"
|
||||
@@ -1395,6 +1450,19 @@ function onKeydown(event: KeyboardEvent) {
|
||||
<Check v-if="isConnectionSelectionChecked" class="h-3 w-3 text-primary" />
|
||||
<Square v-else class="h-3 w-3 stroke-[1.7]" />
|
||||
</button>
|
||||
<button
|
||||
v-if="node.type === 'connection-group'"
|
||||
type="button"
|
||||
data-sidebar-group-selection-toggle="true"
|
||||
class="ml-auto flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground/55 opacity-0 transition-colors transition-opacity hover:bg-secondary/45 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover/sidebar-row:opacity-100"
|
||||
:class="{ 'opacity-100': isConnectionGroupSelectionChecked() || isConnectionGroupMultiSelectActive() }"
|
||||
:aria-label="isConnectionGroupSelectionChecked() ? t('connectionGroup.deselectGroup') : t('connectionGroup.selectGroup')"
|
||||
@mousedown.stop
|
||||
@click="toggleConnectionGroupMultiSelection"
|
||||
>
|
||||
<Check v-if="isConnectionGroupSelectionChecked()" class="h-3 w-3 text-primary" />
|
||||
<Square v-else class="h-3 w-3 stroke-[1.7]" />
|
||||
</button>
|
||||
</div>
|
||||
<template v-if="detailTooltip" #content>
|
||||
<div class="w-max min-w-40 max-w-[min(28rem,calc(100vw-24px))] rounded-md border border-border bg-popover p-2 text-popover-foreground shadow-lg">
|
||||
|
||||
+59
@@ -13,6 +13,65 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("SidebarTreeItemDialogs MongoDB index form", () => {
|
||||
it("keeps the group deletion dialog locked while deletion is running", async () => {
|
||||
const controller = reactive({
|
||||
node: { id: "group-parent", label: "Parent", type: "connection-group" },
|
||||
t: (key: string) => key,
|
||||
highlight: (value: string) => value,
|
||||
showDeleteConfirm: false,
|
||||
showMoveToNewGroupDialog: false,
|
||||
showDeleteGroupConfirm: true,
|
||||
deleteConnectionsWithGroup: true,
|
||||
connectionGroupDeleteConfirmMessage: () => "confirm",
|
||||
connectionGroupDeleteMenuLabel: () => "delete",
|
||||
deletingConnectionGroups: true,
|
||||
confirmDeleteGroup: vi.fn(),
|
||||
showRenameObjectDialog: false,
|
||||
showStructurePreviewDialog: false,
|
||||
showStructureDocCopyDialog: false,
|
||||
showDuplicateDialog: false,
|
||||
showPasteDialog: false,
|
||||
showCreateDatabaseDialog: false,
|
||||
showCreateDatabasePreviewDialog: false,
|
||||
showEditDatabasePropertiesDialog: false,
|
||||
showCreateNacosNamespaceDialog: false,
|
||||
showEditNacosNamespaceDialog: false,
|
||||
showRenameMongoCollectionDialog: false,
|
||||
showCloneMongoCollectionDialog: false,
|
||||
showCreateMongoIndexDialog: false,
|
||||
showMongoIndexManagerDialog: false,
|
||||
showRedisDatabaseAliasDialog: false,
|
||||
showCreateSchemaDialog: false,
|
||||
showEditSchemaCommentDialog: false,
|
||||
});
|
||||
const app = createApp(
|
||||
defineComponent({
|
||||
setup: () => () => h(SidebarTreeItemDialogs, { controller }),
|
||||
}),
|
||||
);
|
||||
mountedApps.push(app);
|
||||
app.use(i18n);
|
||||
app.mount(document.createElement("div"));
|
||||
await nextTick();
|
||||
|
||||
const dialog = document.querySelector<HTMLElement>('[role="dialog"]');
|
||||
const checkbox = dialog?.querySelector<HTMLInputElement>('input[type="checkbox"]');
|
||||
expect(checkbox?.disabled).toBe(true);
|
||||
expect(dialog?.querySelector('[data-slot="dialog-close"]')).toBeNull();
|
||||
|
||||
dialog?.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true, cancelable: true }));
|
||||
await nextTick();
|
||||
expect(controller.showDeleteGroupConfirm).toBe(true);
|
||||
|
||||
controller.deletingConnectionGroups = false;
|
||||
await nextTick();
|
||||
expect(checkbox?.disabled).toBe(false);
|
||||
const closeButton = dialog?.querySelector<HTMLButtonElement>('[data-slot="dialog-close"]');
|
||||
expect(closeButton).not.toBeNull();
|
||||
closeButton?.click();
|
||||
await vi.waitFor(() => expect(controller.showDeleteGroupConfirm).toBe(false));
|
||||
});
|
||||
|
||||
it("mounts the form and overlay from the same controlled dialog state", async () => {
|
||||
const confirmCreateMongoIndex = vi.fn();
|
||||
const closed = vi.fn();
|
||||
|
||||
+35
-1
@@ -6,7 +6,7 @@ import i18n from "@/i18n";
|
||||
import TreeItem from "@/components/sidebar/TreeItem.vue";
|
||||
import { filterSidebarTree } from "@/lib/sidebar/sidebarSearchTree";
|
||||
import { createSidebarTreeRuntime, sidebarTreeRuntimeKey, type SidebarTreeRuntimeHost } from "@/lib/sidebar/sidebarTreeRuntime";
|
||||
import type { TreeNode } from "@/types/database";
|
||||
import type { SidebarLayout, TreeNode } from "@/types/database";
|
||||
|
||||
const connectionStore = {
|
||||
activeConnectionId: "connection-1",
|
||||
@@ -26,6 +26,7 @@ const connectionStore = {
|
||||
selectedTreeNodeId: null as string | null,
|
||||
selectedTreeNodeIds: [] as string[],
|
||||
selectedTreeNodeIdsSet: new Set<string>(),
|
||||
sidebarLayout: { groups: [], order: [] } as SidebarLayout,
|
||||
sidebarTableSearchQueries: {},
|
||||
tableNameFilterForScope: () => undefined,
|
||||
treeNodes: [],
|
||||
@@ -101,6 +102,8 @@ afterEach(() => {
|
||||
connectionStore.selectedTreeNodeId = null;
|
||||
connectionStore.selectedTreeNodeIds = [];
|
||||
connectionStore.selectedTreeNodeIdsSet = new Set<string>();
|
||||
connectionStore.connectionMultiSelectActive = false;
|
||||
connectionStore.sidebarLayout = { groups: [], order: [] };
|
||||
connectionStore.treeNodes = [];
|
||||
connectionStore.treeSelectionAnchorId = null;
|
||||
settingsStore.editorSettings.sidebarActivation = "double";
|
||||
@@ -108,6 +111,37 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("TreeItem load-more activation", () => {
|
||||
it("toggles a connection group through its row checkbox", async () => {
|
||||
const group: TreeNode = {
|
||||
id: "group-1",
|
||||
label: "Group 1",
|
||||
type: "connection-group",
|
||||
children: [],
|
||||
};
|
||||
connectionStore.treeNodes = [group];
|
||||
connectionStore.sidebarLayout = {
|
||||
groups: [{ id: group.id, name: group.label, collapsed: false }],
|
||||
order: [{ type: "group", id: group.id, children: [] }],
|
||||
};
|
||||
const { row } = await mountTreeItem(group);
|
||||
const toggle = row.querySelector<HTMLButtonElement>('[data-sidebar-group-selection-toggle="true"]');
|
||||
expect(toggle).not.toBeNull();
|
||||
|
||||
toggle?.click();
|
||||
|
||||
expect(connectionStore.selectedTreeNodeIds).toEqual([group.id]);
|
||||
expect(connectionStore.selectedTreeNodeId).toBe(group.id);
|
||||
expect(connectionStore.treeSelectionAnchorId).toBe(group.id);
|
||||
expect(connectionStore.connectionMultiSelectActive).toBe(true);
|
||||
|
||||
toggle?.click();
|
||||
|
||||
expect(connectionStore.selectedTreeNodeIds).toEqual([]);
|
||||
expect(connectionStore.selectedTreeNodeId).toBeNull();
|
||||
expect(connectionStore.treeSelectionAnchorId).toBeNull();
|
||||
expect(connectionStore.connectionMultiSelectActive).toBe(false);
|
||||
});
|
||||
|
||||
it("runs load-more on a single click in double-click activation mode", async () => {
|
||||
const node: TreeNode = {
|
||||
id: "connection-1:app:dbo:__procedures:__load_more:200",
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { MongoCreateIndexForm, MongoIndexRow } from "@/lib/sidebar/mongoCol
|
||||
|
||||
export type DuplicateStructureSource = TreeNode & { connectionId: string; database: string };
|
||||
type ConnectionDeleteTarget = TreeNode & { connectionId: string };
|
||||
type ConnectionGroupDeleteTarget = TreeNode & { type: "connection-group" };
|
||||
|
||||
export const fallbackCreateDatabaseCharset = fallbackCreateDatabaseCharsetMetadata();
|
||||
|
||||
@@ -15,6 +16,8 @@ export const sidebarTreeDialogOwner = shallowRef<symbol | null>(null);
|
||||
export const sidebarDangerTarget = shallowRef<TreeNode | null>(null);
|
||||
export const sidebarFormTarget = shallowRef<TreeNode | null>(null);
|
||||
export const connectionDeleteTargetSnapshot = ref<ConnectionDeleteTarget[]>([]);
|
||||
export const connectionGroupDeleteTargetSnapshot = ref<ConnectionGroupDeleteTarget[]>([]);
|
||||
export const deleteConnectionsWithGroup = ref(false);
|
||||
export const showDeleteConfirm = ref(false);
|
||||
export const showDropTableConfirm = ref(false);
|
||||
export const showDropTableChildObjectConfirm = ref(false);
|
||||
@@ -229,4 +232,6 @@ export function resetSidebarTreeDialogState() {
|
||||
sidebarDangerTarget.value = null;
|
||||
sidebarFormTarget.value = null;
|
||||
connectionDeleteTargetSnapshot.value = [];
|
||||
connectionGroupDeleteTargetSnapshot.value = [];
|
||||
deleteConnectionsWithGroup.value = false;
|
||||
}
|
||||
Reference in new issue
Block a user