diff --git a/packages/nodes-base/credentials/WekanApi.credentials.ts b/packages/nodes-base/credentials/WekanApi.credentials.ts new file mode 100644 index 000000000..0642c99c0 --- /dev/null +++ b/packages/nodes-base/credentials/WekanApi.credentials.ts @@ -0,0 +1,31 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class WekanApi implements ICredentialType { + name = 'wekanApi'; + displayName = 'Wekan API'; + documentationUrl = 'wekan'; + properties = [ + { + displayName: 'Username', + name: 'username', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Password', + name: 'password', + type: 'string' as NodePropertyTypes, + default: '', + }, + { + displayName: 'URL', + name: 'url', + type: 'string' as NodePropertyTypes, + default: '', + placeholder: 'https://wekan.yourdomain.com', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Wekan/BoardDescription.ts b/packages/nodes-base/nodes/Wekan/BoardDescription.ts new file mode 100644 index 000000000..d38076380 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/BoardDescription.ts @@ -0,0 +1,307 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const boardOperations = [ + // ---------------------------------- + // board + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'board', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new board', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a board', + }, + { + name: 'Get', + value: 'get', + description: 'Get the data of a board', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all user boards', + }, + ], + default: 'create', + description: 'The operation to perform.', + } +] as INodeProperties[]; + +export const boardFields = [ + + // ---------------------------------- + // board:create + // ---------------------------------- + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + placeholder: 'My board', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + description: 'The title of the board', + }, + { + displayName: 'Owner', + name: 'owner', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + description: 'The user ID in Wekan', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'board', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Active', + name: 'isActive', + type: 'boolean', + default: false, + description: 'Set the board active.', + }, + { + displayName: 'Admin', + name: 'isAdmin', + type: 'boolean', + default: false, + description: 'Set the owner an admin of the board.', + }, + { + displayName: 'Color', + name: 'color', + type: 'options', + options: [ + { + name: 'Belize', + value: 'belize', + }, + { + name: 'Nephritis', + value: 'nephritis', + }, + { + name: 'Pomegranate', + value: 'pomegranate', + }, + { + name: 'Pumpkin', + value: 'pumpkin', + }, + { + name: 'Wisteria', + value: 'wisteria', + }, + { + name: 'Midnight', + value: 'midnight', + }, + ], + default: '', + description: 'The color of the board.', + }, + { + displayName: 'Comment only', + name: 'isCommentOnly', + type: 'boolean', + default: false, + description: 'Only enable comments.', + }, + { + displayName: 'No comments', + name: 'isNoComments', + type: 'boolean', + default: false, + description: 'Disable comments.', + }, + { + displayName: 'Permission', + name: 'permission', + type: 'options', + options: [ + { + name: 'Private', + value: 'private', + }, + { + name: 'Public', + value: 'public', + }, + ], + default: 'private', + description: 'Set the board permission.', + }, + { + displayName: 'Worker', + name: 'isWorker', + type: 'boolean', + default: false, + description: 'Only move cards, assign himself to card and comment.', + }, + ], + }, + + // ---------------------------------- + // board:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'board', + ], + }, + }, + description: 'The ID of the board to delete.', + }, + + // ---------------------------------- + // board:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'board', + ], + }, + }, + description: 'The ID of the board to get.', + }, + + // ---------------------------------- + // board:getAll + // ---------------------------------- + { + displayName: 'User ID', + name: 'IdUser', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'board', + ], + }, + }, + description: 'The ID of the user that boards are attached.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'board', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'board', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 200, + }, + default: 100, + description: 'How many results to return.', + }, + +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/CardCommentDescription.ts b/packages/nodes-base/nodes/Wekan/CardCommentDescription.ts new file mode 100644 index 000000000..ba5d2abf0 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/CardCommentDescription.ts @@ -0,0 +1,470 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const cardCommentOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'cardComment', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a comment on a card', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a comment from a card', + }, + { + name: 'Get', + value: 'get', + description: 'Get a card comment', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all card comments', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const cardCommentFields = [ + // ---------------------------------- + // cardComment:create + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the card', + }, + { + displayName: 'Author ID', + name: 'authorId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The user who posted the comment.', + }, + { + displayName: 'Comment', + name: 'comment', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The comment text.', + }, + + // ---------------------------------- + // cardComment:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the card.', + }, + { + displayName: 'Comment ID', + name: 'commentId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getComments', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the comment to delete.', + }, + + // ---------------------------------- + // cardComment:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the card.', + }, + { + displayName: 'Comment ID', + name: 'commentId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getComments', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the comment to get.', + }, + + // ---------------------------------- + // cardComment:getAll + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'cardComment', + ], + }, + }, + description: 'The ID of the card.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'cardComment', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'cardComment', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 200, + }, + default: 100, + description: 'How many results to return.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/CardDescription.ts b/packages/nodes-base/nodes/Wekan/CardDescription.ts new file mode 100644 index 000000000..6b38270b1 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/CardDescription.ts @@ -0,0 +1,844 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const cardOperations = [ + // ---------------------------------- + // card + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'card', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new card', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a card', + }, + { + name: 'Get', + value: 'get', + description: 'Get a card', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all cards', + }, + { + name: 'Update', + value: 'update', + description: 'Update a card', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const cardFields = [ + // ---------------------------------- + // card:create + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the list to create card in.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + placeholder: 'My card', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The title of the card', + }, + { + displayName: 'Swimlane ID', + name: 'swimlaneId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getSwimlanes', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The swimlane ID of the new card', + }, + { + displayName: 'Author ID', + name: 'authorId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The author ID', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'card', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Assignees', + name: 'assignees', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + description: 'The new list of assignee IDs attached to the card.', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'The new description of the card.', + }, + { + displayName: 'Members', + name: 'members', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + description: 'The new list of member IDs attached to the card.', + }, + ], + }, + + // ---------------------------------- + // card:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the list that card belongs to.' + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the card to delete.', + }, + + // ---------------------------------- + // card:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the list that card belongs to.' + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the card to get.', + }, + + // ---------------------------------- + // card:getAll + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'From Object', + name: 'fromObject', + type: 'options', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + }, + }, + options: [ + { + name: 'List', + value: 'list', + }, + { + name: 'Swimlane', + value: 'swimlane', + }, + ], + default: '', + description: '' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + fromObject: [ + 'list', + ], + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the list that card belongs to.' + }, + { + displayName: 'Swimlane ID', + name: 'swimlaneId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getSwimlanes', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + displayOptions: { + show: { + fromObject: [ + 'swimlane', + ], + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the swimlane that card belongs to.' + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'card', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 200, + }, + default: 100, + description: 'How many results to return.', + }, + + // ---------------------------------- + // card:update + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the list that card belongs to.' + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'card', + ], + }, + }, + description: 'The ID of the card to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'card', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Author ID', + name: 'authorId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + description: 'Update the owner of the card.', + }, + { + displayName: 'Assignees', + name: 'assignees', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + description: 'The new list of assignee IDs attached to the card.', + }, + { + displayName: 'Color', + name: 'color', + type: 'options', + options: [ + { + value: 'white', + name: 'White', + }, + { + value: 'green', + name: 'Green', + }, + { + value: 'yellow', + name: 'Yellow', + }, + { + value: 'orange', + name: 'Orange', + }, + { + value: 'red', + name: 'Red', + }, + { + value: 'purple', + name: 'Purple', + }, + { + value: 'blue', + name: 'Blue', + }, + { + value: 'sky', + name: 'Sky', + }, + { + value: 'lime', + name: 'Lime' + }, + { + value: 'pink', + name: 'Pink', + }, + { + value: 'black', + name: 'Black', + }, + { + value: 'silver', + name: 'Silver', + }, + { + value: 'peachpuff', + name: 'Peachpuff' + }, + { + value: 'crimson', + name: 'Crimson', + }, + { + value: 'plum', + name: 'Plum' + }, + { + value: 'darkgreen', + name: 'Darkgreen', + }, + { + value: 'slateblue', + name: 'Slateblue' + }, + { + value: 'magenta', + name: 'Magenta', + }, + { + value: 'gold', + name: 'Gold', + }, + { + value: 'navy', + name: 'Navy', + }, + { + value: 'gray', + name: 'Gray', + }, + { + value: 'saddlebrown', + name: 'Saddlebrown', + }, + { + value: 'paleturquoise', + name: 'Paleturquoise' + }, + { + value: 'mistyrose', + name: 'Mistyrose', + }, + { + value: 'indigo', + name: 'Indigo', + }, + ], + default: '', + description: 'The new color of the card.', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'The new description of the card.', + }, + { + displayName: 'Due At', + name: 'dueAt', + type: 'dateTime', + default: '', + description: 'The new due at field of the card.', + }, + { + displayName: 'End At', + name: 'endAt', + type: 'dateTime', + default: '', + description: 'The new end at field of the card.', + }, + { + displayName: 'Label IDs', + name: 'labelIds', + type: 'string', + default: '', + description: 'The label IDs attached to the card.', + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + description: 'The new list ID of the card (move operation).', + }, + { + displayName: 'Members', + name: 'members', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + description: 'The new list of member IDs attached to the card.', + }, + { + displayName: 'Over Time', + name: 'isOverTime', + type: 'boolean', + default: false, + description: 'The new over time field of the card.', + }, + { + displayName: 'Parent ID', + name: 'parentId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + description: 'The parent of the card.', + }, + { + displayName: 'Received At', + name: 'receivedAt', + type: 'dateTime', + default: '', + description: 'The new received at field of the card.', + }, + { + displayName: 'Spent Time', + name: 'spentTime', + type: 'number', + typeOptions: { + minValue: 0, + }, + default: '', + description: 'The new spent time field of the card.', + }, + { + displayName: 'Start At', + name: 'startAt', + type: 'dateTime', + default: '', + description: 'The new start at field of the card.', + }, + { + displayName: 'Swimlane ID', + name: 'swimlaneId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getSwimlanes', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + description: 'The new swimlane ID of the card.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'The new title of the card.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/ChecklistDescription.ts b/packages/nodes-base/nodes/Wekan/ChecklistDescription.ts new file mode 100644 index 000000000..7f9722b5e --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/ChecklistDescription.ts @@ -0,0 +1,474 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const checklistOperations = [ + // ---------------------------------- + // checklist + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'checklist', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new checklist', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a checklist', + }, + { + name: 'Get', + value: 'get', + description: 'Get the data of a checklist', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Returns all checklists for the card', + }, + ], + default: 'getAll', + description: 'The operation to perform.', + }, + +] as INodeProperties[]; + +export const checklistFields = [ + // ---------------------------------- + // checklist:create + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the board where the card is in.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the card to add checklist to.', + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The title of the checklist to add.', + }, + { + displayName: 'Items', + name: 'items', + type: 'string', + typeOptions: { + multipleValues: true, + multipleValueButtonText: 'Add Item', + }, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'checklist', + ], + }, + }, + default: [], + description: 'Items to be added to the checklist', + }, + + // ---------------------------------- + // checklist:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the card that checklist belongs to.', + }, + { + displayName: 'Checklist ID', + name: 'checklistId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklists', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the checklist to delete.', + }, + + // ---------------------------------- + // checklist:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the card that checklist belongs to.' + }, + { + displayName: 'Checklist ID', + name: 'checklistId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklists', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the checklist to get.', + }, + + // ---------------------------------- + // checklist:getAll + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'checklist', + ], + }, + }, + description: 'The ID of the card to get checklists.', + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'checklist', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'checklist', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 200, + }, + default: 100, + description: 'How many results to return.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/ChecklistItemDescription.ts b/packages/nodes-base/nodes/Wekan/ChecklistItemDescription.ts new file mode 100644 index 000000000..9c49cd659 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/ChecklistItemDescription.ts @@ -0,0 +1,452 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const checklistItemOperations = [ + // ---------------------------------- + // checklistItem + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'checklistItem', + ], + }, + }, + options: [ + { + name: 'Delete', + value: 'delete', + description: 'Delete a checklist item', + }, + { + name: 'Get', + value: 'get', + description: 'Get a checklist item', + }, + { + name: 'Update', + value: 'update', + description: 'Update a checklist item', + }, + ], + default: 'getAll', + description: 'The operation to perform.', + }, + +] as INodeProperties[]; + +export const checklistItemFields = [ + // ---------------------------------- + // checklistItem:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the card that checklistItem belongs to.' + }, + { + displayName: 'Checklist ID', + name: 'checklistId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklists', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem that card belongs to.', + }, + { + displayName: 'Checklist Item ID', + name: 'checklistItemId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklistItems', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + 'checklistId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem item to get.', + }, + + // ---------------------------------- + // checklistItem:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the card that checklistItem belongs to.' + }, + { + displayName: 'Checklist ID', + name: 'checklistId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklists', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem that card belongs to.', + }, + { + displayName: 'Checklist Item ID', + name: 'checklistItemId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklistItems', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + 'checklistId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem item to get.', + }, + + // ---------------------------------- + // checklistItem:update + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the board that card belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the list that card belongs to.', + }, + { + displayName: 'Card ID', + name: 'cardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getCards', + loadOptionsDependsOn: [ + 'boardId', + 'listId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the card that checklistItem belongs to.' + }, + { + displayName: 'CheckList ID', + name: 'checklistId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklists', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem that card belongs to.', + }, + { + displayName: 'Checklist Item ID', + name: 'checklistItemId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChecklistItems', + loadOptionsDependsOn: [ + 'boardId', + 'cardId', + 'checklistId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + description: 'The ID of the checklistItem item to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'checklistItem', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + description: 'The new title for the checklistItem item.', + }, + { + displayName: 'Finished', + name: 'isFinished', + type: 'boolean', + default: false, + description: 'Item is checked', + }, + ], + }, + +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/GenericFunctions.ts b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts new file mode 100644 index 000000000..e771b1e59 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/GenericFunctions.ts @@ -0,0 +1,78 @@ +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { + OptionsWithUri, +} from 'request'; + +import { + ICredentialDataDecryptedObject, + IDataObject, +} from 'n8n-workflow'; + +export async function getAuthorization( + this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, + credentials?: ICredentialDataDecryptedObject, +): Promise { + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + const { password, username } = credentials; + const options: OptionsWithUri = { + method: 'POST', + form: { + username, + password, + }, + uri: `${credentials.url}/users/login`, + json: true, + }; + + try { + const response = await this.helpers.request!(options); + + return { token: response.token, userId: response.id }; + } catch (error) { + throw new Error('Wekan Error: ' + error.error.reason); + } +} + +export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('wekanApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + query = query || {}; + + const { token } = await getAuthorization.call(this, credentials); + + const options: OptionsWithUri = { + headers: { + 'Accept':'application/json', + 'Authorization': `Bearer ${token}`, + }, + method, + body, + qs: query, + uri: `${credentials.url}/api/${endpoint}`, + json: true, + }; + + try { + return await this.helpers.request!(options); + } catch (error) { + if (error.statusCode === 401) { + throw new Error('The Wekan credentials are not valid!'); + } + + throw error; + } +} diff --git a/packages/nodes-base/nodes/Wekan/ListDescription.ts b/packages/nodes-base/nodes/Wekan/ListDescription.ts new file mode 100644 index 000000000..23b42bf6a --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/ListDescription.ts @@ -0,0 +1,256 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const listOperations = [ + // ---------------------------------- + // list + // ---------------------------------- + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'list', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a new list' + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a list' + }, + { + name: 'Get', + value: 'get', + description: 'Get the data of a list' + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get all board lists' + }, + ], + default: 'create', + description: 'The operation to perform.' + } +] as INodeProperties[]; + +export const listFields = [ + // ---------------------------------- + // list:create + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The ID of the board the list should be created in' + }, + { + displayName: 'Title', + name: 'title', + type: 'string', + default: '', + placeholder: 'My list', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The title of the list' + }, + + // ---------------------------------- + // list:delete + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The ID of the list to delete.' + }, + + // ---------------------------------- + // list:get + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The ID of the board that list belongs to.' + }, + { + displayName: 'List ID', + name: 'listId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getLists', + loadOptionsDependsOn: [ + 'boardId', + ], + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'list', + ], + }, + }, + description: 'The ID of the list to get.' + }, + + // ---------------------------------- + // list:getAll + // ---------------------------------- + { + displayName: 'Board ID', + name: 'boardId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getBoards', + }, + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'list', + ], + }, + }, + description: 'ID of the board where the lists are in' + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'list', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'list', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 200, + }, + default: 100, + description: 'How many results to return.', + }, + +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Wekan/Wekan.node.ts b/packages/nodes-base/nodes/Wekan/Wekan.node.ts new file mode 100644 index 000000000..85ba4faa9 --- /dev/null +++ b/packages/nodes-base/nodes/Wekan/Wekan.node.ts @@ -0,0 +1,687 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + ILoadOptionsFunctions, + INodeExecutionData, + INodePropertyOptions, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + apiRequest, +} from './GenericFunctions'; + +import { + boardFields, + boardOperations, +} from './BoardDescription'; + +import { + cardFields, + cardOperations, +} from './CardDescription'; + +import { + cardCommentFields, + cardCommentOperations, +} from './CardCommentDescription'; + +import { + checklistFields, + checklistOperations, +} from './ChecklistDescription'; + +import { + checklistItemFields, + checklistItemOperations, +} from './ChecklistItemDescription'; + +import { + listFields, + listOperations, +} from './ListDescription'; + +// https://wekan.github.io/api/v4.41/ + +export class Wekan implements INodeType { + description: INodeTypeDescription = { + displayName: 'Wekan', + name: 'wekan', + icon: 'file:wekan.png', + group: ['transform'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Open-Source Kanban', + defaults: { + name: 'Wekan', + color: '#006581', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'wekanApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Board', + value: 'board', + }, + { + name: 'Card', + value: 'card', + }, + { + name: 'Card Comment', + value: 'cardComment', + }, + { + name: 'Checklist', + value: 'checklist', + }, + { + name: 'Checklist Item', + value: 'checklistItem', + }, + { + name: 'List', + value: 'list', + }, + ], + default: 'card', + description: 'The resource to operate on.', + }, + + // ---------------------------------- + // operations + // ---------------------------------- + ...boardOperations, + ...cardOperations, + ...cardCommentOperations, + ...checklistOperations, + ...checklistItemOperations, + ...listOperations, + + // ---------------------------------- + // fields + // ---------------------------------- + ...boardFields, + ...cardFields, + ...cardCommentFields, + ...checklistFields, + ...checklistItemFields, + ...listFields, + ], + }; + + methods = { + loadOptions: { + async getUsers(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const users = await apiRequest.call(this, 'GET', 'users', {}, {}); + for (const user of users) { + returnData.push({ + name: user.username, + value: user._id, + }); + } + return returnData; + }, + async getBoards(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const user = await apiRequest.call(this, 'GET', `user`, {}, {}); + const boards = await apiRequest.call(this, 'GET', `users/${user._id}/boards`, {}, {}); + for (const board of boards) { + returnData.push({ + name: board.title, + value: board._id, + }); + } + return returnData; + }, + async getLists(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const lists = await apiRequest.call(this, 'GET', `boards/${boardId}/lists`, {}, {}); + for (const list of lists) { + returnData.push({ + name: list.title, + value: list._id, + }); + } + return returnData; + }, + async getSwimlanes(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const swimlanes = await apiRequest.call(this, 'GET', `boards/${boardId}/swimlanes`, {}, {}); + for (const swimlane of swimlanes) { + returnData.push({ + name: swimlane.title, + value: swimlane._id, + }); + } + return returnData; + }, + async getCards(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const listId = this.getCurrentNodeParameter('listId') as string; + const cards = await apiRequest.call(this, 'GET', `boards/${boardId}/lists/${listId}/cards`, {}, {}); + for (const card of cards) { + returnData.push({ + name: card.title, + value: card._id, + }); + } + return returnData; + }, + async getChecklists(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const cardId = this.getCurrentNodeParameter('cardId') as string; + const checklists = await apiRequest.call(this, 'GET', `boards/${boardId}/cards/${cardId}/checklists`, {}, {}); + for (const checklist of checklists) { + returnData.push({ + name: checklist.title, + value: checklist._id, + }); + } + return returnData; + }, + async getChecklistItems(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const cardId = this.getCurrentNodeParameter('cardId') as string; + const checklistId = this.getCurrentNodeParameter('checklistId') as string; + const checklist = await apiRequest.call(this, 'GET', `boards/${boardId}/cards/${cardId}/checklists/${checklistId}`, {}, {}); + for (const item of checklist.items) { + returnData.push({ + name: item.title, + value: item._id, + }); + } + return returnData; + }, + async getComments(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const boardId = this.getCurrentNodeParameter('boardId') as string; + const cardId = this.getCurrentNodeParameter('cardId') as string; + const comments = await apiRequest.call(this, 'GET', `boards/${boardId}/cards/${cardId}/comments`, {}, {}); + for (const comment of comments) { + returnData.push({ + name: comment.comment, + value: comment._id, + }); + } + return returnData; + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + let returnAll; + let limit; + + const operation = this.getNodeParameter('operation', 0) as string; + const resource = this.getNodeParameter('resource', 0) as string; + + // For Post + let body: IDataObject; + // For Query string + let qs: IDataObject; + + let requestMethod: string; + let endpoint: string; + + for (let i = 0; i < items.length; i++) { + requestMethod = 'GET'; + endpoint = ''; + body = {}; + qs = {}; + + if (resource === 'board') { + + if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + endpoint = 'boards'; + + body.title = this.getNodeParameter('title', i) as string; + body.owner = this.getNodeParameter('owner', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + + endpoint = `boards/${boardId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + + endpoint = `boards/${boardId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const userId = this.getNodeParameter('IdUser', i) as string; + + returnAll = this.getNodeParameter('returnAll', i) as boolean; + + endpoint = `users/${userId}/boards`; + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + + } else if (resource === 'card') { + + if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}/cards`; + + body.title = this.getNodeParameter('title', i) as string; + body.swimlaneId = this.getNodeParameter('swimlaneId', i) as string; + body.authorId = this.getNodeParameter('authorId', i) as string; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + Object.assign(body, additionalFields); + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}/cards/${cardId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}/cards/${cardId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const fromObject = this.getNodeParameter('fromObject', i) as string; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + + if (fromObject === 'list') { + const listId = this.getNodeParameter('listId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}/cards`; + } + + if (fromObject === 'swimlane') { + const swimlaneId = this.getNodeParameter('swimlaneId', i) as string; + + endpoint = `boards/${boardId}/swimlanes/${swimlaneId}/cards`; + } + + } else if (operation === 'update') { + // ---------------------------------- + // update + // ---------------------------------- + + requestMethod = 'PUT'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}/cards/${cardId}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(body, updateFields); + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + + } else if (resource === 'cardComment') { + + if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/comments`; + + body.authorId = this.getNodeParameter('authorId', i) as string; + body.comment = this.getNodeParameter('comment', i) as string; + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const commentId = this.getNodeParameter('commentId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/comments/${commentId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const commentId = this.getNodeParameter('commentId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/comments/${commentId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/comments`; + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + + } else if (resource === 'list') { + + if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + + const boardId = this.getNodeParameter('boardId', i) as string; + + endpoint = `boards/${boardId}/lists`; + + body.title = this.getNodeParameter('title', i) as string; + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const listId = this.getNodeParameter('listId', i) as string; + + endpoint = `boards/${boardId}/lists/${listId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + + endpoint = `boards/${boardId}/lists`; + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + + } else if (resource === 'checklist') { + + if (operation === 'create') { + // ---------------------------------- + // create + // ---------------------------------- + + requestMethod = 'POST'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists`; + + body.title = this.getNodeParameter('title', i) as string; + + body.items = this.getNodeParameter('items', i) as string[]; + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + + + endpoint = `boards/${boardId}/cards/${cardId}/checklists`; + + } else if (operation === 'getCheckItem') { + // ---------------------------------- + // getCheckItem + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('itemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + } else if (operation === 'deleteCheckItem') { + // ---------------------------------- + // deleteCheckItem + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('itemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + } else if (operation === 'updateCheckItem') { + // ---------------------------------- + // updateCheckItem + // ---------------------------------- + + requestMethod = 'PUT'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('itemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(body, updateFields); + + + + } else { + throw new Error(`The operation "${operation}" is not known!`); + } + } else if (resource === 'checklistItem') { + + if (operation === 'get') { + // ---------------------------------- + // get + // ---------------------------------- + + requestMethod = 'GET'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('checklistItemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + } else if (operation === 'delete') { + // ---------------------------------- + // delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('checklistItemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + } else if (operation === 'update') { + // ---------------------------------- + // update + // ---------------------------------- + + requestMethod = 'PUT'; + + const boardId = this.getNodeParameter('boardId', i) as string; + const cardId = this.getNodeParameter('cardId', i) as string; + const checklistId = this.getNodeParameter('checklistId', i) as string; + const itemId = this.getNodeParameter('checklistItemId', i) as string; + + endpoint = `boards/${boardId}/cards/${cardId}/checklists/${checklistId}/items/${itemId}`; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + Object.assign(body, updateFields); + } + } + let responseData = await apiRequest.call(this, requestMethod, endpoint, body, qs); + + if (returnAll === false) { + limit = this.getNodeParameter('limit', i) as number; + responseData = responseData.splice(0, limit); + } + + 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/Wekan/wekan.png b/packages/nodes-base/nodes/Wekan/wekan.png new file mode 100644 index 000000000..a4fc946c3 Binary files /dev/null and b/packages/nodes-base/nodes/Wekan/wekan.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index d216c58d9..056cce869 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -182,6 +182,7 @@ "dist/credentials/VonageApi.credentials.js", "dist/credentials/WebflowApi.credentials.js", "dist/credentials/WebflowOAuth2Api.credentials.js", + "dist/credentials/WekanApi.credentials.js", "dist/credentials/WooCommerceApi.credentials.js", "dist/credentials/WordpressApi.credentials.js", "dist/credentials/WufooApi.credentials.js", @@ -377,6 +378,7 @@ "dist/nodes/Vonage/Vonage.node.js", "dist/nodes/Webflow/WebflowTrigger.node.js", "dist/nodes/Webhook.node.js", + "dist/nodes/Wekan/Wekan.node.js", "dist/nodes/Wordpress/Wordpress.node.js", "dist/nodes/WooCommerce/WooCommerce.node.js", "dist/nodes/WooCommerce/WooCommerceTrigger.node.js",