mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat: Improvements to pairedItem
This commit is contained in:
parent
2f4f2cfb86
commit
1348349748
|
@ -8,6 +8,7 @@ import {
|
|||
IDataObject,
|
||||
IDeferredPromise,
|
||||
IExecuteResponsePromiseData,
|
||||
IPinData,
|
||||
IRun,
|
||||
IRunData,
|
||||
IRunExecutionData,
|
||||
|
@ -15,7 +16,6 @@ import {
|
|||
ITelemetrySettings,
|
||||
ITelemetryTrackProperties,
|
||||
IWorkflowBase as IWorkflowBaseWorkflow,
|
||||
PinData,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
|
@ -689,7 +689,7 @@ export interface IWorkflowExecutionDataProcess {
|
|||
executionMode: WorkflowExecuteMode;
|
||||
executionData?: IRunExecutionData;
|
||||
runData?: IRunData;
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
retryOf?: number | string;
|
||||
sessionId?: string;
|
||||
startNodes?: string[];
|
||||
|
|
|
@ -70,11 +70,11 @@ import {
|
|||
INodeType,
|
||||
INodeTypeDescription,
|
||||
INodeTypeNameVersion,
|
||||
IPinData,
|
||||
ITelemetrySettings,
|
||||
IWorkflowBase,
|
||||
LoggerProxy,
|
||||
NodeHelpers,
|
||||
PinData,
|
||||
WebhookHttpMethod,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
|
@ -2836,7 +2836,7 @@ const TRIGGER_NODE_SUFFIXES = ['trigger', 'webhook'];
|
|||
const isTrigger = (str: string) =>
|
||||
TRIGGER_NODE_SUFFIXES.some((suffix) => str.toLowerCase().includes(suffix));
|
||||
|
||||
function findFirstPinnedTrigger(workflow: IWorkflowDb, pinData?: PinData) {
|
||||
function findFirstPinnedTrigger(workflow: IWorkflowDb, pinData?: IPinData) {
|
||||
if (!pinData) return;
|
||||
|
||||
const firstPinnedTriggerName = Object.keys(pinData).find(isTrigger);
|
||||
|
|
|
@ -230,6 +230,7 @@ export class WorkflowRunnerProcess {
|
|||
nodeTypes,
|
||||
staticData: this.data.workflowData.staticData,
|
||||
settings: this.data.workflowData.settings,
|
||||
pinData: this.data.pinData,
|
||||
});
|
||||
await checkPermissionsForExecution(this.workflow, userId);
|
||||
const additionalData = await WorkflowExecuteAdditionalData.getBase(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* eslint-disable import/no-cycle */
|
||||
import { Length } from 'class-validator';
|
||||
|
||||
import { IConnections, IDataObject, INode, IWorkflowSettings, PinData } from 'n8n-workflow';
|
||||
import { IConnections, IDataObject, INode, IPinData, IWorkflowSettings } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
BeforeUpdate,
|
||||
|
@ -122,7 +122,7 @@ export class WorkflowEntity implements IWorkflowDb {
|
|||
nullable: true,
|
||||
transformer: serializer,
|
||||
})
|
||||
pinData: PinData;
|
||||
pinData: IPinData;
|
||||
|
||||
@BeforeUpdate()
|
||||
setUpdateDate() {
|
||||
|
|
4
packages/cli/src/requests.d.ts
vendored
4
packages/cli/src/requests.d.ts
vendored
|
@ -6,9 +6,9 @@ import {
|
|||
ICredentialNodeAccess,
|
||||
INode,
|
||||
INodeCredentialTestRequest,
|
||||
IPinData,
|
||||
IRunData,
|
||||
IWorkflowSettings,
|
||||
PinData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { User } from './databases/entities/User';
|
||||
|
@ -72,7 +72,7 @@ export declare namespace WorkflowRequest {
|
|||
{
|
||||
workflowData: IWorkflowDb;
|
||||
runData: IRunData;
|
||||
pinData: PinData;
|
||||
pinData: IPinData;
|
||||
startNodes?: string[];
|
||||
destinationNode?: string;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as utils from './shared/utils';
|
|||
import * as testDb from './shared/testDb';
|
||||
import { WorkflowEntity } from '../../src/databases/entities/WorkflowEntity';
|
||||
import type { Role } from '../../src/databases/entities/Role';
|
||||
import { PinData } from 'n8n-workflow';
|
||||
import { IPinData } from 'n8n-workflow';
|
||||
|
||||
jest.mock('../../src/telemetry');
|
||||
|
||||
|
@ -44,7 +44,7 @@ test('POST /workflows should store pin data for node in workflow', async () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const { pinData } = response.body.data as { pinData: PinData };
|
||||
const { pinData } = response.body.data as { pinData: IPinData };
|
||||
|
||||
expect(pinData).toMatchObject({ Spotify: [{ myKey: 'myValue' }] });
|
||||
});
|
||||
|
@ -59,7 +59,7 @@ test('POST /workflows should set pin data to null if no pin data', async () => {
|
|||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const { pinData } = response.body.data as { pinData: PinData };
|
||||
const { pinData } = response.body.data as { pinData: IPinData };
|
||||
|
||||
expect(pinData).toBeNull();
|
||||
});
|
||||
|
@ -78,7 +78,7 @@ test('GET /workflows/:id should return pin data', async () => {
|
|||
|
||||
expect(workflowRetrievalResponse.statusCode).toBe(200);
|
||||
|
||||
const { pinData } = workflowRetrievalResponse.body.data as { pinData: PinData };
|
||||
const { pinData } = workflowRetrievalResponse.body.data as { pinData: IPinData };
|
||||
|
||||
expect(pinData).toMatchObject({ Spotify: [{ myKey: 'myValue' }] });
|
||||
});
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
INode,
|
||||
INodeConnections,
|
||||
INodeExecutionData,
|
||||
IPinData,
|
||||
IRun,
|
||||
IRunData,
|
||||
IRunExecutionData,
|
||||
|
@ -32,7 +33,6 @@ import {
|
|||
LoggerProxy as Logger,
|
||||
NodeApiError,
|
||||
NodeOperationError,
|
||||
PinData,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
WorkflowOperationError,
|
||||
|
@ -88,7 +88,7 @@ export class WorkflowExecute {
|
|||
workflow: Workflow,
|
||||
startNode?: INode,
|
||||
destinationNode?: string,
|
||||
pinData?: PinData,
|
||||
pinData?: IPinData,
|
||||
): PCancelable<IRun> {
|
||||
// Get the nodes to start workflow execution from
|
||||
startNode = startNode || workflow.getStartNode(destinationNode);
|
||||
|
@ -160,7 +160,7 @@ export class WorkflowExecute {
|
|||
runData: IRunData,
|
||||
startNodes: string[],
|
||||
destinationNode: string,
|
||||
pinData?: PinData,
|
||||
pinData?: IPinData,
|
||||
// @ts-ignore
|
||||
): PCancelable<IRun> {
|
||||
let incomingNodeConnections: INodeConnections | undefined;
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
INodePropertyOptions,
|
||||
INodeTypeDescription,
|
||||
INodeTypeNameVersion,
|
||||
IPinData,
|
||||
IRunExecutionData,
|
||||
IRun,
|
||||
IRunData,
|
||||
|
@ -21,15 +22,9 @@ import {
|
|||
ITelemetrySettings,
|
||||
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
||||
WorkflowExecuteMode,
|
||||
PinData,
|
||||
PublicInstalledPackage,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
COMMUNITY_PACKAGE_MANAGE_ACTIONS,
|
||||
} from './constants';
|
||||
|
||||
|
||||
export * from 'n8n-design-system/src/types';
|
||||
|
||||
declare module 'jsplumb' {
|
||||
|
@ -218,7 +213,7 @@ export interface IStartRunData {
|
|||
startNodes?: string[];
|
||||
destinationNode?: string;
|
||||
runData?: IRunData;
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
}
|
||||
|
||||
export interface IRunDataUi {
|
||||
|
@ -253,7 +248,7 @@ export interface IWorkflowData {
|
|||
connections: IConnections;
|
||||
settings?: IWorkflowSettings;
|
||||
tags?: string[];
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
}
|
||||
|
||||
export interface IWorkflowDataUpdate {
|
||||
|
@ -264,7 +259,7 @@ export interface IWorkflowDataUpdate {
|
|||
settings?: IWorkflowSettings;
|
||||
active?: boolean;
|
||||
tags?: ITag[] | string[]; // string[] when store or requested, ITag[] from API response
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
}
|
||||
|
||||
export interface IWorkflowTemplate {
|
||||
|
@ -287,7 +282,7 @@ export interface IWorkflowDb {
|
|||
connections: IConnections;
|
||||
settings?: IWorkflowSettings;
|
||||
tags?: ITag[] | string[]; // string[] when store or requested, ITag[] from API response
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
}
|
||||
|
||||
// Identical to cli.Interfaces.ts
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div>
|
||||
<div class="error-header">
|
||||
<div class="error-message">{{ $locale.baseText('nodeErrorView.error') + ': ' + getErrorMessage() }}</div>
|
||||
<div class="error-description" v-if="error.description">{{error.description}}</div>
|
||||
<div class="error-description" v-if="error.description">{{getErrorDescription()}}</div>
|
||||
</div>
|
||||
<details>
|
||||
<summary class="error-details__summary">
|
||||
|
@ -139,6 +139,14 @@ export default mixins(
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
getErrorDescription (): string {
|
||||
if (!this.error.context || !this.error.context.descriptionTemplate) {
|
||||
return this.error.description;
|
||||
}
|
||||
|
||||
const parameterName = this.parameterDisplayName(this.error.context.parameter);
|
||||
return this.error.context.descriptionTemplate.replace(/%%PARAMETER%%/g, parameterName);
|
||||
},
|
||||
getErrorMessage (): string {
|
||||
if (!this.error.context || !this.error.context.messageTemplate) {
|
||||
return this.error.message;
|
||||
|
|
|
@ -343,7 +343,6 @@ import {
|
|||
INodeTypeDescription,
|
||||
IRunData,
|
||||
IRunExecutionData,
|
||||
PinData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
|
|
|
@ -21,10 +21,10 @@ import {
|
|||
IContextObject,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
IPinData,
|
||||
IRunData,
|
||||
IRunExecutionData,
|
||||
IWorkflowDataProxyAdditionalKeys,
|
||||
PinData,
|
||||
Workflow,
|
||||
WorkflowDataProxy,
|
||||
} from 'n8n-workflow';
|
||||
|
@ -307,11 +307,11 @@ export default mixins(
|
|||
* Get the node's output using pinData
|
||||
*
|
||||
* @param {string} nodeName The name of the node to get the data of
|
||||
* @param {PinData[string]} pinData The node's pin data
|
||||
* @param {IPinData[string]} pinData The node's pin data
|
||||
* @param {string} filterText Filter text for parameters
|
||||
* @param {boolean} [useShort=false] Use short notation $json vs. $node[NodeName].json
|
||||
*/
|
||||
getNodePinDataOutput(nodeName: string, pinData: PinData[string], filterText: string, useShort = false): IVariableSelectorOption[] | null {
|
||||
getNodePinDataOutput(nodeName: string, pinData: IPinData[string], filterText: string, useShort = false): IVariableSelectorOption[] | null {
|
||||
const outputData = pinData.map((data) => ({ json: data } as INodeExecutionData))[0];
|
||||
|
||||
return this.getNodeOutput(nodeName, outputData, filterText, useShort);
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import Vue from 'vue';
|
||||
import { INodeUi } from "@/Interface";
|
||||
import {IDataObject, PinData} from "n8n-workflow";
|
||||
import {stringSizeInBytes} from "@/components/helpers";
|
||||
import {MAX_WORKFLOW_PINNED_DATA_SIZE, PIN_DATA_NODE_TYPES_DENYLIST} from "@/constants";
|
||||
import { INodeUi } from '@/Interface';
|
||||
import { IPinData } from 'n8n-workflow';
|
||||
import { stringSizeInBytes } from '@/components/helpers';
|
||||
import { MAX_WORKFLOW_PINNED_DATA_SIZE, PIN_DATA_NODE_TYPES_DENYLIST } from '@/constants';
|
||||
|
||||
interface PinDataContext {
|
||||
interface IPinDataContext {
|
||||
node: INodeUi;
|
||||
$showError(error: Error, title: string): void;
|
||||
}
|
||||
|
||||
export const pinData = (Vue as Vue.VueConstructor<Vue & PinDataContext>).extend({
|
||||
export const pinData = (Vue as Vue.VueConstructor<Vue & IPinDataContext>).extend({
|
||||
computed: {
|
||||
pinData (): PinData[string] | undefined {
|
||||
pinData (): IPinData[string] | undefined {
|
||||
return this.node ? this.$store.getters['pinDataByNodeName'](this.node!.name) : undefined;
|
||||
},
|
||||
hasPinData (): boolean {
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
INodeTypeData,
|
||||
INodeTypeDescription,
|
||||
INodeVersionedType,
|
||||
IPinData,
|
||||
IRunData,
|
||||
IRunExecutionData,
|
||||
IWorfklowIssues,
|
||||
|
@ -30,7 +31,6 @@ import {
|
|||
IExecuteData,
|
||||
INodeConnection,
|
||||
IWebhookDescription,
|
||||
PinData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
|
@ -330,11 +330,16 @@ export const workflowHelpers = mixins(
|
|||
|
||||
const workflowName = this.$store.getters.workflowName;
|
||||
|
||||
if (copyData === true) {
|
||||
return new Workflow({ id: workflowId, name: workflowName, nodes: JSON.parse(JSON.stringify(nodes)), connections: JSON.parse(JSON.stringify(connections)), active: false, nodeTypes, settings: this.$store.getters.workflowSettings});
|
||||
} else {
|
||||
return new Workflow({ id: workflowId, name: workflowName, nodes, connections, active: false, nodeTypes, settings: this.$store.getters.workflowSettings});
|
||||
}
|
||||
return new Workflow({
|
||||
id: workflowId,
|
||||
name: workflowName,
|
||||
nodes: copyData ? JSON.parse(JSON.stringify(nodes)) : nodes,
|
||||
connections: copyData? JSON.parse(JSON.stringify(connections)): connections,
|
||||
active: false,
|
||||
nodeTypes,
|
||||
settings: this.$store.getters.workflowSettings,
|
||||
pinData: this.$store.getters.pinData,
|
||||
});
|
||||
},
|
||||
|
||||
// Returns the currently loaded workflow as JSON.
|
||||
|
@ -526,7 +531,7 @@ export const workflowHelpers = mixins(
|
|||
}
|
||||
|
||||
parentNode.forEach((parentNodeName) => {
|
||||
const pinData: PinData[string] = this.$store.getters['pinDataByNodeName'](parentNodeName);
|
||||
const pinData: IPinData[string] = this.$store.getters['pinDataByNodeName'](parentNodeName);
|
||||
|
||||
if (pinData) {
|
||||
runExecutionData = {
|
||||
|
|
|
@ -13,10 +13,10 @@ import {
|
|||
INodeConnections,
|
||||
INodeIssueData,
|
||||
INodeTypeDescription,
|
||||
IPinData,
|
||||
IRunData,
|
||||
ITaskData,
|
||||
IWorkflowSettings,
|
||||
PinData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
|
@ -213,7 +213,7 @@ export const store = new Vuex.Store({
|
|||
},
|
||||
|
||||
// Pin data
|
||||
pinData(state, payload: { node: INodeUi, data: PinData[string] }) {
|
||||
pinData(state, payload: { node: INodeUi, data: IPinData[string] }) {
|
||||
if (state.workflow.pinData) {
|
||||
Vue.set(state.workflow.pinData, payload.node.name, payload.data);
|
||||
}
|
||||
|
@ -651,7 +651,7 @@ export const store = new Vuex.Store({
|
|||
Vue.set(state.workflow, 'settings', workflowSettings);
|
||||
},
|
||||
|
||||
setWorkflowPinData(state, pinData: PinData) {
|
||||
setWorkflowPinData(state, pinData: IPinData) {
|
||||
Vue.set(state.workflow, 'pinData', pinData);
|
||||
|
||||
dataPinningEventBus.$emit('pin-data', pinData);
|
||||
|
@ -905,7 +905,7 @@ export const store = new Vuex.Store({
|
|||
* Pin data
|
||||
*/
|
||||
|
||||
pinData: (state): PinData | undefined => {
|
||||
pinData: (state): IPinData | undefined => {
|
||||
return state.workflow.pinData;
|
||||
},
|
||||
pinDataByNodeName: (state) => (nodeName: string) => {
|
||||
|
|
|
@ -184,18 +184,18 @@ import {
|
|||
IDataObject,
|
||||
INode,
|
||||
INodeConnections,
|
||||
INodeCredentialsDetails,
|
||||
INodeIssues,
|
||||
INodeTypeDescription,
|
||||
INodeTypeNameVersion,
|
||||
NodeHelpers,
|
||||
Workflow,
|
||||
IPinData,
|
||||
IRun,
|
||||
ITaskData,
|
||||
INodeCredentialsDetails,
|
||||
TelemetryHelpers,
|
||||
ITelemetryTrackProperties,
|
||||
IWorkflowBase,
|
||||
PinData,
|
||||
NodeHelpers,
|
||||
TelemetryHelpers,
|
||||
Workflow,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ICredentialsResponse,
|
||||
|
@ -2963,7 +2963,7 @@ export default mixins(
|
|||
await this.importWorkflowData(workflowData);
|
||||
}
|
||||
},
|
||||
addPinDataConnections(pinData: PinData) {
|
||||
addPinDataConnections(pinData: IPinData) {
|
||||
Object.keys(pinData).forEach((nodeName) => {
|
||||
// @ts-ignore
|
||||
const connections = this.instance.getConnections({
|
||||
|
@ -2978,7 +2978,7 @@ export default mixins(
|
|||
});
|
||||
});
|
||||
},
|
||||
removePinDataConnections(pinData: PinData) {
|
||||
removePinDataConnections(pinData: IPinData) {
|
||||
Object.keys(pinData).forEach((nodeName) => {
|
||||
// @ts-ignore
|
||||
const connections = this.instance.getConnections({
|
||||
|
|
|
@ -10,6 +10,7 @@ export class ExpressionError extends ExecutionBaseError {
|
|||
options?: {
|
||||
causeDetailed?: string;
|
||||
description?: string;
|
||||
descriptionTemplate?: string;
|
||||
runIndex?: number;
|
||||
itemIndex?: number;
|
||||
messageTemplate?: string;
|
||||
|
@ -23,6 +24,10 @@ export class ExpressionError extends ExecutionBaseError {
|
|||
this.description = options.description;
|
||||
}
|
||||
|
||||
if (options?.descriptionTemplate !== undefined) {
|
||||
this.context.descriptionTemplate = options.descriptionTemplate;
|
||||
}
|
||||
|
||||
if (options?.causeDetailed !== undefined) {
|
||||
this.context.causeDetailed = options.causeDetailed;
|
||||
}
|
||||
|
|
|
@ -839,10 +839,9 @@ export interface INode {
|
|||
parameters: INodeParameters;
|
||||
credentials?: INodeCredentials;
|
||||
webhookId?: string;
|
||||
pinData?: IDataObject;
|
||||
}
|
||||
|
||||
export interface PinData {
|
||||
export interface IPinData {
|
||||
[nodeName: string]: IDataObject[];
|
||||
}
|
||||
|
||||
|
@ -1328,7 +1327,7 @@ export interface IRunExecutionData {
|
|||
resultData: {
|
||||
error?: ExecutionError;
|
||||
runData: IRunData;
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
lastNodeExecuted?: string;
|
||||
};
|
||||
executionData?: {
|
||||
|
@ -1402,7 +1401,7 @@ export interface IWorkflowBase {
|
|||
connections: IConnections;
|
||||
settings?: IWorkflowSettings;
|
||||
staticData?: IDataObject;
|
||||
pinData?: PinData;
|
||||
pinData?: IPinData;
|
||||
}
|
||||
|
||||
export interface IWorkflowCredentials {
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
INodes,
|
||||
INodeType,
|
||||
INodeTypes,
|
||||
IPinData,
|
||||
IPollFunctions,
|
||||
IRunExecutionData,
|
||||
ITaskDataConnections,
|
||||
|
@ -84,6 +85,8 @@ export class Workflow {
|
|||
// ids of registred webhooks of nodes
|
||||
staticData: IDataObject;
|
||||
|
||||
pinData?: IPinData;
|
||||
|
||||
// constructor(id: string | undefined, nodes: INode[], connections: IConnections, active: boolean, nodeTypes: INodeTypes, staticData?: IDataObject, settings?: IWorkflowSettings) {
|
||||
constructor(parameters: {
|
||||
id?: string;
|
||||
|
@ -94,10 +97,12 @@ export class Workflow {
|
|||
nodeTypes: INodeTypes;
|
||||
staticData?: IDataObject;
|
||||
settings?: IWorkflowSettings;
|
||||
pinData?: IPinData;
|
||||
}) {
|
||||
this.id = parameters.id;
|
||||
this.name = parameters.name;
|
||||
this.nodeTypes = parameters.nodeTypes;
|
||||
this.pinData = parameters.pinData;
|
||||
|
||||
// Save nodes in workflow as object to be able to get the
|
||||
// nodes easily by its name.
|
||||
|
@ -410,6 +415,17 @@ export class Workflow {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pinData of the node with the given name if it exists
|
||||
*
|
||||
* @param {string} nodeName Name of the node to return the pinData of
|
||||
* @returns {(IDataObject[] | undefined)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getPinDataOfNode(nodeName: string): IDataObject[] | undefined {
|
||||
return this.pinData ? this.pinData[nodeName] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames nodes in expressions
|
||||
*
|
||||
|
|
|
@ -532,11 +532,27 @@ export class WorkflowDataProxy {
|
|||
const createExpressionError = (
|
||||
message: string,
|
||||
context?: {
|
||||
messageTemplate?: string;
|
||||
description?: string;
|
||||
causeDetailed?: string;
|
||||
description?: string;
|
||||
descriptionTemplate?: string;
|
||||
messageTemplate?: string;
|
||||
},
|
||||
nodeName?: string,
|
||||
) => {
|
||||
if (nodeName) {
|
||||
const pinData = this.workflow.getPinDataOfNode(nodeName);
|
||||
|
||||
if (pinData) {
|
||||
if (!context) {
|
||||
context = {};
|
||||
}
|
||||
message = `‘${nodeName}‘ must be unpinned to execute`;
|
||||
context.description = `To fetch the data the expression needs, The node ‘${nodeName}’ needs to execute without being pinned. <a>Unpin it</a>`;
|
||||
context.description = `To fetch the data for the expression, you must unpin the node '${nodeName}' and execute the workflow again.`;
|
||||
context.descriptionTemplate = `To fetch the data for the expression under '%%PARAMETER%%', you must unpin the node '${nodeName}' and execute the workflow again.`;
|
||||
}
|
||||
}
|
||||
|
||||
return new ExpressionError(message, {
|
||||
runIndex: that.runIndex,
|
||||
itemIndex: that.itemIndex,
|
||||
|
@ -560,6 +576,7 @@ export class WorkflowDataProxy {
|
|||
};
|
||||
}
|
||||
|
||||
let nodeBeforeLast: string | undefined;
|
||||
while (sourceData !== null && destinationNodeName !== sourceData.previousNode) {
|
||||
taskData =
|
||||
that.runExecutionData!.resultData.runData[sourceData.previousNode][
|
||||
|
@ -569,20 +586,29 @@ export class WorkflowDataProxy {
|
|||
const previousNodeOutput = sourceData.previousNodeOutput || 0;
|
||||
if (previousNodeOutput >= taskData.data!.main.length) {
|
||||
// `Could not resolve as the defined node-output is not valid on node '${sourceData.previousNode}'.`
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’',
|
||||
description: `Apologies, this is an internal error. See details for more information`,
|
||||
causeDetailed: 'Referencing a non-existent output on a node, problem with source data',
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: 'Can’t get data for expression under ‘%%PARAMETER%%’',
|
||||
description: `Apologies, this is an internal error. See details for more information`,
|
||||
causeDetailed:
|
||||
'Referencing a non-existent output on a node, problem with source data',
|
||||
},
|
||||
nodeBeforeLast,
|
||||
);
|
||||
}
|
||||
|
||||
if (pairedItem.item >= taskData.data!.main[previousNodeOutput]!.length) {
|
||||
// `Could not resolve as the defined item index is not valid on node '${sourceData.previousNode}'.
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to an item which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to an item which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
|
||||
},
|
||||
nodeBeforeLast,
|
||||
);
|
||||
}
|
||||
|
||||
const itemPreviousNode: INodeExecutionData =
|
||||
|
@ -590,11 +616,15 @@ export class WorkflowDataProxy {
|
|||
|
||||
if (itemPreviousNode.pairedItem === undefined) {
|
||||
// `Could not resolve, as pairedItem data is missing on node '${sourceData.previousNode}'.`,
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘${sourceData.previousNode}’`,
|
||||
causeDetailed: `Missing pairedItem data (node ‘${sourceData.previousNode}’ did probably not supply it)`,
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `To fetch the data from other nodes that this expression needs, more information is needed from the node ‘${sourceData.previousNode}’`,
|
||||
causeDetailed: `Missing pairedItem data (node ‘${sourceData.previousNode}’ did probably not supply it)`,
|
||||
},
|
||||
sourceData.previousNode,
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(itemPreviousNode.pairedItem)) {
|
||||
|
@ -647,22 +677,31 @@ export class WorkflowDataProxy {
|
|||
});
|
||||
}
|
||||
// `Could not resolve pairedItem as the defined node input '${itemInput}' does not exist on node '${sourceData.previousNode}'.`
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to a node input which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to a node input ‘${itemInput}‘ which does not exist on node ‘${sourceData.previousNode}‘ (node did probably supply a wrong one)`,
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to a node input which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to a node input ‘${itemInput}‘ which does not exist on node ‘${sourceData.previousNode}‘ (node did probably supply a wrong one)`,
|
||||
},
|
||||
nodeBeforeLast,
|
||||
);
|
||||
}
|
||||
|
||||
nodeBeforeLast = sourceData.previousNode;
|
||||
sourceData = taskData.source[pairedItem.input || 0] || null;
|
||||
}
|
||||
|
||||
if (sourceData === null) {
|
||||
// 'Could not resolve, proably no pairedItem exists.'
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Could not resolve, proably no pairedItem exists`,
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Could not resolve, proably no pairedItem exists`,
|
||||
},
|
||||
nodeBeforeLast,
|
||||
);
|
||||
}
|
||||
|
||||
taskData =
|
||||
|
@ -682,11 +721,15 @@ export class WorkflowDataProxy {
|
|||
|
||||
if (pairedItem.item >= taskData.data!.main[previousNodeOutput]!.length) {
|
||||
// `Could not resolve pairedItem as the item with the index '${pairedItem.item}' does not exist on node '${sourceData.previousNode}'.`
|
||||
throw createExpressionError('Can’t get data for expression', {
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to an item which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
|
||||
});
|
||||
throw createExpressionError(
|
||||
'Can’t get data for expression',
|
||||
{
|
||||
messageTemplate: `Can’t get data for expression under ‘%%PARAMETER%%’`,
|
||||
description: `Item points to an item which does not exist`,
|
||||
causeDetailed: `The pairedItem data points to an item ‘${pairedItem.item}‘ which does not exist on node ‘${sourceData.previousNode}‘ (output node did probably supply a wrong one)`,
|
||||
},
|
||||
nodeBeforeLast,
|
||||
);
|
||||
}
|
||||
|
||||
return taskData.data!.main[previousNodeOutput]![pairedItem.item];
|
||||
|
|
Loading…
Reference in a new issue