mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 04:47:29 -08:00
feat(editor): Create separate components for JS and JSON editors (no-changelog) (#8156)
## Summary This is part-1 of refactoring our code editors to extract different type of editors into their own components. In part-2 we'll 1. delete a of unused or duplicate code 2. switch to a `useEditor` composable to bring more UX consistency across all the code editors. ## Review / Merge checklist - [x] PR title and summary are descriptive - [x] Tests included
This commit is contained in:
parent
1286d6583c
commit
216ec079c9
|
@ -133,8 +133,6 @@ export class OutputParserStructured implements INodeType {
|
|||
}`,
|
||||
typeOptions: {
|
||||
rows: 10,
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
|
|
|
@ -117,9 +117,8 @@ export class RetrieverWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Workflow JSON',
|
||||
name: 'workflowJson',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
rows: 10,
|
||||
},
|
||||
displayOptions: {
|
||||
|
@ -257,11 +256,9 @@ export class RetrieverWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Value',
|
||||
name: 'objectValue',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
default: '={}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 2,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -119,9 +119,8 @@ export class ToolWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Workflow JSON',
|
||||
name: 'workflowJson',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
rows: 10,
|
||||
},
|
||||
displayOptions: {
|
||||
|
@ -266,11 +265,9 @@ export class ToolWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Value',
|
||||
name: 'objectValue',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
default: '={}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 2,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -123,11 +123,9 @@ describe('Validation', () => {
|
|||
{
|
||||
displayName: 'Value',
|
||||
name: 'objectValue',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
default: '={}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 2,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -52,7 +52,6 @@ import { Compartment, EditorState } from '@codemirror/state';
|
|||
import type { ViewUpdate } from '@codemirror/view';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { json } from '@codemirror/lang-json';
|
||||
import { python } from '@codemirror/lang-python';
|
||||
import type { CodeExecutionMode, CodeNodeEditorLanguage } from 'n8n-workflow';
|
||||
import { CODE_EXECUTION_MODES, CODE_LANGUAGES } from 'n8n-workflow';
|
||||
|
@ -97,10 +96,9 @@ export default defineComponent({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
rows: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
default: 4,
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
|
@ -177,8 +175,6 @@ export default defineComponent({
|
|||
// eslint-disable-next-line vue/return-in-computed-property
|
||||
languageExtensions(): [LanguageSupport, ...Extension[]] {
|
||||
switch (this.language) {
|
||||
case 'json':
|
||||
return [json()];
|
||||
case 'javaScript':
|
||||
return [javascript(), this.autocompletionExtension('javaScript')];
|
||||
case 'python':
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import type { Diagnostic } from '@codemirror/lint';
|
||||
import { linter as createLinter } from '@codemirror/lint';
|
||||
import { jsonParseLinter } from '@codemirror/lang-json';
|
||||
import type { EditorView } from '@codemirror/view';
|
||||
import * as esprima from 'esprima-next';
|
||||
import type { Node } from 'estree';
|
||||
|
@ -21,8 +20,6 @@ export const linterExtension = defineComponent({
|
|||
switch (language) {
|
||||
case 'javaScript':
|
||||
return createLinter(this.lintSource, { delay: DEFAULT_LINTER_DELAY_IN_MS });
|
||||
case 'json':
|
||||
return createLinter(jsonParseLinter());
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
|
|
@ -54,7 +54,7 @@ export default defineComponent({
|
|||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
default: 4,
|
||||
},
|
||||
disableExpressionColoring: {
|
||||
type: Boolean,
|
||||
|
@ -67,7 +67,8 @@ export default defineComponent({
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
editor: {} as EditorView,
|
||||
editor: null as EditorView | null,
|
||||
editorState: null as EditorState | null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -111,8 +112,6 @@ 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);
|
||||
|
||||
|
|
95
packages/editor-ui/src/components/JsEditor/JsEditor.vue
Normal file
95
packages/editor-ui/src/components/JsEditor/JsEditor.vue
Normal file
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div ref="jsEditor" class="ph-no-capture js-editor"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { acceptCompletion, autocompletion } from '@codemirror/autocomplete';
|
||||
import { indentWithTab, history, redo, toggleComment, undo } from '@codemirror/commands';
|
||||
import { foldGutter, indentOnInput } from '@codemirror/language';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { lintGutter } from '@codemirror/lint';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import type { ViewUpdate } from '@codemirror/view';
|
||||
import {
|
||||
dropCursor,
|
||||
EditorView,
|
||||
highlightActiveLine,
|
||||
highlightActiveLineGutter,
|
||||
keymap,
|
||||
lineNumbers,
|
||||
} from '@codemirror/view';
|
||||
|
||||
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JsEditor',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null as EditorView | null,
|
||||
editorState: null as EditorState | null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
doc(): string {
|
||||
return this.editor?.state.doc.toString() ?? '';
|
||||
},
|
||||
extensions(): Extension[] {
|
||||
const { isReadOnly } = this;
|
||||
const extensions: Extension[] = [
|
||||
javascript(),
|
||||
lineNumbers(),
|
||||
EditorView.lineWrapping,
|
||||
EditorState.readOnly.of(isReadOnly),
|
||||
EditorView.editable.of(!isReadOnly),
|
||||
codeNodeEditorTheme({ isReadOnly, customMinHeight: this.rows }),
|
||||
];
|
||||
if (!isReadOnly) {
|
||||
extensions.push(
|
||||
history(),
|
||||
keymap.of([
|
||||
{ key: 'Mod-z', run: undo },
|
||||
{ key: 'Mod-Shift-z', run: redo },
|
||||
{ key: 'Mod-/', run: toggleComment },
|
||||
{ key: 'Tab', run: acceptCompletion },
|
||||
indentWithTab,
|
||||
]),
|
||||
lintGutter(),
|
||||
autocompletion(),
|
||||
indentOnInput(),
|
||||
highlightActiveLine(),
|
||||
highlightActiveLineGutter(),
|
||||
foldGutter(),
|
||||
dropCursor(),
|
||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (!viewUpdate.docChanged || !this.editor) return;
|
||||
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
||||
}),
|
||||
);
|
||||
}
|
||||
return extensions;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const state = EditorState.create({ doc: this.modelValue, extensions: this.extensions });
|
||||
const parent = this.$refs.jsEditor as HTMLDivElement;
|
||||
this.editor = new EditorView({ parent, state });
|
||||
this.editorState = this.editor.state;
|
||||
},
|
||||
});
|
||||
</script>
|
95
packages/editor-ui/src/components/JsonEditor/JsonEditor.vue
Normal file
95
packages/editor-ui/src/components/JsonEditor/JsonEditor.vue
Normal file
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div ref="jsonEditor" class="ph-no-capture json-editor"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { indentWithTab, history, redo, undo } from '@codemirror/commands';
|
||||
import { bracketMatching, foldGutter, indentOnInput } from '@codemirror/language';
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json';
|
||||
import { lintGutter, linter as createLinter } from '@codemirror/lint';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import type { ViewUpdate } from '@codemirror/view';
|
||||
import {
|
||||
dropCursor,
|
||||
EditorView,
|
||||
highlightActiveLine,
|
||||
highlightActiveLineGutter,
|
||||
keymap,
|
||||
lineNumbers,
|
||||
} from '@codemirror/view';
|
||||
|
||||
import { codeNodeEditorTheme } from '../CodeNodeEditor/theme';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JsonEditor',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null as EditorView | null,
|
||||
editorState: null as EditorState | null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
doc(): string {
|
||||
return this.editor?.state.doc.toString();
|
||||
},
|
||||
extensions(): Extension[] {
|
||||
const { isReadOnly } = this;
|
||||
const extensions: Extension[] = [
|
||||
json(),
|
||||
lineNumbers(),
|
||||
EditorView.lineWrapping,
|
||||
EditorState.readOnly.of(isReadOnly),
|
||||
EditorView.editable.of(!isReadOnly),
|
||||
codeNodeEditorTheme({ isReadOnly, customMinHeight: this.rows }),
|
||||
];
|
||||
if (!isReadOnly) {
|
||||
extensions.push(
|
||||
history(),
|
||||
keymap.of([
|
||||
indentWithTab,
|
||||
{ key: 'Mod-z', run: undo },
|
||||
{ key: 'Mod-Shift-z', run: redo },
|
||||
]),
|
||||
createLinter(jsonParseLinter()),
|
||||
lintGutter(),
|
||||
autocompletion(),
|
||||
indentOnInput(),
|
||||
highlightActiveLine(),
|
||||
highlightActiveLineGutter(),
|
||||
foldGutter(),
|
||||
dropCursor(),
|
||||
bracketMatching(),
|
||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (!viewUpdate.docChanged || !this.editor) return;
|
||||
this.$emit('update:modelValue', this.editor?.state.doc.toString());
|
||||
}),
|
||||
);
|
||||
}
|
||||
return extensions;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const state = EditorState.create({ doc: this.modelValue, extensions: this.extensions });
|
||||
const parent = this.$refs.jsonEditor as HTMLDivElement;
|
||||
this.editor = new EditorView({ parent, state });
|
||||
this.editorState = this.editor.state;
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -124,14 +124,18 @@
|
|||
@update:modelValue="valueChangedDebounced"
|
||||
/>
|
||||
|
||||
<CodeNodeEditor
|
||||
v-else-if="editorType === 'json' && !isExecuteWorkflowNode(node)"
|
||||
:mode="node.parameters.mode"
|
||||
<JsEditor
|
||||
v-else-if="editorType === 'jsEditor'"
|
||||
:model-value="modelValue"
|
||||
:is-read-only="isReadOnly"
|
||||
:rows="getArgument('rows')"
|
||||
@update:modelValue="valueChangedDebounced"
|
||||
/>
|
||||
|
||||
<JsonEditor
|
||||
v-else-if="parameter.type === 'json'"
|
||||
:model-value="modelValue"
|
||||
:default-value="parameter.default"
|
||||
:language="editorLanguage"
|
||||
:is-read-only="isReadOnly"
|
||||
:ai-button-enabled="false"
|
||||
:rows="getArgument('rows')"
|
||||
@update:modelValue="valueChangedDebounced"
|
||||
/>
|
||||
|
@ -396,18 +400,15 @@ import ExpressionParameterInput from '@/components/ExpressionParameterInput.vue'
|
|||
import TextEdit from '@/components/TextEdit.vue';
|
||||
import CodeNodeEditor from '@/components/CodeNodeEditor/CodeNodeEditor.vue';
|
||||
import HtmlEditor from '@/components/HtmlEditor/HtmlEditor.vue';
|
||||
import JsEditor from '@/components/JsEditor/JsEditor.vue';
|
||||
import JsonEditor from '@/components/JsonEditor/JsonEditor.vue';
|
||||
import SqlEditor from '@/components/SqlEditor/SqlEditor.vue';
|
||||
|
||||
import { workflowHelpers } from '@/mixins/workflowHelpers';
|
||||
import { hasExpressionMapping, isValueExpression } from '@/utils/nodeTypesUtils';
|
||||
import { isResourceLocatorValue } from '@/utils/typeGuards';
|
||||
|
||||
import {
|
||||
CUSTOM_API_CALL_KEY,
|
||||
EXECUTE_WORKFLOW_NODE_TYPE,
|
||||
HTML_NODE_TYPE,
|
||||
NODES_USING_CODE_NODE_EDITOR,
|
||||
} from '@/constants';
|
||||
import { CUSTOM_API_CALL_KEY, HTML_NODE_TYPE, NODES_USING_CODE_NODE_EDITOR } from '@/constants';
|
||||
|
||||
import type { PropType } from 'vue';
|
||||
import { debounceHelper } from '@/mixins/debounce';
|
||||
|
@ -432,6 +433,8 @@ export default defineComponent({
|
|||
components: {
|
||||
CodeNodeEditor,
|
||||
HtmlEditor,
|
||||
JsEditor,
|
||||
JsonEditor,
|
||||
SqlEditor,
|
||||
ExpressionEdit,
|
||||
ExpressionParameterInput,
|
||||
|
@ -1119,9 +1122,6 @@ export default defineComponent({
|
|||
isHtmlNode(node: INodeUi): boolean {
|
||||
return node.type === HTML_NODE_TYPE;
|
||||
},
|
||||
isExecuteWorkflowNode(node: INodeUi): boolean {
|
||||
return node.type === EXECUTE_WORKFLOW_NODE_TYPE;
|
||||
},
|
||||
rgbaToHex(value: string): string | null {
|
||||
// Convert rgba to hex from: https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
|
||||
const valueMatch = value.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)$/);
|
||||
|
|
|
@ -236,9 +236,8 @@
|
|||
|
||||
<div v-else-if="editMode.enabled" :class="$style.editMode">
|
||||
<div :class="[$style.editModeBody, 'ignore-key-press']">
|
||||
<CodeNodeEditor
|
||||
<JsonEditor
|
||||
:model-value="editMode.value"
|
||||
language="json"
|
||||
@update:modelValue="ndvStore.setOutputPanelEditModeValue($event)"
|
||||
/>
|
||||
</div>
|
||||
|
@ -604,11 +603,11 @@ import {
|
|||
|
||||
import BinaryDataDisplay from '@/components/BinaryDataDisplay.vue';
|
||||
import NodeErrorView from '@/components/Error/NodeErrorView.vue';
|
||||
import JsonEditor from '@/components/JsonEditor/JsonEditor.vue';
|
||||
|
||||
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||
import { pinData } from '@/mixins/pinData';
|
||||
import type { PinDataSource } from '@/mixins/pinData';
|
||||
import CodeNodeEditor from '@/components/CodeNodeEditor/CodeNodeEditor.vue';
|
||||
import { dataPinningEventBus } from '@/event-bus';
|
||||
import { clearJsonKey, isEmpty } from '@/utils/typesUtils';
|
||||
import { executionDataToJson } from '@/utils/nodeTypesUtils';
|
||||
|
@ -636,7 +635,7 @@ export default defineComponent({
|
|||
components: {
|
||||
BinaryDataDisplay,
|
||||
NodeErrorView,
|
||||
CodeNodeEditor,
|
||||
JsonEditor,
|
||||
RunDataTable,
|
||||
RunDataJson,
|
||||
RunDataSchema,
|
||||
|
|
|
@ -60,6 +60,7 @@ const SQL_DIALECTS = {
|
|||
|
||||
type SQLEditorData = {
|
||||
editor: EditorView | null;
|
||||
editorState: EditorState | null;
|
||||
isFocused: boolean;
|
||||
skipSegments: string[];
|
||||
expressionsDocsUrl: string;
|
||||
|
@ -89,12 +90,13 @@ export default defineComponent({
|
|||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
default: 4,
|
||||
},
|
||||
},
|
||||
data(): SQLEditorData {
|
||||
return {
|
||||
editor: null,
|
||||
editorState: null,
|
||||
expressionsDocsUrl: EXPRESSIONS_DOCS_URL,
|
||||
isFocused: false,
|
||||
skipSegments: ['Statement', 'CompositeIdentifier', 'Parens'],
|
||||
|
@ -132,7 +134,6 @@ export default defineComponent({
|
|||
}),
|
||||
lineNumbers(),
|
||||
EditorView.lineWrapping,
|
||||
EditorState.readOnly.of(this.isReadOnly),
|
||||
EditorView.domEventHandlers({
|
||||
focus: () => {
|
||||
this.isFocused = true;
|
||||
|
@ -162,8 +163,6 @@ 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);
|
||||
|
||||
|
|
19
packages/editor-ui/src/components/__tests__/JsEditor.test.ts
Normal file
19
packages/editor-ui/src/components/__tests__/JsEditor.test.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { createTestingPinia } from '@pinia/testing';
|
||||
import JsEditor from '@/components/JsEditor/JsEditor.vue';
|
||||
import { renderComponent } from '@/__tests__/render';
|
||||
|
||||
describe('JsEditor', () => {
|
||||
const renderEditor = (jsonString: string) =>
|
||||
renderComponent(JsEditor, {
|
||||
global: {
|
||||
plugins: [createTestingPinia()],
|
||||
},
|
||||
props: { modelValue: jsonString },
|
||||
});
|
||||
|
||||
it('renders simple js', async () => {
|
||||
const modelValue = 'return [1, 2, 3]';
|
||||
const result = renderEditor(modelValue);
|
||||
expect(result.container.querySelector('.cm-content')?.textContent).toEqual(modelValue);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import { createTestingPinia } from '@pinia/testing';
|
||||
import JsonEditor from '@/components/JsonEditor/JsonEditor.vue';
|
||||
import { renderComponent } from '@/__tests__/render';
|
||||
|
||||
describe('JsonEditor', () => {
|
||||
const renderEditor = (jsonString: string) =>
|
||||
renderComponent(JsonEditor, {
|
||||
global: {
|
||||
plugins: [createTestingPinia()],
|
||||
},
|
||||
props: { modelValue: jsonString },
|
||||
});
|
||||
|
||||
it('renders simple json', async () => {
|
||||
const modelValue = '{ "testing": [true, 5] }';
|
||||
const result = renderEditor(modelValue);
|
||||
expect(result.container.querySelector('.cm-content')?.textContent).toEqual(modelValue);
|
||||
});
|
||||
|
||||
it('renders multiline json', async () => {
|
||||
const modelValue = '{\n\t"testing": [true, 5]\n}';
|
||||
const result = renderEditor(modelValue);
|
||||
const gutter = result.container.querySelector('.cm-gutters');
|
||||
expect(gutter?.querySelectorAll('.cm-lineNumbers .cm-gutterElement').length).toEqual(4);
|
||||
|
||||
const content = result.container.querySelector('.cm-content');
|
||||
const lines = [...content!.querySelectorAll('.cm-line').values()].map((l) => l.textContent);
|
||||
expect(lines).toEqual(['{', '\t"testing": [true, 5]', '}']);
|
||||
});
|
||||
});
|
|
@ -68,10 +68,6 @@ const JSON_PARAM: INodeProperties = {
|
|||
displayName: 'JSON Payload',
|
||||
name: 'payloadJson',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
editor: 'code',
|
||||
},
|
||||
default: '',
|
||||
};
|
||||
|
||||
|
|
|
@ -55,14 +55,14 @@ const versionDescription: INodeTypeDescription = {
|
|||
displayName: 'Allowed Mentions',
|
||||
name: 'allowedMentions',
|
||||
type: 'json',
|
||||
typeOptions: { alwaysOpenEditWindow: true, editor: 'code' },
|
||||
typeOptions: { alwaysOpenEditWindow: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Attachments',
|
||||
name: 'attachments',
|
||||
type: 'json',
|
||||
typeOptions: { alwaysOpenEditWindow: true, editor: 'code' },
|
||||
typeOptions: { alwaysOpenEditWindow: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
|
@ -75,14 +75,14 @@ const versionDescription: INodeTypeDescription = {
|
|||
displayName: 'Components',
|
||||
name: 'components',
|
||||
type: 'json',
|
||||
typeOptions: { alwaysOpenEditWindow: true, editor: 'code' },
|
||||
typeOptions: { alwaysOpenEditWindow: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Embeds',
|
||||
name: 'embeds',
|
||||
type: 'json',
|
||||
typeOptions: { alwaysOpenEditWindow: true, editor: 'code' },
|
||||
typeOptions: { alwaysOpenEditWindow: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ const versionDescription: INodeTypeDescription = {
|
|||
displayName: 'JSON Payload',
|
||||
name: 'payloadJson',
|
||||
type: 'json',
|
||||
typeOptions: { alwaysOpenEditWindow: true, editor: 'code' },
|
||||
typeOptions: { alwaysOpenEditWindow: true },
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
|
|
|
@ -416,11 +416,9 @@ export const embedsFixedCollection: INodeProperties = {
|
|||
{
|
||||
displayName: 'Value',
|
||||
name: 'json',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
default: '={}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 2,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -111,9 +111,8 @@ export class ExecuteWorkflow implements INodeType {
|
|||
{
|
||||
displayName: 'Workflow JSON',
|
||||
name: 'workflowJson',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
rows: 10,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { readFile as fsReadFile } from 'fs/promises';
|
||||
import {
|
||||
NodeOperationError,
|
||||
type IExecuteFunctions,
|
||||
type IExecuteWorkflowInfo,
|
||||
jsonParse,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeOperationError, jsonParse } from 'n8n-workflow';
|
||||
import type { IWorkflowBase, IExecuteFunctions, IExecuteWorkflowInfo } from 'n8n-workflow';
|
||||
|
||||
export async function getWorkflowInfo(this: IExecuteFunctions, source: string, itemIndex = 0) {
|
||||
const workflowInfo: IExecuteWorkflowInfo = {};
|
||||
|
@ -33,8 +29,7 @@ export async function getWorkflowInfo(this: IExecuteFunctions, source: string, i
|
|||
workflowInfo.code = jsonParse(workflowJson);
|
||||
} else if (source === 'parameter') {
|
||||
// Read workflow from parameter
|
||||
const workflowJson = this.getNodeParameter('workflowJson', itemIndex) as string;
|
||||
workflowInfo.code = jsonParse(workflowJson);
|
||||
workflowInfo.code = this.getNodeParameter('workflowJson', itemIndex) as IWorkflowBase;
|
||||
} else if (source === 'url') {
|
||||
// Read workflow from url
|
||||
const workflowUrl = this.getNodeParameter('workflowUrl', itemIndex) as string;
|
||||
|
|
|
@ -40,7 +40,7 @@ export class Function implements INodeType {
|
|||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
codeAutocomplete: 'function',
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
type: 'string',
|
||||
|
|
|
@ -40,7 +40,7 @@ export class FunctionItem implements INodeType {
|
|||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
codeAutocomplete: 'functionItem',
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
type: 'string',
|
||||
|
|
|
@ -596,7 +596,7 @@ export class ItemListsV1 implements INodeType {
|
|||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
default: `// The two items to compare are in the variables a and b
|
||||
|
|
|
@ -598,7 +598,7 @@ export class ItemListsV2 implements INodeType {
|
|||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
default: `// The two items to compare are in the variables a and b
|
||||
|
|
|
@ -96,7 +96,7 @@ const properties: INodeProperties[] = [
|
|||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
default: `// The two items to compare are in the variables a and b
|
||||
|
|
|
@ -115,8 +115,6 @@ export class RespondToWebhook implements INodeType {
|
|||
},
|
||||
default: '{\n "myField": "value"\n}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 4,
|
||||
},
|
||||
description: 'The HTTP response JSON data',
|
||||
|
|
|
@ -139,11 +139,9 @@ const properties: INodeProperties[] = [
|
|||
{
|
||||
displayName: 'Value',
|
||||
name: 'objectValue',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
default: '={}',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 2,
|
||||
},
|
||||
displayOptions: {
|
||||
|
|
|
@ -15,10 +15,8 @@ const properties: INodeProperties[] = [
|
|||
{
|
||||
displayName: 'JSON Output',
|
||||
name: 'jsonOutput',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
editorLanguage: 'json',
|
||||
rows: 5,
|
||||
},
|
||||
default: '{\n "my_field_1": "value",\n "my_field_2": 1\n}',
|
||||
|
|
|
@ -13,13 +13,12 @@ const properties: INodeProperties[] = [
|
|||
{
|
||||
displayName: 'Query',
|
||||
name: 'queryJson',
|
||||
type: 'string',
|
||||
type: 'json',
|
||||
required: true,
|
||||
default: '=[\n {\n "_name": "listOrganisation"\n }\n]',
|
||||
description: 'Search for objects with filtering and sorting capabilities',
|
||||
hint: 'The query should be an array of operations with the required selection and optional filtering, sorting, and pagination. See <a href="https://docs.strangebee.com/thehive/api-docs/#operation/Query%20API" target="_blank">Query API</a> for more information.',
|
||||
typeOptions: {
|
||||
editor: 'json',
|
||||
rows: 10,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -106,7 +106,7 @@ export class Sort implements INodeType {
|
|||
type: 'string',
|
||||
typeOptions: {
|
||||
alwaysOpenEditWindow: true,
|
||||
editor: 'code',
|
||||
editor: 'jsEditor',
|
||||
rows: 10,
|
||||
},
|
||||
default: `// The two items to compare are in the variables a and b
|
||||
|
|
|
@ -3,7 +3,7 @@ export const WAIT_TIME_UNLIMITED = '3000-01-01T00:00:00.000Z';
|
|||
|
||||
export const LOG_LEVELS = ['silent', 'error', 'warn', 'info', 'debug', 'verbose'] as const;
|
||||
|
||||
export const CODE_LANGUAGES = ['javaScript', 'json', 'python'] as const;
|
||||
export const CODE_LANGUAGES = ['javaScript', 'python'] as const;
|
||||
export const CODE_EXECUTION_MODES = ['runOnceForAllItems', 'runOnceForEachItem'] as const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1078,7 +1078,7 @@ export type NodePropertyTypes =
|
|||
|
||||
export type CodeAutocompleteTypes = 'function' | 'functionItem';
|
||||
|
||||
export type EditorType = 'code' | 'codeNodeEditor' | 'htmlEditor' | 'sqlEditor' | 'json';
|
||||
export type EditorType = 'codeNodeEditor' | 'jsEditor' | 'htmlEditor' | 'sqlEditor';
|
||||
export type CodeNodeEditorLanguage = (typeof CODE_LANGUAGES)[number];
|
||||
export type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];
|
||||
export type SQLDialect =
|
||||
|
@ -1105,7 +1105,6 @@ export interface INodePropertyTypeOptions {
|
|||
alwaysOpenEditWindow?: boolean; // Supported by: json
|
||||
codeAutocomplete?: CodeAutocompleteTypes; // Supported by: string
|
||||
editor?: EditorType; // Supported by: string
|
||||
editorLanguage?: CodeNodeEditorLanguage; // Supported by: string in combination with editor: codeNodeEditor
|
||||
sqlDialect?: SQLDialect; // Supported by: sqlEditor
|
||||
loadOptionsDependsOn?: string[]; // Supported by: options
|
||||
loadOptionsMethod?: string; // Supported by: options
|
||||
|
|
Loading…
Reference in a new issue