From 42758988f2fc2c484906e21fe79668963970627d Mon Sep 17 00:00:00 2001 From: ricardo Date: Fri, 6 Nov 2020 20:18:10 -0500 Subject: [PATCH] :sparkles: Airtable Trigger --- .../nodes/Airtable/AirtableTrigger.node.ts | 148 ++++++++++++++++++ .../nodes/Airtable/GenericFunctions.ts | 6 +- packages/nodes-base/package.json | 1 + 3 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 packages/nodes-base/nodes/Airtable/AirtableTrigger.node.ts diff --git a/packages/nodes-base/nodes/Airtable/AirtableTrigger.node.ts b/packages/nodes-base/nodes/Airtable/AirtableTrigger.node.ts new file mode 100644 index 0000000000..b0136649e0 --- /dev/null +++ b/packages/nodes-base/nodes/Airtable/AirtableTrigger.node.ts @@ -0,0 +1,148 @@ +import { + IPollFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + apiRequestAllItems, +} from './GenericFunctions'; + +import * as moment from 'moment'; + +export class AirtableTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Airtable Trigger', + name: 'airtableTrigger', + icon: 'file:airtable.png', + group: ['trigger'], + version: 1, + description: 'Starts the workflow when Airtable events occur', + subtitle: '={{$parameter["event"]}}', + defaults: { + name: 'Airtable Trigger', + color: '#445599', + }, + credentials: [ + { + name: 'airtableApi', + required: true, + }, + ], + polling: true, + inputs: [], + outputs: ['main'], + properties: [ + { + displayName: 'Base ID', + name: 'baseId', + type: 'string', + default: '', + required: true, + }, + { + displayName: 'Table ID', + name: 'tableId', + type: 'string', + default: '', + required: true, + }, { + displayName: 'Trigger Field', + name: 'triggerField', + type: 'string', + default: '', + description: `A Created Time or Last Modified Time field that will be used to sort records.
+ If you do not have a Created Time or Last Modified Time field in your schema, please create one,
+ because without this field trigger will not work correctly.`, + required: true, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + options: [ + { + displayName: 'Fields', + name: 'fields', + type: 'string', + default: '', + description: `Fields to be included in the response.
+ Multiple ones can be set separated by comma. Example: name,id.
+ By default just the trigger field will be included.`, + }, + { + displayName: 'Formula', + name: 'formula', + type: 'string', + default: '', + description: '', + }, + { + displayName: 'View ID', + name: 'viewId', + type: 'string', + default: '', + description: '', + }, + ], + }, + ], + }; + + async poll(this: IPollFunctions): Promise { + + const webhookData = this.getWorkflowStaticData('node'); + + const qs: IDataObject = {}; + + const additionalFields = this.getNodeParameter('additionalFields') as IDataObject; + + const base = this.getNodeParameter('baseId') as string; + + const table = this.getNodeParameter('tableId') as string; + + const triggerField = this.getNodeParameter('triggerField') as string; + + const endpoint = `${base}/${table}`; + + const now = moment().utc().format(); + + const startDate = webhookData.lastTimeChecked as string || now; + + const endDate = now; + + qs['fields[]'] = [triggerField]; + + if (additionalFields.viewId) { + qs.view = additionalFields.viewId; + } + + if (additionalFields.fields) { + qs['fields[]'] = (additionalFields.fields as string).split(','); + } + + qs.filterByFormula = `IS_AFTER({${triggerField}}, DATETIME_PARSE("${startDate}", "YYYY-MM-DD HH:mm:ss"))`; + + if (additionalFields.formula) { + qs.filterByFormula = `AND(${qs.filterByFormula}, ${additionalFields.formula})`; + } + + const { records } = await apiRequestAllItems.call(this, 'GET', endpoint, {}, qs); + + webhookData.lastTimeChecked = endDate; + + if (Array.isArray(records) && records.length) { + + return [this.helpers.returnJsonArray(records)]; + } + + return null; + } +} diff --git a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts index dd9c0aab91..e5d53567e9 100644 --- a/packages/nodes-base/nodes/Airtable/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Airtable/GenericFunctions.ts @@ -5,7 +5,7 @@ import { } from 'n8n-core'; import { OptionsWithUri } from 'request'; -import { IDataObject } from 'n8n-workflow'; +import { IDataObject, IPollFunctions } from 'n8n-workflow'; /** @@ -17,7 +17,7 @@ import { IDataObject } from 'n8n-workflow'; * @param {object} body * @returns {Promise} */ -export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any +export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('airtableApi'); if (credentials === undefined) { @@ -77,7 +77,7 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa * @param {IDataObject} [query] * @returns {Promise} */ -export async function apiRequestAllItems(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any +export async function apiRequestAllItems(this: IHookFunctions | IExecuteFunctions | IPollFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise { // tslint:disable-line:no-any if (query === undefined) { query = {}; diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 29a0b90bb7..5e7fd2b583 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -215,6 +215,7 @@ "dist/nodes/ActiveCampaign/ActiveCampaignTrigger.node.js", "dist/nodes/AgileCrm/AgileCrm.node.js", "dist/nodes/Airtable/Airtable.node.js", + "dist/nodes/Airtable/AirtableTrigger.node.js", "dist/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.js", "dist/nodes/Amqp/Amqp.node.js", "dist/nodes/Amqp/AmqpTrigger.node.js",