mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-10 22:54:05 -08:00
a2f628927d
* add panel * add workflow activation hints * support service trigger nodes * update polling state * support more views * update when trigger panel shows * update start/error nodes * add cron/interval info box * clean up start node * fix up webhook views * remove console log * add listening state * clean up loading state * update loading state * fix up animation * update views * add executions hint * update views * update accordian styling * address more issues * disable execute button if issues * disable if it has issues * add stop waiting button * can activate workflow when dsiabled * update el * fix has issues * add margin bttm * update views * close ndv * add shake * update copies * add error when polling node is missing one * update package lock * hide switch * hide binary data that's missing keys * hide main bar if ndv is open * remove waiting to execute * change accordion bg color * capitalize text * disable trigger panel in read only views * remove webhook title * update webhook desc * update component * update webhook executions note * update header * update webhook url * update exec help * bring back waiting to execute for non triggers * add transition fade * set shake * add helpful tooltip * add nonactive text * add inactive text * hide trigger panel by default * remove unused import * update pulse animation * handle empty values for options * update text * add flag for mock manual executions * add overrides * Add overrides * update check * update package lock; show button for others * hide more info * update other core nodes * update service name * remove panel from nodes * update panel * last tweaks * add telemetry event * add telemetry; address issues * address feedback * address feedback * address feedback * fix previous * fix previous * fix bug * fix bug with webhookbased * add extra break * update telemetry * update telemetry * add telemetry req * add info icon story; use icon component * clean css; en.json * clean en.json * rename key * add key * sort keys alpha * handle activation if active + add previous state to telemetry * stop activation if active * remove unnessary tracking * remove unused import * remove unused * remove unnessary flag * rewrite in ts * move pulse to design system * clean up * clean up * clean up * disable tslint check * disable tslint check
356 lines
8.3 KiB
TypeScript
356 lines
8.3 KiB
TypeScript
import { ITriggerFunctions } from 'n8n-core';
|
||
import {
|
||
INodeType,
|
||
INodeTypeDescription,
|
||
ITriggerResponse,
|
||
} 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',
|
||
name: 'cron',
|
||
icon: 'fa:calendar',
|
||
group: ['trigger', 'schedule'],
|
||
version: 1,
|
||
description: 'Triggers the workflow at a specific time',
|
||
eventTriggerDescription: '',
|
||
activationMessage: 'Your cron trigger will now trigger executions on the schedule you have defined.',
|
||
defaults: {
|
||
name: 'Cron',
|
||
color: '#00FF00',
|
||
},
|
||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||
inputs: [],
|
||
outputs: ['main'],
|
||
properties: [
|
||
{
|
||
displayName: 'This workflow will run on the schedule you define here once you <a data-key="activate">activate</a> it.<br><br>For testing, you can also trigger it manually: by going back to the canvas and clicking ‘execute workflow’',
|
||
name: 'notice',
|
||
type: 'notice',
|
||
default: '',
|
||
},
|
||
{
|
||
displayName: 'Trigger Times',
|
||
name: 'triggerTimes',
|
||
type: 'fixedCollection',
|
||
typeOptions: {
|
||
multipleValues: true,
|
||
multipleValueButtonText: 'Add Time',
|
||
},
|
||
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:<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>.',
|
||
},
|
||
{
|
||
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',
|
||
},
|
||
],
|
||
},
|
||
],
|
||
},
|
||
],
|
||
};
|
||
|
||
|
||
|
||
async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
|
||
|
||
const triggerTimes = this.getNodeParameter('triggerTimes') as unknown as {
|
||
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(' '));
|
||
}
|
||
}
|
||
|
||
// The trigger function to execute when the cron-time got reached
|
||
// or when manually triggered
|
||
const executeTrigger = () => {
|
||
this.emit([this.helpers.returnJsonArray([{}])]);
|
||
};
|
||
|
||
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));
|
||
}
|
||
|
||
// Stop the cron-jobs
|
||
async function closeFunction() {
|
||
for (const cronJob of cronJobs) {
|
||
cronJob.stop();
|
||
}
|
||
}
|
||
|
||
async function manualTriggerFunction() {
|
||
executeTrigger();
|
||
}
|
||
|
||
return {
|
||
closeFunction,
|
||
manualTriggerFunction,
|
||
};
|
||
}
|
||
}
|