diff --git a/packages/cli/test/integration/shared/types.d.ts b/packages/cli/test/integration/shared/types.d.ts
index 9b45b7b93a..1e74ad548f 100644
--- a/packages/cli/test/integration/shared/types.d.ts
+++ b/packages/cli/test/integration/shared/types.d.ts
@@ -41,15 +41,6 @@ export type PostgresSchemaSection = {
[K in 'host' | 'port' | 'schema' | 'user' | 'password']: { env: string };
};
-export interface TriggerTime {
- mode: string;
- hour: number;
- minute: number;
- dayOfMonth: number;
- weekeday: number;
- [key: string]: string | number;
-}
-
export type InstalledPackagePayload = {
packageName: string;
installedVersion: string;
diff --git a/packages/cli/test/integration/shared/utils.ts b/packages/cli/test/integration/shared/utils.ts
index 1e16f75f3e..eaff862f10 100644
--- a/packages/cli/test/integration/shared/utils.ts
+++ b/packages/cli/test/integration/shared/utils.ts
@@ -20,6 +20,9 @@ import {
ITriggerFunctions,
ITriggerResponse,
LoggerProxy,
+ NodeHelpers,
+ TriggerTime,
+ toCronExpression,
} from 'n8n-workflow';
import config from '../../../config';
@@ -56,7 +59,6 @@ import type {
InstalledNodePayload,
InstalledPackagePayload,
PostgresSchemaSection,
- TriggerTime,
} from './types';
import type { N8nApp } from '../../../src/UserManagement/Interfaces';
import { workflowsController } from '../../../src/api/workflows.api';
@@ -281,192 +283,7 @@ export async function initNodeTypes() {
default: {},
description: 'Triggers for the workflow',
placeholder: 'Add Cron 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: 'Every X',
- value: 'everyX',
- },
- {
- 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', 'everyX'],
- },
- },
- 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', 'everyX'],
- },
- },
- 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:
- Seconds: 0-59
- Minutes: 0 - 59
- Hours: 0 - 23
- Day of Month: 1 - 31
- Months: 0 - 11 (Jan - Dec)
- Day of Week: 0 - 6 (Sun - Sat)
.',
- },
- {
- displayName: 'Value',
- name: 'value',
- type: 'number',
- typeOptions: {
- minValue: 0,
- maxValue: 1000,
- },
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- default: 2,
- description: 'All how many X minutes/hours it should trigger.',
- },
- {
- displayName: 'Unit',
- name: 'unit',
- type: 'options',
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- options: [
- {
- name: 'Minutes',
- value: 'minutes',
- },
- {
- name: 'Hours',
- value: 'hours',
- },
- ],
- default: 'hours',
- description: 'If it should trigger all X minutes or hours.',
- },
- ],
- },
- ],
+ options: NodeHelpers.cronNodeOptions,
},
],
},
@@ -475,61 +292,8 @@ export async function initNodeTypes() {
item: TriggerTime[];
};
- // Define the order the cron-time-parameter appear
- const parameterOrder = [
- 'second', // 0 - 59
- 'minute', // 0 - 59
- 'hour', // 0 - 23
- 'dayOfMonth', // 1 - 31
- 'month', // 0 - 11(Jan - Dec)
- 'weekday', // 0 - 6(Sun - Sat)
- ];
-
// Get all the trigger times
- const cronTimes: string[] = [];
- let cronTime: string[];
- let parameterName: string;
- if (triggerTimes.item !== undefined) {
- for (const item of triggerTimes.item) {
- cronTime = [];
- if (item.mode === 'custom') {
- cronTimes.push(item.cronExpression as string);
- continue;
- }
- if (item.mode === 'everyMinute') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} * * * * *`);
- continue;
- }
- if (item.mode === 'everyX') {
- if (item.unit === 'minutes') {
- cronTimes.push(
- `${Math.floor(Math.random() * 60).toString()} */${item.value} * * * *`,
- );
- } else if (item.unit === 'hours') {
- cronTimes.push(
- `${Math.floor(Math.random() * 60).toString()} 0 */${item.value} * * *`,
- );
- }
- continue;
- }
-
- for (parameterName of parameterOrder) {
- if (item[parameterName] !== undefined) {
- // Value is set so use it
- cronTime.push(item[parameterName] as string);
- } else if (parameterName === 'second') {
- // For seconds we use by default a random one to make sure to
- // balance the load a little bit over time
- cronTime.push(Math.floor(Math.random() * 60).toString());
- } else {
- // For all others set "any"
- cronTime.push('*');
- }
- }
-
- cronTimes.push(cronTime.join(' '));
- }
- }
+ const cronTimes = (triggerTimes.item || []).map(toCronExpression);
// The trigger function to execute when the cron-time got reached
// or when manually triggered
@@ -540,10 +304,7 @@ export async function initNodeTypes() {
const timezone = this.getTimezone();
// Start the cron-jobs
- const cronJobs: CronJob[] = [];
- for (const cronTime of cronTimes) {
- cronJobs.push(new CronJob(cronTime, executeTrigger, undefined, true, timezone));
- }
+ const cronJobs = cronTimes.map(cronTime => new CronJob(cronTime, executeTrigger, undefined, true, timezone));
// Stop the cron-jobs
async function closeFunction() {
@@ -929,4 +690,3 @@ export const emptyPackage = () => {
return Promise.resolve(installedPackage);
};
-
diff --git a/packages/core/src/ActiveWorkflows.ts b/packages/core/src/ActiveWorkflows.ts
index 4ea94b0a2e..01271de8fb 100644
--- a/packages/core/src/ActiveWorkflows.ts
+++ b/packages/core/src/ActiveWorkflows.ts
@@ -12,6 +12,8 @@ import {
ITriggerResponse,
IWorkflowExecuteAdditionalData,
LoggerProxy as Logger,
+ TriggerTime,
+ toCronExpression,
Workflow,
WorkflowActivateMode,
WorkflowActivationError,
@@ -19,7 +21,7 @@ import {
} from 'n8n-workflow';
// eslint-disable-next-line import/no-cycle
-import { ITriggerTime, IWorkflowData } from '.';
+import type { IWorkflowData } from '.';
export class ActiveWorkflows {
private workflowData: {
@@ -156,60 +158,11 @@ export class ActiveWorkflows {
const pollFunctions = getPollFunctions(workflow, node, additionalData, mode, activation);
const pollTimes = pollFunctions.getNodeParameter('pollTimes') as unknown as {
- item: ITriggerTime[];
+ item: TriggerTime[];
};
- // Define the order the cron-time-parameter appear
- const parameterOrder = [
- 'second', // 0 - 59
- 'minute', // 0 - 59
- 'hour', // 0 - 23
- 'dayOfMonth', // 1 - 31
- 'month', // 0 - 11(Jan - Dec)
- 'weekday', // 0 - 6(Sun - Sat)
- ];
-
// Get all the trigger times
- const cronTimes: string[] = [];
- let cronTime: string[];
- let parameterName: string;
- if (pollTimes.item !== undefined) {
- for (const item of pollTimes.item) {
- cronTime = [];
- if (item.mode === 'custom') {
- cronTimes.push((item.cronExpression as string).trim());
- continue;
- }
- if (item.mode === 'everyMinute') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} * * * * *`);
- continue;
- }
- if (item.mode === 'everyX') {
- if (item.unit === 'minutes') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} */${item.value} * * * *`);
- } else if (item.unit === 'hours') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} 0 */${item.value} * * *`);
- }
- continue;
- }
-
- for (parameterName of parameterOrder) {
- if (item[parameterName] !== undefined) {
- // Value is set so use it
- cronTime.push(item[parameterName] as string);
- } else if (parameterName === 'second') {
- // For seconds we use by default a random one to make sure to
- // balance the load a little bit over time
- cronTime.push(Math.floor(Math.random() * 60).toString());
- } else {
- // For all others set "any"
- cronTime.push('*');
- }
- }
-
- cronTimes.push(cronTime.join(' '));
- }
- }
+ const cronTimes = (pollTimes.item || []).map(toCronExpression);
// The trigger function to execute when the cron-time got reached
const executeTrigger = async () => {
diff --git a/packages/core/src/Interfaces.ts b/packages/core/src/Interfaces.ts
index 1e0ad62bbe..5efda21290 100644
--- a/packages/core/src/Interfaces.ts
+++ b/packages/core/src/Interfaces.ts
@@ -180,15 +180,6 @@ export interface ITriggerFunctions extends ITriggerFunctionsBase {
};
}
-export interface ITriggerTime {
- mode: string;
- hour: number;
- minute: number;
- dayOfMonth: number;
- weekeday: number;
- [key: string]: string | number;
-}
-
export interface IUserSettings {
encryptionKey?: string;
tunnelSubdomain?: string;
diff --git a/packages/nodes-base/nodes/Cron/Cron.node.ts b/packages/nodes-base/nodes/Cron/Cron.node.ts
index 5d018a1269..718d15f8f0 100644
--- a/packages/nodes-base/nodes/Cron/Cron.node.ts
+++ b/packages/nodes-base/nodes/Cron/Cron.node.ts
@@ -1,17 +1,15 @@
import { ITriggerFunctions } from 'n8n-core';
-import { INodeType, INodeTypeDescription, ITriggerResponse } from 'n8n-workflow';
+import {
+ INodeType,
+ INodeTypeDescription,
+ ITriggerResponse,
+ NodeHelpers,
+ toCronExpression,
+ TriggerTime,
+} from 'n8n-workflow';
import { CronJob } from 'cron';
-interface TriggerTime {
- mode: string;
- hour: number;
- minute: number;
- dayOfMonth: number;
- weekeday: number;
- [key: string]: string | number;
-}
-
export class Cron implements INodeType {
description: INodeTypeDescription = {
displayName: 'Cron',
@@ -49,194 +47,7 @@ export class Cron implements INodeType {
default: {},
description: 'Triggers for the workflow',
placeholder: 'Add Cron Time',
- options: [
- {
- name: 'item',
- displayName: 'Item',
- values: [
- {
- displayName: 'Mode',
- name: 'mode',
- type: 'options',
- // eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
- 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: 'Every X',
- value: 'everyX',
- },
- {
- 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', 'everyX'],
- },
- },
- 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', 'everyX'],
- },
- },
- 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'],
- },
- },
- // eslint-disable-next-line n8n-nodes-base/node-param-options-type-unsorted-items
- 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:- Seconds: 0-59
- Minutes: 0 - 59
- Hours: 0 - 23
- Day of Month: 1 - 31
- Months: 0 - 11 (Jan - Dec)
- Day of Week: 0 - 6 (Sun - Sat)
.',
- },
- {
- displayName: 'Value',
- name: 'value',
- type: 'number',
- typeOptions: {
- minValue: 0,
- maxValue: 1000,
- },
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- default: 2,
- description: 'All how many X minutes/hours it should trigger',
- },
- {
- displayName: 'Unit',
- name: 'unit',
- type: 'options',
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- options: [
- {
- name: 'Minutes',
- value: 'minutes',
- },
- {
- name: 'Hours',
- value: 'hours',
- },
- ],
- default: 'hours',
- description: 'If it should trigger all X minutes or hours',
- },
- ],
- },
- ],
+ options: NodeHelpers.cronNodeOptions,
},
],
};
@@ -246,57 +57,8 @@ export class Cron implements INodeType {
item: TriggerTime[];
};
- // Define the order the cron-time-parameter appear
- const parameterOrder = [
- 'second', // 0 - 59
- 'minute', // 0 - 59
- 'hour', // 0 - 23
- 'dayOfMonth', // 1 - 31
- 'month', // 0 - 11(Jan - Dec)
- 'weekday', // 0 - 6(Sun - Sat)
- ];
-
// Get all the trigger times
- const cronTimes: string[] = [];
- let cronTime: string[];
- let parameterName: string;
- if (triggerTimes.item !== undefined) {
- for (const item of triggerTimes.item) {
- cronTime = [];
- if (item.mode === 'custom') {
- cronTimes.push(item.cronExpression as string);
- continue;
- }
- if (item.mode === 'everyMinute') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} * * * * *`);
- continue;
- }
- if (item.mode === 'everyX') {
- if (item.unit === 'minutes') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} */${item.value} * * * *`);
- } else if (item.unit === 'hours') {
- cronTimes.push(`${Math.floor(Math.random() * 60).toString()} 0 */${item.value} * * *`);
- }
- continue;
- }
-
- for (parameterName of parameterOrder) {
- if (item[parameterName] !== undefined) {
- // Value is set so use it
- cronTime.push(item[parameterName] as string);
- } else if (parameterName === 'second') {
- // For seconds we use by default a random one to make sure to
- // balance the load a little bit over time
- cronTime.push(Math.floor(Math.random() * 60).toString());
- } else {
- // For all others set "any"
- cronTime.push('*');
- }
- }
-
- cronTimes.push(cronTime.join(' '));
- }
- }
+ const cronTimes = (triggerTimes.item || []).map(toCronExpression);
// The trigger function to execute when the cron-time got reached
// or when manually triggered
@@ -307,10 +69,7 @@ export class Cron implements INodeType {
const timezone = this.getTimezone();
// Start the cron-jobs
- const cronJobs: CronJob[] = [];
- for (const cronTime of cronTimes) {
- cronJobs.push(new CronJob(cronTime, executeTrigger, undefined, true, timezone));
- }
+ const cronJobs = cronTimes.map(cronTime => new CronJob(cronTime, executeTrigger, undefined, true, timezone));
// Stop the cron-jobs
async function closeFunction() {
diff --git a/packages/workflow/src/Cron.ts b/packages/workflow/src/Cron.ts
new file mode 100644
index 0000000000..fb1446fa04
--- /dev/null
+++ b/packages/workflow/src/Cron.ts
@@ -0,0 +1,68 @@
+interface BaseTriggerTime {
+ mode: T;
+}
+
+type CronExpression = string;
+interface CustomTrigger extends BaseTriggerTime<'custom'> {
+ cronExpression: CronExpression;
+}
+
+interface EveryX extends BaseTriggerTime<'everyX'> {
+ unit: U;
+ value: number;
+}
+
+type EveryMinute = BaseTriggerTime<'everyMinute'>;
+type EveryXMinutes = EveryX<'minutes'>;
+
+interface EveryHour extends BaseTriggerTime<'everyHour'> {
+ minute: number; // 0 - 59
+}
+type EveryXHours = EveryX<'hours'>;
+
+interface EveryDay extends BaseTriggerTime<'everyDay'> {
+ hour: number; // 0 - 23
+ minute: number; // 0 - 59
+}
+
+interface EveryWeek extends BaseTriggerTime<'everyWeek'> {
+ hour: number; // 0 - 23
+ minute: number; // 0 - 59
+ weekday: number; // 0 - 6(Sun - Sat)
+}
+
+interface EveryMonth extends BaseTriggerTime<'everyMonth'> {
+ hour: number; // 0 - 23
+ minute: number; // 0 - 59
+ dayOfMonth: number; // 1 - 31
+}
+
+export type TriggerTime =
+ | CustomTrigger
+ | EveryMinute
+ | EveryXMinutes
+ | EveryHour
+ | EveryXHours
+ | EveryDay
+ | EveryWeek
+ | EveryMonth;
+
+const randomSecond = () => Math.floor(Math.random() * 60).toString();
+
+export const toCronExpression = (item: TriggerTime): CronExpression => {
+ if (item.mode === 'everyMinute') return `${randomSecond()} * * * * *`;
+ if (item.mode === 'everyHour') return `${randomSecond()} ${item.minute} * * * *`;
+
+ if (item.mode === 'everyX') {
+ if (item.unit === 'minutes') return `${randomSecond()} */${item.value} * * * *`;
+ if (item.unit === 'hours') return `${randomSecond()} 0 */${item.value} * * *`;
+ }
+ if (item.mode === 'everyDay') return `${randomSecond()} ${item.minute} ${item.hour} * * *`;
+ if (item.mode === 'everyWeek')
+ return `${randomSecond()} ${item.minute} ${item.hour} * * ${item.weekday}`;
+
+ if (item.mode === 'everyMonth')
+ return `${randomSecond()} ${item.minute} ${item.hour} ${item.dayOfMonth} * *`;
+
+ return item.cronExpression.trim();
+};
diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts
index e55da58148..63d20bad05 100644
--- a/packages/workflow/src/NodeHelpers.ts
+++ b/packages/workflow/src/NodeHelpers.ts
@@ -38,6 +38,193 @@ import {
import { Workflow } from './Workflow';
+export const cronNodeOptions: INodePropertyCollection[] = [
+ {
+ 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: 'Every X',
+ value: 'everyX',
+ },
+ {
+ 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', 'everyX'],
+ },
+ },
+ 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', 'everyX'],
+ },
+ },
+ 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:- Seconds: 0-59
- Minutes: 0 - 59
- Hours: 0 - 23
- Day of Month: 1 - 31
- Months: 0 - 11 (Jan - Dec)
- Day of Week: 0 - 6 (Sun - Sat)
',
+ },
+ {
+ displayName: 'Value',
+ name: 'value',
+ type: 'number',
+ typeOptions: {
+ minValue: 0,
+ maxValue: 1000,
+ },
+ displayOptions: {
+ show: {
+ mode: ['everyX'],
+ },
+ },
+ default: 2,
+ description: 'All how many X minutes/hours it should trigger',
+ },
+ {
+ displayName: 'Unit',
+ name: 'unit',
+ type: 'options',
+ displayOptions: {
+ show: {
+ mode: ['everyX'],
+ },
+ },
+ options: [
+ {
+ name: 'Minutes',
+ value: 'minutes',
+ },
+ {
+ name: 'Hours',
+ value: 'hours',
+ },
+ ],
+ default: 'hours',
+ description: 'If it should trigger all X minutes or hours',
+ },
+ ],
+ },
+];
+
/**
* Gets special parameters which should be added to nodeTypes depending
* on their type or configuration
@@ -60,192 +247,7 @@ export function getSpecialNodeParameters(nodeType: INodeType): INodeProperties[]
default: { item: [{ mode: 'everyMinute' }] },
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: 'Every X',
- value: 'everyX',
- },
- {
- 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', 'everyX'],
- },
- },
- 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', 'everyX'],
- },
- },
- 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:- Seconds: 0-59
- Minutes: 0 - 59
- Hours: 0 - 23
- Day of Month: 1 - 31
- Months: 0 - 11 (Jan - Dec)
- Day of Week: 0 - 6 (Sun - Sat)
',
- },
- {
- displayName: 'Value',
- name: 'value',
- type: 'number',
- typeOptions: {
- minValue: 0,
- maxValue: 1000,
- },
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- default: 2,
- description: 'All how many X minutes/hours it should trigger',
- },
- {
- displayName: 'Unit',
- name: 'unit',
- type: 'options',
- displayOptions: {
- show: {
- mode: ['everyX'],
- },
- },
- options: [
- {
- name: 'Minutes',
- value: 'minutes',
- },
- {
- name: 'Hours',
- value: 'hours',
- },
- ],
- default: 'hours',
- description: 'If it should trigger all X minutes or hours',
- },
- ],
- },
- ],
+ options: cronNodeOptions,
},
];
}
diff --git a/packages/workflow/src/index.ts b/packages/workflow/src/index.ts
index 5ae90bce09..a006e9d9d6 100644
--- a/packages/workflow/src/index.ts
+++ b/packages/workflow/src/index.ts
@@ -3,6 +3,7 @@ import * as LoggerProxy from './LoggerProxy';
import * as NodeHelpers from './NodeHelpers';
import * as ObservableObject from './ObservableObject';
+export * from './Cron';
export * from './DeferredPromise';
export * from './Interfaces';
export * from './Expression';
diff --git a/packages/workflow/test/Cron.test.ts b/packages/workflow/test/Cron.test.ts
new file mode 100644
index 0000000000..43c122ee96
--- /dev/null
+++ b/packages/workflow/test/Cron.test.ts
@@ -0,0 +1,75 @@
+import { toCronExpression } from "../src/Cron"
+
+describe('Cron', () => {
+ describe('toCronExpression', () => {
+ test('should generate a valid cron for `everyMinute` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyMinute',
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] \* \* \* \* \*$/)
+ })
+
+ test('should generate a valid cron for `everyHour` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyHour',
+ minute: 11,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] 11 \* \* \* \*$/)
+ })
+
+ test('should generate a valid cron for `everyX[minutes]` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyX',
+ unit: 'minutes',
+ value: 42,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] \*\/42 \* \* \* \*$/)
+ })
+
+ test('should generate a valid cron for `everyX[hours]` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyX',
+ unit: 'hours',
+ value: 3,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] 0 \*\/3 \* \* \*$/)
+ })
+
+ test('should generate a valid cron for `everyDay` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyDay',
+ hour: 13,
+ minute: 17,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] 17 13 \* \* \*$/)
+ })
+
+ test('should generate a valid cron for `everyWeek` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyWeek',
+ hour: 13,
+ minute: 17,
+ weekday: 4,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] 17 13 \* \* 4$/)
+ })
+
+ test('should generate a valid cron for `everyMonth` triggers', () => {
+ const expression = toCronExpression({
+ mode: 'everyMonth',
+ hour: 13,
+ minute: 17,
+ dayOfMonth: 12,
+ })
+ expect(expression).toMatch(/^[1-6]?[0-9] 17 13 12 \* \*$/)
+ })
+
+ test('should trim custom cron expressions', () => {
+ const expression = toCronExpression({
+ mode: 'custom',
+ cronExpression: ' 0 9-17 * * * ',
+ })
+ expect(expression).toEqual('0 9-17 * * *')
+ })
+ })
+})