Skip to content

Commit

Permalink
fix(editor): Prevent NodeCreator from swallowing AskAssistant enter e…
Browse files Browse the repository at this point in the history
…vent (#11532)
  • Loading branch information
CharlieKolb authored Nov 7, 2024
1 parent 6e2809b commit db94f16
Show file tree
Hide file tree
Showing 12 changed files with 53 additions and 16 deletions.
16 changes: 16 additions & 0 deletions cypress/e2e/45-ai-assistant.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ 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();
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(() => {
Expand Down Expand Up @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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..."
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
7 changes: 5 additions & 2 deletions packages/editor-ui/src/components/ParameterInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/components/RunData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/components/TextEdit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')"
Expand Down
16 changes: 8 additions & 8 deletions packages/editor-ui/src/components/WorkflowSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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')"
Expand Down Expand Up @@ -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')"
Expand Down Expand Up @@ -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')"
Expand Down Expand Up @@ -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')"
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/composables/useClipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/composables/useKeybindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/views/NodeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit db94f16

Please sign in to comment.