fix(connection): 复制连接时保持在同一组内

- 修改 `addConnection` 方法以支持指定目标组 ID
- 更新 `duplicateConnection` 函数以传递目标组 ID
- 添加测试用例以验证复制连接的功能
This commit is contained in:
二丫讲梵 2026-07-02 10:34:48 +08:00 committed by GitHub
parent 60f941aa27
commit c2cc9f22cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 3 deletions

View File

@ -1459,7 +1459,7 @@ async function duplicateConnection() {
const config = connectionStore.getConfig(connId);
if (!config) return;
const newConfig = { ...config, id: uuid(), name: `${config.name} (Copy)` };
await connectionStore.addConnection(newConfig);
await connectionStore.addConnection(newConfig, connectionStore.groupIdForConnection(connId));
toast(t("connection.duplicated"), 2000);
}

View File

@ -9,6 +9,7 @@ import {
emptyLayout,
appendConnectionToLayout,
removeConnectionFromSidebarLayout,
findConnectionLocation,
createGroup as createGroupOp,
renameGroup as renameGroupOp,
deleteGroup as deleteGroupOp,
@ -994,7 +995,7 @@ export const useConnectionStore = defineStore("connection", () => {
if (scope === "root") rebuildTreeNodes();
}
async function addConnection(config: ConnectionConfig) {
async function addConnection(config: ConnectionConfig, targetGroupId?: string | null) {
const normalized = normalizeConnection(config);
const existing = connections.value.findIndex((c) => c.id === normalized.id);
const nextConnections = [...connections.value];
@ -1002,7 +1003,8 @@ export const useConnectionStore = defineStore("connection", () => {
nextConnections[existing] = normalized;
} else {
nextConnections.push(normalized);
sidebarLayout.value = appendConnectionToLayout(sidebarLayout.value, normalized.id, newConnectionGroupId.value);
const groupId = targetGroupId !== undefined ? targetGroupId : newConnectionGroupId.value;
sidebarLayout.value = appendConnectionToLayout(sidebarLayout.value, normalized.id, groupId);
}
await persistConnections(nextConnections);
connections.value = nextConnections;
@ -4057,6 +4059,9 @@ export const useConnectionStore = defineStore("connection", () => {
moveConnectionToGroup(connectionId: string, groupId: string | null) {
updateLayoutAndRebuild(moveConnectionToGroupOp(sidebarLayout.value, connectionId, groupId));
},
groupIdForConnection(connectionId: string): string | null {
return findConnectionLocation(sidebarLayout.value, connectionId)?.groupId ?? null;
},
reorderSidebarEntry(draggedId: string, targetId: string, position: DropPosition) {
updateLayoutAndRebuild(reorderEntryOp(sidebarLayout.value, draggedId, targetId, position));
},

View File

@ -100,6 +100,59 @@ test("connecting a grouped connection updates it in place instead of adding a ro
}
});
test("duplicating a grouped connection keeps the copy in the same group", async () => {
const originalFetch = globalThis.fetch;
const storage = installMemoryStorage();
const originalConnection = conn("conn-1", "Grouped MySQL");
let savedConnections: ConnectionConfig[] = [originalConnection];
let savedLayout: SidebarLayout | null = {
groups: [{ id: "group-1", name: "Group", collapsed: false }],
order: [{ type: "group", id: "group-1", connectionIds: ["conn-1"] }],
};
globalThis.fetch = (async (input, init) => {
const url = String(input);
if (url === "/api/connection/list") {
return new Response(JSON.stringify(savedConnections), { status: 200, headers: { "Content-Type": "application/json" } });
}
if (url === "/api/layout/sidebar") {
if (init?.method === "POST") {
savedLayout = JSON.parse(String(init.body ?? "null"));
return new Response("null", { status: 200, headers: { "Content-Type": "application/json" } });
}
return new Response(JSON.stringify(savedLayout), { status: 200, headers: { "Content-Type": "application/json" } });
}
if (url === "/api/connection/save") {
savedConnections = JSON.parse(String(init?.body ?? "[]"));
return new Response("null", { status: 200, headers: { "Content-Type": "application/json" } });
}
return new Response("null", { status: 200, headers: { "Content-Type": "application/json" } });
}) as typeof fetch;
try {
setActivePinia(createPinia());
const store = useConnectionStore();
await store.initFromDisk();
const copy = { ...originalConnection, id: "conn-copy", name: "Grouped MySQL (Copy)" };
await store.addConnection(copy, store.groupIdForConnection(originalConnection.id));
assert.deepEqual(
store.treeNodes.map((node) => node.id),
["group-1"],
);
assert.equal(store.treeNodes[0].type, "connection-group");
assert.deepEqual(
store.treeNodes[0].children?.map((node) => node.id),
["conn-1", "conn-copy"],
);
assert.equal(countConnectionNodes(store.treeNodes, "conn-copy"), 1);
} finally {
globalThis.fetch = originalFetch;
storage.restore();
}
});
test("importing grouped dbx connections remaps exported layout to new connection ids", async () => {
const originalFetch = globalThis.fetch;
const storage = installMemoryStorage();