From 9320d415d63fce7eb02cc350c2041c111ef2aaba Mon Sep 17 00:00:00 2001 From: ricardo Date: Thu, 26 Mar 2020 15:39:31 -0400 Subject: [PATCH 1/2] :sparkles: Monday.com node --- .../credentials/MondayApi.credentials.ts | 17 + .../nodes/Monday/BoardDescription.ts | 619 ++++++++++++++++++ .../nodes/Monday/GenericFunctions.ts | 62 ++ .../nodes-base/nodes/Monday/Monday.node.ts | 409 ++++++++++++ packages/nodes-base/nodes/Monday/monday.png | Bin 0 -> 4407 bytes packages/nodes-base/package.json | 6 +- 6 files changed, 1111 insertions(+), 2 deletions(-) create mode 100644 packages/nodes-base/credentials/MondayApi.credentials.ts create mode 100644 packages/nodes-base/nodes/Monday/BoardDescription.ts create mode 100644 packages/nodes-base/nodes/Monday/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/Monday/Monday.node.ts create mode 100644 packages/nodes-base/nodes/Monday/monday.png diff --git a/packages/nodes-base/credentials/MondayApi.credentials.ts b/packages/nodes-base/credentials/MondayApi.credentials.ts new file mode 100644 index 0000000000..69ebed1398 --- /dev/null +++ b/packages/nodes-base/credentials/MondayApi.credentials.ts @@ -0,0 +1,17 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class MondayApi implements ICredentialType { + name = 'mondayApi'; + displayName = 'Monday.com API'; + properties = [ + { + displayName: 'Token V2', + name: 'apiToken', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Monday/BoardDescription.ts b/packages/nodes-base/nodes/Monday/BoardDescription.ts new file mode 100644 index 0000000000..48328cd419 --- /dev/null +++ b/packages/nodes-base/nodes/Monday/BoardDescription.ts @@ -0,0 +1,619 @@ +import { INodeProperties } from "n8n-workflow"; + +export const boardOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'board', + ], + }, + }, + options: [ + { + name: 'Add Column', + value: 'addColumn', + description: 'Add column to a board', + }, + { + name: 'Archive', + value: 'archive', + description: 'Archive a board', + }, + { + name: 'Create', + value: 'create', + description: 'Create a new board', + }, + { + name: 'Create Group', + value: 'createGroup', + description: 'Create a group in a board', + }, + { + name: 'Create Item', + value: 'createItem', + description: `Create a item in a board's group`, + }, + { + name: 'Get', + value: 'get', + description: 'Get a board', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all boards', + }, + { + name: 'Get Columns', + value: 'getColumns', + description: `Get board's columns`, + }, + { + name: 'Get Groups', + value: 'getGroups', + description: `Get board's groups`, + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const boardFields = [ +/* -------------------------------------------------------------------------- */ +/* board:addColumn */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'addColumn', + ], + }, + }, + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'addColumn', + ], + }, + }, + }, + { + displayName: 'Column Type', + name: 'columnType', + type: 'options', + options: [ + { + name: 'Country', + value: 'country', + }, + { + name: 'Checkbox', + value: 'checkbox', + }, + { + name: 'Date', + value: 'date', + }, + { + name: 'Dropdown', + value: 'dropdown', + }, + { + name: 'Email', + value: 'email', + }, + { + name: 'Hour', + value: 'hour', + }, + { + name: 'Link', + value: 'Link', + }, + { + name: 'Long Text', + value: 'longText', + }, + { + name: 'Numbers', + value: 'numbers', + }, + { + name: 'People', + value: 'people', + }, + { + name: 'Person', + value: 'person', + }, + { + name: 'Phone', + value: 'phone', + }, + { + name: 'Rating', + value: 'rating', + }, + { + name: 'Status', + value: 'status', + }, + { + name: 'Tags', + value: 'tags', + }, + { + name: 'Team', + value: 'team', + }, + { + name: 'Text', + value: 'text', + }, + { + name: 'Timeline', + value: 'timeline', + }, + { + name: 'Timezone', + value: 'timezone', + }, + { + name: 'Week', + value: 'week', + }, + { + name: 'World Clock', + value: 'worldClock', + }, + ], + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'addColumn', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'addColumn', + ], + resource: [ + 'board', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Defauls', + name: 'defaults', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: `The new column's defaults.`, + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* board:archive */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'archive', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* board:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + default: '', + description: `The board's name`, + }, + { + displayName: 'Kind', + name: 'kind', + type: 'options', + options: [ + { + name: 'Share', + value: 'share', + }, + { + name: 'Public', + value: 'public', + }, + { + name: 'Private', + value: 'private', + }, + ], + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + default: '', + description: `The board's kind (public / private / share)`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Template ID', + name: 'templateId', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: 0, + description: 'Optional board template id', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* board:createGroup */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'createGroup', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'createGroup', + ], + resource: [ + 'board', + ], + }, + }, + default: '', + description: `The group name`, + }, +/* -------------------------------------------------------------------------- */ +/* board:createItem */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'createItem', + ], + }, + }, + }, + { + displayName: 'Group ID', + name: 'groupId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getGroups', + loadOptionsDependsOn: 'boardId', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'createItem', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'createItem', + ], + resource: [ + 'board', + ], + }, + }, + default: '', + description: `The new item's name.`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'createItem', + ], + resource: [ + 'board', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Column Values', + name: 'columnValues', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: 'The column values of the new item', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* board:deleteGroup */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'deleteGroup', + ], + }, + }, + }, + { + displayName: 'Group ID', + name: 'groupId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getGroups', + loadOptionsDependsOn: 'boardId', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'deleteGroup', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* board:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'string', + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'get', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* board:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +/* -------------------------------------------------------------------------- */ +/* board:getColumns */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'getColumns', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* board:getGroups */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'board', + ], + operation: [ + 'getGroups', + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Monday/GenericFunctions.ts b/packages/nodes-base/nodes/Monday/GenericFunctions.ts new file mode 100644 index 0000000000..51fed16f84 --- /dev/null +++ b/packages/nodes-base/nodes/Monday/GenericFunctions.ts @@ -0,0 +1,62 @@ +import { OptionsWithUri } from 'request'; + +import { + IExecuteFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { + IDataObject, + IHookFunctions, + IWebhookFunctions +} from 'n8n-workflow'; + +export async function mondayApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, body: any = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const credentials = this.getCredentials('mondayApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const endpoint = 'https://api.monday.com/v2/'; + + let options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': credentials.apiToken, + }, + method: 'POST', + body, + uri: endpoint, + json: true + }; + options = Object.assign({}, options, option); + try { + return await this.helpers.request!(options); + } catch (error) { + if (error.response) { + const errorMessage = error.response.body.error_message; + throw new Error(`Monday error response [${error.statusCode}]: ${errorMessage}`); + } + throw error; + } +} + +export async function mondayApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, body: any = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + body.variables.limit = 50; + body.variables.page = 1; + + do { + responseData = await mondayApiRequest.call(this, body); + returnData.push.apply(returnData, responseData['data'][propertyName]); + body.variables.page++; + } while ( + responseData['data'][propertyName].length > 0 + ); + return returnData; +} diff --git a/packages/nodes-base/nodes/Monday/Monday.node.ts b/packages/nodes-base/nodes/Monday/Monday.node.ts new file mode 100644 index 0000000000..37e3dad512 --- /dev/null +++ b/packages/nodes-base/nodes/Monday/Monday.node.ts @@ -0,0 +1,409 @@ +import { + BINARY_ENCODING, + IExecuteFunctions, +} from 'n8n-core'; +import { + IDataObject, + ILoadOptionsFunctions, + INodeTypeDescription, + INodeExecutionData, + INodeType, + INodePropertyOptions, +} from 'n8n-workflow'; + +import { + mondayApiRequest, + mondayApiRequestAllItems, +} from './GenericFunctions'; + +import { + boardFields, + boardOperations, +} from './BoardDescription'; + +import { snakeCase } from 'change-case'; + +interface IGraphqlBody { + query: string; + variables: IDataObject; +} + +export class Monday implements INodeType { + description: INodeTypeDescription = { + displayName: 'Monday.com', + name: 'monday.com', + icon: 'file:monday.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume Monday.com API', + defaults: { + name: 'Monday.com', + color: '#000000', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'mondayApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Board', + value: 'board', + }, + ], + default: 'board', + description: 'Resource to consume.', + }, + ...boardOperations, + ...boardFields, + ], + }; + + methods = { + loadOptions: { + // Get all the available boards to display them to user so that he can + // select them easily + async getBoards(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const body = { + query: + `query ($page: Int, $limit: Int) { + boards (page: $page, limit: $limit){ + id + description + name + } + }`, + variables: { + page: 1, + }, + }; + const boards = await mondayApiRequestAllItems.call(this, 'boards', body); + for (const board of boards) { + const boardName = board.name; + const boardId = board.id; + const boardDescription = board.description; + returnData.push({ + name: boardName, + value: boardId, + description: boardDescription, + }); + } + return returnData; + }, + // Get all the available groups to display them to user so that he can + // select them easily + async getGroups(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = parseInt(this.getCurrentNodeParameter('boardId') as string, 10); + const body = { + query: + `query ($boardId: Int!) { + boards ( ids: [$boardId]){ + groups () { + id + title + } + } + }`, + variables: { + boardId, + }, + }; + const { data } = await mondayApiRequest.call(this, body); + const groups = data.boards[0].groups; + for (const group of groups) { + const groupName = group.title; + const groupId = group.id; + returnData.push({ + name: groupName, + value: groupId, + }); + } + return returnData; + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + let responseData; + const qs: IDataObject = {}; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < length; i++) { + if (resource === 'board') { + if (operation === 'addColumn') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const title = this.getNodeParameter('title', i) as string; + const columnType = this.getNodeParameter('columnType', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $title: String!, $columnType: ColumnType, $defaults: JSON ) { + create_column (board_id: $boardId, title: $title, column_type: $columnType, defaults: $defaults) { + id + } + }`, + variables: { + boardId, + title, + columnType: snakeCase(columnType), + }, + }; + + if (additionalFields.defaults) { + try { + JSON.parse(additionalFields.defaults as string); + } catch (e) { + throw new Error('Defauls must be a valid JSON'); + } + body.variables.defaults = JSON.stringify(JSON.parse(additionalFields.defaults as string)); + } + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_column; + } + if (operation === 'archive') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + + const body: IGraphqlBody = { + query: + `mutation ($id: Int!) { + archive_board (board_id: $id) { + id + } + }`, + variables: { + id: boardId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.archive_board; + } + if (operation === 'create') { + const name = this.getNodeParameter('name', i) as string; + const kind = this.getNodeParameter('kind', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const body: IGraphqlBody = { + query: + `mutation ($name: String!, $kind: BoardKind!, $templateId: Int) { + create_board (board_name: $name, board_kind: $kind, template_id: $templateId) { + id + } + }`, + variables: { + name, + kind, + }, + }; + + if (additionalFields.templateId) { + body.variables.templateId = additionalFields.templateId as number; + } + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_board; + } + if (operation === 'createGroup') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const name = this.getNodeParameter('name', i) as string; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupName: String!) { + create_group (board_id: $boardId, group_name: $groupName) { + id + } + }`, + variables: { + boardId, + groupName: name, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_group; + } + if (operation === 'createItem') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const groupId = this.getNodeParameter('groupId', i) as string; + const itemName = this.getNodeParameter('name', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupId: String!, $itemName: String!, $columnValues: JSON) { + create_item (board_id: $boardId, group_id: $groupId, item_name: $itemName, column_values: $columnValues) { + id + } + }`, + variables: { + boardId, + groupId, + itemName, + }, + }; + + if (additionalFields.columnValues) { + try { + JSON.parse(additionalFields.columnValues as string); + } catch (e) { + throw new Error('Custom Values must be a valid JSON'); + } + body.variables.columnValues = JSON.stringify(JSON.parse(additionalFields.columnValues as string)); + } + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_item; + } + if (operation === 'deleteGroup') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const groupId = this.getNodeParameter('groupId', i) as string; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupId: String!) { + delete_group (board_id: $boardId, group_id: $groupId) { + id + } + }`, + variables: { + boardId, + groupId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.delete_group; + } + if (operation === 'get') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + + const body: IGraphqlBody = { + query: + `query ($id: [Int]) { + boards (ids: $id){ + id + name + description + state + board_folder_id + board_kind + owner() { + id + } + } + }`, + variables: { + id: boardId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.boards; + } + if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + const body: IGraphqlBody = { + query: + `query ($page: Int, $limit: Int) { + boards (page: $page, limit: $limit){ + id + name + description + state + board_folder_id + board_kind + owner() { + id + } + } + }`, + variables: { + page: 1, + }, + }; + + if (returnAll === true) { + responseData = await mondayApiRequestAllItems.call(this, 'boards', body); + } else { + body.variables.limit = this.getNodeParameter('limit', i) as number, + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.boards; + } + } + if (operation === 'getColumns') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + + const body: IGraphqlBody = { + query: + `query ($boardId: [Int]) { + boards (ids: $boardId){ + columns() { + id + title + type + settings_str + archived + } + } + }`, + variables: { + page: 1, + boardId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.boards[0].columns; + } + if (operation === 'getGroups') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + + const body: IGraphqlBody = { + query: + `query ($boardId: [Int]) { + boards (ids: $boardId, ){ + id + groups() { + title + color + position + archived + } + } + }`, + variables: { + boardId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.boards[0].groups; + } + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Monday/monday.png b/packages/nodes-base/nodes/Monday/monday.png new file mode 100644 index 0000000000000000000000000000000000000000..4246ff07d57297a892e2a5f98585599fc514168e GIT binary patch literal 4407 zcma)Ac|6o@_Z|~jN;I;Bm_|a`#u~Od3xUW{obE@&iS4>*LBWyKKDI;Oqe;^kef@G3jhFc8yo3a zFs;G%=Ge*n^pGD9W*QcXg`qB>xKnhN`BH$jF?K0GQ2>~?CetNgsTi;~;i5Z5(_0(zB}0?xZ-*5i z;4djuH*JUw${dU&lCfY_c@=p@2%HNH2E)kCE}9m42H)V!H*LrTDwU+Epg^P1_^cG>zRURE)b5)>seD49Mg0&YF7q zNL7R`LIa_pfrLW!)pe07YI^$ms>)CmMOAgA8cg9I(4S-cMyrP<T^sUU{IAVy_w!|Xn)rYAql-{hgR1H)A~cxxxBdJB`m>*(%+5q7PXgAR`c0|x zPo>BHUFlcmU!XskzmMS;sb9|R*W>hk4*yyd@$W^yj#uv|^p~RB2SD=#8P61g**?v1 zC`{oWv0w6;T$)HS7DFYHEs4a7@c-%8;fu8Y2m8hdQ`o*dzg(uTH}y-Dc~#+DOyu`# z59cE074HWCcC#4kAuPRF=IwkVEUgc0cBZwICdfHfb>B$HO15Iy<%!& z(WjkRoJN;X*47M%b5D3uuZC)MJDd~ob5cCybFiwWwEv>7FU;sxf^9}-2xD-sY!@Ua zgU$1WV}PR}_tRPHvr=@lNIY6_E}_cqHFqjvw>#@a(dWLq-oNmQU!OYDW26$k`gZ_u zr(a$*_q%rLzBw0_OnzlYXnH@WFD-DXCRKRZ8tVm^l&K z5;T3P(p$3j!BTCO1@yhR*W01fMrv}%gI)O>N`4TCw?}w$W6bOJKjaBb5z!q2kr-oz zjH15OMnB6_A26JDckK>7$v3cJKi<)OdnCdoKHfV~vbV#TelS^#?Rj702)dv;A&Ftq z%3FGI@JjHG?1^)1k~fcn5`g-~$5qZqM(=Ty0K0d$#0d+AX)BBTq_`bonKTH&ZZ z*qo<|47Uoh$}i2mIx?t?wmOC3A4dVhU-*QP$`rhUllx^y}>Zah9yzE-`*>!xD<~ST7lnHtd z^`cu5G>#OaO?wkN2OqyaT+a~2rN|t5}->^S;vO%>ImjxK(Y6gAT>5hty^%#8amdlMQ}{=kxuAQ47BK}U~4enMG7cn z62wMZRsfkyo@-Wl+g(92_>8Q44c6v#y{$Ffm8-$6U0>{eJoBk-WALj} z5|xu~k`XG&Z+7YJZC5JWm|1+m?xLFVk~nF3)iCtvJG&|IG11CCLbuvce7NDP^$DyUZTe1QyZRCN;)@~liTt3#U(*Xz{eHQMT4flSvC5YR4%#X%+3jeYmB zCmeYY``fzsRoJaK=dBx6uRmymM7rFP8zP0zwHb4>NR%nD>T9Xg+p_Yw>fGKVIPFp9 zG|W=vhye0j>^3*p?}p#g!R;Z?Eg7b>7to`*q#j=m_Q53D^Cf^XV%)aLy0+`CR zA$`glAqY;RL*lPcs(or#tA=S*q2JNaha9=8>U}mgr*h=z`d7*)WLG?3OO9}aPAj_@ z{qsRF{wSRutw@myx+6SVomI#+=6PYH`7r;0lOZ&7(4wO+PU>o{t)Cbnd@!JK?kx-* zpT$Y=pf^e3JeWgLo^urt>XE!NZamE5Sy_{zxb|%3(N&}}jV}S2P$}-SrMRcdk24gm zb$xVCHShFkK_O?QV)T${Z*a3(vu)l8qf&8bIHzhEpVryqBy2K&PIi)2YPs41_Ua^8Jh=%uA%=*6n=5hIL==t1Y=s&ZY5FX>Vyy zrzL?v3zTEu*b!WcR_wgEdqkP^fx|dV24hoq);e-b3B2%lF$O7|you*(IkNOE9p02-l8c4ak9=4Cl@W7e0%$fDp<>4B#_@&4`<&BFCW408_w#Jj}S+$77 zE{9oC32tzIwnT^yV#lQ50o?4mmi#%JV(gmOy@==f++9huFu@d&5ATe1%ScIODz`-G zJ8;VptsIN7EBq_G5}7=29nVf*%3a1Rm2X;~we@X1$dlLFrQ>K054;EO9}z+19(`2D zDK3j6MUe#D1XAakcY*pVACn8um@9t*4>)9n#7nVHcN!l*pEF)bPTIH38a^;>-!^lM zEoalJ{$06Yv!+-{xum6AOtI!wN5`xOhoW(bQOWsw*KL5 zUUVD99y+oZ>KY_*)Gb0UbJ=pB>2tFcJg{TTq5b%&D>?UJ-5l=)uYX*5t(Hb+$xUr6 zck@kGHzD^6^oEouL`N9@H5#)wf9QVBD({O zAj@N0-jGIR#a$BLzB`h{LggA6TTAazHPrUeruOvwCERbCItyt9Qr8#b-x>QSk{dH3BW&jv(jS0t@%Q&i-Y}1QRT^Es z#d#;rKSwmAQCMz4de%6iBHZHqta->|tD9y~0oh>-AH<6`lAlhT^zAQ}qfHCi9@^WA zo4>p?Ij96|MuBpd|BgJKO@7s8SQeE1oYf#oC}G`;Ry-3N7~x!IA7&!LS*E1AIm-z8 zn20H&#Hq(DXNj!JDbd5T46jFs4y}0h!o;RxD_AYU4)HHpx~H=ihrvRN_OHFwuTjq2 zyaw?-*nNZZ%vw*re6x|O+ZD_M3$c`l0QL9M_rj1BUU2tURI@d74;;+h=w+_jX*O|f z-@EY1lLo?LDxwIV&V6--7e0n)Pr5p&4L|;)#xGgbDEUc@r>CwQY9iIo0TlpYkM}p$ zyEzeNFS^_z#VGM(j9O!AMNpQg@h9!;hgjWO$%d=$XX*C=xLw4uwGC*%Ao0Kk_fGw+ z0XBmp4}6~RjOLE03!GyFIf%~)Zei=HJJtxW*{zzSwnQ#f)JPC$N6^8{nXRsv)CD$m z-{iJ@R2IF^1_HmJ6*b1Te*F5wj7l_z*Q@zFhqV51OaOa}TA0&>3;@l@9ex)lqPRfA zHCzIzEEKE*(Is8^c0tIoY(Jfo{TEZH{Z}kpYL*a$;qLm3xsixJrfT?+u4elF>OKbp zr$_pIWGVAwdKaTxx=Ky{m+Vuo!Q&}3mEI8^@?>Julye!f<@5) literal 0 HcmV?d00001 diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 61f9e7eda2..78cf3e8b80 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -74,7 +74,8 @@ "dist/credentials/MandrillApi.credentials.js", "dist/credentials/MattermostApi.credentials.js", "dist/credentials/MauticApi.credentials.js", - "dist/credentials/MoceanApi.credentials.js", + "dist/credentials/MoceanApi.credentials.js", + "dist/credentials/MondayApi.credentials.js", "dist/credentials/MongoDb.credentials.js", "dist/credentials/Msg91Api.credentials.js", "dist/credentials/MySql.credentials.js", @@ -184,7 +185,8 @@ "dist/nodes/Mautic/Mautic.node.js", "dist/nodes/Mautic/MauticTrigger.node.js", "dist/nodes/Merge.node.js", - "dist/nodes/Mocean/Mocean.node.js", + "dist/nodes/Mocean/Mocean.node.js", + "dist/nodes/Monday/Monday.node.js", "dist/nodes/MongoDb/MongoDb.node.js", "dist/nodes/MoveBinaryData.node.js", "dist/nodes/Msg91/Msg91.node.js", From 1050f13d54e445d680ce5b5836eb2d85da5278bb Mon Sep 17 00:00:00 2001 From: ricardo Date: Fri, 27 Mar 2020 15:17:10 -0400 Subject: [PATCH 2/2] :zap: Added improvements --- .../nodes/Monday/BoardColumnDescription.ts | 230 ++++++++++ .../nodes/Monday/BoardDescription.ts | 418 +---------------- .../nodes/Monday/BoardGroupDescription.ts | 151 ++++++ .../nodes/Monday/BoardItemDescription.ts | 380 ++++++++++++++++ .../nodes/Monday/GenericFunctions.ts | 12 +- .../nodes-base/nodes/Monday/Monday.node.ts | 428 +++++++++++++----- 6 files changed, 1096 insertions(+), 523 deletions(-) create mode 100644 packages/nodes-base/nodes/Monday/BoardColumnDescription.ts create mode 100644 packages/nodes-base/nodes/Monday/BoardGroupDescription.ts create mode 100644 packages/nodes-base/nodes/Monday/BoardItemDescription.ts diff --git a/packages/nodes-base/nodes/Monday/BoardColumnDescription.ts b/packages/nodes-base/nodes/Monday/BoardColumnDescription.ts new file mode 100644 index 0000000000..469444bebc --- /dev/null +++ b/packages/nodes-base/nodes/Monday/BoardColumnDescription.ts @@ -0,0 +1,230 @@ +import { + INodeProperties +} from "n8n-workflow"; + +export const boardColumnOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new column', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all columns', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const boardColumnFields = [ +/* -------------------------------------------------------------------------- */ +/* boardColumn:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Column Type', + name: 'columnType', + type: 'options', + default: '', + options: [ + { + name: 'Country', + value: 'country', + }, + { + name: 'Checkbox', + value: 'checkbox', + }, + { + name: 'Date', + value: 'date', + }, + { + name: 'Dropdown', + value: 'dropdown', + }, + { + name: 'Email', + value: 'email', + }, + { + name: 'Hour', + value: 'hour', + }, + { + name: 'Link', + value: 'Link', + }, + { + name: 'Long Text', + value: 'longText', + }, + { + name: 'Numbers', + value: 'numbers', + }, + { + name: 'People', + value: 'people', + }, + { + name: 'Person', + value: 'person', + }, + { + name: 'Phone', + value: 'phone', + }, + { + name: 'Rating', + value: 'rating', + }, + { + name: 'Status', + value: 'status', + }, + { + name: 'Tags', + value: 'tags', + }, + { + name: 'Team', + value: 'team', + }, + { + name: 'Text', + value: 'text', + }, + { + name: 'Timeline', + value: 'timeline', + }, + { + name: 'Timezone', + value: 'timezone', + }, + { + name: 'Week', + value: 'week', + }, + { + name: 'World Clock', + value: 'worldClock', + }, + ], + required: true, + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + operation: [ + 'create', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Defauls', + name: 'defaults', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: `The new column's defaults.`, + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* boardColumn:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardColumn', + ], + operation: [ + 'getAll', + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Monday/BoardDescription.ts b/packages/nodes-base/nodes/Monday/BoardDescription.ts index 48328cd419..4acf32284e 100644 --- a/packages/nodes-base/nodes/Monday/BoardDescription.ts +++ b/packages/nodes-base/nodes/Monday/BoardDescription.ts @@ -1,4 +1,6 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, + } from "n8n-workflow"; export const boardOperations = [ { @@ -13,11 +15,6 @@ export const boardOperations = [ }, }, options: [ - { - name: 'Add Column', - value: 'addColumn', - description: 'Add column to a board', - }, { name: 'Archive', value: 'archive', @@ -28,16 +25,6 @@ export const boardOperations = [ value: 'create', description: 'Create a new board', }, - { - name: 'Create Group', - value: 'createGroup', - description: 'Create a group in a board', - }, - { - name: 'Create Item', - value: 'createItem', - description: `Create a item in a board's group`, - }, { name: 'Get', value: 'get', @@ -48,16 +35,6 @@ export const boardOperations = [ value: 'getAll', description: 'Get all boards', }, - { - name: 'Get Columns', - value: 'getColumns', - description: `Get board's columns`, - }, - { - name: 'Get Groups', - value: 'getGroups', - description: `Get board's groups`, - }, ], default: 'create', description: 'The operation to perform.', @@ -65,175 +42,7 @@ export const boardOperations = [ ] as INodeProperties[]; export const boardFields = [ -/* -------------------------------------------------------------------------- */ -/* board:addColumn */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'addColumn', - ], - }, - }, - }, - { - displayName: 'Title', - name: 'title', - type: 'string', - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'addColumn', - ], - }, - }, - }, - { - displayName: 'Column Type', - name: 'columnType', - type: 'options', - options: [ - { - name: 'Country', - value: 'country', - }, - { - name: 'Checkbox', - value: 'checkbox', - }, - { - name: 'Date', - value: 'date', - }, - { - name: 'Dropdown', - value: 'dropdown', - }, - { - name: 'Email', - value: 'email', - }, - { - name: 'Hour', - value: 'hour', - }, - { - name: 'Link', - value: 'Link', - }, - { - name: 'Long Text', - value: 'longText', - }, - { - name: 'Numbers', - value: 'numbers', - }, - { - name: 'People', - value: 'people', - }, - { - name: 'Person', - value: 'person', - }, - { - name: 'Phone', - value: 'phone', - }, - { - name: 'Rating', - value: 'rating', - }, - { - name: 'Status', - value: 'status', - }, - { - name: 'Tags', - value: 'tags', - }, - { - name: 'Team', - value: 'team', - }, - { - name: 'Text', - value: 'text', - }, - { - name: 'Timeline', - value: 'timeline', - }, - { - name: 'Timezone', - value: 'timezone', - }, - { - name: 'Week', - value: 'week', - }, - { - name: 'World Clock', - value: 'worldClock', - }, - ], - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'addColumn', - ], - }, - }, - }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - displayOptions: { - show: { - operation: [ - 'addColumn', - ], - resource: [ - 'board', - ], - }, - }, - default: {}, - options: [ - { - displayName: 'Defauls', - name: 'defaults', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - default: '', - description: `The new column's defaults.`, - }, - ], - }, + /* -------------------------------------------------------------------------- */ /* board:archive */ /* -------------------------------------------------------------------------- */ @@ -241,6 +50,7 @@ export const boardFields = [ displayName: 'Board ID', name: 'boardId', type: 'options', + default: '', typeOptions: { loadOptionsMethod: 'getBoards', }, @@ -255,6 +65,7 @@ export const boardFields = [ ], }, }, + description: 'Board unique identifiers.', }, /* -------------------------------------------------------------------------- */ /* board:create */ @@ -339,183 +150,13 @@ export const boardFields = [ ], }, /* -------------------------------------------------------------------------- */ -/* board:createGroup */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'createGroup', - ], - }, - }, - }, - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - displayOptions: { - show: { - operation: [ - 'createGroup', - ], - resource: [ - 'board', - ], - }, - }, - default: '', - description: `The group name`, - }, -/* -------------------------------------------------------------------------- */ -/* board:createItem */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'createItem', - ], - }, - }, - }, - { - displayName: 'Group ID', - name: 'groupId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getGroups', - loadOptionsDependsOn: 'boardId', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'createItem', - ], - }, - }, - }, - { - displayName: 'Name', - name: 'name', - type: 'string', - required: true, - displayOptions: { - show: { - operation: [ - 'createItem', - ], - resource: [ - 'board', - ], - }, - }, - default: '', - description: `The new item's name.`, - }, - { - displayName: 'Additional Fields', - name: 'additionalFields', - type: 'collection', - placeholder: 'Add Field', - displayOptions: { - show: { - operation: [ - 'createItem', - ], - resource: [ - 'board', - ], - }, - }, - default: {}, - options: [ - { - displayName: 'Column Values', - name: 'columnValues', - type: 'json', - typeOptions: { - alwaysOpenEditWindow: true, - }, - default: '', - description: 'The column values of the new item', - }, - ], - }, -/* -------------------------------------------------------------------------- */ -/* board:deleteGroup */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'deleteGroup', - ], - }, - }, - }, - { - displayName: 'Group ID', - name: 'groupId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getGroups', - loadOptionsDependsOn: 'boardId', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'deleteGroup', - ], - }, - }, - }, -/* -------------------------------------------------------------------------- */ /* board:get */ /* -------------------------------------------------------------------------- */ { displayName: 'Board ID', name: 'boardId', type: 'string', + default: '', required: true, displayOptions: { show: { @@ -527,6 +168,7 @@ export const boardFields = [ ], }, }, + description: 'Board unique identifiers.', }, /* -------------------------------------------------------------------------- */ /* board:getAll */ @@ -572,48 +214,4 @@ export const boardFields = [ default: 50, description: 'How many results to return.', }, -/* -------------------------------------------------------------------------- */ -/* board:getColumns */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'getColumns', - ], - }, - }, - }, -/* -------------------------------------------------------------------------- */ -/* board:getGroups */ -/* -------------------------------------------------------------------------- */ - { - displayName: 'Board ID', - name: 'boardId', - type: 'options', - typeOptions: { - loadOptionsMethod: 'getBoards', - }, - required: true, - displayOptions: { - show: { - resource: [ - 'board', - ], - operation: [ - 'getGroups', - ], - }, - }, - }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Monday/BoardGroupDescription.ts b/packages/nodes-base/nodes/Monday/BoardGroupDescription.ts new file mode 100644 index 0000000000..7fded3c0cf --- /dev/null +++ b/packages/nodes-base/nodes/Monday/BoardGroupDescription.ts @@ -0,0 +1,151 @@ +import { + INodeProperties, +} from "n8n-workflow"; + +export const boardGroupOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'boardGroup', + ], + }, + }, + options: [ + { + name: 'Delete', + value: 'delete', + description: 'Delete a group in a board', + }, + { + name: 'Create', + value: 'create', + description: 'Create a group in a board', + }, + { + name: 'Get All', + value: 'getAll', + description: `Get board's groups`, + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const boardGroupFields = [ + +/* -------------------------------------------------------------------------- */ +/* boardGroup:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardGroup', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'boardGroup', + ], + }, + }, + default: '', + description: `The group name`, + }, +/* -------------------------------------------------------------------------- */ +/* boardGroup:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardGroup', + ], + operation: [ + 'delete', + ], + }, + }, + }, + { + displayName: 'Group ID', + name: 'groupId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getGroups', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardGroup', + ], + operation: [ + 'delete', + ], + }, + }, + }, +/* -------------------------------------------------------------------------- */ +/* boardGroup:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardGroup', + ], + operation: [ + 'getAll', + ], + }, + }, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Monday/BoardItemDescription.ts b/packages/nodes-base/nodes/Monday/BoardItemDescription.ts new file mode 100644 index 0000000000..7cf7df54eb --- /dev/null +++ b/packages/nodes-base/nodes/Monday/BoardItemDescription.ts @@ -0,0 +1,380 @@ +import { + INodeProperties, + } from "n8n-workflow"; + +export const boardItemOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: `Create an item in a board's group`, + }, + { + name: 'Delete', + value: 'delete', + description: `Delete an item`, + }, + { + name: 'Get', + value: 'get', + description: 'Get an item', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all item', + }, + { + name: 'Get By Column Value', + value: 'getByColumnValue', + description: 'Get items by column value', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const boardItemFields = [ + +/* -------------------------------------------------------------------------- */ +/* boardItem:create */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Group ID', + name: 'groupId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getGroups', + loadOptionsDependsOn: [ + 'boardId' + ], + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'create', + ], + }, + }, + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'boardItem', + ], + }, + }, + default: '', + description: `The new item's name.`, + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'boardItem', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Column Values', + name: 'columnValues', + type: 'json', + typeOptions: { + alwaysOpenEditWindow: true, + }, + default: '', + description: 'The column values of the new item', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* boardItem:delete */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Item ID', + name: 'itemId', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'delete', + ], + }, + }, + description: `Item's ID` + }, +/* -------------------------------------------------------------------------- */ +/* boardItem:get */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Item ID', + name: 'itemId', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'get', + ], + }, + }, + description: `Item's ID (Multiple can be added separated by comma)` + }, +/* -------------------------------------------------------------------------- */ +/* boardItem:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + default: '', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Group ID', + name: 'groupId', + default: '', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getGroups', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getAll', + ], + }, + }, + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getAll', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getAll', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +/* -------------------------------------------------------------------------- */ +/* boardItem:getByColumnValue */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getByColumnValue', + ], + }, + }, + description: 'The unique identifier of the board.', + }, + { + displayName: 'Column ID', + name: 'columnId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getColumns', + loadOptionsDependsOn: [ + 'boardId' + ], + }, + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getByColumnValue', + ], + }, + }, + description: `The column's unique identifier.`, + }, + { + displayName: 'Column Value', + name: 'columnValue', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getByColumnValue', + ], + }, + }, + description: 'The column value to search items by.' + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getByColumnValue', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + resource: [ + 'boardItem', + ], + operation: [ + 'getByColumnValue', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 100, + }, + default: 50, + description: 'How many results to return.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Monday/GenericFunctions.ts b/packages/nodes-base/nodes/Monday/GenericFunctions.ts index 51fed16f84..2836afde1a 100644 --- a/packages/nodes-base/nodes/Monday/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Monday/GenericFunctions.ts @@ -1,4 +1,6 @@ -import { OptionsWithUri } from 'request'; +import { + OptionsWithUri, + } from 'request'; import { IExecuteFunctions, @@ -11,6 +13,10 @@ import { IWebhookFunctions } from 'n8n-workflow'; +import { + get, +} from 'lodash'; + export async function mondayApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, body: any = {}, option: IDataObject = {}): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('mondayApi'); @@ -53,10 +59,10 @@ export async function mondayApiRequestAllItems(this: IHookFunctions | IExecuteFu do { responseData = await mondayApiRequest.call(this, body); - returnData.push.apply(returnData, responseData['data'][propertyName]); + returnData.push.apply(returnData, get(responseData, propertyName)); body.variables.page++; } while ( - responseData['data'][propertyName].length > 0 + get(responseData, propertyName).length > 0 ); return returnData; } diff --git a/packages/nodes-base/nodes/Monday/Monday.node.ts b/packages/nodes-base/nodes/Monday/Monday.node.ts index 37e3dad512..5071996fb2 100644 --- a/packages/nodes-base/nodes/Monday/Monday.node.ts +++ b/packages/nodes-base/nodes/Monday/Monday.node.ts @@ -1,7 +1,7 @@ import { - BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; + import { IDataObject, ILoadOptionsFunctions, @@ -21,7 +21,24 @@ import { boardOperations, } from './BoardDescription'; -import { snakeCase } from 'change-case'; +import { + boardColumnFields, + boardColumnOperations, +} from './BoardColumnDescription'; + +import { + boardGroupFields, + boardGroupOperations, +} from './BoardGroupDescription'; + +import { + boardItemFields, + boardItemOperations, +} from './BoardItemDescription'; + +import { + snakeCase, + } from 'change-case'; interface IGraphqlBody { query: string; @@ -59,12 +76,34 @@ export class Monday implements INodeType { name: 'Board', value: 'board', }, + { + name: 'Board Column', + value: 'boardColumn', + }, + { + name: 'Board Group', + value: 'boardGroup', + }, + { + name: 'Board Item', + value: 'boardItem', + }, ], default: 'board', description: 'Resource to consume.', }, + //BOARD ...boardOperations, ...boardFields, + // BOARD COLUMN + ...boardColumnOperations, + ...boardColumnFields, + // BOARD GROUP + ...boardGroupOperations, + ...boardGroupFields, + // BOARD ITEM + ...boardItemOperations, + ...boardItemFields, ], }; @@ -87,7 +126,7 @@ export class Monday implements INodeType { page: 1, }, }; - const boards = await mondayApiRequestAllItems.call(this, 'boards', body); + const boards = await mondayApiRequestAllItems.call(this, 'data.boards', body); for (const board of boards) { const boardName = board.name; const boardId = board.id; @@ -100,6 +139,38 @@ export class Monday implements INodeType { } return returnData; }, + // Get all the available columns to display them to user so that he can + // select them easily + async getColumns(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = parseInt(this.getCurrentNodeParameter('boardId') as string, 10); + const body: IGraphqlBody = { + query: + `query ($boardId: [Int]) { + boards (ids: $boardId){ + columns() { + id + title + } + } + }`, + variables: { + page: 1, + boardId, + }, + }; + const { data } = await mondayApiRequest.call(this, body); + const columns = data.boards[0].columns; + for (const column of columns) { + const columnName = column.title; + const columnId = column.id; + returnData.push({ + name: columnName, + value: columnId, + }); + } + return returnData; + }, // Get all the available groups to display them to user so that he can // select them easily async getGroups(this: ILoadOptionsFunctions): Promise { @@ -144,38 +215,6 @@ export class Monday implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; for (let i = 0; i < length; i++) { if (resource === 'board') { - if (operation === 'addColumn') { - const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); - const title = this.getNodeParameter('title', i) as string; - const columnType = this.getNodeParameter('columnType', i) as string; - const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; - - const body: IGraphqlBody = { - query: - `mutation ($boardId: Int!, $title: String!, $columnType: ColumnType, $defaults: JSON ) { - create_column (board_id: $boardId, title: $title, column_type: $columnType, defaults: $defaults) { - id - } - }`, - variables: { - boardId, - title, - columnType: snakeCase(columnType), - }, - }; - - if (additionalFields.defaults) { - try { - JSON.parse(additionalFields.defaults as string); - } catch (e) { - throw new Error('Defauls must be a valid JSON'); - } - body.variables.defaults = JSON.stringify(JSON.parse(additionalFields.defaults as string)); - } - - responseData = await mondayApiRequest.call(this, body); - responseData = responseData.data.create_column; - } if (operation === 'archive') { const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); @@ -219,78 +258,6 @@ export class Monday implements INodeType { responseData = await mondayApiRequest.call(this, body); responseData = responseData.data.create_board; } - if (operation === 'createGroup') { - const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); - const name = this.getNodeParameter('name', i) as string; - - const body: IGraphqlBody = { - query: - `mutation ($boardId: Int!, $groupName: String!) { - create_group (board_id: $boardId, group_name: $groupName) { - id - } - }`, - variables: { - boardId, - groupName: name, - }, - }; - - responseData = await mondayApiRequest.call(this, body); - responseData = responseData.data.create_group; - } - if (operation === 'createItem') { - const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); - const groupId = this.getNodeParameter('groupId', i) as string; - const itemName = this.getNodeParameter('name', i) as string; - const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; - - const body: IGraphqlBody = { - query: - `mutation ($boardId: Int!, $groupId: String!, $itemName: String!, $columnValues: JSON) { - create_item (board_id: $boardId, group_id: $groupId, item_name: $itemName, column_values: $columnValues) { - id - } - }`, - variables: { - boardId, - groupId, - itemName, - }, - }; - - if (additionalFields.columnValues) { - try { - JSON.parse(additionalFields.columnValues as string); - } catch (e) { - throw new Error('Custom Values must be a valid JSON'); - } - body.variables.columnValues = JSON.stringify(JSON.parse(additionalFields.columnValues as string)); - } - - responseData = await mondayApiRequest.call(this, body); - responseData = responseData.data.create_item; - } - if (operation === 'deleteGroup') { - const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); - const groupId = this.getNodeParameter('groupId', i) as string; - - const body: IGraphqlBody = { - query: - `mutation ($boardId: Int!, $groupId: String!) { - delete_group (board_id: $boardId, group_id: $groupId) { - id - } - }`, - variables: { - boardId, - groupId, - }, - }; - - responseData = await mondayApiRequest.call(this, body); - responseData = responseData.data.delete_group; - } if (operation === 'get') { const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); @@ -341,14 +308,48 @@ export class Monday implements INodeType { }; if (returnAll === true) { - responseData = await mondayApiRequestAllItems.call(this, 'boards', body); + responseData = await mondayApiRequestAllItems.call(this, 'data.boards', body); } else { body.variables.limit = this.getNodeParameter('limit', i) as number, responseData = await mondayApiRequest.call(this, body); responseData = responseData.data.boards; } } - if (operation === 'getColumns') { + } + if (resource === 'boardColumn') { + if (operation === 'create') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const title = this.getNodeParameter('title', i) as string; + const columnType = this.getNodeParameter('columnType', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $title: String!, $columnType: ColumnType, $defaults: JSON ) { + create_column (board_id: $boardId, title: $title, column_type: $columnType, defaults: $defaults) { + id + } + }`, + variables: { + boardId, + title, + columnType: snakeCase(columnType), + }, + }; + + if (additionalFields.defaults) { + try { + JSON.parse(additionalFields.defaults as string); + } catch (e) { + throw new Error('Defauls must be a valid JSON'); + } + body.variables.defaults = JSON.stringify(JSON.parse(additionalFields.defaults as string)); + } + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_column; + } + if (operation === 'getAll') { const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); const body: IGraphqlBody = { @@ -373,7 +374,49 @@ export class Monday implements INodeType { responseData = await mondayApiRequest.call(this, body); responseData = responseData.data.boards[0].columns; } - if (operation === 'getGroups') { + } + if (resource === 'boardGroup') { + if (operation === 'create') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const name = this.getNodeParameter('name', i) as string; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupName: String!) { + create_group (board_id: $boardId, group_name: $groupName) { + id + } + }`, + variables: { + boardId, + groupName: name, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_group; + } + if (operation === 'delete') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const groupId = this.getNodeParameter('groupId', i) as string; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupId: String!) { + delete_group (board_id: $boardId, group_id: $groupId) { + id + } + }`, + variables: { + boardId, + groupId, + }, + }; + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.delete_group; + } + if (operation === 'getAll') { const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); const body: IGraphqlBody = { @@ -382,6 +425,7 @@ export class Monday implements INodeType { boards (ids: $boardId, ){ id groups() { + id title color position @@ -398,6 +442,170 @@ export class Monday implements INodeType { responseData = responseData.data.boards[0].groups; } } + if (resource === 'boardItem') { + if (operation === 'create') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const groupId = this.getNodeParameter('groupId', i) as string; + const itemName = this.getNodeParameter('name', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + const body: IGraphqlBody = { + query: + `mutation ($boardId: Int!, $groupId: String!, $itemName: String!, $columnValues: JSON) { + create_item (board_id: $boardId, group_id: $groupId, item_name: $itemName, column_values: $columnValues) { + id + } + }`, + variables: { + boardId, + groupId, + itemName, + }, + }; + + if (additionalFields.columnValues) { + try { + JSON.parse(additionalFields.columnValues as string); + } catch (e) { + throw new Error('Custom Values must be a valid JSON'); + } + body.variables.columnValues = JSON.stringify(JSON.parse(additionalFields.columnValues as string)); + } + + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.create_item; + } + if (operation === 'delete') { + const itemId = parseInt((this.getNodeParameter('itemId', i) as string), 10); + + const body: IGraphqlBody = { + query: + `mutation ($itemId: Int!) { + delete_item (item_id: $itemId) { + id + } + }`, + variables: { + itemId, + }, + }; + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.delete_item; + } + if (operation === 'get') { + const itemIds = ((this.getNodeParameter('itemId', i) as string).split(',') as string[]).map((n) => parseInt(n, 10)); + + const body: IGraphqlBody = { + query: + `query ($itemId: [Int!]){ + items (ids: $itemId) { + id + name + created_at + state + column_values() { + id + text + title + type + value + additional_info + } + } + }`, + variables: { + itemId: itemIds, + }, + }; + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.items; + } + if (operation === 'getAll') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const groupId = this.getNodeParameter('groupId', i) as string; + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + const body: IGraphqlBody = { + query: + `query ($boardId: [Int], $groupId: [String], $page: Int, $limit: Int) { + boards (ids: $boardId) { + groups (ids: $groupId) { + id + items(limit: $limit, page: $page) { + id + name + created_at + state + column_values() { + id + text + title + type + value + additional_info + } + } + } + } + }`, + variables: { + boardId, + groupId, + }, + }; + + if (returnAll) { + responseData = await mondayApiRequestAllItems.call(this, 'data.boards[0].groups[0].items', body); + } else { + body.variables.limit = this.getNodeParameter('limit', i) as number; + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.boards[0].groups[0].items; + } + + } + if (operation === 'getByColumnValue') { + const boardId = parseInt(this.getNodeParameter('boardId', i) as string, 10); + const columnId = this.getNodeParameter('columnId', i) as string; + const columnValue = this.getNodeParameter('columnValue', i) as string; + const returnAll = this.getNodeParameter('returnAll', i) as boolean; + + const body: IGraphqlBody = { + query: + `query ($boardId: Int!, $columnId: String!, $columnValue: String!, $page: Int, $limit: Int ){ + items_by_column_values (board_id: $boardId, column_id: $columnId, column_value: $columnValue, page: $page, limit: $limit) { + id + name + created_at + state + board { + id + } + column_values() { + id + text + title + type + value + additional_info + } + } + }`, + variables: { + boardId, + columnId, + columnValue, + }, + }; + + if (returnAll) { + responseData = await mondayApiRequestAllItems.call(this, 'data.items_by_column_values', body); + } else { + body.variables.limit = this.getNodeParameter('limit', i) as number; + responseData = await mondayApiRequest.call(this, body); + responseData = responseData.data.items_by_column_values; + } + } + } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else {