mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-20 04:20:10 +00:00
## Summary Adds VS Code-style multi-keybinding support to the Keybinding settings panel. Commands can now have multiple keybindings displayed, expanded, and individually managed. - Fixes #1088 ## Changes ### Store (`keybindingStore.ts`) - `removeAllKeybindingsForCommand(commandId)` — unsets all bindings for a command - `updateSpecificKeybinding(old, new)` — replaces a single binding without affecting others - `resetKeybindingForCommand` — updated to restore **all** default bindings, not just the first - `isCommandKeybindingModified` — updated to compare full sorted sets of bindings ### UI (`KeybindingPanel.vue`) - **Data model**: `keybinding: KeybindingImpl | null` → `keybindings: KeybindingImpl[]` - **Multi-binding display**: shows up to 2 combos inline with `, ` separator, then `+ N more` badge - **Expand/collapse**: click any row with 2+ bindings to expand individual binding rows; chevron-right icon rotates on expand - **Per-binding actions**: edit (pencil), reset, trash on each expanded sub-row - **Parent row actions**: `+`/trash for 2+ bindings, pencil/reset/trash for 1, `+`/disabled for 0 - **Edit modes**: `edit` (replace specific binding via `updateSpecificKeybinding`) and `add` (append via `addUserKeybinding`) - **Right-click context menu**: Change keybinding, Add new, Reset to default, Remove keybinding — with proper disabled states and lucide icons - **Remove all dialog**: confirmation via `showSmallLayoutDialog` with `RemoveAllKeybindingsHeader`/`Content` components - **Reset all dialog**: confirmation via `showConfirmDialog` before resetting all keybindings to defaults - **Double-click**: 0 bindings → add, 1 → edit, 2+ → no-op (single click toggles expand) - **Consistent alignment**: commands without chevron get `pl-5` padding to align with those that have it ### Tests (`keybindingStore.test.ts`) - 7 new tests covering `removeAllKeybindingsForCommand`, `updateSpecificKeybinding`, multi-binding `isCommandKeybindingModified`, and multi-binding `resetKeybindingForCommand` ### i18n (`main.json`) - 11 new keys: removeAllKeybindingsTitle/Message, removeAll, changeKeybinding, addNewKeybinding, resetToDefault, removeKeybinding, nMoreKeybindings, resetAllKeybindingsTitle/Message, allKeybindingsReset ### New components - `RemoveAllKeybindingsHeader.vue` — dialog header - `RemoveAllKeybindingsContent.vue` — dialog body with Close/Remove all buttons ## Test plan - [x] `pnpm typecheck` passes - [x] `pnpm lint` passes (no new errors) - [x] `pnpm vitest run src/platform/keybindings/` — 45 tests pass - [x] CodeRabbit review — 0 findings - [ ] Manual: open Settings → Keybindings, verify multi-binding commands (e.g. Delete Selected Items, Zoom In) show multiple combos - [ ] Manual: click row to expand, verify per-binding actions work - [ ] Manual: right-click row, verify context menu actions - [ ] Manual: click trash on 2+ binding command, verify "Remove all" confirmation dialog - [ ] Manual: click "Reset All" button, verify confirmation dialog appears - [ ] Manual: add/edit/remove individual bindings, verify persistence ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9738-feat-multi-keybinding-support-in-settings-panel-3206d73d365081e9b08bd3cfe21495f1) by [Unito](https://www.unito.io)
68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import { computed, reactive } from 'vue'
|
|
|
|
import EditKeybindingContent from '@/components/dialog/content/setting/keybinding/EditKeybindingContent.vue'
|
|
import EditKeybindingFooter from '@/components/dialog/content/setting/keybinding/EditKeybindingFooter.vue'
|
|
import EditKeybindingHeader from '@/components/dialog/content/setting/keybinding/EditKeybindingHeader.vue'
|
|
import type { KeyComboImpl } from '@/platform/keybindings/keyCombo'
|
|
import type { KeybindingImpl } from '@/platform/keybindings/keybinding'
|
|
import { useKeybindingStore } from '@/platform/keybindings/keybindingStore'
|
|
import { useDialogService } from '@/services/dialogService'
|
|
|
|
export const DIALOG_KEY = 'edit-keybinding'
|
|
|
|
export interface EditKeybindingDialogState {
|
|
commandId: string
|
|
newCombo: KeyComboImpl | null
|
|
currentCombo: KeyComboImpl | null
|
|
mode: 'edit' | 'add'
|
|
existingBinding: KeybindingImpl | null
|
|
}
|
|
|
|
export function useEditKeybindingDialog() {
|
|
const { showSmallLayoutDialog } = useDialogService()
|
|
const keybindingStore = useKeybindingStore()
|
|
|
|
function show(options: {
|
|
commandId: string
|
|
commandLabel: string
|
|
currentCombo: KeyComboImpl | null
|
|
mode?: 'edit' | 'add'
|
|
existingBinding?: KeybindingImpl | null
|
|
}) {
|
|
const dialogState = reactive<EditKeybindingDialogState>({
|
|
commandId: options.commandId,
|
|
newCombo: options.currentCombo,
|
|
currentCombo: options.currentCombo,
|
|
mode: options.mode ?? 'edit',
|
|
existingBinding: options.existingBinding ?? null
|
|
})
|
|
|
|
const existingKeybindingOnCombo = computed(() => {
|
|
if (!dialogState.newCombo) return null
|
|
if (dialogState.currentCombo?.equals(dialogState.newCombo)) return null
|
|
return keybindingStore.getKeybinding(dialogState.newCombo)
|
|
})
|
|
|
|
function onUpdateCombo(combo: KeyComboImpl) {
|
|
dialogState.newCombo = combo
|
|
}
|
|
|
|
showSmallLayoutDialog({
|
|
key: DIALOG_KEY,
|
|
headerComponent: EditKeybindingHeader,
|
|
footerComponent: EditKeybindingFooter,
|
|
component: EditKeybindingContent,
|
|
props: {
|
|
dialogState,
|
|
onUpdateCombo,
|
|
commandLabel: options.commandLabel,
|
|
existingKeybindingOnCombo
|
|
},
|
|
headerProps: {},
|
|
footerProps: { dialogState, existingKeybindingOnCombo }
|
|
})
|
|
}
|
|
|
|
return { show }
|
|
}
|