feat(connection): add copy connection name
This commit is contained in:
parent
7ee335e38a
commit
f2ce70dd68
|
|
@ -11,7 +11,7 @@ import { filterSidebarSearchRootsByConnectionState, filterSidebarTree, filterSid
|
|||
import { isCancelSearchShortcut, isCopySidebarSelectionShortcut, isEditSidebarConnectionShortcut, isPasteSidebarSelectionShortcut } from "@/lib/editor/keyboardShortcuts";
|
||||
import { copyNameForTreeNode, objectSourceKindForTreeNode } from "@/lib/sidebar/treeNodeClick";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { connectionPasteTargetGroupId, selectedConnectionClipboardNodes, selectedConnectionEditTarget } from "@/lib/sidebar/sidebarConnectionSelection";
|
||||
import { connectionPasteTargetGroupId, copySelectedConnectionsToClipboards, selectedConnectionEditTarget } from "@/lib/sidebar/sidebarConnectionSelection";
|
||||
import { isEditableSidebarTypeSearchTarget, sidebarTypeSearchNextQuery } from "@/lib/sidebar/sidebarTypeSearch";
|
||||
import { usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
|
||||
import { connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
|
||||
|
|
@ -1304,11 +1304,10 @@ function requestSelectedConnectionEdit(): boolean {
|
|||
function copySelectedSidebarNames(): boolean {
|
||||
const nodes = selectedSidebarNodesInVisibleOrder();
|
||||
if (nodes.length === 0) return false;
|
||||
const connectionNodes = selectedConnectionClipboardNodes(nodes);
|
||||
if (connectionNodes.length > 0) {
|
||||
const copiedCount = store.copyConnectionsToTreeClipboard(connectionNodes.map((node) => node.connectionId));
|
||||
if (copiedCount > 0) toast(t("connection.copied"), 2000);
|
||||
return copiedCount > 0;
|
||||
const copiedCount = copySelectedConnectionsToClipboards(nodes, (connectionIds) => store.copyConnectionsToTreeClipboard(connectionIds), copyToClipboard);
|
||||
if (copiedCount > 0) {
|
||||
toast(t("connection.copied"), 2000);
|
||||
return true;
|
||||
}
|
||||
const tableNodes = nodes.filter((node) => node.type === "table" && !!node.connectionId && !!node.database);
|
||||
store.treeClipboard =
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,14 @@ async function copySelectedNames() {
|
|||
const connectionTargets = selectedConnectionClipboardTargets(activeNode.value, nodes);
|
||||
if (connectionTargets.length > 0) {
|
||||
const copiedCount = connectionStore.copyConnectionsToTreeClipboard(connectionTargets.map((node) => node.connectionId));
|
||||
if (copiedCount > 0) toast(t("connection.copied"), 2000);
|
||||
if (copiedCount > 0) {
|
||||
try {
|
||||
await copyToClipboard(connectionTargets.map(copyNameForTreeNode).join("\n"));
|
||||
} catch {
|
||||
/* system clipboard copy is best-effort */
|
||||
}
|
||||
toast(t("connection.copied"), 2000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
updateTreeClipboardForNodes(nodes);
|
||||
|
|
@ -3504,6 +3511,9 @@ function buildConnectionSidebarMenu(context: SidebarMenuFactoryContext): boolean
|
|||
} else {
|
||||
items.push({ label: t("contextMenu.closeConnection"), action: disconnectConnection, icon: Unplug });
|
||||
}
|
||||
items.push({ label: "", separator: true });
|
||||
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
|
||||
items.push({ label: "", separator: true });
|
||||
items.push({ label: t("contextMenu.newQuery"), action: newQuery, icon: TerminalSquare });
|
||||
if (currentDatabaseType() === "redis") {
|
||||
items.push({ label: t("contextMenu.instanceInfo"), action: openRedisInstanceInfo, icon: Info });
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { selectedConnectionDeleteTargets, selectedConnectionDuplicateTargets } from "@/lib/sidebar/sidebarConnectionSelection";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { copySelectedConnectionsToClipboards, selectedConnectionDeleteTargets, selectedConnectionDuplicateTargets } from "@/lib/sidebar/sidebarConnectionSelection";
|
||||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
function node(id: string, type: TreeNode["type"] = "connection"): TreeNode {
|
||||
|
|
@ -32,4 +32,22 @@ describe("sidebar connection selection", () => {
|
|||
|
||||
expect(selectedConnectionDuplicateTargets(current, selected)).toEqual(selectedConnectionDeleteTargets(current, selected));
|
||||
});
|
||||
|
||||
it("copies selected connection names to the system clipboard for the sidebar copy shortcut", () => {
|
||||
const copyConnectionsToTreeClipboard = vi.fn(() => 2);
|
||||
const copyToSystemClipboard = vi.fn(() => Promise.resolve());
|
||||
|
||||
expect(copySelectedConnectionsToClipboards([node("conn-1"), node("conn-2")], copyConnectionsToTreeClipboard, copyToSystemClipboard)).toBe(2);
|
||||
expect(copyConnectionsToTreeClipboard).toHaveBeenCalledWith(["conn-1", "conn-2"]);
|
||||
expect(copyToSystemClipboard).toHaveBeenCalledWith("conn-1\nconn-2");
|
||||
});
|
||||
|
||||
it("keeps the tree clipboard copy when system clipboard access is denied", async () => {
|
||||
const copyConnectionsToTreeClipboard = vi.fn(() => 1);
|
||||
const copyToSystemClipboard = vi.fn(() => Promise.reject(new Error("denied")));
|
||||
|
||||
expect(copySelectedConnectionsToClipboards([node("conn-1")], copyConnectionsToTreeClipboard, copyToSystemClipboard)).toBe(1);
|
||||
await Promise.resolve();
|
||||
expect(copyConnectionsToTreeClipboard).toHaveBeenCalledWith(["conn-1"]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { TreeNode } from "@/types/database";
|
||||
import { copyNameForTreeNode } from "@/lib/sidebar/treeNodeClick";
|
||||
|
||||
type ConnectionTreeNode = TreeNode & { connectionId: string };
|
||||
|
||||
|
|
@ -39,6 +40,18 @@ export function selectedConnectionClipboardNodes(selectedNodes: TreeNode[]): Con
|
|||
return selectedNodes;
|
||||
}
|
||||
|
||||
export function copySelectedConnectionsToClipboards(selectedNodes: TreeNode[], copyConnectionsToTreeClipboard: (connectionIds: string[]) => number, copyToSystemClipboard: (text: string) => Promise<void>): number {
|
||||
const connectionNodes = selectedConnectionClipboardNodes(selectedNodes);
|
||||
if (connectionNodes.length === 0) return 0;
|
||||
|
||||
const copiedCount = copyConnectionsToTreeClipboard(connectionNodes.map((node) => node.connectionId));
|
||||
if (copiedCount > 0) {
|
||||
// Connection duplication uses the tree clipboard, so keep it available even if OS clipboard access is denied.
|
||||
void copyToSystemClipboard(connectionNodes.map(copyNameForTreeNode).join("\n")).catch(() => {});
|
||||
}
|
||||
return copiedCount;
|
||||
}
|
||||
|
||||
export function connectionPasteTargetGroupId(node: TreeNode | null | undefined, groupIdForConnection: (connectionId: string) => string | null): string | null {
|
||||
if (!node) return null;
|
||||
if (node.type === "connection-group") return node.id;
|
||||
|
|
|
|||
Loading…
Reference in New Issue