Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
apDayjs,
|
||||
getCorrectedFormat,
|
||||
optionalTimeFormats,
|
||||
parseDate,
|
||||
timeFormat,
|
||||
timeFormatDescription,
|
||||
timeParts,
|
||||
timeZoneOptions,
|
||||
} from '../common';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const addSubtractDateAction = createAction({
|
||||
name: 'add_subtract_date',
|
||||
displayName: 'Add/Subtract Time',
|
||||
description: 'Add or subtract time from a date',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
inputDate: Property.ShortText({
|
||||
displayName: 'Input Date',
|
||||
description: 'Enter the input date',
|
||||
required: true,
|
||||
}),
|
||||
inputDateFormat: Property.StaticDropdown({
|
||||
displayName: 'From Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: getCorrectedFormat(timeFormat.format00),
|
||||
}),
|
||||
outputFormat: Property.StaticDropdown({
|
||||
displayName: 'To Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: getCorrectedFormat(timeFormat.format00),
|
||||
}),
|
||||
expression: Property.LongText({
|
||||
displayName: 'Expression',
|
||||
description: `Provide an expression to add or subtract using the following units (year , month , day , hour , minute or second).
|
||||
\nExamples:\n+ 2 second + 1 hour \n+ 1 year - 3 day - 2 month \n+ 5 minute`,
|
||||
required: true,
|
||||
}),
|
||||
timeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'Time Zone',
|
||||
description: 'Optional: Set a timezone for the calculation to handle DST correctly',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: false,
|
||||
}),
|
||||
setTime: Property.ShortText({
|
||||
displayName: 'Set Time To (24h format)',
|
||||
description: 'Optional: Set the result to a specific time (e.g., "10:00" or "14:30"). This allows scheduling at a specific time after adding/subtracting dates. Leave empty to keep the calculated time.',
|
||||
required: false,
|
||||
}),
|
||||
useCurrentTime: Property.Checkbox({
|
||||
displayName: 'Use Current Time',
|
||||
description: 'If checked, the current time will be used instead of the time from "Set Time To" field.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
// Ensure all dayjs plugins are properly extended
|
||||
|
||||
|
||||
const inputDate = context.propsValue.inputDate;
|
||||
const inputDateFormat = getCorrectedFormat(context.propsValue.inputDateFormat);
|
||||
const outputFormat = getCorrectedFormat(context.propsValue.outputFormat);
|
||||
const expression = context.propsValue.expression;
|
||||
const timeZone = context.propsValue.timeZone as string | undefined;
|
||||
const setTime = context.propsValue.setTime as string | undefined;
|
||||
const useCurrentTime = context.propsValue.useCurrentTime as boolean;
|
||||
|
||||
if (setTime && setTime.trim() !== '') {
|
||||
await propsValidation.validateZod({ time: setTime }, {
|
||||
time: z.string().regex(/^\d\d:\d\d$/),
|
||||
});
|
||||
}
|
||||
|
||||
const BeforeDate = parseDate(inputDate, inputDateFormat);
|
||||
let AfterDate = addSubtractTime(BeforeDate.toDate(), expression, timeZone);
|
||||
|
||||
if (timeZone && (setTime || useCurrentTime)) {
|
||||
let timeToSet = setTime;
|
||||
|
||||
if (useCurrentTime) {
|
||||
const now = apDayjs().tz(timeZone);
|
||||
timeToSet = `${now.hour().toString().padStart(2, '0')}:${now.minute().toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
if (timeToSet && timeToSet.trim() !== '') {
|
||||
const [hours, minutes] = timeToSet.split(':').map(Number);
|
||||
|
||||
if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
|
||||
throw new Error(
|
||||
`Invalid time value - hours: ${hours} (must be 0-23), minutes: ${minutes} (must be 0-59)`
|
||||
);
|
||||
}
|
||||
|
||||
AfterDate = AfterDate.tz(timeZone).hour(hours).minute(minutes).second(0).millisecond(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeZone) {
|
||||
return { result: AfterDate.tz(timeZone).format(outputFormat) };
|
||||
} else {
|
||||
return { result: AfterDate.format(outputFormat) };
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function addSubtractTime(date: Date, expression: string, timeZone?: string): dayjs.Dayjs {
|
||||
// remove all the spaces and line breaks from the expression
|
||||
expression = expression.replace(/(\r\n|\n|\r)/gm, '').replace(/ /g, '');
|
||||
const parts = expression.split(/(\+|-)/);
|
||||
let sign = 1;
|
||||
const numbers = [];
|
||||
const units = [];
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
if (parts[i] === '+') sign = 1;
|
||||
else if (parts[i] === '-') sign = -1;
|
||||
else if (parts[i] === '') continue;
|
||||
let number = '';
|
||||
let unit = '';
|
||||
for (let j = 0; j < parts[i].length; j++) {
|
||||
if (parts[i][j] === ' ') continue;
|
||||
if (parts[i][j] >= '0' && parts[i][j] <= '9') {
|
||||
if (unit !== '') {
|
||||
numbers.push(sign * parseInt(number));
|
||||
units.push(unit);
|
||||
number = '';
|
||||
unit = '';
|
||||
}
|
||||
number += parts[i][j];
|
||||
} else {
|
||||
if (number === '') continue;
|
||||
unit += parts[i][j];
|
||||
}
|
||||
}
|
||||
if (unit !== '') {
|
||||
numbers.push(sign * parseInt(number));
|
||||
units.push(unit);
|
||||
}
|
||||
}
|
||||
|
||||
// Create timezone-aware dayjs object if timezone is provided
|
||||
let dayjsDate = timeZone ? apDayjs(date).tz(timeZone) : apDayjs(date);
|
||||
|
||||
for (let i = 0; i < numbers.length; i++) {
|
||||
const val = units[i].toLowerCase() as timeParts;
|
||||
switch (val) {
|
||||
case timeParts.year:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'year');
|
||||
break;
|
||||
case timeParts.month:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'month');
|
||||
break;
|
||||
case timeParts.day:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'day');
|
||||
break;
|
||||
case timeParts.hour:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'hour');
|
||||
break;
|
||||
case timeParts.minute:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'minute');
|
||||
break;
|
||||
case timeParts.second:
|
||||
dayjsDate = dayjsDate.add(numbers[i], 'second');
|
||||
break;
|
||||
case timeParts.dayOfWeek:
|
||||
case timeParts.monthName:
|
||||
case timeParts.unix_time:
|
||||
break;
|
||||
default: {
|
||||
const nvr: never = val;
|
||||
console.error(nvr, 'unhandled case was reached');
|
||||
}
|
||||
}
|
||||
}
|
||||
return dayjsDate;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework'
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
timeFormat,
|
||||
timeParts,
|
||||
timeFormatDescription,
|
||||
parseDate,
|
||||
getCorrectedFormat,
|
||||
apDayjs,
|
||||
} from '../common';
|
||||
|
||||
export const dateDifferenceAction = createAction({
|
||||
name: 'date_difference',
|
||||
displayName: 'Date Difference',
|
||||
description: 'Get the difference between two dates',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
startDate: Property.ShortText({
|
||||
displayName: 'Starting Date',
|
||||
description: 'Enter the starting date',
|
||||
required: true,
|
||||
}),
|
||||
startDateFormat: Property.StaticDropdown({
|
||||
displayName: 'Starting date format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
endDate: Property.ShortText({
|
||||
displayName: 'Ending Date',
|
||||
description: 'Enter the ending date',
|
||||
required: true,
|
||||
}),
|
||||
endDateFormat: Property.StaticDropdown({
|
||||
displayName: 'Ending date format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
unitDifference: Property.StaticMultiSelectDropdown({
|
||||
displayName: 'Unit',
|
||||
description: 'Select the unit of difference between the two dates',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Year', value: timeParts.year },
|
||||
{ label: 'Month', value: timeParts.month },
|
||||
{ label: 'Day', value: timeParts.day },
|
||||
{ label: 'Hour', value: timeParts.hour },
|
||||
{ label: 'Minute', value: timeParts.minute },
|
||||
{ label: 'Second', value: timeParts.second },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
defaultValue: [timeParts.year],
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
|
||||
const inputStartDate = context.propsValue.startDate;
|
||||
const startDateFormat = getCorrectedFormat(context.propsValue.startDateFormat);
|
||||
const inputEndDate = context.propsValue.endDate;
|
||||
const endDateFormat = getCorrectedFormat(context.propsValue.endDateFormat);
|
||||
const startDate = parseDate(inputStartDate, startDateFormat);
|
||||
const endDate = parseDate(inputEndDate, endDateFormat);
|
||||
|
||||
const unitDifference = context.propsValue.unitDifference;
|
||||
const difference = apDayjs.duration(endDate.diff(startDate));
|
||||
|
||||
const outputresponse: Record<string, number> = {};
|
||||
for (let i = 0; i < unitDifference.length; i++) {
|
||||
switch (unitDifference[i]) {
|
||||
case timeParts.year:
|
||||
outputresponse[timeParts.year] = difference.years();
|
||||
break;
|
||||
case timeParts.month:
|
||||
outputresponse[timeParts.month] = difference.months();
|
||||
break;
|
||||
case timeParts.day:
|
||||
outputresponse[timeParts.day] = difference.days();
|
||||
break;
|
||||
case timeParts.hour:
|
||||
outputresponse[timeParts.hour] = difference.hours();
|
||||
break;
|
||||
case timeParts.minute:
|
||||
outputresponse[timeParts.minute] = difference.minutes();
|
||||
break;
|
||||
case timeParts.second:
|
||||
outputresponse[timeParts.second] = difference.seconds();
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Invalid unit :\n${JSON.stringify(unitDifference[i])}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return outputresponse;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
timeFormat,
|
||||
timeParts,
|
||||
timeFormatDescription,
|
||||
parseDate,
|
||||
getCorrectedFormat,
|
||||
} from '../common';
|
||||
|
||||
export const extractDateParts = createAction({
|
||||
name: 'extract_date_parts',
|
||||
displayName: 'Extract Date Units',
|
||||
description:
|
||||
'Extract date units ( year , month , day , hour , minute , second , day of week , month name ) from a date',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
inputDate: Property.ShortText({
|
||||
displayName: 'Input Date',
|
||||
description: 'Enter the input date',
|
||||
required: true,
|
||||
}),
|
||||
inputFormat: Property.StaticDropdown({
|
||||
displayName: 'From Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
unitExtract: Property.StaticMultiSelectDropdown({
|
||||
displayName: 'Unit to Extract',
|
||||
description: 'Select the unit to extract from the date',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Year', value: timeParts.year },
|
||||
{ label: 'Month', value: timeParts.month },
|
||||
{ label: 'Day', value: timeParts.day },
|
||||
{ label: 'Hour', value: timeParts.hour },
|
||||
{ label: 'Minute', value: timeParts.minute },
|
||||
{ label: 'Second', value: timeParts.second },
|
||||
{ label: 'Day of Week', value: timeParts.dayOfWeek },
|
||||
{ label: 'Month name', value: timeParts.monthName },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
defaultValue: [timeParts.year],
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
|
||||
const inputDate = context.propsValue.inputDate;
|
||||
const inputFormat = getCorrectedFormat(context.propsValue.inputFormat);
|
||||
const unitExtract = context.propsValue.unitExtract;
|
||||
|
||||
const BeforeDate = parseDate(inputDate, inputFormat);
|
||||
const outputresponse: Record<string, any> = {};
|
||||
|
||||
for (let i = 0; i < unitExtract.length; i++) {
|
||||
switch (unitExtract[i]) {
|
||||
case timeParts.year:
|
||||
outputresponse[timeParts.year] = BeforeDate.year();
|
||||
break;
|
||||
case timeParts.month:
|
||||
// dayjs months are 0-indexed
|
||||
outputresponse[timeParts.month] = BeforeDate.month() + 1;
|
||||
break;
|
||||
case timeParts.day:
|
||||
outputresponse[timeParts.day] = BeforeDate.date();
|
||||
break;
|
||||
case timeParts.hour:
|
||||
outputresponse[timeParts.hour] = BeforeDate.hour();
|
||||
break;
|
||||
case timeParts.minute:
|
||||
outputresponse[timeParts.minute] = BeforeDate.minute();
|
||||
break;
|
||||
case timeParts.second:
|
||||
outputresponse[timeParts.second] = BeforeDate.second();
|
||||
break;
|
||||
case timeParts.dayOfWeek:
|
||||
outputresponse[timeParts.dayOfWeek] = BeforeDate.format('dddd');
|
||||
break;
|
||||
case timeParts.monthName:
|
||||
outputresponse[timeParts.monthName] = BeforeDate.format('MMMM');
|
||||
break;
|
||||
case timeParts.unix_time:
|
||||
default:
|
||||
throw new Error(
|
||||
`Invalid unit to extract :\n${JSON.stringify(unitExtract[i])}`
|
||||
);
|
||||
}
|
||||
}
|
||||
return outputresponse;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
parseDate,
|
||||
timeFormat,
|
||||
timeFormatDescription,
|
||||
timeZoneOptions,
|
||||
getCorrectedFormat,
|
||||
} from '../common';
|
||||
|
||||
export const formatDateAction = createAction({
|
||||
name: 'format_date',
|
||||
displayName: 'Format Date',
|
||||
description: 'Converts a date from one format to another',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
inputDate: Property.ShortText({
|
||||
displayName: 'Input Date',
|
||||
description: 'Enter the input date',
|
||||
required: true,
|
||||
}),
|
||||
inputFormat: Property.StaticDropdown({
|
||||
displayName: 'From Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
inputTimeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'From Time Zone',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: 'UTC',
|
||||
}),
|
||||
outputFormat: Property.StaticDropdown({
|
||||
displayName: 'To Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
outputTimeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'To Time Zone',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: 'UTC',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
|
||||
const inputDate = context.propsValue.inputDate;
|
||||
const inputFormat = getCorrectedFormat(context.propsValue.inputFormat);
|
||||
const inputTimeZone = context.propsValue.inputTimeZone as string;
|
||||
const outputFormat = getCorrectedFormat(context.propsValue.outputFormat);
|
||||
const outputTimeZone = context.propsValue.outputTimeZone as string;
|
||||
|
||||
return {
|
||||
result: changeDateFormat(
|
||||
inputDate,
|
||||
inputFormat,
|
||||
inputTimeZone,
|
||||
outputFormat,
|
||||
outputTimeZone
|
||||
),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
function changeDateFormat(
|
||||
inputDate: string,
|
||||
inputFormat: string,
|
||||
inputTimeZone: string,
|
||||
outputFormat: string,
|
||||
outputTimeZone: string
|
||||
): string {
|
||||
const parsedDate = parseDate(inputDate, inputFormat);
|
||||
|
||||
return parsedDate.tz(inputTimeZone, true).tz(outputTimeZone).format(outputFormat);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
timeFormat,
|
||||
timeFormatDescription,
|
||||
timeZoneOptions,
|
||||
getCorrectedFormat,
|
||||
apDayjs
|
||||
} from '../common';
|
||||
|
||||
export const getCurrentDate = createAction({
|
||||
name: 'get_current_date',
|
||||
displayName: 'Get Current Date',
|
||||
description: 'Get the current date',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
timeFormat: Property.StaticDropdown({
|
||||
displayName: 'To Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
timeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'Time Zone',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: 'UTC',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const timeFormat = getCorrectedFormat(context.propsValue.timeFormat);
|
||||
const timeZone = context.propsValue.timeZone;
|
||||
return { result: apDayjs().tz(timeZone).format(timeFormat) };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
Property,
|
||||
createAction,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
timeFormat,
|
||||
timeFormatDescription,
|
||||
timeZoneOptions,
|
||||
getCorrectedFormat,
|
||||
apDayjs,
|
||||
} from '../common';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const nextDayofWeek = createAction({
|
||||
name: 'next_day_of_week',
|
||||
displayName: 'Next Day of Week',
|
||||
description: 'Get the date and time of the next day of the week',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
weekday: Property.StaticDropdown({
|
||||
displayName: 'Weekday',
|
||||
description:
|
||||
'The weekday that you would like to get the date and time of.',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Sunday', value: 0 },
|
||||
{ label: 'Monday', value: 1 },
|
||||
{ label: 'Tuesday', value: 2 },
|
||||
{ label: 'Wednesday', value: 3 },
|
||||
{ label: 'Thursday', value: 4 },
|
||||
{ label: 'Friday', value: 5 },
|
||||
{ label: 'Saturday', value: 6 },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
}),
|
||||
time: Property.ShortText({
|
||||
displayName: '24h Time',
|
||||
description:
|
||||
'The time that you would like to get the date and time of. This must be in 24h format.',
|
||||
required: false,
|
||||
defaultValue: '00:00',
|
||||
}),
|
||||
currentTime: Property.Checkbox({
|
||||
displayName: 'Use Current Time',
|
||||
description:
|
||||
'If checked, the current time will be used instead of the time specified above.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
timeFormat: Property.StaticDropdown({
|
||||
displayName: 'To Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
timeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'Time Zone',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: 'UTC',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
time: z.string().regex(/^\d\d:\d\d$/),
|
||||
});
|
||||
|
||||
const timeFormat = getCorrectedFormat(context.propsValue.timeFormat);
|
||||
const timeZone = context.propsValue.timeZone as string;
|
||||
const dayIndex = context.propsValue.weekday as number;
|
||||
const currentTime = context.propsValue.currentTime as boolean;
|
||||
let time = context.propsValue.time as string;
|
||||
|
||||
let nextOccurrence = apDayjs().tz(timeZone);
|
||||
|
||||
if (currentTime === true) {
|
||||
time = `${nextOccurrence.hour()}:${nextOccurrence.minute()}`;
|
||||
}
|
||||
const [hours, minutes] = time.split(':').map(Number);
|
||||
|
||||
// Validate inputs
|
||||
if (
|
||||
dayIndex < 0 ||
|
||||
dayIndex > 6 ||
|
||||
hours < 0 ||
|
||||
hours > 23 ||
|
||||
minutes < 0 ||
|
||||
minutes > 59
|
||||
) {
|
||||
throw new Error(
|
||||
`Invalid input \ndayIndex: ${dayIndex} \nhours: ${hours} \nminutes: ${minutes}`
|
||||
);
|
||||
}
|
||||
|
||||
// Set the time
|
||||
nextOccurrence = nextOccurrence.hour(hours).minute(minutes).second(0).millisecond(0);
|
||||
|
||||
// Calculate the day difference
|
||||
let dayDiff = dayIndex - nextOccurrence.day();
|
||||
if (
|
||||
dayDiff < 0 ||
|
||||
(dayDiff === 0 && nextOccurrence.isBefore(apDayjs().tz(timeZone)))
|
||||
) {
|
||||
// If it's a past day in the week or today but past time, move to next week
|
||||
dayDiff += 7;
|
||||
}
|
||||
// Set the date to the next occurrence of the given day
|
||||
nextOccurrence = nextOccurrence.add(dayDiff, 'day');
|
||||
|
||||
return { result: nextOccurrence.format(timeFormat) };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,130 @@
|
||||
import {
|
||||
Property,
|
||||
createAction,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import {
|
||||
optionalTimeFormats,
|
||||
timeFormat,
|
||||
timeFormatDescription,
|
||||
timeZoneOptions,
|
||||
getCorrectedFormat,
|
||||
apDayjs,
|
||||
} from '../common';
|
||||
import { z } from 'zod';
|
||||
import { propsValidation } from '@activepieces/pieces-common';
|
||||
|
||||
export const nextDayofYear = createAction({
|
||||
name: 'next_day_of_year',
|
||||
displayName: 'Next Day of Year',
|
||||
description: 'Get the date and time of the next day of the year',
|
||||
errorHandlingOptions: {
|
||||
continueOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
retryOnFailure: {
|
||||
hide: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
month: Property.StaticDropdown({
|
||||
displayName: 'Month',
|
||||
description: 'The month that you would like to get the date and time of.',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'January', value: 1 },
|
||||
{ label: 'February', value: 2 },
|
||||
{ label: 'March', value: 3 },
|
||||
{ label: 'April', value: 4 },
|
||||
{ label: 'May', value: 5 },
|
||||
{ label: 'June', value: 6 },
|
||||
{ label: 'July', value: 7 },
|
||||
{ label: 'August', value: 8 },
|
||||
{ label: 'September', value: 9 },
|
||||
{ label: 'October', value: 10 },
|
||||
{ label: 'November', value: 11 },
|
||||
{ label: 'December', value: 12 },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
}),
|
||||
day: Property.Number({
|
||||
displayName: 'Day of Month',
|
||||
description:
|
||||
'The day of the month that you would like to get the date and time of.',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
time: Property.ShortText({
|
||||
displayName: '24h Time',
|
||||
description:
|
||||
'The time that you would like to get the date and time of. This must be in 24h format.',
|
||||
required: false,
|
||||
defaultValue: '00:00',
|
||||
}),
|
||||
currentTime: Property.Checkbox({
|
||||
displayName: 'Use Current Time',
|
||||
description:
|
||||
'If checked, the current time will be used instead of the time specified above.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
timeFormat: Property.StaticDropdown({
|
||||
displayName: 'To Time Format',
|
||||
description: timeFormatDescription,
|
||||
options: {
|
||||
options: optionalTimeFormats,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: timeFormat.format00,
|
||||
}),
|
||||
timeZone: Property.StaticDropdown<string>({
|
||||
displayName: 'Time Zone',
|
||||
options: {
|
||||
options: timeZoneOptions,
|
||||
},
|
||||
required: true,
|
||||
defaultValue: 'UTC',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
await propsValidation.validateZod(context.propsValue, {
|
||||
day: z.number().min(1).max(31),
|
||||
time: z.string().regex(/^\d\d:\d\d$/),
|
||||
});
|
||||
|
||||
const timeFormat = getCorrectedFormat(context.propsValue.timeFormat);
|
||||
const timeZone = context.propsValue.timeZone as string;
|
||||
const currentTime = context.propsValue.currentTime as boolean;
|
||||
const month = context.propsValue.month as number;
|
||||
const day = context.propsValue.day as number;
|
||||
let time = context.propsValue.time as string;
|
||||
|
||||
let nextOccurrence = apDayjs().tz(timeZone);
|
||||
|
||||
if (currentTime === true) {
|
||||
time = `${nextOccurrence.hour()}:${nextOccurrence.minute()}`;
|
||||
}
|
||||
const [hours, minutes] = time.split(':').map(Number);
|
||||
|
||||
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
||||
throw new Error(`Invalid input \nmonth: ${month} \nday: ${day}`);
|
||||
}
|
||||
|
||||
const currentYear = nextOccurrence.year();
|
||||
|
||||
nextOccurrence = apDayjs().tz(timeZone)
|
||||
.year(currentYear)
|
||||
.month(month - 1)
|
||||
.date(day)
|
||||
.hour(hours)
|
||||
.minute(minutes)
|
||||
.second(0)
|
||||
.millisecond(0);
|
||||
|
||||
if (nextOccurrence.isBefore(apDayjs().tz(timeZone))) {
|
||||
nextOccurrence = nextOccurrence.add(1, 'year');
|
||||
}
|
||||
|
||||
return { result: nextOccurrence.format(timeFormat) };
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user