2023-01-27 03:22:44 -08:00
import type {
2023-03-09 09:13:15 -08:00
IExecuteFunctions ,
2021-08-21 05:11:32 -07:00
INodeExecutionData ,
INodeTypeDescription ,
2023-07-04 07:17:50 -07:00
INodeProperties ,
IDisplayOptions ,
2021-08-21 05:11:32 -07:00
} from 'n8n-workflow' ;
2023-07-04 07:17:50 -07:00
import { WAIT_TIME_UNLIMITED } from 'n8n-workflow' ;
import {
authenticationProperty ,
credentialsProperty ,
defaultWebhookDescription ,
httpMethodsProperty ,
optionsProperty ,
responseBinaryPropertyNameProperty ,
responseCodeProperty ,
responseDataProperty ,
responseModeProperty ,
} from '../Webhook/description' ;
import { Webhook } from '../Webhook/Webhook.node' ;
const displayOnWebhook : IDisplayOptions = {
show : {
resume : [ 'webhook' ] ,
} ,
} ;
export class Wait extends Webhook {
authPropertyName = 'incomingAuthentication' ;
2021-08-21 05:11:32 -07:00
description : INodeTypeDescription = {
displayName : 'Wait' ,
name : 'wait' ,
icon : 'fa:pause-circle' ,
group : [ 'organization' ] ,
version : 1 ,
description : 'Wait before continue with execution' ,
defaults : {
name : 'Wait' ,
color : '#804050' ,
} ,
inputs : [ 'main' ] ,
outputs : [ 'main' ] ,
2023-07-04 07:17:50 -07:00
credentials : credentialsProperty ( this . authPropertyName ) ,
2021-08-21 05:11:32 -07:00
webhooks : [
{
2023-07-04 07:17:50 -07:00
. . . defaultWebhookDescription ,
2021-08-21 05:11:32 -07:00
responseData : '={{$parameter["responseData"]}}' ,
path : '={{$parameter["options"]["webhookSuffix"] || ""}}' ,
restartWebhook : true ,
} ,
] ,
properties : [
{
displayName : 'Resume' ,
name : 'resume' ,
type : 'options' ,
options : [
{
2022-06-03 10:23:49 -07:00
name : 'After Time Interval' ,
2021-08-21 05:11:32 -07:00
value : 'timeInterval' ,
description : 'Waits for a certain amount of time' ,
} ,
{
2022-06-03 10:23:49 -07:00
name : 'At Specified Time' ,
2021-08-21 05:11:32 -07:00
value : 'specificTime' ,
2021-08-26 08:27:19 -07:00
description : 'Waits until a specific date and time to continue' ,
2021-08-21 05:11:32 -07:00
} ,
{
2022-06-03 10:23:49 -07:00
name : 'On Webhook Call' ,
2021-08-21 05:11:32 -07:00
value : 'webhook' ,
2021-08-26 08:27:19 -07:00
description : 'Waits for a webhook call before continuing' ,
2021-08-21 05:11:32 -07:00
} ,
] ,
default : 'timeInterval' ,
2021-08-26 08:27:19 -07:00
description : 'Determines the waiting mode to use before the workflow continues' ,
2021-08-21 05:11:32 -07:00
} ,
2023-07-04 07:17:50 -07:00
{
. . . authenticationProperty ( this . authPropertyName ) ,
description :
'If and how incoming resume-webhook-requests to $execution.resumeUrl should be authenticated for additional security' ,
displayOptions : displayOnWebhook ,
} ,
2021-08-21 05:11:32 -07:00
// ----------------------------------
// resume:specificTime
// ----------------------------------
{
displayName : 'Date and Time' ,
name : 'dateTime' ,
type : 'dateTime' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
resume : [ 'specificTime' ] ,
2021-08-21 05:11:32 -07:00
} ,
} ,
default : '' ,
description : 'The date and time to wait for before continuing' ,
} ,
// ----------------------------------
// resume:timeInterval
// ----------------------------------
{
2021-08-26 08:27:19 -07:00
displayName : 'Wait Amount' ,
2021-08-21 05:11:32 -07:00
name : 'amount' ,
type : 'number' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
resume : [ 'timeInterval' ] ,
2021-08-21 05:11:32 -07:00
} ,
} ,
typeOptions : {
minValue : 0 ,
numberPrecision : 2 ,
} ,
default : 1 ,
description : 'The time to wait' ,
} ,
{
2021-08-26 08:27:19 -07:00
displayName : 'Wait Unit' ,
2021-08-21 05:11:32 -07:00
name : 'unit' ,
type : 'options' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
resume : [ 'timeInterval' ] ,
2021-08-21 05:11:32 -07:00
} ,
} ,
options : [
{
name : 'Seconds' ,
value : 'seconds' ,
} ,
{
name : 'Minutes' ,
value : 'minutes' ,
} ,
{
name : 'Hours' ,
value : 'hours' ,
} ,
{
name : 'Days' ,
value : 'days' ,
} ,
] ,
default : 'hours' ,
2021-08-26 08:27:19 -07:00
description : 'The time unit of the Wait Amount value' ,
2021-08-21 05:11:32 -07:00
} ,
// ----------------------------------
// resume:webhook
// ----------------------------------
{
2022-08-17 08:50:24 -07:00
displayName :
2022-09-29 14:02:25 -07:00
'The webhook URL will be generated at run time. It can be referenced with the <strong>$execution.resumeUrl</strong> variable. Send it somewhere before getting to this node. <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/?utm_source=n8n_app&utm_medium=node_settings_modal-credential_link&utm_campaign=n8n-nodes-base.wait" target="_blank">More info</a>' ,
2021-08-21 05:11:32 -07:00
name : 'webhookNotice' ,
type : 'notice' ,
2023-07-04 07:17:50 -07:00
displayOptions : displayOnWebhook ,
2021-08-21 05:11:32 -07:00
default : '' ,
} ,
{
2023-07-04 07:17:50 -07:00
. . . httpMethodsProperty ,
displayOptions : displayOnWebhook ,
2021-08-26 08:27:19 -07:00
description : 'The HTTP method of the Webhook call' ,
2021-08-21 05:11:32 -07:00
} ,
{
2023-07-04 07:17:50 -07:00
. . . responseCodeProperty ,
displayOptions : displayOnWebhook ,
2021-08-21 05:11:32 -07:00
} ,
{
2023-07-04 07:17:50 -07:00
. . . responseModeProperty ,
displayOptions : displayOnWebhook ,
2021-08-21 05:11:32 -07:00
} ,
{
2023-07-04 07:17:50 -07:00
. . . responseDataProperty ,
2021-08-21 05:11:32 -07:00
displayOptions : {
show : {
2023-07-04 07:17:50 -07:00
. . . responseDataProperty . displayOptions ? . show ,
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
} ,
{
2023-07-04 07:17:50 -07:00
. . . responseBinaryPropertyNameProperty ,
2021-08-21 05:11:32 -07:00
displayOptions : {
show : {
2023-07-04 07:17:50 -07:00
. . . responseBinaryPropertyNameProperty . displayOptions ? . show ,
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
} ,
{
2022-06-03 10:23:49 -07:00
displayName : 'Limit Wait Time' ,
2021-08-21 05:11:32 -07:00
name : 'limitWaitTime' ,
type : 'boolean' ,
default : false ,
2022-06-20 07:54:01 -07:00
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
2022-08-17 08:50:24 -07:00
description :
'If no webhook call is received, the workflow will automatically resume execution after the specified limit type' ,
2023-07-04 07:17:50 -07:00
displayOptions : displayOnWebhook ,
2021-08-21 05:11:32 -07:00
} ,
{
2022-06-03 10:23:49 -07:00
displayName : 'Limit Type' ,
2021-08-21 05:11:32 -07:00
name : 'limitType' ,
type : 'options' ,
default : 'afterTimeInterval' ,
2022-08-17 08:50:24 -07:00
description :
'Sets the condition for the execution to resume. Can be a specified date or after some time.' ,
2021-08-21 05:11:32 -07:00
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
limitWaitTime : [ true ] ,
2023-07-04 07:17:50 -07:00
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
options : [
{
2022-06-03 10:23:49 -07:00
name : 'After Time Interval' ,
2021-08-26 08:27:19 -07:00
description : 'Waits for a certain amount of time' ,
2021-08-21 05:11:32 -07:00
value : 'afterTimeInterval' ,
} ,
{
2022-06-03 10:23:49 -07:00
name : 'At Specified Time' ,
2021-08-26 08:27:19 -07:00
description : 'Waits until the set date and time to continue' ,
2021-08-21 05:11:32 -07:00
value : 'atSpecifiedTime' ,
} ,
] ,
} ,
{
displayName : 'Amount' ,
name : 'resumeAmount' ,
type : 'number' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
limitType : [ 'afterTimeInterval' ] ,
limitWaitTime : [ true ] ,
2023-07-04 07:17:50 -07:00
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
typeOptions : {
minValue : 0 ,
numberPrecision : 2 ,
} ,
default : 1 ,
description : 'The time to wait' ,
} ,
{
displayName : 'Unit' ,
name : 'resumeUnit' ,
type : 'options' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
limitType : [ 'afterTimeInterval' ] ,
limitWaitTime : [ true ] ,
2023-07-04 07:17:50 -07:00
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
options : [
{
name : 'Seconds' ,
value : 'seconds' ,
} ,
{
name : 'Minutes' ,
value : 'minutes' ,
} ,
{
name : 'Hours' ,
value : 'hours' ,
} ,
{
name : 'Days' ,
value : 'days' ,
} ,
] ,
default : 'hours' ,
description : 'Unit of the interval value' ,
} ,
{
displayName : 'Max Date and Time' ,
name : 'maxDateAndTime' ,
type : 'dateTime' ,
displayOptions : {
show : {
2022-08-17 08:50:24 -07:00
limitType : [ 'atSpecifiedTime' ] ,
limitWaitTime : [ true ] ,
2023-07-04 07:17:50 -07:00
. . . displayOnWebhook . show ,
2021-08-21 05:11:32 -07:00
} ,
} ,
default : '' ,
2021-08-26 08:27:19 -07:00
description : 'Continue execution after the specified date and time' ,
2021-08-21 05:11:32 -07:00
} ,
{
2023-07-04 07:17:50 -07:00
. . . optionsProperty ,
displayOptions : displayOnWebhook ,
2021-08-21 05:11:32 -07:00
options : [
2023-07-04 07:17:50 -07:00
. . . ( optionsProperty . options as INodeProperties [ ] ) ,
2021-08-21 05:11:32 -07:00
{
displayName : 'Webhook Suffix' ,
name : 'webhookSuffix' ,
type : 'string' ,
default : '' ,
placeholder : 'webhook' ,
2022-08-17 08:50:24 -07:00
description :
'This suffix path will be appended to the restart URL. Helpful when using multiple wait nodes. Note: Does not support expressions.' ,
2021-08-21 05:11:32 -07:00
} ,
] ,
} ,
] ,
} ;
2023-07-04 07:17:50 -07:00
async execute ( context : IExecuteFunctions ) : Promise < INodeExecutionData [ ] [ ] > {
const resume = context . getNodeParameter ( 'resume' , 0 ) as string ;
2021-08-21 05:11:32 -07:00
if ( resume === 'webhook' ) {
2023-07-04 07:17:50 -07:00
return this . handleWebhookResume ( context ) ;
2021-08-21 05:11:32 -07:00
}
let waitTill : Date ;
if ( resume === 'timeInterval' ) {
2023-07-04 07:17:50 -07:00
const unit = context . getNodeParameter ( 'unit' , 0 ) as string ;
2021-08-21 05:11:32 -07:00
2023-07-04 07:17:50 -07:00
let waitAmount = context . getNodeParameter ( 'amount' , 0 ) as number ;
2021-08-21 05:11:32 -07:00
if ( unit === 'minutes' ) {
waitAmount *= 60 ;
}
if ( unit === 'hours' ) {
waitAmount *= 60 * 60 ;
}
if ( unit === 'days' ) {
waitAmount *= 60 * 60 * 24 ;
}
waitAmount *= 1000 ;
waitTill = new Date ( new Date ( ) . getTime ( ) + waitAmount ) ;
} else {
// resume: dateTime
2023-07-04 07:17:50 -07:00
const dateTime = context . getNodeParameter ( 'dateTime' , 0 ) as string ;
2021-08-21 05:11:32 -07:00
waitTill = new Date ( dateTime ) ;
}
const waitValue = Math . max ( waitTill . getTime ( ) - new Date ( ) . getTime ( ) , 0 ) ;
if ( waitValue < 65000 ) {
// If wait time is shorter than 65 seconds leave execution active because
// we just check the database every 60 seconds.
2022-11-08 06:28:21 -08:00
return new Promise ( ( resolve , _reject ) = > {
2021-08-21 05:11:32 -07:00
setTimeout ( ( ) = > {
2023-07-04 07:17:50 -07:00
resolve ( [ context . getInputData ( ) ] ) ;
2021-08-21 05:11:32 -07:00
} , waitValue ) ;
} ) ;
}
2023-07-04 07:17:50 -07:00
// If longer than 65 seconds put execution to wait
return this . putToWait ( context , waitTill ) ;
}
private async handleWebhookResume ( context : IExecuteFunctions ) {
let waitTill = new Date ( WAIT_TIME_UNLIMITED ) ;
const limitWaitTime = context . getNodeParameter ( 'limitWaitTime' , 0 ) ;
if ( limitWaitTime === true ) {
const limitType = context . getNodeParameter ( 'limitType' , 0 ) ;
if ( limitType === 'afterTimeInterval' ) {
let waitAmount = context . getNodeParameter ( 'resumeAmount' , 0 ) as number ;
const resumeUnit = context . getNodeParameter ( 'resumeUnit' , 0 ) ;
if ( resumeUnit === 'minutes' ) {
waitAmount *= 60 ;
}
if ( resumeUnit === 'hours' ) {
waitAmount *= 60 * 60 ;
}
if ( resumeUnit === 'days' ) {
waitAmount *= 60 * 60 * 24 ;
}
waitAmount *= 1000 ;
waitTill = new Date ( new Date ( ) . getTime ( ) + waitAmount ) ;
} else {
waitTill = new Date ( context . getNodeParameter ( 'maxDateAndTime' , 0 ) as string ) ;
}
}
return this . putToWait ( context , waitTill ) ;
}
2021-08-21 05:11:32 -07:00
2023-07-04 07:17:50 -07:00
private async putToWait ( context : IExecuteFunctions , waitTill : Date ) {
await context . putExecutionToWait ( waitTill ) ;
return [ context . getInputData ( ) ] ;
2021-08-21 05:11:32 -07:00
}
}