mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Fix SQL editors not always re-rendering when query changes (#8621)
This commit is contained in:
parent
8c665e4d20
commit
8e9d3106a5
|
@ -27,6 +27,26 @@ describe('SQL editors', () => {
|
||||||
ndv.getters.sqlEditorContainer().should('contain', 'SELECT * FROM `testTable` LIMIT 10');
|
ndv.getters.sqlEditorContainer().should('contain', 'SELECT * FROM `testTable` LIMIT 10');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should update expression output dropdown as the query is edited', () => {
|
||||||
|
workflowPage.actions.addInitialNodeToCanvas('MySQL', {
|
||||||
|
action: 'Execute a SQL query',
|
||||||
|
});
|
||||||
|
ndv.actions.close();
|
||||||
|
|
||||||
|
workflowPage.actions.openNode('When clicking "Test workflow"');
|
||||||
|
ndv.actions.setPinnedData([{ table: 'test_table' }]);
|
||||||
|
ndv.actions.close();
|
||||||
|
|
||||||
|
workflowPage.actions.openNode('MySQL');
|
||||||
|
ndv.getters
|
||||||
|
.sqlEditorContainer()
|
||||||
|
.find('.cm-content')
|
||||||
|
.type('SELECT * FROM {{ $json.table }}', { parseSpecialCharSequences: false });
|
||||||
|
workflowPage.getters
|
||||||
|
.inlineExpressionEditorOutput()
|
||||||
|
.should('have.text', 'SELECT * FROM test_table');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not push NDV header out with a lot of code in Postgres editor', () => {
|
it('should not push NDV header out with a lot of code in Postgres editor', () => {
|
||||||
workflowPage.actions.addInitialNodeToCanvas('Postgres', {
|
workflowPage.actions.addInitialNodeToCanvas('Postgres', {
|
||||||
action: 'Execute a SQL query',
|
action: 'Execute a SQL query',
|
||||||
|
|
|
@ -43,6 +43,7 @@ import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
|
||||||
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
||||||
import type { Range, Section } from './types';
|
import type { Range, Section } from './types';
|
||||||
import { nonTakenRanges } from './utils';
|
import { nonTakenRanges } from './utils';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'HtmlEditor',
|
name: 'HtmlEditor',
|
||||||
|
@ -79,6 +80,16 @@ export default defineComponent({
|
||||||
editorState: null as EditorState | null,
|
editorState: null as EditorState | null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
displayableSegments(segments, newSegments) {
|
||||||
|
if (isEqual(segments, newSegments)) return;
|
||||||
|
|
||||||
|
highlighter.removeColor(this.editor, this.plaintextSegments);
|
||||||
|
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||||
|
|
||||||
|
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
||||||
|
},
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
doc(): string {
|
doc(): string {
|
||||||
return this.editor.state.doc.toString();
|
return this.editor.state.doc.toString();
|
||||||
|
@ -124,13 +135,10 @@ export default defineComponent({
|
||||||
EditorView.editable.of(!this.isReadOnly),
|
EditorView.editable.of(!this.isReadOnly),
|
||||||
EditorState.readOnly.of(this.isReadOnly),
|
EditorState.readOnly.of(this.isReadOnly),
|
||||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||||
if (!viewUpdate.docChanged) return;
|
if (!this.editor || !viewUpdate.docChanged) return;
|
||||||
|
|
||||||
this.getHighlighter()?.removeColor(this.editor, this.htmlSegments);
|
// Force segments value update by keeping track of editor state
|
||||||
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
this.editorState = this.editor.state;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
||||||
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-on-click-outside="onBlur" :class="$style.sqlEditor">
|
<div v-on-click-outside="onBlur" :class="$style.sqlEditor">
|
||||||
<div ref="sqlEditor" data-test-id="sql-editor-container"></div>
|
<div :class="$style.codemirror" ref="sqlEditor" data-test-id="sql-editor-container"></div>
|
||||||
<slot name="suffix" />
|
<slot name="suffix" />
|
||||||
<InlineExpressionEditorOutput
|
<InlineExpressionEditorOutput
|
||||||
v-if="!fillParent"
|
v-if="!fillParent"
|
||||||
|
@ -49,6 +49,7 @@ import {
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
|
import { enterKeyMap, tabKeyMap } from '../CodeNodeEditor/baseExtensions';
|
||||||
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
const SQL_DIALECTS = {
|
const SQL_DIALECTS = {
|
||||||
StandardSQL,
|
StandardSQL,
|
||||||
|
@ -171,12 +172,10 @@ export default defineComponent({
|
||||||
dropCursor(),
|
dropCursor(),
|
||||||
bracketMatching(),
|
bracketMatching(),
|
||||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||||
if (!viewUpdate.docChanged || !this.editor) return;
|
if (!this.editor || !viewUpdate.docChanged) return;
|
||||||
|
|
||||||
highlighter.removeColor(this.editor as EditorView, this.plaintextSegments);
|
// Force segments value update by keeping track of editor state
|
||||||
highlighter.addColor(this.editor as EditorView, this.resolvableSegments);
|
this.editorState = this.editor.state;
|
||||||
|
|
||||||
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -184,18 +183,13 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'ndvStore.ndvInputData'() {
|
displayableSegments(segments, newSegments) {
|
||||||
this.editor?.dispatch({
|
if (isEqual(segments, newSegments)) return;
|
||||||
changes: {
|
|
||||||
from: 0,
|
|
||||||
to: this.editor.state.doc.length,
|
|
||||||
insert: this.modelValue,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
highlighter.removeColor(this.editor, this.plaintextSegments);
|
||||||
this.editor?.contentDOM.blur();
|
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||||
});
|
|
||||||
|
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -244,9 +238,9 @@ export default defineComponent({
|
||||||
.sqlEditor {
|
.sqlEditor {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
& > div {
|
.codemirror {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import type { EditorView } from '@codemirror/view';
|
||||||
import type { TargetItem } from '@/Interface';
|
import type { TargetItem } from '@/Interface';
|
||||||
import type { Html, Plaintext, RawSegment, Resolvable, Segment } from '@/types/expressions';
|
import type { Html, Plaintext, RawSegment, Resolvable, Segment } from '@/types/expressions';
|
||||||
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
|
||||||
export const expressionManager = defineComponent({
|
export const expressionManager = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -98,12 +99,17 @@ export const expressionManager = defineComponent({
|
||||||
|
|
||||||
if (skipSegments.includes(node.type.name)) return;
|
if (skipSegments.includes(node.type.name)) return;
|
||||||
|
|
||||||
rawSegments.push({
|
const newSegment: RawSegment = {
|
||||||
from: node.from,
|
from: node.from,
|
||||||
to: node.to,
|
to: node.to,
|
||||||
text,
|
text,
|
||||||
token: node.type.name === 'Resolvable' ? 'Resolvable' : 'Plaintext',
|
token: node.type.name === 'Resolvable' ? 'Resolvable' : 'Plaintext',
|
||||||
});
|
};
|
||||||
|
|
||||||
|
// Avoid duplicates
|
||||||
|
if (isEqual(newSegment, rawSegments.at(-1))) return;
|
||||||
|
|
||||||
|
rawSegments.push(newSegment);
|
||||||
});
|
});
|
||||||
|
|
||||||
return rawSegments.reduce<Segment[]>((acc, segment) => {
|
return rawSegments.reduce<Segment[]>((acc, segment) => {
|
||||||
|
|
Loading…
Reference in a new issue