diff --git a/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts b/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts index 38032890b1..e0724e9fae 100644 --- a/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts +++ b/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts @@ -11,6 +11,7 @@ import { } from 'n8n-workflow'; import { clickupApiRequest, + clickupApiRequestAllItems, } from './GenericFunctions'; import { taskFields, @@ -298,6 +299,58 @@ export class ClickUp implements INodeType { const taskId = this.getNodeParameter('id', i) as string; responseData = await clickupApiRequest.call(this, 'GET', `/task/${taskId}`); } + if (operation === 'getAll') { + const returnAll = true; + //const returnAll = this.getNodeParameter('returnAll', i) as boolean; + const filters = this.getNodeParameter('filters', i) as IDataObject; + if (filters.archived) { + qs.archived = filters.archived as boolean; + } + if (filters.subtasks) { + qs.subtasks = filters.subtasks as boolean; + } + if (filters.includeClosed) { + qs.include_closed = filters.includeClosed as boolean; + } + if (filters.orderBy) { + qs.order_by = filters.orderBy as string; + } + if (filters.statuses) { + qs.statuses = filters.statuses as string[]; + } + if (filters.assignees) { + qs.assignees = filters.assignees as string[]; + } + if (filters.tags) { + qs.tags = filters.tags as string[]; + } + if (filters.dueDateGt) { + qs.due_date_gt = new Date(filters.dueDateGt as string).getTime(); + } + if (filters.dueDateLt) { + qs.due_date_lt = new Date(filters.dueDateLt as string).getTime(); + } + if (filters.dateCreatedGt) { + qs.date_created_gt = new Date(filters.dateCreatedGt as string).getTime(); + } + if (filters.dateCreatedLt) { + qs.date_created_lt = new Date(filters.dateCreatedLt as string).getTime(); + } + if (filters.dateUpdatedGt) { + qs.date_updated_gt = new Date(filters.dateUpdatedGt as string).getTime(); + } + if (filters.dateUpdatedLt) { + qs.date_updated_lt = new Date(filters.dateUpdatedLt as string).getTime(); + } + const listId = this.getNodeParameter('list', i) as string; + if (returnAll === true) { + responseData = await clickupApiRequestAllItems.call(this, 'tasks', 'GET', `/list/${listId}/task`, {}, qs); + } else { + // qs.limit = this.getNodeParameter('limit', i) as number; + // responseData = await clickupApiRequest.call(this, 'GET', `/list/${listId}/task`, {}, qs); + // responseData = responseData.tasks; + } + } if (operation === 'delete') { const taskId = this.getNodeParameter('id', i) as string; responseData = await clickupApiRequest.call(this, 'DELETE', `/task/${taskId}`, {}); diff --git a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts index 08375c5317..08965c29a0 100644 --- a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts @@ -7,6 +7,7 @@ import { IWebhookFunctions, } from 'n8n-core'; import { IDataObject } from 'n8n-workflow'; +import { response } from 'express'; export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('clickUpApi'); @@ -35,3 +36,22 @@ export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions throw new Error('ClickUp Error: ' + errorMessage); } } + +export async function clickupApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string ,method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + query.page = 0; + query.limit = 100; + + do { + responseData = await clickupApiRequest.call(this, method, resource, body, query); + returnData.push.apply(returnData, responseData[propertyName]); + query.page++; + } while ( + responseData[propertyName] && + responseData[propertyName].length !== 0 + ); + return returnData; +} diff --git a/packages/nodes-base/nodes/ClickUp/TaskDescription.ts b/packages/nodes-base/nodes/ClickUp/TaskDescription.ts index 62b8c570ff..c2ef973690 100644 --- a/packages/nodes-base/nodes/ClickUp/TaskDescription.ts +++ b/packages/nodes-base/nodes/ClickUp/TaskDescription.ts @@ -28,6 +28,11 @@ export const taskOperations = [ value: 'get', description: 'Get a task', }, + { + name: 'Get all', + value: 'getAll', + description: 'Get all tasks', + }, { name: 'Update', value: 'update', @@ -452,7 +457,332 @@ export const taskFields = [ description: 'Task ID', }, /* -------------------------------------------------------------------------- */ -/* task:delete */ +/* task:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Team', + name: 'team', + type: 'options', + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getTeams', + }, + required: true, + }, + { + displayName: 'Space', + name: 'space', + type: 'options', + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getSpaces', + loadOptionsDependsOn: [ + 'team', + ] + }, + required: true, + }, + { + displayName: 'Folderless List', + name: 'folderless', + type: 'boolean', + default: false, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + required: true, + }, + { + displayName: 'Folder', + name: 'folder', + type: 'options', + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + folderless: [ + false, + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getFolders', + loadOptionsDependsOn: [ + 'space', + ], + }, + required: true, + }, + { + displayName: 'List', + name: 'list', + type: 'options', + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + folderless: [ + true, + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getFolderlessLists', + loadOptionsDependsOn: [ + 'space', + ], + }, + required: true, + }, + { + displayName: 'List', + name: 'list', + type: 'options', + default: '', + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + folderless: [ + false, + ], + }, + }, + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'folder', + ] + }, + required: true, + }, + // { + // displayName: 'Return All', + // name: 'returnAll', + // type: 'boolean', + // displayOptions: { + // show: { + // resource: [ + // 'task', + // ], + // operation: [ + // 'getAll', + // ], + // }, + // }, + // default: true, + // description: 'If all results should be returned or only up to a given limit.', + // }, + // { + // displayName: 'Limit', + // name: 'limit', + // type: 'number', + // displayOptions: { + // show: { + // resource: [ + // 'task', + // ], + // operation: [ + // 'getAll', + // ], + // returnAll: [ + // false, + // ], + // }, + // }, + // typeOptions: { + // minValue: 1, + // maxValue: 100, + // }, + // default: 50, + // description: 'How many results to return.', + // }, + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + default: {}, + displayOptions: { + show: { + resource: [ + 'task', + ], + operation: [ + 'getAll', + ], + }, + }, + options: [ + { + displayName: 'Assignees', + name: 'assignees', + type: 'multiOptions', + loadOptionsDependsOn: [ + 'list', + ], + typeOptions: { + loadOptionsMethod: 'getAssignees', + }, + + default: [], + }, + { + displayName: 'Archived', + name: 'archived', + type: 'boolean', + default: false, + }, + { + displayName: 'Subtasks', + name: 'subtasks', + type: 'boolean', + default: false, + description: 'Include subtasks, default false', + }, + { + displayName: 'Include Closed', + name: 'includeClosed', + type: 'boolean', + default: false, + description: 'the api does not include closed tasks. Set this to true and dont send a status filter to include closed tasks', + }, + { + displayName: 'Order By', + name: 'orderBy', + type: 'options', + default: '', + options: [ + { + name: 'ID', + value: 'id', + }, + { + name: 'Created', + value: 'created', + }, + { + name: 'Updated', + value: 'updated', + }, + { + name: 'Due Date', + value: 'dueDate', + }, + ], + }, + { + displayName: 'Statuses', + name: 'statuses', + type: 'multiOptions', + loadOptionsDependsOn: [ + 'list', + ], + typeOptions: { + loadOptionsMethod: 'getStatuses', + }, + default: [], + }, + { + displayName: 'Tags', + name: 'tags', + type: 'multiOptions', + loadOptionsDependsOn: [ + 'space', + ], + typeOptions: { + loadOptionsMethod: 'getTags', + }, + default: [], + description: 'The array of tags applied to this task', + }, + { + displayName: 'Due Date Greater Than', + name: 'dueDateGt', + type: 'dateTime', + default: '', + description: 'Filter due date greater than', + }, + { + displayName: 'Due Date Less Than', + name: 'dueDateLt', + type: 'dateTime', + default: '', + description: 'Filter due date less than', + }, + { + displayName: 'Date Created Greater Than', + name: 'dateCreatedGt', + type: 'dateTime', + default: '', + description: 'Filter date created greater', + }, + { + displayName: 'Date Created Less Than', + name: 'dateCreatedLt', + type: 'dateTime', + default: '', + description: 'Filter date created less than posix time', + }, + { + displayName: 'Date Updated Greater Than', + name: 'dateUpdatedGt', + type: 'dateTime', + default: '', + description: 'Filter date updated greater than', + }, + { + displayName: 'Date Update Less Than', + name: 'dateUpdatedLt', + type: 'dateTime', + default: '', + description: 'Filter date updated less than', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* task:delete */ /* -------------------------------------------------------------------------- */ { displayName: 'ID',