mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix: fix expression editor bug causing code mirror to no longer be reactive
This commit is contained in:
parent
5784750940
commit
972eae880b
|
@ -9,7 +9,6 @@
|
|||
}"
|
||||
aria-checked="true"
|
||||
>
|
||||
<input type="radio" tabindex="-1" autocomplete="off" :class="$style.input" :value="value" />
|
||||
<div
|
||||
:class="{
|
||||
[$style.button]: true,
|
||||
|
@ -18,7 +17,6 @@
|
|||
[$style.disabled]: disabled,
|
||||
}"
|
||||
:data-test-id="`radio-button-${value}`"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
{{ label }}
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
:active="modelValue === option.value"
|
||||
:size="size"
|
||||
:disabled="disabled || option.disabled"
|
||||
@click="() => onClick(option)"
|
||||
@click.prevent.stop="onClick(option)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
<template>
|
||||
<el-tooltip v-bind="{ ...$props, ...$attrs }">
|
||||
<template v-for="(_, slotName) in $slots" #[slotName]>
|
||||
<slot :name="slotName" />
|
||||
<div
|
||||
:key="slotName"
|
||||
v-if="slotName === 'content' && buttons.length"
|
||||
:class="$style.buttons"
|
||||
:style="{ justifyContent: justifyButtons }"
|
||||
>
|
||||
<n8n-button
|
||||
v-for="button in buttons"
|
||||
:key="button.attrs.label"
|
||||
v-bind="button.attrs"
|
||||
v-on="button.listeners"
|
||||
/>
|
||||
</div>
|
||||
<template #content>
|
||||
<n8n-button
|
||||
v-for="button in buttons"
|
||||
:key="button.attrs.label"
|
||||
v-bind="button.attrs"
|
||||
v-on="button.listeners"
|
||||
/>
|
||||
<slot name="content"></slot>
|
||||
</template>
|
||||
<slot />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@ export default defineComponent({
|
|||
EditorView.updateListener.of((viewUpdate) => {
|
||||
if (!this.editor || !viewUpdate.docChanged) return;
|
||||
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
highlighter.removeColor(this.editor, this.plaintextSegments);
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
|
||||
|
@ -94,6 +96,7 @@ export default defineComponent({
|
|||
}),
|
||||
});
|
||||
|
||||
this.editorState = this.editor.state;
|
||||
this.editor.focus();
|
||||
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
:path="path"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@update="onChange"
|
||||
@change="onChange"
|
||||
ref="inlineInput"
|
||||
/>
|
||||
<n8n-icon
|
||||
|
|
|
@ -106,6 +106,8 @@ export default defineComponent({
|
|||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (!viewUpdate.docChanged) return;
|
||||
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
this.getHighlighter()?.removeColor(this.editor, this.htmlSegments);
|
||||
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||
|
||||
|
@ -270,6 +272,7 @@ export default defineComponent({
|
|||
const state = EditorState.create({ doc, extensions: this.extensions });
|
||||
|
||||
this.editor = new EditorView({ parent: this.root(), state });
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
this.getHighlighter()?.addColor(this.editor, this.resolvableSegments);
|
||||
},
|
||||
|
|
|
@ -114,6 +114,9 @@ export default defineComponent({
|
|||
EditorView.updateListener.of((viewUpdate) => {
|
||||
if (!this.editor || !viewUpdate.docChanged) return;
|
||||
|
||||
// Force segments value update by keeping track of editor state
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
highlighter.removeColor(this.editor, this.plaintextSegments);
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
|
||||
|
@ -137,10 +140,11 @@ export default defineComponent({
|
|||
extensions,
|
||||
}),
|
||||
});
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
highlighter.addColor(this.editor, this.resolvableSegments);
|
||||
|
||||
this.$emit('update', {
|
||||
this.$emit('change', {
|
||||
value: this.unresolvedExpression,
|
||||
segments: this.displayableSegments,
|
||||
});
|
||||
|
|
|
@ -133,14 +133,14 @@
|
|||
|
||||
<n8n-input
|
||||
v-else
|
||||
v-model="tempValue"
|
||||
:modelValue="tempValue"
|
||||
ref="inputField"
|
||||
class="input-with-opener"
|
||||
:size="inputSize"
|
||||
:type="getStringInputType"
|
||||
:rows="getArgument('rows')"
|
||||
:disabled="isReadOnly"
|
||||
@update:modelValue="onTextInputChange($event) && valueChanged($event)"
|
||||
@update:modelValue="onUpdateTextInput"
|
||||
@keydown.stop
|
||||
@focus="setFocus"
|
||||
@blur="onBlur"
|
||||
|
@ -220,7 +220,7 @@
|
|||
:min="getArgument('minValue')"
|
||||
:precision="getArgument('numberPrecision')"
|
||||
:disabled="isReadOnly"
|
||||
@update:modelValue="onTextInputChange($event) && valueChanged($event)"
|
||||
@update:modelValue="onUpdateTextInput"
|
||||
@focus="setFocus"
|
||||
@blur="onBlur"
|
||||
@keydown.stop
|
||||
|
@ -1022,6 +1022,10 @@ export default defineComponent({
|
|||
valueChangedDebounced(value: NodeParameterValueType | {} | Date) {
|
||||
void this.callDebounced('valueChanged', { debounceTime: 100 }, value);
|
||||
},
|
||||
onUpdateTextInput(value: string) {
|
||||
this.valueChanged(value);
|
||||
this.onTextInputChange(value);
|
||||
},
|
||||
valueChanged(value: NodeParameterValueType | {} | Date) {
|
||||
if (this.parameter.name === 'nodeCredentialType') {
|
||||
this.activeCredentialType = value as string;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<template #options>
|
||||
<parameter-options
|
||||
:parameter="parameter"
|
||||
:modelValue="value"
|
||||
:value="value"
|
||||
:isReadOnly="false"
|
||||
:showOptions="true"
|
||||
:isValueExpression="isValueExpression"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<parameter-options
|
||||
v-if="displayOptions"
|
||||
:parameter="parameter"
|
||||
:modelValue="value"
|
||||
:value="value"
|
||||
:isReadOnly="isReadOnly"
|
||||
:showOptions="displayOptions"
|
||||
:showExpressionSelector="showExpressionSelector"
|
||||
|
@ -234,12 +234,14 @@ export default defineComponent({
|
|||
this.menuExpanded = expanded;
|
||||
},
|
||||
optionSelected(command: string) {
|
||||
console.log('optionSelected', command);
|
||||
this.eventBus.emit('optionSelected', command);
|
||||
},
|
||||
valueChanged(parameterData: IUpdateInformation) {
|
||||
this.$emit('update', parameterData);
|
||||
},
|
||||
onTextInput(parameterData: IUpdateInformation) {
|
||||
console.log('onTextInput', parameterData);
|
||||
if (isValueExpression(this.parameter, parameterData.value)) {
|
||||
this.eventBus.emit('optionSelected', 'addExpression');
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
:expressionEvaluated="expressionValueComputed"
|
||||
:label="label"
|
||||
:data-test-id="`parameter-input-${parameter.name}`"
|
||||
:event-bus="internalEventBus"
|
||||
:event-bus="eventBus"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@drop="onDrop"
|
||||
|
@ -72,17 +72,6 @@ export default defineComponent({
|
|||
ParameterInput,
|
||||
InputHint,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
internalEventBus: createEventBus(),
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.eventBus.on('optionSelected', this.optionSelected);
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.eventBus.off('optionSelected', this.optionSelected);
|
||||
},
|
||||
props: {
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
|
@ -231,9 +220,6 @@ export default defineComponent({
|
|||
onDrop(data: string) {
|
||||
this.$emit('drop', data);
|
||||
},
|
||||
optionSelected(command: string) {
|
||||
this.internalEventBus.emit('optionSelected', command);
|
||||
},
|
||||
onValueChanged(parameterData: IUpdateInformation) {
|
||||
this.$emit('update', parameterData);
|
||||
},
|
||||
|
|
|
@ -55,7 +55,7 @@ export default defineComponent({
|
|||
isReadOnly: {
|
||||
type: Boolean,
|
||||
},
|
||||
modelValue: {
|
||||
value: {
|
||||
type: [Object, String, Number, Boolean, Array] as PropType<NodeParameterValueType>,
|
||||
},
|
||||
showOptions: {
|
||||
|
@ -88,10 +88,10 @@ export default defineComponent({
|
|||
},
|
||||
computed: {
|
||||
isDefault(): boolean {
|
||||
return this.parameter.default === this.modelValue;
|
||||
return this.parameter.default === this.value;
|
||||
},
|
||||
isValueExpression(): boolean {
|
||||
return isValueExpression(this.parameter, this.modelValue);
|
||||
return isValueExpression(this.parameter, this.value);
|
||||
},
|
||||
isHtmlEditor(): boolean {
|
||||
return this.getArgument('editor') === 'htmlEditor';
|
||||
|
@ -153,8 +153,8 @@ export default defineComponent({
|
|||
if (
|
||||
this.hasRemoteMethod ||
|
||||
(this.parameter.type === 'resourceLocator' &&
|
||||
isResourceLocatorValue(this.modelValue) &&
|
||||
this.modelValue.mode === 'list')
|
||||
isResourceLocatorValue(this.value) &&
|
||||
this.value.mode === 'list')
|
||||
) {
|
||||
return [
|
||||
{
|
||||
|
@ -173,6 +173,7 @@ export default defineComponent({
|
|||
this.$emit('menu-expanded', visible);
|
||||
},
|
||||
onViewSelected(selected: string) {
|
||||
console.log('onViewSelected', selected);
|
||||
if (selected === 'expression') {
|
||||
this.$emit(
|
||||
'update:modelValue',
|
||||
|
|
|
@ -146,11 +146,10 @@
|
|||
></n8n-option>
|
||||
</n8n-select>
|
||||
|
||||
<n8n-tooltip
|
||||
placement="right"
|
||||
v-if="canLinkRuns"
|
||||
:content="$locale.baseText(linkedRuns ? 'runData.unlinking.hint' : 'runData.linking.hint')"
|
||||
>
|
||||
<n8n-tooltip placement="right" v-if="canLinkRuns">
|
||||
<template #content>
|
||||
{{ $locale.baseText(linkedRuns ? 'runData.unlinking.hint' : 'runData.linking.hint') }}
|
||||
</template>
|
||||
<n8n-icon-button
|
||||
v-if="linkedRuns"
|
||||
icon="unlink"
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
highlightActiveLineGutter,
|
||||
keymap,
|
||||
lineNumbers,
|
||||
ViewUpdate,
|
||||
} from '@codemirror/view';
|
||||
import {
|
||||
MSSQL,
|
||||
|
@ -167,6 +168,8 @@ export default defineComponent({
|
|||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (!viewUpdate.docChanged || !this.editor) return;
|
||||
|
||||
this.editorState = this.editor.state;
|
||||
|
||||
highlighter.removeColor(this.editor as EditorView, this.plaintextSegments);
|
||||
highlighter.addColor(this.editor as EditorView, this.resolvableSegments);
|
||||
|
||||
|
@ -182,6 +185,7 @@ export default defineComponent({
|
|||
|
||||
const state = EditorState.create({ doc: this.modelValue, extensions: this.extensions });
|
||||
this.editor = new EditorView({ parent: this.$refs.sqlEditor as HTMLDivElement, state });
|
||||
this.editorState = this.editor.state;
|
||||
highlighter.addColor(this.editor as EditorView, this.resolvableSegments);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -24,6 +24,7 @@ export const expressionManager = defineComponent({
|
|||
return {
|
||||
editor: {} as EditorView,
|
||||
skipSegments: [] as string[],
|
||||
editorState: undefined,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
|
@ -72,24 +73,24 @@ export const expressionManager = defineComponent({
|
|||
},
|
||||
|
||||
segments(): Segment[] {
|
||||
if (!this.editor?.state) return [];
|
||||
if (!this.editorState || !this.editorState) return [];
|
||||
|
||||
const rawSegments: RawSegment[] = [];
|
||||
|
||||
const fullTree = ensureSyntaxTree(
|
||||
this.editor.state,
|
||||
this.editor.state.doc.length,
|
||||
this.editorState,
|
||||
this.editorState.doc.length,
|
||||
EXPRESSION_EDITOR_PARSER_TIMEOUT,
|
||||
);
|
||||
|
||||
if (fullTree === null) {
|
||||
throw new Error(`Failed to parse expression: ${this.editor.state.doc.toString()}`);
|
||||
throw new Error(`Failed to parse expression: ${this.editorValue}`);
|
||||
}
|
||||
|
||||
const skipSegments = ['Program', 'Script', 'Document', ...this.skipSegments];
|
||||
|
||||
fullTree.cursor().iterate((node) => {
|
||||
const text = this.editor.state.sliceDoc(node.from, node.to);
|
||||
const text = this.editorState.sliceDoc(node.from, node.to);
|
||||
|
||||
if (skipSegments.includes(node.type.name)) return;
|
||||
|
||||
|
|
|
@ -630,14 +630,6 @@ export default defineComponent({
|
|||
NODE_CREATOR_OPEN_SOURCES,
|
||||
};
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.resetWorkspace();
|
||||
// Make sure the event listeners get removed again else we
|
||||
// could add up with them registered multiple times
|
||||
document.removeEventListener('keydown', this.keyDown);
|
||||
document.removeEventListener('keyup', this.keyUp);
|
||||
this.unregisterCustomAction('showNodeCreator');
|
||||
},
|
||||
methods: {
|
||||
showTriggerMissingToltip(isVisible: boolean) {
|
||||
this.showTriggerMissingTooltip = isVisible;
|
||||
|
@ -3961,6 +3953,12 @@ export default defineComponent({
|
|||
nodeViewEventBus.off('saveWorkflow', this.saveCurrentWorkflowExternal);
|
||||
},
|
||||
beforeUnmount() {
|
||||
// Make sure the event listeners get removed again else we
|
||||
// could add up with them registered multiple times
|
||||
document.removeEventListener('keydown', this.keyDown);
|
||||
document.removeEventListener('keyup', this.keyUp);
|
||||
this.unregisterCustomAction('showNodeCreator');
|
||||
|
||||
this.resetWorkspace();
|
||||
this.instance.unbind();
|
||||
this.instance.destroy();
|
||||
|
|
|
@ -89,8 +89,8 @@ export default mergeConfig(
|
|||
defineConfig({
|
||||
define: {
|
||||
// This causes test to fail but is required for actually running it
|
||||
...(NODE_ENV !== 'test' ? { global: 'globalThis' } : {}),
|
||||
...(NODE_ENV === 'development' ? { process: { env: {} } } : {}),
|
||||
// ...(NODE_ENV !== 'test' ? { 'global': 'globalThis' } : {}),
|
||||
...(NODE_ENV === 'development' ? { 'process.env': {} } : {}),
|
||||
BASE_PATH: `'${publicPath}'`,
|
||||
},
|
||||
plugins,
|
||||
|
|
Loading…
Reference in a new issue