fix(editor): Fix condition for opening the rename node prompt (no-changelog) (#18962)

This commit is contained in:
Suguru Inoue
2025-08-29 16:42:59 +02:00
committed by GitHub
parent 21077e9110
commit 6a400732ae
6 changed files with 61 additions and 14 deletions

View File

@@ -55,7 +55,7 @@ defineExpose({
:virtual-triggering="virtualRef !== undefined"
:virtual-ref="virtualRef"
:width="virtualRefSize.width.value"
:popper-class="$style.popper"
:popper-class="`${$style.popper} ignore-key-press-canvas`"
:popper-options="{
modifiers: [
{ name: 'flip', enabled: false },

View File

@@ -38,7 +38,7 @@ defineExpose({
:visible="isVisible"
placement="left"
:show-arrow="false"
:popper-class="$style.component"
:popper-class="`${$style.component} ignore-key-press-canvas`"
:width="360"
:offset="8"
append-to="body"

View File

@@ -1,4 +1,5 @@
import { PopOutWindowKey } from '@/constants';
import { shouldIgnoreCanvasShortcut } from '@/utils/canvasUtils';
import { useDeviceSupport } from '@n8n/composables/useDeviceSupport';
import { useActiveElement, useEventListener } from '@vueuse/core';
import type { MaybeRefOrGetter } from 'vue';
@@ -36,16 +37,9 @@ export const useKeybindings = (
const isDisabled = computed(() => toValue(options?.disabled));
const ignoreKeyPresses = computed(() => {
if (!activeElement.value) return false;
const active = activeElement.value;
const isInput = ['INPUT', 'TEXTAREA'].includes(active.tagName);
const isContentEditable = active.closest('[contenteditable]') !== null;
const isIgnoreClass = active.closest('.ignore-key-press-canvas') !== null;
return isInput || isContentEditable || isIgnoreClass;
});
const ignoreKeyPresses = computed(
() => activeElement.value && shouldIgnoreCanvasShortcut(activeElement.value),
);
const normalizedKeymap = computed(() =>
Object.fromEntries(

View File

@@ -7,6 +7,7 @@ import {
mapLegacyConnectionsToCanvasConnections,
mapLegacyEndpointsToCanvasConnectionPort,
parseCanvasConnectionHandleString,
shouldIgnoreCanvasShortcut,
} from '@/utils/canvasUtils';
import type { IConnection, IConnections, INodeTypeDescription } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
@@ -1051,3 +1052,44 @@ describe('insertSpacersBetweenEndpoints', () => {
expect(result).toEqual([{ index: 0, required: true }, null, null, null]);
});
});
describe(shouldIgnoreCanvasShortcut, () => {
it('should return false if given element is a div element', () => {
expect(shouldIgnoreCanvasShortcut(document.createElement('div'))).toEqual(false);
});
it('should return true if given element is an input element', () => {
expect(shouldIgnoreCanvasShortcut(document.createElement('input'))).toEqual(true);
});
it('should return true if given element is a textarea element', () => {
expect(shouldIgnoreCanvasShortcut(document.createElement('textarea'))).toEqual(true);
});
it('should return true if given element is an element with contenteditable attribute', () => {
const div = document.createElement('div');
div.setAttribute('contenteditable', 'true');
expect(shouldIgnoreCanvasShortcut(div)).toEqual(true);
});
it('should return true if given element is a child of an element with contenteditable attribute', () => {
const parent = document.createElement('div');
const child = document.createElement('div');
parent.appendChild(child);
parent.setAttribute('contenteditable', 'true');
expect(shouldIgnoreCanvasShortcut(child)).toEqual(true);
});
it('should return true if given element is has class "ignore-key-press-canvas"', () => {
const div = document.createElement('div');
div.classList.add('ignore-key-press-canvas');
expect(shouldIgnoreCanvasShortcut(div)).toEqual(true);
});
});

View File

@@ -263,3 +263,11 @@ export function insertSpacersBetweenEndpoints<T>(endpoints: T[], requiredEndpoin
return endpointsWithSpacers;
}
export function shouldIgnoreCanvasShortcut(el: Element): boolean {
return (
['INPUT', 'TEXTAREA'].includes(el.tagName) ||
el.closest('[contenteditable]') !== null ||
el.closest('.ignore-key-press-canvas') !== null
);
}

View File

@@ -122,7 +122,10 @@ import { useClipboard } from '@/composables/useClipboard';
import { useBeforeUnload } from '@/composables/useBeforeUnload';
import { getResourcePermissions } from '@n8n/permissions';
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
import { createCanvasConnectionHandleString } from '@/utils/canvasUtils';
import {
createCanvasConnectionHandleString,
shouldIgnoreCanvasShortcut,
} from '@/utils/canvasUtils';
import { isValidNodeConnectionType } from '@/utils/typeGuards';
import { getSampleWorkflowByTemplateId } from '@/utils/templates/workflowSamples';
import type { CanvasLayoutEvent } from '@/composables/useCanvasLayout';
@@ -917,7 +920,7 @@ async function onOpenRenameNodeModal(id: string) {
const activeElement = document.activeElement;
if (activeElement && activeElement.tagName === 'INPUT') {
if (activeElement && shouldIgnoreCanvasShortcut(activeElement)) {
// If an input is focused, do not open the rename modal
return;
}