import { IBinaryKeyData, ICredentialType, INodeCredentialDescription, NodeHelpers, INodeParameters, INodeExecutionData, INodeIssues, INodeIssueObjectProperty, INodeProperties, INodeTypeDescription, IRunData, IRunExecutionData, ITaskDataConnections, } from 'n8n-workflow'; import { ICredentialsResponse, INodeUi, } from '../../Interface'; import { restApi } from '@/components/mixins/restApi'; import { get } from 'lodash'; import mixins from 'vue-typed-mixins'; export const nodeHelpers = mixins( restApi, ) .extend({ methods: { // Returns the parameter value getParameterValue (nodeValues: INodeParameters, parameterName: string, path: string) { return get( nodeValues, path ? path + '.' + parameterName : parameterName, ); }, // Returns if the given parameter should be displayed or not displayParameter (nodeValues: INodeParameters, parameter: INodeProperties | INodeCredentialDescription, path: string) { return NodeHelpers.displayParameterPath(nodeValues, parameter, path); }, // Returns all the issues of the node getNodeIssues (nodeType: INodeTypeDescription | null, node: INodeUi, ignoreIssues?: string[]): INodeIssues | null { let nodeIssues: INodeIssues | null = null; ignoreIssues = ignoreIssues || []; if (node.disabled === true) { // Ignore issues on disabled nodes return null; } if (nodeType === null) { // Node type is not known if (!ignoreIssues.includes('typeUnknown')) { nodeIssues = { typeUnknown: true, }; } } else { // Node type is known // Add potential parameter issues if (!ignoreIssues.includes('parameters')) { nodeIssues = NodeHelpers.getNodeParametersIssues(nodeType.properties, node); } if (!ignoreIssues.includes('credentials')) { // Add potential credential issues const nodeCredentialIssues = this.getNodeCredentialIssues(node, nodeType); if (nodeIssues === null) { nodeIssues = nodeCredentialIssues; } else { NodeHelpers.mergeIssues(nodeIssues, nodeCredentialIssues); } } } if (this.hasNodeExecutionIssues(node) === true && !ignoreIssues.includes('execution')) { if (nodeIssues === null) { nodeIssues = {}; } nodeIssues.execution = true; } return nodeIssues; }, // Set the status on all the nodes which produced an error so that it can be // displayed in the node-view hasNodeExecutionIssues (node: INodeUi): boolean { const workflowResultData: IRunData = this.$store.getters.getWorkflowRunData; if (workflowResultData === null || !workflowResultData.hasOwnProperty(node.name)) { return false; } for (const taskData of workflowResultData[node.name]) { if (taskData.error !== undefined) { return true; } } return false; }, // Updates the execution issues. updateNodesExecutionIssues () { const nodes = this.$store.getters.allNodes; for (const node of nodes) { this.$store.commit('setNodeIssue', { node: node.name, type: 'execution', value: this.hasNodeExecutionIssues(node) ? true : null, }); } }, // Returns all the credential-issues of the node getNodeCredentialIssues (node: INodeUi, nodeType?: INodeTypeDescription): INodeIssues | null { if (nodeType === undefined) { nodeType = this.$store.getters.nodeType(node.type); } if (nodeType === null || nodeType!.credentials === undefined) { // Node does not need any credentials or nodeType could not be found return null; } if (nodeType!.credentials === undefined) { // No credentials defined for node type return null; } const foundIssues: INodeIssueObjectProperty = {}; let userCredentials: ICredentialsResponse[] | null; let credentialType: ICredentialType | null; let credentialDisplayName: string; let selectedCredentials: string; for (const credentialTypeDescription of nodeType!.credentials!) { // Check if credentials should be displayed else ignore if (this.displayParameter(node.parameters, credentialTypeDescription, '') !== true) { continue; } // Get the display name of the credential type credentialType = this.$store.getters.credentialType(credentialTypeDescription.name); if (credentialType === null) { credentialDisplayName = credentialTypeDescription.name; } else { credentialDisplayName = credentialType.displayName; } if (node.credentials === undefined || node.credentials[credentialTypeDescription.name] === undefined) { // Credentials are not set if (credentialTypeDescription.required === true) { foundIssues[credentialTypeDescription.name] = [`Credentials for "${credentialDisplayName}" are not set.`]; } } else { // If they are set check if the value is valid selectedCredentials = node.credentials[credentialTypeDescription.name]; userCredentials = this.$store.getters.credentialsByType(credentialTypeDescription.name); if (userCredentials === null) { userCredentials = []; } if (userCredentials.find((credentialData) => credentialData.name === selectedCredentials) === undefined) { foundIssues[credentialTypeDescription.name] = [`Credentials with name "${selectedCredentials}" do not exist for "${credentialDisplayName}".`]; } } } // TODO: Could later check also if the node has access to the credentials if (Object.keys(foundIssues).length === 0) { return null; } return { credentials: foundIssues, }; }, // Updates the node credential issues updateNodesCredentialsIssues () { const nodes = this.$store.getters.allNodes; let issues: INodeIssues | null; for (const node of nodes) { issues = this.getNodeCredentialIssues(node); this.$store.commit('setNodeIssue', { node: node.name, type: 'credentials', value: issues === null ? null : issues.credentials, }); } }, getNodeInputData (node: INodeUi | null, runIndex = 0, outputIndex = 0): INodeExecutionData[] { if (node === null) { return []; } if (this.$store.getters.getWorkflowExecution === null) { return []; } const executionData: IRunExecutionData = this.$store.getters.getWorkflowExecution.data; const runData = executionData.resultData.runData; if (runData === null || runData[node.name] === undefined || !runData[node.name][runIndex].data || runData[node.name][runIndex].data === undefined ) { return []; } return this.getMainInputData(runData[node.name][runIndex].data!, outputIndex); }, // Returns the data of the main input getMainInputData (connectionsData: ITaskDataConnections, outputIndex: number): INodeExecutionData[] { if (!connectionsData || !connectionsData.hasOwnProperty('main') || connectionsData.main === undefined || connectionsData.main.length < outputIndex) { return []; } return connectionsData.main[outputIndex] as INodeExecutionData[]; }, // Returns all the binary data of all the entries getBinaryData (workflowRunData: IRunData | null, node: string | null, runIndex: number, outputIndex: number): IBinaryKeyData[] { if (node === null) { return []; } const runData: IRunData | null = workflowRunData; if (runData === null || !runData[node] || !runData[node][runIndex] || !runData[node][runIndex].data ) { return []; } const inputData = this.getMainInputData(runData[node][runIndex].data!, outputIndex); const returnData: IBinaryKeyData[] = []; for (let i = 0; i < inputData.length; i++) { if (inputData[i].hasOwnProperty('binary') && inputData[i].binary !== undefined) { returnData.push(inputData[i].binary!); } } return returnData; }, }, });