Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Google Calendar Node): Start and End defaults for event.create and calendar.availability #12438

Closed
10 changes: 6 additions & 4 deletions packages/nodes-base/nodes/Google/Calendar/CalendarDescription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ export const calendarFields: INodeProperties[] = [
resource: ['calendar'],
},
},
default: '',
description: 'Start of the interval',
default: '={{ $now.toISO() }}',
description:
'Start of the interval, use <a href="https://docs.n8n.io/code/cookbook/luxon/" target="_blank">expression</a> to set a date, or switch to fixed mode to choose date from widget',
},
{
displayName: 'End Time',
Expand All @@ -100,8 +101,9 @@ export const calendarFields: INodeProperties[] = [
resource: ['calendar'],
},
},
default: '',
description: 'End of the interval',
default: "={{ $now.plus(1, 'hour').toISO() }}",
description:
'End of the interval, use <a href="https://docs.n8n.io/code/cookbook/luxon/" target="_blank">expression</a> to set a date, or switch to fixed mode to choose date from widget',
},
{
displayName: 'Options',
Expand Down
10 changes: 6 additions & 4 deletions packages/nodes-base/nodes/Google/Calendar/EventDescription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ export const eventFields: INodeProperties[] = [
resource: ['event'],
},
},
default: '',
description: 'Start time of the event',
default: '={{ $now.toISO() }}',
description:
'Start time of the event, use <a href="https://docs.n8n.io/code/cookbook/luxon/" target="_blank">expression</a> to set a date, or switch to fixed mode to choose date from widget',
},
{
displayName: 'End',
Expand All @@ -128,8 +129,9 @@ export const eventFields: INodeProperties[] = [
resource: ['event'],
},
},
default: '',
description: 'End time of the event',
default: "={{ $now.plus(1, 'hour').toISO() }}",
description:
'End time of the event, use <a href="https://docs.n8n.io/code/cookbook/luxon/" target="_blank">expression</a> to set a date, or switch to fixed mode to choose date from widget',
},
{
displayName: 'Use Default Reminders',
Expand Down
6 changes: 6 additions & 0 deletions packages/nodes-base/nodes/Google/Calendar/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DateTime } from 'luxon';
import moment from 'moment-timezone';
import type {
IDataObject,
Expand Down Expand Up @@ -193,3 +194,8 @@ export function addTimezoneToDate(date: string, timezone: string) {
if (hasTimezone(date)) return date;
return moment.tz(date, timezone).utc().format();
}

export function dateTimeToIso<T>(date: T): string {
if (date instanceof DateTime) return date.toISO();
return date as string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type { IEvent } from './EventInterface';
import {
addNextOccurrence,
addTimezoneToDate,
dateTimeToIso,
encodeURIComponentOnce,
getCalendars,
getTimezones,
Expand Down Expand Up @@ -148,8 +149,8 @@ export class GoogleCalendar implements INodeType {
const calendarId = decodeURIComponent(
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
);
const timeMin = this.getNodeParameter('timeMin', i) as string;
const timeMax = this.getNodeParameter('timeMax', i) as string;
const timeMin = dateTimeToIso(this.getNodeParameter('timeMin', i));
const timeMax = dateTimeToIso(this.getNodeParameter('timeMax', i));
const options = this.getNodeParameter('options', i);
const outputFormat = options.outputFormat || 'availability';
const tz = this.getNodeParameter('options.timezone', i, '', {
Expand Down Expand Up @@ -200,8 +201,8 @@ export class GoogleCalendar implements INodeType {
const calendarId = encodeURIComponentOnce(
this.getNodeParameter('calendar', i, '', { extractValue: true }) as string,
);
const start = this.getNodeParameter('start', i) as string;
const end = this.getNodeParameter('end', i) as string;
const start = dateTimeToIso(this.getNodeParameter('start', i));
const end = dateTimeToIso(this.getNodeParameter('end', i));
const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean;
const additionalFields = this.getNodeParameter('additionalFields', i);

Expand Down
2 changes: 1 addition & 1 deletion packages/workflow/src/NodeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,7 @@ function addToIssuesIfMissing(
if (
(nodeProperties.type === 'string' && (value === '' || value === undefined)) ||
(nodeProperties.type === 'multiOptions' && Array.isArray(value) && value.length === 0) ||
(nodeProperties.type === 'dateTime' && value === undefined) ||
(nodeProperties.type === 'dateTime' && (value === '' || value === undefined)) ||
(nodeProperties.type === 'options' && (value === '' || value === undefined)) ||
((nodeProperties.type === 'resourceLocator' || nodeProperties.type === 'workflowSelector') &&
!isValidResourceLocatorParameterValue(value as INodeParameterResourceLocator))
Expand Down
53 changes: 53 additions & 0 deletions packages/workflow/test/NodeHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4195,4 +4195,57 @@ describe('NodeHelpers', () => {
});
}
});

describe('getParameterIssues, required parameters validation', () => {
const testNode: INode = {
id: '12345',
name: 'Test Node',
typeVersion: 1,
type: 'n8n-nodes-base.testNode',
position: [1, 1],
parameters: {},
};

it('Should validate required dateTime parameters if empty string', () => {
const nodeProperties: INodeProperties = {
displayName: 'Date Time',
name: 'testDateTime',
type: 'dateTime',
default: '',
required: true,
};
const nodeValues: INodeParameters = {
testDateTime: '',
};

const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);

expect(result).toEqual({
parameters: {
testDateTime: ['Parameter "Date Time" is required.'],
},
});
});

it('Should validate required dateTime parameters if empty undefined', () => {
const nodeProperties: INodeProperties = {
displayName: 'Date Time',
name: 'testDateTime',
type: 'dateTime',
default: '',
required: true,
};
const nodeValues: INodeParameters = {
testDateTime: undefined,
};

const result = getParameterIssues(nodeProperties, nodeValues, '', testNode);

expect(result).toEqual({
parameters: {
testDateTime: ['Parameter "Date Time" is required.'],
},
});
});
});
});
Loading