mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
fix(editor): Prevent NodeCreator from swallowing AskAssistant enter event (#11532)
This commit is contained in:
parent
6e2809b490
commit
db94f169fc
|
@ -4,6 +4,7 @@ import { clickCreateNewCredential, openCredentialSelect } from '../composables/n
|
|||
import { GMAIL_NODE_NAME, SCHEDULE_TRIGGER_NODE_NAME } from '../constants';
|
||||
import { CredentialsModal, CredentialsPage, NDV, WorkflowPage } from '../pages';
|
||||
import { AIAssistant } from '../pages/features/ai-assistant';
|
||||
import { NodeCreator } from '../pages/features/node-creator';
|
||||
import { getVisibleSelect } from '../utils';
|
||||
|
||||
const wf = new WorkflowPage();
|
||||
|
@ -11,6 +12,7 @@ const ndv = new NDV();
|
|||
const aiAssistant = new AIAssistant();
|
||||
const credentialsPage = new CredentialsPage();
|
||||
const credentialsModal = new CredentialsModal();
|
||||
const nodeCreatorFeature = new NodeCreator();
|
||||
|
||||
describe('AI Assistant::disabled', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -280,6 +282,20 @@ describe('AI Assistant::enabled', () => {
|
|||
wf.getters.isWorkflowSaved();
|
||||
aiAssistant.getters.placeholderMessage().should('not.exist');
|
||||
});
|
||||
|
||||
it('should send message via enter even with global NodeCreator panel opened', () => {
|
||||
cy.intercept('POST', '/rest/ai/chat', {
|
||||
statusCode: 200,
|
||||
fixture: 'aiAssistant/responses/simple_message_response.json',
|
||||
}).as('chatRequest');
|
||||
|
||||
wf.actions.addInitialNodeToCanvas(SCHEDULE_TRIGGER_NODE_NAME);
|
||||
aiAssistant.actions.openChat();
|
||||
nodeCreatorFeature.actions.openNodeCreator();
|
||||
aiAssistant.getters.chatInput().type('Hello{Enter}');
|
||||
|
||||
aiAssistant.getters.placeholderMessage().should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('AI Assistant Credential Help', () => {
|
||||
|
|
|
@ -317,6 +317,7 @@ async function onCopyButtonClick(content: string, e: MouseEvent) {
|
|||
<textarea
|
||||
ref="chatInput"
|
||||
v-model="textInputValue"
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
:disabled="sessionEnded"
|
||||
:placeholder="t('assistantChat.inputPlaceholder')"
|
||||
rows="1"
|
||||
|
|
|
@ -156,6 +156,7 @@ exports[`AskAssistantChat > does not render retry button if no error is present
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
@ -903,6 +904,7 @@ Testing more code
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
@ -1078,6 +1080,7 @@ exports[`AskAssistantChat > renders default placeholder chat correctly 1`] = `
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
@ -1323,6 +1326,7 @@ exports[`AskAssistantChat > renders end of session chat correctly 1`] = `
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
disabled=""
|
||||
placeholder="Enter your response..."
|
||||
|
@ -1493,6 +1497,7 @@ exports[`AskAssistantChat > renders error message correctly with retry button 1`
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
@ -1737,6 +1742,7 @@ catch(e) {
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
@ -1913,6 +1919,7 @@ exports[`AskAssistantChat > renders streaming chat correctly 1`] = `
|
|||
data-test-id="chat-input-wrapper"
|
||||
>
|
||||
<textarea
|
||||
class="ignore-key-press-node-creator ignore-key-press-canvas"
|
||||
data-test-id="chat-input"
|
||||
placeholder="Enter your response..."
|
||||
rows="1"
|
||||
|
|
|
@ -62,6 +62,16 @@ export const useKeyboardNavigation = defineStore('nodeCreatorKeyboardNavigation'
|
|||
}
|
||||
|
||||
async function onKeyDown(e: KeyboardEvent) {
|
||||
// We generally want a global listener across the app
|
||||
// But specific components may overrule this by adopting
|
||||
// the 'ignore-key-press-node-creator' class
|
||||
if (
|
||||
e.target instanceof Element &&
|
||||
e.target.classList.contains('ignore-key-press-node-creator')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pressedKey = e.key;
|
||||
if (!WATCHED_KEYS.includes(pressedKey)) return;
|
||||
e.preventDefault();
|
||||
|
|
|
@ -1023,7 +1023,7 @@ onUpdated(async () => {
|
|||
@update:model-value="expressionUpdated"
|
||||
></ExpressionEditModal>
|
||||
|
||||
<div class="parameter-input ignore-key-press" :style="parameterInputWrapperStyle">
|
||||
<div class="parameter-input ignore-key-press-canvas" :style="parameterInputWrapperStyle">
|
||||
<ResourceLocator
|
||||
v-if="parameter.type === 'resourceLocator'"
|
||||
ref="resourceLocator"
|
||||
|
@ -1098,7 +1098,10 @@ onUpdated(async () => {
|
|||
:before-close="closeCodeEditDialog"
|
||||
data-test-id="code-editor-fullscreen"
|
||||
>
|
||||
<div :key="codeEditDialogVisible.toString()" class="ignore-key-press code-edit-dialog">
|
||||
<div
|
||||
:key="codeEditDialogVisible.toString()"
|
||||
class="ignore-key-press-canvas code-edit-dialog"
|
||||
>
|
||||
<CodeNodeEditor
|
||||
v-if="editorType === 'codeNodeEditor'"
|
||||
:mode="codeEditorMode"
|
||||
|
|
|
@ -1409,7 +1409,7 @@ defineExpose({ enterEditMode });
|
|||
</div>
|
||||
|
||||
<div v-else-if="editMode.enabled" :class="$style.editMode">
|
||||
<div :class="[$style.editModeBody, 'ignore-key-press']">
|
||||
<div :class="[$style.editModeBody, 'ignore-key-press-canvas']">
|
||||
<JsonEditor
|
||||
:model-value="editMode.value"
|
||||
:fill-parent="true"
|
||||
|
|
|
@ -68,7 +68,7 @@ const closeDialog = () => {
|
|||
.inputLabelDisplayName(parameter, path)}`"
|
||||
:before-close="closeDialog"
|
||||
>
|
||||
<div class="ignore-key-press">
|
||||
<div class="ignore-key-press-canvas">
|
||||
<n8n-input-label :label="$locale.nodeText().inputLabelDisplayName(parameter, path)">
|
||||
<div @keydown.stop @keydown.esc="onKeyDownEsc">
|
||||
<n8n-input
|
||||
|
|
|
@ -536,7 +536,7 @@ onMounted(() => {
|
|||
data-test-id="workflow-lm-chat-dialog"
|
||||
:style="messageVars"
|
||||
>
|
||||
<MessagesList :messages="messages" :class="[$style.messages, 'ignore-key-press']">
|
||||
<MessagesList :messages="messages" :class="[$style.messages, 'ignore-key-press-canvas']">
|
||||
<template #beforeMessage="{ message }">
|
||||
<MessageOptionTooltip
|
||||
v-if="message.sender === 'bot' && !message.id.includes('preload')"
|
||||
|
|
|
@ -486,7 +486,7 @@ onMounted(async () => {
|
|||
<el-col :span="10" class="setting-name">
|
||||
{{ $locale.baseText('workflowSettings.executionOrder') + ':' }}
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.executionOrder"
|
||||
placeholder="Select Execution Order"
|
||||
|
@ -517,7 +517,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.errorWorkflow"
|
||||
placeholder="Select Workflow"
|
||||
|
@ -548,7 +548,7 @@ onMounted(async () => {
|
|||
</n8n-tooltip>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.callerPolicy"
|
||||
:disabled="readOnlyEnv || !workflowPermissions.update"
|
||||
|
@ -598,7 +598,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.timezone"
|
||||
placeholder="Select Timezone"
|
||||
|
@ -627,7 +627,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.saveDataErrorExecution"
|
||||
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
||||
|
@ -656,7 +656,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.saveDataSuccessExecution"
|
||||
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
||||
|
@ -685,7 +685,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.saveManualExecutions"
|
||||
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
||||
|
@ -714,7 +714,7 @@ onMounted(async () => {
|
|||
<font-awesome-icon icon="question-circle" />
|
||||
</n8n-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="14" class="ignore-key-press">
|
||||
<el-col :span="14" class="ignore-key-press-canvas">
|
||||
<n8n-select
|
||||
v-model="workflowSettings.saveExecutionProgress"
|
||||
:placeholder="$locale.baseText('workflowSettings.selectOption')"
|
||||
|
|
|
@ -14,7 +14,7 @@ export function useClipboard(
|
|||
const { debounce } = useDebounce();
|
||||
const { copy, copied, isSupported, text } = useClipboardCore({ legacy: true });
|
||||
|
||||
const ignoreClasses = ['el-messsage-box', 'ignore-key-press'];
|
||||
const ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas'];
|
||||
const initialized = ref(false);
|
||||
|
||||
const onPasteCallback = ref<ClipboardEventFn | null>(options.onPaste || null);
|
||||
|
|
|
@ -22,7 +22,7 @@ export const useKeybindings = (
|
|||
const active = activeElement.value;
|
||||
const isInput = ['INPUT', 'TEXTAREA'].includes(active.tagName);
|
||||
const isContentEditable = active.closest('[contenteditable]') !== null;
|
||||
const isIgnoreClass = active.closest('.ignore-key-press') !== null;
|
||||
const isIgnoreClass = active.closest('.ignore-key-press-canvas') !== null;
|
||||
|
||||
return isInput || isContentEditable || isIgnoreClass;
|
||||
});
|
||||
|
|
|
@ -1268,7 +1268,7 @@ export default defineComponent({
|
|||
element instanceof HTMLElement &&
|
||||
element.className &&
|
||||
typeof element.className === 'string' &&
|
||||
element.className.includes('ignore-key-press')
|
||||
element.className.includes('ignore-key-press-canvas')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue