mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
feat(editor): Add examples for root expression methods (#9373)
This commit is contained in:
parent
7cb431f506
commit
a591f63e3f
|
@ -1,5 +1,5 @@
|
|||
import { NODE_TYPES_EXCLUDED_FROM_AUTOCOMPLETION } from '../constants';
|
||||
import { addVarType } from '../utils';
|
||||
import { addInfoRenderer, addVarType } from '../utils';
|
||||
import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
|
@ -128,7 +128,7 @@ export function useBaseCompletions(
|
|||
|
||||
return {
|
||||
from: preCursor.from,
|
||||
options,
|
||||
options: options.map(addInfoRenderer),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { addVarType, escape } from '../utils';
|
||||
import { addInfoRenderer, addVarType, escape } from '../utils';
|
||||
import type { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
|
||||
|
@ -18,15 +18,6 @@ export function useExecutionCompletions() {
|
|||
|
||||
if (!preCursor || (preCursor.from === preCursor.to && !context.explicit)) return null;
|
||||
|
||||
const buildLinkNode = (text: string) => {
|
||||
const wrapper = document.createElement('span');
|
||||
// This is being loaded from the locales file. This could
|
||||
// cause an XSS of some kind but multiple other locales strings
|
||||
// do the same thing.
|
||||
wrapper.innerHTML = text;
|
||||
return () => wrapper;
|
||||
};
|
||||
|
||||
const options: Completion[] = [
|
||||
{
|
||||
label: `${matcher}.id`,
|
||||
|
@ -46,29 +37,25 @@ export function useExecutionCompletions() {
|
|||
},
|
||||
{
|
||||
label: `${matcher}.customData.set("key", "value")`,
|
||||
info: buildLinkNode(i18n.baseText('codeNodeEditor.completer.$execution.customData.set()')),
|
||||
info: i18n.baseText('codeNodeEditor.completer.$execution.customData.set'),
|
||||
},
|
||||
{
|
||||
label: `${matcher}.customData.get("key")`,
|
||||
info: buildLinkNode(i18n.baseText('codeNodeEditor.completer.$execution.customData.get()')),
|
||||
info: i18n.baseText('codeNodeEditor.completer.$execution.customData.get'),
|
||||
},
|
||||
{
|
||||
label: `${matcher}.customData.setAll({})`,
|
||||
info: buildLinkNode(
|
||||
i18n.baseText('codeNodeEditor.completer.$execution.customData.setAll()'),
|
||||
),
|
||||
info: i18n.baseText('codeNodeEditor.completer.$execution.customData.setAll'),
|
||||
},
|
||||
{
|
||||
label: `${matcher}.customData.getAll()`,
|
||||
info: buildLinkNode(
|
||||
i18n.baseText('codeNodeEditor.completer.$execution.customData.getAll()'),
|
||||
),
|
||||
info: i18n.baseText('codeNodeEditor.completer.$execution.customData.getAll'),
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
from: preCursor.from,
|
||||
options: options.map(addVarType),
|
||||
options: options.map(addVarType).map(addInfoRenderer),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import type * as esprima from 'esprima-next';
|
|||
import type { Completion } from '@codemirror/autocomplete';
|
||||
import type { Node } from 'estree';
|
||||
import type { RangeNode } from './types';
|
||||
import { sanitizeHtml } from '@/utils/htmlUtils';
|
||||
|
||||
export function walk<T extends RangeNode>(
|
||||
node: Node | esprima.Program,
|
||||
|
@ -40,3 +41,15 @@ export const escape = (str: string) =>
|
|||
export const toVariableOption = (label: string) => ({ label, type: 'variable' });
|
||||
|
||||
export const addVarType = (option: Completion) => ({ ...option, type: 'variable' });
|
||||
|
||||
export const addInfoRenderer = (option: Completion): Completion => {
|
||||
const { info } = option;
|
||||
if (typeof info === 'string') {
|
||||
option.info = () => {
|
||||
const wrapper = document.createElement('span');
|
||||
wrapper.innerHTML = sanitizeHtml(info);
|
||||
return wrapper;
|
||||
};
|
||||
}
|
||||
return option;
|
||||
};
|
||||
|
|
|
@ -772,11 +772,19 @@ describe('Resolution-based completions', () => {
|
|||
test('should not display type information for other completions', () => {
|
||||
vi.spyOn(workflowHelpers, 'resolveParameter').mockReturnValue({
|
||||
str: 'bar',
|
||||
id: '123',
|
||||
isExecuted: false,
|
||||
});
|
||||
|
||||
expect(completions('{{ $execution.| }}')?.every((item) => !item.detail)).toBe(true);
|
||||
expect(completions('{{ $input.params.| }}')?.every((item) => !item.detail)).toBe(true);
|
||||
expect(completions('{{ $("My Node").| }}')?.every((item) => !item.detail)).toBe(true);
|
||||
expect(completions('{{ $execution.| }}')).not.toContainEqual(
|
||||
expect.objectContaining({ detail: expect.any(String) }),
|
||||
);
|
||||
expect(completions('{{ $input.params.| }}')).not.toContainEqual(
|
||||
expect.objectContaining({ detail: expect.any(String) }),
|
||||
);
|
||||
expect(completions('{{ $("My Node").| }}')).not.toContainEqual(
|
||||
expect.objectContaining({ detail: expect.any(String) }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -55,7 +55,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$json',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$json,
|
||||
description: i18n.baseText('codeNodeEditor.completer.json'),
|
||||
docURL: 'https://docs.n8n.io/data/data-structure/',
|
||||
}),
|
||||
},
|
||||
|
@ -65,7 +65,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$binary',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$binary,
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$now',
|
||||
returnType: 'DateTime',
|
||||
description: i18n.rootVars.$now,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$now'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -83,25 +83,36 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer(
|
||||
{
|
||||
name: '$if',
|
||||
returnType: 'boolean',
|
||||
description: i18n.rootVars.$if,
|
||||
returnType: 'any',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if'),
|
||||
args: [
|
||||
{
|
||||
name: 'condition',
|
||||
optional: false,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if.args.condition'),
|
||||
type: 'boolean',
|
||||
},
|
||||
{
|
||||
name: 'valueIfTrue',
|
||||
optional: false,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if.args.valueIfTrue'),
|
||||
type: 'any',
|
||||
},
|
||||
{
|
||||
name: 'valueIfFalse',
|
||||
optional: false,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if.args.valueIfFalse'),
|
||||
type: 'any',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: '$if($now.hour < 17, "Good day", "Good evening")',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if.examples.1'),
|
||||
},
|
||||
{
|
||||
description: i18n.baseText('codeNodeEditor.completer.$if.examples.2'),
|
||||
example:
|
||||
'$if($now.hour < 10, "Good morning", $if($now.hour < 17, "Good day", "Good evening"))',
|
||||
},
|
||||
],
|
||||
},
|
||||
true,
|
||||
),
|
||||
|
@ -112,20 +123,26 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer(
|
||||
{
|
||||
name: '$ifEmpty',
|
||||
returnType: 'boolean',
|
||||
description: i18n.rootVars.$ifEmpty,
|
||||
returnType: 'any',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$ifEmpty'),
|
||||
args: [
|
||||
{
|
||||
name: 'value',
|
||||
optional: false,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$ifEmpty.args.value'),
|
||||
type: 'any',
|
||||
},
|
||||
{
|
||||
name: 'valueIfEmpty',
|
||||
optional: false,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$ifEmpty.args.valueIfEmpty'),
|
||||
type: 'any',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: '"Hi " + $ifEmpty(name, "there")',
|
||||
evaluated: 'e.g. "Hi Nathan" or "Hi there"',
|
||||
},
|
||||
],
|
||||
},
|
||||
true,
|
||||
),
|
||||
|
@ -135,8 +152,8 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
section: METADATA_SECTION,
|
||||
info: createInfoBoxRenderer({
|
||||
name: '$execution',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$execution,
|
||||
returnType: 'ExecData',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -145,7 +162,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$itemIndex',
|
||||
returnType: 'number',
|
||||
description: i18n.rootVars.$itemIndex,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$itemIndex'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -154,7 +171,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$input',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$input,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$input'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -163,7 +180,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$parameter',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$parameter,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$parameter'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -171,8 +188,8 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
section: METADATA_SECTION,
|
||||
info: createInfoBoxRenderer({
|
||||
name: '$prevNode',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$prevNode,
|
||||
returnType: 'PrevNodeData',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$prevNode'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -181,7 +198,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$runIndex',
|
||||
returnType: 'number',
|
||||
description: i18n.rootVars.$runIndex,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$runIndex'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -190,7 +207,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$today',
|
||||
returnType: 'DateTime',
|
||||
description: i18n.rootVars.$today,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$today'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -199,7 +216,7 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$vars',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$vars,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$vars'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -207,8 +224,8 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
section: METADATA_SECTION,
|
||||
info: createInfoBoxRenderer({
|
||||
name: '$workflow',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$workflow,
|
||||
returnType: 'WorkflowData',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$workflow'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -217,8 +234,44 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
info: createInfoBoxRenderer(
|
||||
{
|
||||
name: '$jmespath',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath'),
|
||||
returnType: 'any',
|
||||
description: i18n.rootVars.$jmespath,
|
||||
args: [
|
||||
{
|
||||
name: 'obj',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.args.obj'),
|
||||
type: 'Object | Array',
|
||||
},
|
||||
{
|
||||
name: 'expression',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.args.expression'),
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example:
|
||||
'data = {\n "people": [\n {\n "name": "Bob",\n "age": 20,\n "other": "foo"\n },\n {\n "name": "Fred",\n "age": 25,\n "other": "bar"\n },\n {\n "name": "George",\n "age": 30,\n "other": "baz"\n }\n ]\n}\n\n$jmespath(data.people, \'[*].name\')',
|
||||
evaluated: "['Bob', 'Fred', 'George']",
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.examples.1'),
|
||||
},
|
||||
{
|
||||
example: "$jmespath(data.people, '[?age > `20`].[name, age]')",
|
||||
evaluated: "[['Fred', 25], ['George', 30]]",
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.examples.2'),
|
||||
},
|
||||
{
|
||||
example: "$jmespath(data.people, '[?age > `20`].name | [0]')",
|
||||
evaluated: 'Fred',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.examples.3'),
|
||||
},
|
||||
{
|
||||
example:
|
||||
'data = {\n "reservations": [\n {\n "id": 1,\n "guests": [\n {\n "name": "Nathan",\n "requirements": {\n "room": "double",\n "meal": "vegetarian"\n }\n },\n {\n "name": "Meg",\n "requirements": {\n "room": "single"\n }\n }\n ]\n },\n {\n "id": 2,\n "guests": [\n {\n "name": "Lex",\n "requirements": {\n "room": "double"\n }\n }\n ]\n }\n ]\n}\n\n$jmespath(data, "reservations[].guests[?requirements.room==\'double\'][].name")',
|
||||
evaluated: "['Nathan', 'Lex']",
|
||||
description: i18n.baseText('codeNodeEditor.completer.$jmespath.examples.4'),
|
||||
},
|
||||
],
|
||||
},
|
||||
true,
|
||||
),
|
||||
|
@ -230,24 +283,16 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
{
|
||||
name: '$max',
|
||||
returnType: 'number',
|
||||
description: i18n.rootVars.$max,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$max'),
|
||||
args: [
|
||||
{
|
||||
name: 'number1',
|
||||
optional: false,
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'number2',
|
||||
optional: true,
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'numberN',
|
||||
optional: true,
|
||||
name: 'numbers',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$max.args.numbers'),
|
||||
type: 'number',
|
||||
variadic: true,
|
||||
},
|
||||
],
|
||||
examples: [{ example: '$max(1, 5, 42, 0.5)', evaluated: '42' }],
|
||||
},
|
||||
true,
|
||||
),
|
||||
|
@ -259,24 +304,16 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
{
|
||||
name: '$min',
|
||||
returnType: 'number',
|
||||
description: i18n.rootVars.$min,
|
||||
description: i18n.baseText('codeNodeEditor.completer.$min'),
|
||||
args: [
|
||||
{
|
||||
name: 'number1',
|
||||
optional: false,
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'number2',
|
||||
optional: true,
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'numberN',
|
||||
optional: true,
|
||||
name: 'numbers',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$max.args.numbers'),
|
||||
variadic: true,
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
examples: [{ example: '$min(1, 5, 42, 0.5)', evaluated: '0.5' }],
|
||||
},
|
||||
true,
|
||||
),
|
||||
|
@ -284,7 +321,11 @@ export const ROOT_DOLLAR_COMPLETIONS: Completion[] = [
|
|||
{
|
||||
label: '$nodeVersion',
|
||||
section: METADATA_SECTION,
|
||||
info: i18n.rootVars.$nodeVersion,
|
||||
info: createInfoBoxRenderer({
|
||||
name: '$nodeVersion',
|
||||
returnType: 'number',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$nodeVersion'),
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ import {
|
|||
isSplitInBatchesAbsent,
|
||||
longestCommonPrefix,
|
||||
prefixMatch,
|
||||
setRank,
|
||||
sortCompletionsAlpha,
|
||||
splitBaseTail,
|
||||
stripExcessParens,
|
||||
|
@ -244,6 +243,20 @@ export const isInputData = (base: string): boolean => {
|
|||
);
|
||||
};
|
||||
|
||||
export const isItem = (input: AutocompleteInput<IDataObject>): boolean => {
|
||||
const { base, resolved } = input;
|
||||
return /^(\$\(.*\)|\$input)/.test(base) && 'pairedItem' in resolved;
|
||||
};
|
||||
|
||||
export const isBinary = (input: AutocompleteInput<IDataObject>): boolean => {
|
||||
const { base, resolved } = input;
|
||||
return (
|
||||
/^(\$\(.*\)\..*\.binary\..*|\$binary)/.test(base) &&
|
||||
'mimeType' in resolved &&
|
||||
'fileExtension' in resolved
|
||||
);
|
||||
};
|
||||
|
||||
export const getDetail = (base: string, value: unknown): string | undefined => {
|
||||
const type = getType(value);
|
||||
if (!isInputData(base) || type === 'function') return undefined;
|
||||
|
@ -300,29 +313,54 @@ const createCompletionOption = ({
|
|||
return option;
|
||||
};
|
||||
|
||||
const customObjectOptions = (input: AutocompleteInput<IDataObject>): Completion[] => {
|
||||
const { base, resolved } = input;
|
||||
|
||||
if (!resolved) return [];
|
||||
|
||||
if (base === '$execution') {
|
||||
return executionOptions();
|
||||
} else if (base === '$execution.customData') {
|
||||
return customDataOptions();
|
||||
} else if (base === '$workflow') {
|
||||
return workflowOptions();
|
||||
} else if (base === '$input') {
|
||||
return inputOptions(base);
|
||||
} else if (base === '$prevNode') {
|
||||
return prevNodeOptions();
|
||||
} else if (/^\$\(['"][\S\s]+['"]\)$/.test(base)) {
|
||||
return nodeRefOptions(base);
|
||||
} else if (base === '$response') {
|
||||
return responseOptions();
|
||||
} else if (isItem(input)) {
|
||||
return itemOptions();
|
||||
} else if (isBinary(input)) {
|
||||
return binaryOptions();
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
const objectOptions = (input: AutocompleteInput<IDataObject>): Completion[] => {
|
||||
const { base, resolved, transformLabel = (label) => label } = input;
|
||||
const rank = setRank(['item', 'all', 'first', 'last']);
|
||||
const SKIP = new Set(['__ob__', 'pairedItem']);
|
||||
|
||||
if (isSplitInBatchesAbsent()) SKIP.add('context');
|
||||
|
||||
const name = /^\$\(.*\)$/.test(base) ? '$()' : base;
|
||||
|
||||
if (['$input', '$()'].includes(name) && hasNoParams(base)) SKIP.add('params');
|
||||
|
||||
let rawKeys = Object.keys(resolved);
|
||||
|
||||
if (name === '$()') {
|
||||
rawKeys = Reflect.ownKeys(resolved) as string[];
|
||||
}
|
||||
|
||||
if (base === 'Math') {
|
||||
const descriptors = Object.getOwnPropertyDescriptors(Math);
|
||||
rawKeys = Object.keys(descriptors).sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
const localKeys = rank(rawKeys)
|
||||
const customOptions = customObjectOptions(input);
|
||||
if (customOptions.length > 0) {
|
||||
// Only return completions that are present in the resolved data
|
||||
return customOptions.filter((option) => option.label in resolved);
|
||||
}
|
||||
|
||||
const localKeys = rawKeys
|
||||
.filter((key) => !SKIP.has(key) && !isPseudoParam(key))
|
||||
.map((key) => {
|
||||
ensureKeyCanBeResolved(resolved, key);
|
||||
|
@ -330,28 +368,26 @@ const objectOptions = (input: AutocompleteInput<IDataObject>): Completion[] => {
|
|||
const resolvedProp = resolved[key];
|
||||
|
||||
const isFunction = typeof resolvedProp === 'function';
|
||||
const hasArgs = isFunction && resolvedProp.length > 0 && name !== '$()';
|
||||
const hasArgs = isFunction && resolvedProp.length > 0;
|
||||
|
||||
const option: Completion = {
|
||||
label: isFunction ? key + '()' : key,
|
||||
section: getObjectPropertySection({ name, key, isFunction }),
|
||||
section: isFunction ? METHODS_SECTION : FIELDS_SECTION,
|
||||
apply: needsBracketAccess
|
||||
? applyBracketAccessCompletion
|
||||
: applyCompletion({
|
||||
hasArgs,
|
||||
transformLabel,
|
||||
}),
|
||||
detail: getDetail(name, resolvedProp),
|
||||
detail: getDetail(base, resolvedProp),
|
||||
};
|
||||
|
||||
const infoKey = [name, key].join('.');
|
||||
const infoName = needsBracketAccess ? applyBracketAccess(key) : key;
|
||||
option.info = createCompletionOption({
|
||||
name: infoName,
|
||||
doc: {
|
||||
name: infoName,
|
||||
returnType: isFunction ? 'any' : getType(resolvedProp),
|
||||
description: i18n.proxyVars[infoKey],
|
||||
},
|
||||
isFunction,
|
||||
transformLabel,
|
||||
|
@ -366,6 +402,7 @@ const objectOptions = (input: AutocompleteInput<IDataObject>): Completion[] => {
|
|||
/json('])$/.test(base) ||
|
||||
base === '$execution' ||
|
||||
base.endsWith('params') ||
|
||||
base.endsWith('binary') ||
|
||||
base === 'Math';
|
||||
|
||||
if (skipObjectExtensions) {
|
||||
|
@ -386,23 +423,6 @@ const objectOptions = (input: AutocompleteInput<IDataObject>): Completion[] => {
|
|||
});
|
||||
};
|
||||
|
||||
const getObjectPropertySection = ({
|
||||
name,
|
||||
key,
|
||||
isFunction,
|
||||
}: {
|
||||
name: string;
|
||||
key: string;
|
||||
isFunction: boolean;
|
||||
}): CompletionSection => {
|
||||
if (name === '$input' || name === '$()') {
|
||||
if (key === 'item') return RECOMMENDED_SECTION;
|
||||
return OTHER_SECTION;
|
||||
}
|
||||
|
||||
return isFunction ? METHODS_SECTION : FIELDS_SECTION;
|
||||
};
|
||||
|
||||
const applySections = ({
|
||||
options,
|
||||
sections,
|
||||
|
@ -685,6 +705,420 @@ export const variablesOptions = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export const responseOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'statusCode',
|
||||
returnType: 'number',
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$response.statusCode'),
|
||||
},
|
||||
{
|
||||
name: 'statusMessage',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$response.statusMessage'),
|
||||
},
|
||||
{
|
||||
name: 'headers',
|
||||
returnType: 'Object',
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$response.headers'),
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
returnType: 'Object',
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$response.body'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const executionOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'id',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.id'),
|
||||
},
|
||||
{
|
||||
name: 'mode',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.mode'),
|
||||
},
|
||||
|
||||
{
|
||||
name: 'resumeUrl',
|
||||
returnType: 'string',
|
||||
docURL: 'https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.resumeUrl'),
|
||||
},
|
||||
{
|
||||
name: 'resumeFormUrl',
|
||||
returnType: 'string',
|
||||
docURL: 'https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.resumeFormUrl'),
|
||||
},
|
||||
{
|
||||
name: 'customData',
|
||||
returnType: 'CustomData',
|
||||
docURL: 'https://docs.n8n.io/workflows/executions/custom-executions-data/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const customDataOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'get',
|
||||
returnType: 'any',
|
||||
docURL: 'https://docs.n8n.io/workflows/executions/custom-executions-data/',
|
||||
args: [
|
||||
{
|
||||
name: 'key',
|
||||
description: 'The key (identifier) under which the data is stored',
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData.get'),
|
||||
examples: [
|
||||
{
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.$execution.customData.get.examples.1',
|
||||
),
|
||||
example: '$execution.customData.get("user_email")',
|
||||
evaluated: '"me@example.com"',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'set',
|
||||
returnType: 'void',
|
||||
args: [
|
||||
{
|
||||
name: 'key',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData.set.args.key'),
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'value',
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.$execution.customData.set.args.value',
|
||||
),
|
||||
type: 'any',
|
||||
},
|
||||
],
|
||||
docURL: 'https://docs.n8n.io/workflows/executions/custom-executions-data/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData.set'),
|
||||
examples: [
|
||||
{
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.$execution.customData.set.examples.1',
|
||||
),
|
||||
example: '$execution.customData.set("user_email", "me@example.com")',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'getAll',
|
||||
returnType: 'object',
|
||||
docURL: 'https://docs.n8n.io/workflows/executions/custom-executions-data/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData.getAll'),
|
||||
examples: [
|
||||
{
|
||||
example: '$execution.customData.getAll()',
|
||||
evaluated: '{ user_email: "me@example.com", id: 1234 }',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'setAll',
|
||||
returnType: 'void',
|
||||
args: [
|
||||
{
|
||||
name: 'obj',
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.$execution.customData.setAll.args.obj',
|
||||
),
|
||||
type: 'object',
|
||||
},
|
||||
],
|
||||
docURL: 'https://docs.n8n.io/workflows/executions/custom-executions-data/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$execution.customData.setAll'),
|
||||
examples: [
|
||||
{ example: '$execution.customData.setAll({ user_email: "me@example.com", id: 1234 })' },
|
||||
],
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc, isFunction: true }));
|
||||
};
|
||||
|
||||
export const nodeRefOptions = (base: string) => {
|
||||
const itemArgs = [
|
||||
{
|
||||
name: 'branchIndex',
|
||||
optional: true,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.args.branchIndex'),
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'runIndex',
|
||||
optional: true,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.args.runIndex'),
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
];
|
||||
|
||||
const options: Array<{ doc: DocMetadata; isFunction?: boolean }> = [
|
||||
{
|
||||
doc: {
|
||||
name: 'item',
|
||||
returnType: 'Item',
|
||||
docURL: 'https://docs.n8n.io/data/data-mapping/data-item-linking/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.item'),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'isExecuted',
|
||||
returnType: 'boolean',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.isExecuted'),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'params',
|
||||
returnType: 'NodeParams',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.params'),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'itemMatching',
|
||||
returnType: 'Item',
|
||||
args: [
|
||||
{
|
||||
name: 'currentItemIndex',
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.selector.itemMatching.args.currentItemIndex',
|
||||
),
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
docURL: 'https://docs.n8n.io/data/data-mapping/data-item-linking/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.itemMatching'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'first',
|
||||
returnType: 'Item',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.first'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'last',
|
||||
returnType: 'Item',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.last'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'all',
|
||||
returnType: 'Item[]',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.all'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
];
|
||||
|
||||
return applySections({
|
||||
options: options
|
||||
.filter((option) => !(option.doc.name === 'params' && hasNoParams(base)))
|
||||
.map(({ doc, isFunction }) => createCompletionOption({ name: doc.name, doc, isFunction })),
|
||||
sections: {},
|
||||
recommended: ['item'],
|
||||
});
|
||||
};
|
||||
|
||||
export const inputOptions = (base: string) => {
|
||||
const itemArgs = [
|
||||
{
|
||||
name: 'branchIndex',
|
||||
optional: true,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.args.branchIndex'),
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'runIndex',
|
||||
optional: true,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.args.runIndex'),
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
];
|
||||
|
||||
const options: Array<{ doc: DocMetadata; isFunction?: boolean }> = [
|
||||
{
|
||||
doc: {
|
||||
name: 'item',
|
||||
returnType: 'Item',
|
||||
docURL: 'https://docs.n8n.io/data/data-mapping/data-item-linking/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.item'),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'params',
|
||||
returnType: 'NodeParams',
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.params'),
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'first',
|
||||
returnType: 'Item',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.first'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'last',
|
||||
returnType: 'Item',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.last'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
{
|
||||
doc: {
|
||||
name: 'all',
|
||||
returnType: 'Item[]',
|
||||
args: itemArgs,
|
||||
description: i18n.baseText('codeNodeEditor.completer.selector.all'),
|
||||
},
|
||||
isFunction: true,
|
||||
},
|
||||
];
|
||||
|
||||
return applySections({
|
||||
options: options
|
||||
.filter((option) => !(option.doc.name === 'params' && hasNoParams(base)))
|
||||
.map(({ doc, isFunction }) => createCompletionOption({ name: doc.name, doc, isFunction })),
|
||||
recommended: ['item'],
|
||||
sections: {},
|
||||
});
|
||||
};
|
||||
|
||||
export const prevNodeOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'name',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$prevNode.name'),
|
||||
},
|
||||
{
|
||||
name: 'outputIndex',
|
||||
returnType: 'number',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$prevNode.outputIndex'),
|
||||
},
|
||||
{
|
||||
name: 'runIndex',
|
||||
returnType: 'number',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$prevNode.runIndex'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const itemOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'json',
|
||||
returnType: 'object',
|
||||
docURL: 'https://docs.n8n.io/data/data-structure/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.item.json'),
|
||||
},
|
||||
{
|
||||
name: 'binary',
|
||||
returnType: 'object',
|
||||
docURL: 'https://docs.n8n.io/data/data-structure/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.item.binary'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const binaryOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'id',
|
||||
returnType: 'String',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.id'),
|
||||
},
|
||||
{
|
||||
name: 'fileExtension',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.fileExtension'),
|
||||
},
|
||||
{
|
||||
name: 'fileName',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.fileName'),
|
||||
},
|
||||
{
|
||||
name: 'fileSize',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.fileSize'),
|
||||
},
|
||||
{
|
||||
name: 'fileType',
|
||||
returnType: 'String',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.fileType'),
|
||||
},
|
||||
{
|
||||
name: 'mimeType',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.mimeType'),
|
||||
},
|
||||
{
|
||||
name: 'directory',
|
||||
returnType: 'String',
|
||||
description: i18n.baseText('codeNodeEditor.completer.binary.directory'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const workflowOptions = () => {
|
||||
return [
|
||||
{
|
||||
name: 'id',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$workflow.id'),
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
returnType: 'string',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$workflow.name'),
|
||||
},
|
||||
{
|
||||
name: 'active',
|
||||
returnType: 'boolean',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$workflow.active'),
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc }));
|
||||
};
|
||||
|
||||
export const secretOptions = (base: string) => {
|
||||
const externalSecretsStore = useExternalSecretsStore();
|
||||
let resolved: Resolved;
|
||||
|
@ -841,18 +1275,89 @@ const createLuxonAutocompleteOption = ({
|
|||
* Methods defined on the global `Object`.
|
||||
*/
|
||||
export const objectGlobalOptions = () => {
|
||||
return ['assign', 'entries', 'keys', 'values'].map((key) => {
|
||||
const option: Completion = {
|
||||
label: key + '()',
|
||||
type: 'function',
|
||||
};
|
||||
|
||||
const info = i18n.globalObject[key];
|
||||
|
||||
if (info) option.info = info;
|
||||
|
||||
return option;
|
||||
});
|
||||
return [
|
||||
{
|
||||
name: 'assign',
|
||||
description: i18n.baseText('codeNodeEditor.completer.globalObject.assign'),
|
||||
args: [
|
||||
{
|
||||
name: 'target',
|
||||
type: 'object',
|
||||
},
|
||||
{
|
||||
name: 'sources',
|
||||
variadic: true,
|
||||
type: 'object',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: "Object.assign(\n {},\n { id: 1, name: 'Apple' },\n { name: 'Banana' }\n);",
|
||||
evaluated: "{ id: 1, name: 'Banana' }",
|
||||
},
|
||||
],
|
||||
returnType: 'object',
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign',
|
||||
},
|
||||
{
|
||||
name: 'entries',
|
||||
returnType: 'Array<[string, any]>',
|
||||
args: [
|
||||
{
|
||||
name: 'obj',
|
||||
type: 'object',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: "Object.entries({ id: 1, name: 'Apple' })",
|
||||
evaluated: "[['id', 1], ['name', 'Apple']]",
|
||||
},
|
||||
],
|
||||
description: i18n.baseText('codeNodeEditor.completer.globalObject.entries'),
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries',
|
||||
},
|
||||
{
|
||||
name: 'keys',
|
||||
args: [
|
||||
{
|
||||
name: 'obj',
|
||||
type: 'object',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: "Object.keys({ id: 1, name: 'Apple' })",
|
||||
evaluated: "['id', 'name']",
|
||||
},
|
||||
],
|
||||
returnType: 'string[]',
|
||||
description: i18n.baseText('codeNodeEditor.completer.globalObject.keys'),
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys',
|
||||
},
|
||||
{
|
||||
name: 'values',
|
||||
args: [
|
||||
{
|
||||
name: 'obj',
|
||||
type: 'object',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
{
|
||||
example: "Object.values({ id: 1, name: 'Apple' })",
|
||||
evaluated: "[1, 'Apple']",
|
||||
},
|
||||
],
|
||||
description: i18n.baseText('codeNodeEditor.completer.globalObject.values'),
|
||||
returnType: 'Array',
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values',
|
||||
},
|
||||
].map((doc) => createCompletionOption({ name: doc.name, doc, isFunction: true }));
|
||||
};
|
||||
|
||||
const regexes = {
|
||||
|
|
|
@ -60,7 +60,8 @@ export function dollarOptions(): Completion[] {
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$pageCount',
|
||||
returnType: 'number',
|
||||
description: i18n.rootVars.$pageCount,
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$pageCount'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -68,8 +69,9 @@ export function dollarOptions(): Completion[] {
|
|||
section: RECOMMENDED_SECTION,
|
||||
info: createInfoBoxRenderer({
|
||||
name: '$response',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$response,
|
||||
returnType: 'HTTPResponse',
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$response'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
@ -78,7 +80,8 @@ export function dollarOptions(): Completion[] {
|
|||
info: createInfoBoxRenderer({
|
||||
name: '$request',
|
||||
returnType: 'object',
|
||||
description: i18n.rootVars.$request,
|
||||
docURL: 'https://docs.n8n.io/code/builtin/http-node-variables/',
|
||||
description: i18n.baseText('codeNodeEditor.completer.$request'),
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
|
|
@ -960,13 +960,13 @@ export const luxonInstanceDocs: Required<NativeDoc> = {
|
|||
returnType: 'DateTime',
|
||||
args: [
|
||||
{
|
||||
name: 'zone',
|
||||
name: 'offset',
|
||||
optional: true,
|
||||
description: i18n.baseText(
|
||||
'codeNodeEditor.completer.luxon.instanceMethods.toUTC.args.zone',
|
||||
'codeNodeEditor.completer.luxon.instanceMethods.toUTC.args.offset',
|
||||
),
|
||||
default: '"local"',
|
||||
type: 'string',
|
||||
default: '0',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'options',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { i18n } from '@/plugins/i18n';
|
||||
import type { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
||||
import { prefixMatch } from './utils';
|
||||
import { createInfoBoxRenderer } from './infoBoxRenderer';
|
||||
|
||||
/**
|
||||
* Completions offered at the initial position for any char other than `$`.
|
||||
|
@ -23,16 +24,32 @@ export function nonDollarCompletions(context: CompletionContext): CompletionResu
|
|||
const nonDollarOptions = [
|
||||
{
|
||||
label: 'DateTime',
|
||||
type: 'keyword',
|
||||
info: i18n.rootVars.DateTime,
|
||||
info: createInfoBoxRenderer({
|
||||
name: 'DateTime',
|
||||
returnType: 'DateTimeGlobal',
|
||||
description: i18n.baseText('codeNodeEditor.completer.dateTime'),
|
||||
docURL: 'https://moment.github.io/luxon/api-docs/index.html#datetime',
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Math',
|
||||
type: 'keyword',
|
||||
info: createInfoBoxRenderer({
|
||||
name: 'Math',
|
||||
returnType: 'MathGlobal',
|
||||
description: i18n.baseText('codeNodeEditor.completer.math'),
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math',
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: 'Object',
|
||||
type: 'keyword',
|
||||
info: createInfoBoxRenderer({
|
||||
name: 'Object',
|
||||
returnType: 'ObjectGlobal',
|
||||
description: i18n.baseText('codeNodeEditor.completer.globalObject'),
|
||||
docURL:
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -61,21 +61,6 @@ export function longestCommonPrefix(...strings: string[]) {
|
|||
export const prefixMatch = (first: string, second: string) =>
|
||||
first.startsWith(second) && first !== second;
|
||||
|
||||
/**
|
||||
* Make a function to bring selected elements to the start of an array, in order.
|
||||
*/
|
||||
export const setRank = (selected: string[]) => (full: string[]) => {
|
||||
const fullCopy = [...full];
|
||||
|
||||
[...selected].reverse().forEach((s) => {
|
||||
const index = fullCopy.indexOf(s);
|
||||
|
||||
if (index !== -1) fullCopy.unshift(fullCopy.splice(index, 1)[0]);
|
||||
});
|
||||
|
||||
return fullCopy;
|
||||
};
|
||||
|
||||
export const isPseudoParam = (candidate: string) => {
|
||||
const PSEUDO_PARAMS = ['notice']; // user input disallowed
|
||||
|
||||
|
|
|
@ -357,67 +357,6 @@ export class I18nClass {
|
|||
});
|
||||
}
|
||||
|
||||
rootVars = {
|
||||
$binary: this.baseText('codeNodeEditor.completer.binary'),
|
||||
$execution: this.baseText('codeNodeEditor.completer.$execution'),
|
||||
$ifEmpty: this.baseText('codeNodeEditor.completer.$ifEmpty'),
|
||||
$input: this.baseText('codeNodeEditor.completer.$input'),
|
||||
$jmespath: this.baseText('codeNodeEditor.completer.$jmespath'),
|
||||
$json: this.baseText('codeNodeEditor.completer.json'),
|
||||
$itemIndex: this.baseText('codeNodeEditor.completer.$itemIndex'),
|
||||
$now: this.baseText('codeNodeEditor.completer.$now'),
|
||||
$parameter: this.baseText('codeNodeEditor.completer.$parameter'),
|
||||
$prevNode: this.baseText('codeNodeEditor.completer.$prevNode'),
|
||||
$if: this.baseText('codeNodeEditor.completer.$if'),
|
||||
$max: this.baseText('codeNodeEditor.completer.$max'),
|
||||
$min: this.baseText('codeNodeEditor.completer.$min'),
|
||||
$runIndex: this.baseText('codeNodeEditor.completer.$runIndex'),
|
||||
$today: this.baseText('codeNodeEditor.completer.$today'),
|
||||
$vars: this.baseText('codeNodeEditor.completer.$vars'),
|
||||
$workflow: this.baseText('codeNodeEditor.completer.$workflow'),
|
||||
DateTime: this.baseText('codeNodeEditor.completer.dateTime'),
|
||||
$request: this.baseText('codeNodeEditor.completer.$request'),
|
||||
$response: this.baseText('codeNodeEditor.completer.$response'),
|
||||
$pageCount: this.baseText('codeNodeEditor.completer.$pageCount'),
|
||||
$nodeVersion: this.baseText('codeNodeEditor.completer.$nodeVersion'),
|
||||
} as const satisfies Record<string, string | undefined>;
|
||||
|
||||
proxyVars: Record<string, string | undefined> = {
|
||||
'$input.all': this.baseText('codeNodeEditor.completer.$input.all'),
|
||||
'$input.first': this.baseText('codeNodeEditor.completer.$input.first'),
|
||||
'$input.item': this.baseText('codeNodeEditor.completer.$input.item'),
|
||||
'$input.last': this.baseText('codeNodeEditor.completer.$input.last'),
|
||||
|
||||
'$().all': this.baseText('codeNodeEditor.completer.selector.all'),
|
||||
'$().context': this.baseText('codeNodeEditor.completer.selector.context'),
|
||||
'$().first': this.baseText('codeNodeEditor.completer.selector.first'),
|
||||
'$().item': this.baseText('codeNodeEditor.completer.selector.item'),
|
||||
'$().itemMatching': this.baseText('codeNodeEditor.completer.selector.itemMatching'),
|
||||
'$().last': this.baseText('codeNodeEditor.completer.selector.last'),
|
||||
'$().params': this.baseText('codeNodeEditor.completer.selector.params'),
|
||||
'$().isExecuted': this.baseText('codeNodeEditor.completer.selector.isExecuted'),
|
||||
|
||||
'$prevNode.name': this.baseText('codeNodeEditor.completer.$prevNode.name'),
|
||||
'$prevNode.outputIndex': this.baseText('codeNodeEditor.completer.$prevNode.outputIndex'),
|
||||
'$prevNode.runIndex': this.baseText('codeNodeEditor.completer.$prevNode.runIndex'),
|
||||
|
||||
'$execution.id': this.baseText('codeNodeEditor.completer.$workflow.id'),
|
||||
'$execution.mode': this.baseText('codeNodeEditor.completer.$execution.mode'),
|
||||
'$execution.resumeUrl': this.baseText('codeNodeEditor.completer.$execution.resumeUrl'),
|
||||
'$execution.resumeFormUrl': this.baseText('codeNodeEditor.completer.$execution.resumeFormUrl'),
|
||||
|
||||
'$workflow.active': this.baseText('codeNodeEditor.completer.$workflow.active'),
|
||||
'$workflow.id': this.baseText('codeNodeEditor.completer.$workflow.id'),
|
||||
'$workflow.name': this.baseText('codeNodeEditor.completer.$workflow.name'),
|
||||
};
|
||||
|
||||
globalObject: Record<string, string | undefined> = {
|
||||
assign: this.baseText('codeNodeEditor.completer.globalObject.assign'),
|
||||
entries: this.baseText('codeNodeEditor.completer.globalObject.entries'),
|
||||
keys: this.baseText('codeNodeEditor.completer.globalObject.keys'),
|
||||
values: this.baseText('codeNodeEditor.completer.globalObject.values'),
|
||||
};
|
||||
|
||||
autocompleteUIValues: Record<string, string | undefined> = {
|
||||
docLinkLabel: this.baseText('expressionEdit.learnMore'),
|
||||
};
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
"useJson": "Access the properties of an item under `.json`, e.g. `item.json`"
|
||||
},
|
||||
"completer": {
|
||||
"all": "Get all items",
|
||||
"first": "Get the first item",
|
||||
"last": "Get the last item",
|
||||
"itemMatching": "Get the item matching a specified input item. Pass the input item index"
|
||||
"all": "Returns an array of the node's output items",
|
||||
"first": "Returns the first item output by the node",
|
||||
"last": "Returns the last item output by the node",
|
||||
"itemMatching": "Returns the matching item, i.e. the one used to produce the item in the current node at the specified index."
|
||||
}
|
||||
},
|
||||
"name": "Name",
|
||||
|
@ -190,55 +190,91 @@
|
|||
"codeEdit.edit": "Edit",
|
||||
"codeNodeEditor.askAi": "✨ Ask AI",
|
||||
"codeNodeEditor.completer.$()": "Output data of the {nodeName} node",
|
||||
"codeNodeEditor.completer.$execution": "Information about the current execution",
|
||||
"codeNodeEditor.completer.$execution.id": "The ID of the current execution",
|
||||
"codeNodeEditor.completer.$execution.mode": "How the execution was triggered: 'test' or 'production'",
|
||||
"codeNodeEditor.completer.$execution.resumeUrl": "Used when using the 'wait' node to wait for a webhook. The webhook to call to resume execution",
|
||||
"codeNodeEditor.completer.$execution.resumeFormUrl": "Used when using the 'wait' node to wait for a form submission. The url of form submitting which will resume execution",
|
||||
"codeNodeEditor.completer.$execution.customData.set()": "Set custom data for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||
"codeNodeEditor.completer.$execution.customData.get()": "Get custom data set in the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||
"codeNodeEditor.completer.$execution.customData.setAll()": "Set multiple custom data key/value pairs with an object for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||
"codeNodeEditor.completer.$execution.customData.getAll()": "Get all custom data for the current execution. <a href=\"https://docs.n8n.io/workflows/executions/custom-executions-data/\" target=\"_blank\">Learn More</a>",
|
||||
"codeNodeEditor.completer.$ifEmpty": "Checks whether the first parameter is empty, and if so returns the second parameter. Otherwise returns the first parameter. The following count as empty: null/undefined values, empty strings, empty arrays, objects with no keys.",
|
||||
"codeNodeEditor.completer.$input": "This node’s input data",
|
||||
"codeNodeEditor.completer.$execution": "Retrieve or set metadata for the current execution",
|
||||
"codeNodeEditor.completer.$execution.id": "The ID of the current workflow execution",
|
||||
"codeNodeEditor.completer.$execution.mode": "Returns either <code>test</code> (meaning the execution was triggered by clicking a button in n8n) or <code>production</code> (meaning the execution was triggered automatically)",
|
||||
"codeNodeEditor.completer.$execution.resumeUrl": "The webhook URL to call to resume a workflow waiting at a 'Wait' node.",
|
||||
"codeNodeEditor.completer.$execution.resumeFormUrl": "The URL to access a form generated by the 'Wait' node.",
|
||||
"codeNodeEditor.completer.$execution.customData": "Set and get custom execution data (e.g. to filter executions by). You can also do this with the 'Execution Data' node.",
|
||||
"codeNodeEditor.completer.$execution.customData.set": "Stores custom execution data under the key specified. Use this to easily filter executions by this data.",
|
||||
"codeNodeEditor.completer.$execution.customData.set.args.key": "The key (identifier) under which the data is stored",
|
||||
"codeNodeEditor.completer.$execution.customData.set.args.value": "The data to store",
|
||||
"codeNodeEditor.completer.$execution.customData.set.examples.1": "Store the user's email, to easily retrieve all execs related to that user later",
|
||||
"codeNodeEditor.completer.$execution.customData.get": "Returns the custom execution data stored under the given key.",
|
||||
"codeNodeEditor.completer.$execution.customData.get.args.key": "The key (identifier) under which the data is stored",
|
||||
"codeNodeEditor.completer.$execution.customData.get.examples.1": "Get the user's email (which was previously stored)",
|
||||
"codeNodeEditor.completer.$execution.customData.setAll": "Sets multiple key-value pairs of custom data for the execution. Use this to easily filter executions by this data.",
|
||||
"codeNodeEditor.completer.$execution.customData.setAll.args.obj": "A JavaScript object containing key-value pairs of the data to set",
|
||||
"codeNodeEditor.completer.$execution.customData.getAll": "Returns all the key-value pairs of custom data that have been set in the current execution.",
|
||||
"codeNodeEditor.completer.$ifEmpty": "Returns the first parameter if it isn't empty, otherwise returns the second parameter. The following count as empty: <code>\"</code>, <code>[]</code>, <code>{'{}'}</code>, <code>null</code>, <code>undefined</code>",
|
||||
"codeNodeEditor.completer.$ifEmpty.args.value": "The value to return, provided it isn't empty",
|
||||
"codeNodeEditor.completer.$ifEmpty.args.valueIfEmpty": "What to return if <code>value</code> is empty",
|
||||
"codeNodeEditor.completer.$input": "The input data of the current node",
|
||||
"codeNodeEditor.completer.$input.all": "@:_reusableBaseText.codeNodeEditor.completer.all",
|
||||
"codeNodeEditor.completer.$input.first": "@:_reusableBaseText.codeNodeEditor.completer.first",
|
||||
"codeNodeEditor.completer.$input.item": "The item that generated the current one",
|
||||
"codeNodeEditor.completer.$input.itemMatching": "@:_reusableBaseText.codeNodeEditor.completer.itemMatching",
|
||||
"codeNodeEditor.completer.$input.last": "@:_reusableBaseText.codeNodeEditor.completer.last",
|
||||
"codeNodeEditor.completer.$itemIndex": "The position of the current item in the list of items",
|
||||
"codeNodeEditor.completer.$jmespath": "Evaluate a JMESPath expression",
|
||||
"codeNodeEditor.completer.$if": "Function that takes a condition and returns a value based on whether it's true or false.",
|
||||
"codeNodeEditor.completer.$max": "Returns the largest of the numbers given as input parameters, or -Infinity if there are no parameters.",
|
||||
"codeNodeEditor.completer.$min": "Returns the smallest of the numbers given as input parameters, or Infinity if there are no parameters.",
|
||||
"codeNodeEditor.completer.$now": "The current timestamp (as a Luxon object)",
|
||||
"codeNodeEditor.completer.$parameter": "The parameters of the current node",
|
||||
"codeNodeEditor.completer.$prevNode": "The node providing the input data for this run",
|
||||
"codeNodeEditor.completer.$prevNode.name": "The name of the node providing the input data for this run",
|
||||
"codeNodeEditor.completer.$prevNode.outputIndex": "The output connector of the node providing input data for this run",
|
||||
"codeNodeEditor.completer.$prevNode.runIndex": "The run of the node providing input data to the current one",
|
||||
"codeNodeEditor.completer.$runIndex": "The index of the current run of this node",
|
||||
"codeNodeEditor.completer.$today": "A timestamp representing the current day (at midnight, as a Luxon object)",
|
||||
"codeNodeEditor.completer.$nodeVersion": "The type version of the current node",
|
||||
"codeNodeEditor.completer.$vars": "The variables defined in your instance",
|
||||
"codeNodeEditor.completer.$itemIndex": "The position of the item currently being processed in the list of input items",
|
||||
"codeNodeEditor.completer.$jmespath": "Extracts data from an object (or array of objects) using a <a target=\"_blank\" href=\"https://docs.n8n.io/code/cookbook/jmespath/\">JMESPath</a> expression. Useful for querying complex, nested objects. Returns <code>undefined</code> if the expression is invalid.",
|
||||
"codeNodeEditor.completer.$jmespath.args.obj": "The Object or array of Objects to retrieve data from",
|
||||
"codeNodeEditor.completer.$jmespath.args.expression": "A <a target=\"_blank\" href=\"https://jmespath.org/examples.html\">JMESPath expression</a> defining the data to retrieve from the object",
|
||||
"codeNodeEditor.completer.$jmespath.examples.1": "Get all names, in an array",
|
||||
"codeNodeEditor.completer.$jmespath.examples.2": "Get the names and ages of everyone under 20",
|
||||
"codeNodeEditor.completer.$jmespath.examples.3": "Get the name of the first person under 20",
|
||||
"codeNodeEditor.completer.$jmespath.examples.4": "Get the names of all the guests in each reservation that require a double room",
|
||||
"codeNodeEditor.completer.$if": "Returns one of two values depending on the <code>condition</code>. Similar to the <code>?</code> operator in JavaScript.",
|
||||
"codeNodeEditor.completer.$if.args.condition": "The check to make. Should evaluate to either <code>true</code> or <code>false</code>",
|
||||
"codeNodeEditor.completer.$if.args.valueIfTrue": "The value to return if the condition is true",
|
||||
"codeNodeEditor.completer.$if.args.valueIfFalse": "The value to return if the condition is false",
|
||||
"codeNodeEditor.completer.$if.examples.1": "Return \"Good day\" if time is before 5pm, otherwise \"Good evening\"",
|
||||
"codeNodeEditor.completer.$if.examples.2": "$if() calls can be combined\nReturn \"Good morning\" if time is before 10am, \"Good day\" it's before 5pm, otherwise \"Good evening\"",
|
||||
"codeNodeEditor.completer.$max": "Returns the highest of the given numbers, or -Infinity if there are no parameters.",
|
||||
"codeNodeEditor.completer.$max.args.numbers": "The numbers to compare",
|
||||
"codeNodeEditor.completer.$min": "Returns the lowest of the given numbers, or Infinity if there are no parameters.",
|
||||
"codeNodeEditor.completer.$now": "A DateTime representing the current moment. \n\nUses the workflow's time zone (which can be changed in the workflow settings).",
|
||||
"codeNodeEditor.completer.$parameter": "The configuration settings of the current node. These are the parameters you fill out within the node's UI (e.g. its operation).",
|
||||
"codeNodeEditor.completer.$prevNode": "Information about the node that the current input came from. \n\nWhen in a 'Merge' node, always uses the first input connector.",
|
||||
"codeNodeEditor.completer.$prevNode.name": "The name of the node that the current input came from. \n\nAlways uses the current node's first input connector if there is more than one (e.g. in the 'Merge' node).",
|
||||
"codeNodeEditor.completer.$prevNode.outputIndex": "The index of the output connector that the current input came from. Use this when the previous node had multiple outputs (such as an 'If' or 'Switch' node). \n\nAlways uses the current node's first input connector if there is more than one (e.g. in the 'Merge' node).",
|
||||
"codeNodeEditor.completer.$prevNode.runIndex": "The run of the previous node that generated the current input. \n\nAlways uses the current node's first input connector if there is more than one (e.g. in the 'Merge' node). ",
|
||||
"codeNodeEditor.completer.$runIndex": "The index of the current run of the current node execution. Starts at 0.",
|
||||
"codeNodeEditor.completer.$nodeVersion": "The version of the current node (as displayed at the bottom of the nodes's settings pane)",
|
||||
"codeNodeEditor.completer.$today": "A DateTime representing midnight at the start of the current day. \n\nUses the instance's time zone (unless overridden in the workflow's settings).",
|
||||
"codeNodeEditor.completer.$vars": "The <a target=\"_blank\" href=\"https://docs.n8n.io/code/variables/\">variables</a> available to the workflow",
|
||||
"codeNodeEditor.completer.$vars.varName": "Variable set on this n8n instance. All variables evaluate to strings.",
|
||||
"codeNodeEditor.completer.$secrets": "The external secrets connected to your instance",
|
||||
"codeNodeEditor.completer.$secrets.provider": "External secrets providers connected to this n8n instance.",
|
||||
"codeNodeEditor.completer.$secrets.provider.varName": "External secrets connected to this n8n instance. All secrets evaluate to strings.",
|
||||
"codeNodeEditor.completer.$workflow": "Information about the workflow",
|
||||
"codeNodeEditor.completer.$workflow.active": "Whether the workflow is active or not (boolean)",
|
||||
"codeNodeEditor.completer.$workflow.id": "The ID of the workflow",
|
||||
"codeNodeEditor.completer.$workflow.name": "The name of the workflow",
|
||||
"codeNodeEditor.completer.$response": "The response object received by the HTTP node.",
|
||||
"codeNodeEditor.completer.$request": "The request object sent by the HTTP node.",
|
||||
"codeNodeEditor.completer.$pageCount": "Tracks how many pages the HTTP node has fetched.",
|
||||
"codeNodeEditor.completer.dateTime": "Luxon DateTime. Use this object to parse, format and manipulate dates and times",
|
||||
"codeNodeEditor.completer.binary": "The item's binary (file) data",
|
||||
"codeNodeEditor.completer.globalObject.assign": "Copy of the object containing all enumerable own properties",
|
||||
"codeNodeEditor.completer.$workflow": "Information about the current workflow",
|
||||
"codeNodeEditor.completer.$workflow.active": "Whether the workflow is active",
|
||||
"codeNodeEditor.completer.$workflow.id": "The workflow ID. Can also be found in the workflow's URL.",
|
||||
"codeNodeEditor.completer.$workflow.name": "The name of the workflow, as shown at the top of the editor",
|
||||
"codeNodeEditor.completer.$response": "The response returned by the last HTTP call. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.$response.headers": "The headers returned by the last HTTP call. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.$response.statusCode": "The HTTP status code returned by the last HTTP call. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.$response.statusMessage": "An optional message regarding the request status. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.$response.body": "The body of the response object from the last HTTP call. Only available in the 'HTTP Request' node",
|
||||
"codeNodeEditor.completer.$request": "The request object sent during the last run of the node. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.$pageCount": "The number of results pages the node has fetched. Only available in the 'HTTP Request' node.",
|
||||
"codeNodeEditor.completer.dateTime": "Luxon DateTime. Use this object to parse, format and manipulate dates and times.",
|
||||
"codeNodeEditor.completer.binary": "Returns any binary input data to the current node, for the current item. Shorthand for <code>$input.item.binary</code>.",
|
||||
"codeNodeEditor.completer.binary.mimeType": "A string representing the format of the file's contents, e.g. <code>image/jpeg</code>",
|
||||
"codeNodeEditor.completer.binary.fileSize": "A string representing the size of the file (e.g. <code>1 kB</code>)",
|
||||
"codeNodeEditor.completer.binary.fileName": "The name of the file, including extension",
|
||||
"codeNodeEditor.completer.binary.fileExtension": "The suffix attached to the filename (e.g. <code>txt</code>)",
|
||||
"codeNodeEditor.completer.binary.fileType": "A string representing the type of the file, e.g. <code>image</code>. Corresponds to the first part of the MIME type.",
|
||||
"codeNodeEditor.completer.binary.id": "The unique ID of the file. Used to identify the file when it is stored on disk or in a storage service such as S3.",
|
||||
"codeNodeEditor.completer.binary.directory": "The path to the directory that the file is stored in. Useful for distinguishing between files with the same name in different directories. Not set if n8n is configured to store files in its database.",
|
||||
"codeNodeEditor.completer.item.binary": "Returns any binary data the item contains.",
|
||||
"codeNodeEditor.completer.item.json": "Returns the JSON data the item contains.",
|
||||
"codeNodeEditor.completer.math": "Mathematical utility methods",
|
||||
"codeNodeEditor.completer.globalObject": "Methods to manipulate JavaScript Objects",
|
||||
"codeNodeEditor.completer.globalObject.assign": "Merge all enumerable object properties into a target object. Returns the modified target object.",
|
||||
"codeNodeEditor.completer.globalObject.entries": "The object's keys and values",
|
||||
"codeNodeEditor.completer.globalObject.keys": "The object's keys",
|
||||
"codeNodeEditor.completer.globalObject.values": "The object's values",
|
||||
"codeNodeEditor.completer.json": "The item's JSON data. When in doubt, use this",
|
||||
"codeNodeEditor.completer.json": "Returns the JSON input data to the current node, for the current item. Shorthand for <code>$input.item.json</code>.",
|
||||
"codeNodeEditor.completer.luxon.dateTimeStaticMethods.expandFormat": "Produce the the fully expanded format token for the locale Does NOT quote characters, so quoted tokens will not round trip correctly.",
|
||||
"codeNodeEditor.completer.luxon.dateTimeStaticMethods.fromFormat": "Create a DateTime from an input string and format string.",
|
||||
"codeNodeEditor.completer.luxon.dateTimeStaticMethods.fromFormatExplain": "Explain how a string would be parsed by fromFormat().",
|
||||
|
@ -347,8 +383,8 @@
|
|||
"codeNodeEditor.completer.luxon.instanceMethods.toSQLTime": "Returns a string representation of this DateTime appropriate for use in SQL Time.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toSeconds": "Returns a Unix timestamp in seconds (the number elapsed since 1st Jan 1970)",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toString": "Returns a string representation of the DateTime. Similar to <code>toISO()</code>. For more formatting options, see <code>format()</code> or <code>toLocaleString()</code>.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUTC": "Converts the DateTime to the given time zone. The DateTime still represents the same moment unless specified in the options. See also <code>toLocal()</code> and <code>toUTC()</code>.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUTC.args.zone": "A zone identifier, either in the format 'America/New_York', 'UTC+3', or the strings 'local' or 'utc'",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUTC": "Converts a DateTime to the UTC time zone. The DateTime still represents the same moment unless specified in the parameters. Use <code>setZone()</code> to convert to other zones.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUTC.args.offset": "An offset from UTC in minutes",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUTC.args.opts": "Options that affect the output. Possible properties:\n<code>keepCalendarTime</code> (boolean): Whether to keep the time the same and only change the offset. Defaults to false.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.toUnixInteger": "Returns the epoch seconds (as a whole number) of this DateTime.",
|
||||
"codeNodeEditor.completer.luxon.instanceMethods.until": "Return an Interval spanning between this DateTime and another DateTime.",
|
||||
|
@ -365,11 +401,14 @@
|
|||
"codeNodeEditor.completer.selector.all": "@:_reusableBaseText.codeNodeEditor.completer.all",
|
||||
"codeNodeEditor.completer.selector.context": "Extra data about the node",
|
||||
"codeNodeEditor.completer.selector.first": "@:_reusableBaseText.codeNodeEditor.completer.first",
|
||||
"codeNodeEditor.completer.selector.item": "The item that generated the current one",
|
||||
"codeNodeEditor.completer.selector.item": "Returns the matching item, i.e. the one used to produce the current item in the current node.",
|
||||
"codeNodeEditor.completer.selector.args.branchIndex": "The output branch of the node to use. Defaults to the first branch (index 0)",
|
||||
"codeNodeEditor.completer.selector.args.runIndex": "The run of the node to use. Defaults to the first run (index 0)",
|
||||
"codeNodeEditor.completer.selector.itemMatching": "@:_reusableBaseText.codeNodeEditor.completer.itemMatching",
|
||||
"codeNodeEditor.completer.selector.itemMatching.args.currentItemIndex": "The index of the item in the current node to be matched with.",
|
||||
"codeNodeEditor.completer.selector.last": "@:_reusableBaseText.codeNodeEditor.completer.last",
|
||||
"codeNodeEditor.completer.selector.params": "The parameters of the node",
|
||||
"codeNodeEditor.completer.selector.isExecuted": "Whether the node has executed",
|
||||
"codeNodeEditor.completer.selector.params": "The configuration settings of the given node. These are the parameters you fill out within the node's UI (e.g. its operation).",
|
||||
"codeNodeEditor.completer.selector.isExecuted": "Is <code>true</code> if the node has executed, <code>false</code> otherwise",
|
||||
"codeNodeEditor.completer.section.input": "Input",
|
||||
"codeNodeEditor.completer.section.prevNodes": "Earlier nodes",
|
||||
"codeNodeEditor.completer.section.metadata": "Metadata",
|
||||
|
@ -883,7 +922,7 @@
|
|||
"ndv.output.items": "{count} item | {count} items",
|
||||
"ndv.output.noOutputData.message": "n8n stops executing the workflow when a node has no output data. You can change this default behaviour via",
|
||||
"ndv.output.noOutputData.message.settings": "Settings",
|
||||
"ndv.output.noOutputData.message.settingsOption": "> “Always Output Data”.",
|
||||
"ndv.output.noOutputData.message.settingsOption": "> \"Always Output Data\".",
|
||||
"ndv.output.noOutputData.title": "No output data returned",
|
||||
"ndv.output.noOutputDataInBranch": "No output data in this branch",
|
||||
"ndv.output.of": " of ",
|
||||
|
@ -1087,17 +1126,17 @@
|
|||
"nodeErrorView.theErrorCauseIsTooLargeToBeDisplayed": "The error cause is too large to be displayed",
|
||||
"nodeErrorView.time": "Time",
|
||||
"nodeErrorView.inputPanel.previousNodeError.title": "Error running node '{nodeName}'",
|
||||
"nodeErrorView.description.pairedItemInvalidInfo": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/”>matching item</a>. This is because the node <strong>'{nodeCause}'</strong> returned incorrect matching information (for item {itemIndex} of run {runIndex}). <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code>.",
|
||||
"nodeErrorView.description.pairedItemNoInfo": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/”>matching item</a>. The node <strong>'{nodeCause}'</strong> didn't return enough information.",
|
||||
"nodeErrorView.description.pairedItemNoInfoCodeNode": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. You can either: <ul><li>Add the <a href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/\">missing information</a> to the node <strong>'{nodeCause}'</strong></li><li>Or use <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code></li></ul>",
|
||||
"nodeErrorView.description.pairedItemInvalidInfo": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. This is because the node <strong>'{nodeCause}'</strong> returned incorrect matching information (for item {itemIndex} of run {runIndex}). <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code>.",
|
||||
"nodeErrorView.description.pairedItemNoInfo": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. The node <strong>'{nodeCause}'</strong> didn't return enough information.",
|
||||
"nodeErrorView.description.pairedItemNoInfoCodeNode": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. You can either: <ul><li>Add the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/\">missing information</a> to the node <strong>'{nodeCause}'</strong></li><li>Or use <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code></li></ul>",
|
||||
"nodeErrorView.description.pairedItemNoConnection": "There is no connection back to the node <strong>'{nodeCause}'</strong>, but it's used in an expression here.<br/><br/>Please wire up the node (there can be other nodes in between).",
|
||||
"nodeErrorView.description.pairedItemNoConnectionCodeNode": "There is no connection back to the node <strong>'{nodeCause}'</strong>, but it's used in code here.<br/><br/>Please wire up the node (there can be other nodes in between).",
|
||||
"nodeErrorView.description.noNodeExecutionData": "An expression references the node <strong>'{nodeCause}'</strong>, but it hasn't been executed yet. Either change the expression, or re-wire your workflow to make sure that node executes first.",
|
||||
"nodeErrorView.description.nodeNotFound": "The node <strong>'{nodeCause}'</strong> doesn't exist, but it's used in an expression here.",
|
||||
"nodeErrorView.description.noInputConnection": "This node has no input data. Please make sure this node is connected to another node.",
|
||||
"nodeErrorView.description.pairedItemMultipleMatches": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/”>matching item</a>. (There are multiple possible matches) <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code> or <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/”>reference a different node</a>.",
|
||||
"nodeErrorView.description.pairedItemMultipleMatchesCodeNode": "The code here won't work because it uses <code>.item</code> and n8n can't figure out the <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/”>matching item</a>. (There are multiple possible matches) <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code> or <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/”>reference a different node</a>.",
|
||||
"nodeErrorView.description.pairedItemPinned": "The <a href=”https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/”>item-matching</a> data in that node may be stale. It is needed by an expression in this node that uses <code>.item</code>.",
|
||||
"nodeErrorView.description.pairedItemMultipleMatches": "An expression here won't work because it uses <code>.item</code> and n8n can't figure out the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. (There are multiple possible matches) <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code> or <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/\">reference a different node</a>.",
|
||||
"nodeErrorView.description.pairedItemMultipleMatchesCodeNode": "The code here won't work because it uses <code>.item</code> and n8n can't figure out the <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">matching item</a>. (There are multiple possible matches) <br/><br/>Try using <code>.first()</code>, <code>.last()</code> or <code>.all()[index]</code> instead of <code>.item</code> or <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-code-node/\">reference a different node</a>.",
|
||||
"nodeErrorView.description.pairedItemPinned": "The <a target=\"_blank\" href=\"https://docs.n8n.io/data/data-mapping/data-item-linking/item-linking-errors/\">item-matching</a> data in that node may be stale. It is needed by an expression in this node that uses <code>.item</code>.",
|
||||
"nodeHelpers.credentialsUnset": "Credentials for '{credentialType}' are not set.",
|
||||
"nodeSettings.alwaysOutputData.description": "If active, will output a single, empty item when the output would have been empty. Use to prevent the workflow finishing on this node.",
|
||||
"nodeSettings.alwaysOutputData.displayName": "Always Output Data",
|
||||
|
@ -1566,7 +1605,7 @@
|
|||
"settings.users.confirmDataHandlingAfterDeletion": "What should we do with their data?",
|
||||
"settings.users.confirmUserDeletion": "Are you sure you want to delete this invited user?",
|
||||
"settings.users.delete": "Delete",
|
||||
"settings.users.deleteConfirmationMessage": "Type “delete all data” to confirm",
|
||||
"settings.users.deleteConfirmationMessage": "Type \"delete all data\" to confirm",
|
||||
"settings.users.deleteConfirmationText": "delete all data",
|
||||
"settings.users.deleteUser": "Delete {user}",
|
||||
"settings.users.actions.delete": "Delete User",
|
||||
|
|
Loading…
Reference in a new issue