mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
✨ Add polling support to Trigger-Nodes
This commit is contained in:
@@ -107,6 +107,10 @@ export interface IDataObject {
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecutePollFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IPollFunctions;
|
||||
}
|
||||
|
||||
export interface IGetExecuteTriggerFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): ITriggerFunctions;
|
||||
}
|
||||
@@ -208,6 +212,19 @@ export interface IHookFunctions {
|
||||
};
|
||||
}
|
||||
|
||||
export interface IPollFunctions {
|
||||
__emit(data: INodeExecutionData[][]): void;
|
||||
getCredentials(type: string): ICredentialDataDecryptedObject | undefined;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
};
|
||||
}
|
||||
|
||||
export interface ITriggerFunctions {
|
||||
emit(data: INodeExecutionData[][]): void;
|
||||
getCredentials(type: string): ICredentialDataDecryptedObject | undefined;
|
||||
@@ -285,6 +302,7 @@ export interface INodeExecutionData {
|
||||
|
||||
|
||||
export interface INodeExecuteFunctions {
|
||||
getExecutePollFunctions: IGetExecutePollFunctions;
|
||||
getExecuteTriggerFunctions: IGetExecuteTriggerFunctions;
|
||||
getExecuteFunctions: IGetExecuteFunctions;
|
||||
getExecuteSingleFunctions: IGetExecuteSingleFunctions;
|
||||
@@ -363,6 +381,10 @@ export interface IParameterDependencies {
|
||||
[key: string]: string[];
|
||||
}
|
||||
|
||||
export interface IPollResponse {
|
||||
closeFunction?: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface ITriggerResponse {
|
||||
closeFunction?: () => Promise<void>;
|
||||
// To manually trigger the run
|
||||
@@ -376,6 +398,7 @@ export interface INodeType {
|
||||
description: INodeTypeDescription;
|
||||
execute?(this: IExecuteFunctions): Promise<INodeExecutionData[][] | null>;
|
||||
executeSingle?(this: IExecuteSingleFunctions): Promise<INodeExecutionData>;
|
||||
poll?(this: IPollFunctions): Promise<INodeExecutionData[][] | null>;
|
||||
trigger?(this: ITriggerFunctions): Promise<ITriggerResponse | undefined>;
|
||||
webhook?(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
||||
hooks?: {
|
||||
@@ -447,6 +470,7 @@ export interface INodeTypeDescription {
|
||||
properties: INodeProperties[];
|
||||
credentials?: INodeCredentialDescription[];
|
||||
maxNodes?: number; // How many nodes of that type can be created in a workflow
|
||||
polling?: boolean;
|
||||
subtitle?: string;
|
||||
hooks?: {
|
||||
[key: string]: INodeHookDescription[] | undefined;
|
||||
|
||||
@@ -23,6 +23,194 @@ import {
|
||||
|
||||
import { get } from 'lodash';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets special parameters which should be added to nodeTypes depending
|
||||
* on their type or configuration
|
||||
*
|
||||
* @export
|
||||
* @param {INodeType} nodeType
|
||||
* @returns
|
||||
*/
|
||||
export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
if (nodeType.description.polling === true) {
|
||||
return [
|
||||
{
|
||||
displayName: 'Poll Times',
|
||||
name: 'pollTimes',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: true,
|
||||
multipleValueButtonText: 'Add Poll Time',
|
||||
},
|
||||
default: {},
|
||||
description: 'Time at which polling should occur.',
|
||||
placeholder: 'Add Poll Time',
|
||||
options: [
|
||||
{
|
||||
name: 'item',
|
||||
displayName: 'Item',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Mode',
|
||||
name: 'mode',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'Every Minute',
|
||||
value: 'everyMinute',
|
||||
},
|
||||
{
|
||||
name: 'Every Hour',
|
||||
value: 'everyHour',
|
||||
},
|
||||
{
|
||||
name: 'Every Day',
|
||||
value: 'everyDay',
|
||||
},
|
||||
{
|
||||
name: 'Every Week',
|
||||
value: 'everyWeek',
|
||||
},
|
||||
{
|
||||
name: 'Every Month',
|
||||
value: 'everyMonth',
|
||||
},
|
||||
{
|
||||
name: 'Custom',
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
default: 'everyDay',
|
||||
description: 'How often to trigger.',
|
||||
},
|
||||
{
|
||||
displayName: 'Hour',
|
||||
name: 'hour',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
maxValue: 23,
|
||||
},
|
||||
displayOptions: {
|
||||
hide: {
|
||||
mode: [
|
||||
'custom',
|
||||
'everyHour',
|
||||
'everyMinute',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: 14,
|
||||
description: 'The hour of the day to trigger (24h format).',
|
||||
},
|
||||
{
|
||||
displayName: 'Minute',
|
||||
name: 'minute',
|
||||
type: 'number',
|
||||
typeOptions: {
|
||||
minValue: 0,
|
||||
maxValue: 59,
|
||||
},
|
||||
displayOptions: {
|
||||
hide: {
|
||||
mode: [
|
||||
'custom',
|
||||
'everyMinute',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: 0,
|
||||
description: 'The minute of the day to trigger.',
|
||||
},
|
||||
{
|
||||
displayName: 'Day of Month',
|
||||
name: 'dayOfMonth',
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyMonth',
|
||||
],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
minValue: 1,
|
||||
maxValue: 31,
|
||||
},
|
||||
default: 1,
|
||||
description: 'The day of the month to trigger.',
|
||||
},
|
||||
{
|
||||
displayName: 'Weekday',
|
||||
name: 'weekday',
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyWeek',
|
||||
],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Monday',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: 'Tuesday',
|
||||
value: '2',
|
||||
},
|
||||
{
|
||||
name: 'Wednesday',
|
||||
value: '3',
|
||||
},
|
||||
{
|
||||
name: 'Thursday',
|
||||
value: '4',
|
||||
},
|
||||
{
|
||||
name: 'Friday',
|
||||
value: '5',
|
||||
},
|
||||
{
|
||||
name: 'Saturday',
|
||||
value: '6',
|
||||
},
|
||||
{
|
||||
name: 'Sunday',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
default: '1',
|
||||
description: 'The weekday to trigger.',
|
||||
},
|
||||
{
|
||||
displayName: 'Cron Expression',
|
||||
name: 'cronExpression',
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'custom',
|
||||
],
|
||||
},
|
||||
},
|
||||
default: '* * * * * *',
|
||||
description: 'Use custom cron expression. Values and ranges as follows:<ul><li>Seconds: 0-59</li><li>Minutes: 0 - 59</li><li>Hours: 0 - 23</li><li>Day of Month: 1 - 31</li><li>Months: 0 - 11 (Jan - Dec)</li><li>Day of Week: 0 - 6 (Sun - Sat)</li></ul>',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the parameter should be displayed or not
|
||||
*
|
||||
|
||||
@@ -3,27 +3,28 @@ import {
|
||||
IConnections,
|
||||
IGetExecuteTriggerFunctions,
|
||||
INode,
|
||||
NodeHelpers,
|
||||
INodes,
|
||||
INodeExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeParameters,
|
||||
INodeIssues,
|
||||
NodeParameterValue,
|
||||
INodeParameters,
|
||||
INodeType,
|
||||
INodeTypes,
|
||||
ObservableObject,
|
||||
IPollFunctions,
|
||||
IRunExecutionData,
|
||||
ITaskDataConnections,
|
||||
ITriggerResponse,
|
||||
IWebhookData,
|
||||
IWebhookResponseData,
|
||||
WebhookSetupMethodNames,
|
||||
WorkflowDataProxy,
|
||||
IWorfklowIssues,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
WorkflowExecuteMode,
|
||||
IWorkflowSettings,
|
||||
NodeHelpers,
|
||||
NodeParameterValue,
|
||||
ObservableObject,
|
||||
WebhookSetupMethodNames,
|
||||
WorkflowDataProxy,
|
||||
WorkflowExecuteMode,
|
||||
} from './';
|
||||
|
||||
// @ts-ignore
|
||||
@@ -188,7 +189,7 @@ export class Workflow {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodeType.trigger !== undefined || nodeType.webhook !== undefined) {
|
||||
if (nodeType.poll !== undefined || nodeType.trigger !== undefined || nodeType.webhook !== undefined) {
|
||||
// Is a trigger node. So workflow can be activated.
|
||||
return true;
|
||||
}
|
||||
@@ -289,6 +290,30 @@ export class Workflow {
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getTriggerNodes(): INode[] {
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.trigger );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the poll nodes in the workflow
|
||||
*
|
||||
* @returns {INode[]}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getPollNodes(): INode[] {
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.poll );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the nodes in the workflow for which the given
|
||||
* checkFunction return true
|
||||
*
|
||||
* @param {(nodeType: INodeType) => boolean} checkFunction
|
||||
* @returns {INode[]}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
queryNodes(checkFunction: (nodeType: INodeType) => boolean): INode[] {
|
||||
const returnNodes: INode[] = [];
|
||||
|
||||
// Check if it has any of them
|
||||
@@ -304,7 +329,7 @@ export class Workflow {
|
||||
|
||||
nodeType = this.nodeTypes.getByName(node.type);
|
||||
|
||||
if (nodeType !== undefined && nodeType.trigger) {
|
||||
if (nodeType !== undefined && checkFunction(nodeType)) {
|
||||
returnNodes.push(node);
|
||||
}
|
||||
}
|
||||
@@ -729,14 +754,14 @@ export class Workflow {
|
||||
|
||||
// Check which node to return as start node
|
||||
|
||||
// Check if there are any trigger nodes and then return the first one
|
||||
// Check if there are any trigger or poll nodes and then return the first one
|
||||
let node: INode;
|
||||
let nodeType: INodeType;
|
||||
for (const nodeName of nodeNames) {
|
||||
node = this.nodes[nodeName];
|
||||
nodeType = this.nodeTypes.getByName(node.type) as INodeType;
|
||||
|
||||
if (nodeType.trigger !== undefined) {
|
||||
if (nodeType.trigger !== undefined || nodeType.poll !== undefined) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -994,6 +1019,30 @@ export class Workflow {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs the given trigger node so that it can trigger the workflow
|
||||
* when the node has data.
|
||||
*
|
||||
* @param {INode} node
|
||||
* @param {IPollFunctions} pollFunctions
|
||||
* @returns
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runPoll(node: INode, pollFunctions: IPollFunctions): Promise<INodeExecutionData[][] | null> {
|
||||
const nodeType = this.nodeTypes.getByName(node.type);
|
||||
|
||||
if (nodeType === undefined) {
|
||||
throw new Error(`The node type "${node.type}" of node "${node.name}" is not known.`);
|
||||
}
|
||||
|
||||
if (!nodeType.poll) {
|
||||
throw new Error(`The node type "${node.type}" of node "${node.name}" does not have a poll function defined.`);
|
||||
}
|
||||
|
||||
return nodeType.poll!.call(pollFunctions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the webhook data to see what it should return and if the
|
||||
* workflow should be started or not
|
||||
@@ -1096,6 +1145,9 @@ export class Workflow {
|
||||
} else if (nodeType.execute) {
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteFunctions(this, runExecutionData, runIndex, connectionInputData, inputData, node, additionalData, mode);
|
||||
return nodeType.execute.call(thisArgs);
|
||||
} else if (nodeType.poll) {
|
||||
const thisArgs = nodeExecuteFunctions.getExecutePollFunctions(this, node, additionalData, mode);
|
||||
return nodeType.poll.call(thisArgs);
|
||||
} else if (nodeType.trigger) {
|
||||
if (mode === 'manual') {
|
||||
// In manual mode start the trigger
|
||||
|
||||
Reference in New Issue
Block a user