feat(sidebar): add connection copy paste shortcuts
This commit is contained in:
19 files changed
+509
-20
No files matched your search
@@ -3,6 +3,7 @@ import { DEFAULT_SHORTCUT_SETTINGS, SHORTCUT_DEFINITIONS, findShortcutConflict,
|
||||
|
||||
describe("shortcutRegistry editor actions", () => {
|
||||
const formatterEditorActionIds: ShortcutActionId[] = ["formatSql", "indentMore", "indentLess", "duplicateLine", "deleteLine", "moveLineUp", "moveLineDown", "copyLineUp", "copyLineDown", "undo", "redo", "selectAll"];
|
||||
const sidebarShortcutActionIds: ShortcutActionId[] = ["copySidebarSelection", "pasteSidebarSelection", "editSidebarConnection"];
|
||||
|
||||
it("registers formatter editor shortcuts in the generic editor scope", () => {
|
||||
for (const actionId of formatterEditorActionIds) {
|
||||
@@ -36,4 +37,20 @@ describe("shortcutRegistry editor actions", () => {
|
||||
|
||||
expect(findShortcutConflict("duplicateLine", shortcuts.duplicateLine, shortcuts)).toBe("find");
|
||||
});
|
||||
|
||||
it("registers sidebar shortcuts in the sidebar scope", () => {
|
||||
for (const actionId of sidebarShortcutActionIds) {
|
||||
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === actionId);
|
||||
|
||||
expect(definition?.scope).toBe("sidebar");
|
||||
expect(DEFAULT_SHORTCUT_SETTINGS[actionId]).toBe(definition?.defaultShortcut);
|
||||
}
|
||||
});
|
||||
|
||||
it("detects conflicts only within sidebar shortcuts", () => {
|
||||
const shortcuts = normalizeShortcutSettings({ copySidebarSelection: "Mod+E" });
|
||||
|
||||
expect(findShortcutConflict("copySidebarSelection", shortcuts.copySidebarSelection, shortcuts)).toBe("editSidebarConnection");
|
||||
expect(findShortcutConflict("copyCurrentRow", shortcuts.copyCurrentRow, shortcuts)).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -146,6 +146,18 @@ export function isToggleSidebarShortcut(event: ShortcutLikeEvent, shortcuts?: Pa
|
||||
return matchesShortcut(event, actionShortcut("toggleSidebar", shortcuts));
|
||||
}
|
||||
|
||||
export function isCopySidebarSelectionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("copySidebarSelection", shortcuts));
|
||||
}
|
||||
|
||||
export function isPasteSidebarSelectionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("pasteSidebarSelection", shortcuts));
|
||||
}
|
||||
|
||||
export function isEditSidebarConnectionShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("editSidebarConnection", shortcuts));
|
||||
}
|
||||
|
||||
export function isQuickOpenShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("quickOpen", shortcuts));
|
||||
}
|
||||
|
||||
@@ -40,9 +40,12 @@ export type ShortcutActionId =
|
||||
| "refreshData"
|
||||
| "toggleTranspose"
|
||||
| "cancelSearch"
|
||||
| "toggleSidebar";
|
||||
| "toggleSidebar"
|
||||
| "copySidebarSelection"
|
||||
| "pasteSidebarSelection"
|
||||
| "editSidebarConnection";
|
||||
|
||||
export type ShortcutScope = "global" | "editor" | "grid" | "search";
|
||||
export type ShortcutScope = "global" | "editor" | "grid" | "search" | "sidebar";
|
||||
|
||||
export interface ShortcutDefinition {
|
||||
id: ShortcutActionId;
|
||||
@@ -306,6 +309,24 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+B",
|
||||
},
|
||||
{
|
||||
id: "copySidebarSelection",
|
||||
labelKey: "settings.shortcutCopySidebarSelection",
|
||||
scope: "sidebar",
|
||||
defaultShortcut: "Mod+C",
|
||||
},
|
||||
{
|
||||
id: "pasteSidebarSelection",
|
||||
labelKey: "settings.shortcutPasteSidebarSelection",
|
||||
scope: "sidebar",
|
||||
defaultShortcut: "Mod+V",
|
||||
},
|
||||
{
|
||||
id: "editSidebarConnection",
|
||||
labelKey: "settings.shortcutEditSidebarConnection",
|
||||
scope: "sidebar",
|
||||
defaultShortcut: "Mod+E",
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_SHORTCUT_SETTINGS: ShortcutSettings = Object.fromEntries(SHORTCUT_DEFINITIONS.map((definition) => [definition.id, definition.defaultShortcut])) as ShortcutSettings;
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { TreeNode } from "@/types/database";
|
||||
|
||||
type ConnectionTreeNode = TreeNode & { connectionId: string };
|
||||
|
||||
function isConnectionNode(node: TreeNode): node is ConnectionTreeNode {
|
||||
export function isConnectionNode(node: TreeNode): node is ConnectionTreeNode {
|
||||
return node.type === "connection" && !!node.connectionId;
|
||||
}
|
||||
|
||||
@@ -22,3 +22,26 @@ export function selectedConnectionDeleteTargets(currentNode: TreeNode, selectedN
|
||||
export function selectedConnectionDuplicateTargets(currentNode: TreeNode, selectedNodes: TreeNode[]): ConnectionTreeNode[] {
|
||||
return selectedConnectionActionTargets(currentNode, selectedNodes);
|
||||
}
|
||||
|
||||
export function selectedConnectionClipboardTargets(currentNode: TreeNode, selectedNodes: TreeNode[]): ConnectionTreeNode[] {
|
||||
return selectedConnectionActionTargets(currentNode, selectedNodes);
|
||||
}
|
||||
|
||||
export function selectedConnectionEditTarget(currentNode: TreeNode, selectedNodes: TreeNode[]): ConnectionTreeNode | null {
|
||||
if (!isConnectionNode(currentNode)) return null;
|
||||
const selectedContainsCurrent = selectedNodes.some((node) => node.id === currentNode.id);
|
||||
if (selectedNodes.length > 1 && selectedContainsCurrent) return null;
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
export function selectedConnectionClipboardNodes(selectedNodes: TreeNode[]): ConnectionTreeNode[] {
|
||||
if (selectedNodes.length === 0 || !selectedNodes.every(isConnectionNode)) return [];
|
||||
return selectedNodes;
|
||||
}
|
||||
|
||||
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;
|
||||
if (isConnectionNode(node)) return groupIdForConnection(node.connectionId);
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user