@blickwerk/n8n-nodes-microsoft-planner 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Blickwerk Media UG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # n8n-nodes-microsoft-planner
2
+
3
+ This is an n8n community node that allows you to interact with Microsoft Planner in your n8n workflows.
4
+
5
+ [n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
6
+
7
+ [Microsoft Planner](https://www.microsoft.com/en-us/microsoft-365/business/task-management-software) is a task management tool that helps teams organize, assign, and collaborate on tasks.
8
+
9
+ ## Installation
10
+
11
+ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
12
+
13
+ ### Community Node
14
+
15
+ 1. Go to **Settings > Community Nodes** in your n8n instance
16
+ 2. Select **Install**
17
+ 3. Enter `n8n-nodes-microsoft-planner` in **Enter npm package name**
18
+ 4. Agree to the [risks](https://docs.n8n.io/integrations/community-nodes/risks/) of using community nodes
19
+ 5. Select **Install**
20
+
21
+ After installing the node, you can use it like any other node in your workflows.
22
+
23
+ ### Manual Installation
24
+
25
+ To install manually from source:
26
+
27
+ ```bash
28
+ npm install n8n-nodes-microsoft-planner
29
+ ```
30
+
31
+ ## Prerequisites
32
+
33
+ You need to have:
34
+ - An active Microsoft 365 subscription
35
+ - A Microsoft Planner plan created
36
+ - Azure AD App Registration with the following API permissions:
37
+ - `Tasks.ReadWrite` - Read and write tasks
38
+ - `Group.ReadWrite.All` - Read and write all groups (required for Planner)
39
+
40
+ ## Setting up Azure AD App
41
+
42
+ 1. Go to [Azure Portal](https://portal.azure.com/)
43
+ 2. Navigate to **Azure Active Directory > App registrations**
44
+ 3. Click **New registration**
45
+ 4. Give it a name (e.g., "n8n Microsoft Planner Integration")
46
+ 5. Select **Accounts in this organizational directory only**
47
+ 6. Add redirect URI: `https://your-n8n-instance.com/rest/oauth2-credential/callback`
48
+ 7. Click **Register**
49
+
50
+ ### Configure API Permissions
51
+
52
+ 1. Go to **API permissions**
53
+ 2. Click **Add a permission**
54
+ 3. Select **Microsoft Graph**
55
+ 4. Select **Delegated permissions**
56
+ 5. Add the following permissions:
57
+ - `Tasks.ReadWrite`
58
+ - `Group.ReadWrite.All`
59
+ 6. Click **Grant admin consent**
60
+
61
+ ### Create Client Secret
62
+
63
+ 1. Go to **Certificates & secrets**
64
+ 2. Click **New client secret**
65
+ 3. Add a description and select expiration
66
+ 4. Copy the **Value** (you won't see it again!)
67
+
68
+ ### Get Application Details
69
+
70
+ - **Client ID**: Found on the app overview page
71
+ - **Client Secret**: The value you copied in the previous step
72
+
73
+ ## Credentials
74
+
75
+ Configure the Microsoft Planner OAuth2 API credentials in n8n:
76
+
77
+ 1. In n8n, go to **Credentials > New**
78
+ 2. Search for **Microsoft Planner OAuth2 API**
79
+ 3. Enter your **Client ID** and **Client Secret**
80
+ 4. Click **Connect my account**
81
+ 5. Complete the OAuth flow
82
+
83
+ ## Operations
84
+
85
+ ### Task
86
+
87
+ - **Create** - Create a new task
88
+ - **Get** - Get a task by ID
89
+ - **Get Many** - Get multiple tasks from a plan or bucket
90
+ - **Update** - Update an existing task
91
+ - **Delete** - Delete a task
92
+
93
+ ## Usage
94
+
95
+ ### Creating a Task
96
+
97
+ To create a task, you need:
98
+ - **Plan ID**: The ID of the plan
99
+ - **Bucket ID**: The ID of the bucket within the plan
100
+ - **Title**: The task title
101
+
102
+ Optional fields:
103
+ - Description
104
+ - Priority (0-10, where 0 is most urgent)
105
+ - Due Date Time
106
+ - Start Date Time
107
+ - Percent Complete
108
+
109
+ ### Getting Tasks
110
+
111
+ You can retrieve tasks by:
112
+ - **Task ID**: Get a specific task
113
+ - **Plan ID**: Get all tasks in a plan
114
+ - **Bucket ID**: Get all tasks in a bucket
115
+
116
+ ### Updating a Task
117
+
118
+ To update a task, provide the Task ID and the fields you want to update.
119
+
120
+ ### Finding Plan and Bucket IDs
121
+
122
+ You can find Plan IDs and Bucket IDs using the Microsoft Graph Explorer:
123
+
124
+ 1. Go to [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)
125
+ 2. Sign in with your Microsoft account
126
+ 3. Use these queries:
127
+ - Get all plans: `GET https://graph.microsoft.com/v1.0/me/planner/plans`
128
+ - Get buckets in a plan: `GET https://graph.microsoft.com/v1.0/planner/plans/{plan-id}/buckets`
129
+
130
+ ## Compatibility
131
+
132
+ Tested with n8n version 1.0.0 and above.
133
+
134
+ ## Resources
135
+
136
+ - [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
137
+ - [Microsoft Graph Planner API documentation](https://docs.microsoft.com/en-us/graph/api/resources/planner-overview)
138
+ - [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)
139
+
140
+ ## Version History
141
+
142
+ ### 1.0.0
143
+ - Initial release
144
+ - Support for creating and retrieving Planner tasks
145
+ - OAuth2 authentication
146
+
147
+ ## License
148
+
149
+ [MIT](LICENSE.md)
150
+
151
+ ## Author
152
+
153
+ Developed by **Blickwerk Media UG**
154
+
155
+ ## Support
156
+
157
+ For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/blickwerk/n8n-nodes-microsoft-planner).
@@ -0,0 +1,10 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class MicrosoftPlannerOAuth2Api implements ICredentialType {
3
+ name: string;
4
+ extends: string[];
5
+ displayName: string;
6
+ documentationUrl: string;
7
+ properties: INodeProperties[];
8
+ authenticate: IAuthenticateGeneric;
9
+ test: ICredentialTestRequest;
10
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MicrosoftPlannerOAuth2Api = void 0;
4
+ class MicrosoftPlannerOAuth2Api {
5
+ constructor() {
6
+ this.name = 'microsoftPlannerOAuth2Api';
7
+ this.extends = ['oAuth2Api'];
8
+ this.displayName = 'Microsoft Planner OAuth2 API';
9
+ this.documentationUrl = 'https://docs.microsoft.com/en-us/graph/auth-v2-user';
10
+ this.properties = [
11
+ {
12
+ displayName: 'Grant Type',
13
+ name: 'grantType',
14
+ type: 'hidden',
15
+ default: 'authorizationCode',
16
+ },
17
+ {
18
+ displayName: 'Authorization URL',
19
+ name: 'authUrl',
20
+ type: 'hidden',
21
+ default: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
22
+ required: true,
23
+ },
24
+ {
25
+ displayName: 'Access Token URL',
26
+ name: 'accessTokenUrl',
27
+ type: 'hidden',
28
+ default: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
29
+ required: true,
30
+ },
31
+ {
32
+ displayName: 'Scope',
33
+ name: 'scope',
34
+ type: 'hidden',
35
+ default: 'openid offline_access Tasks.ReadWrite Group.ReadWrite.All',
36
+ },
37
+ {
38
+ displayName: 'Auth URI Query Parameters',
39
+ name: 'authQueryParameters',
40
+ type: 'hidden',
41
+ default: 'response_mode=query',
42
+ },
43
+ {
44
+ displayName: 'Authentication',
45
+ name: 'authentication',
46
+ type: 'hidden',
47
+ default: 'body',
48
+ },
49
+ {
50
+ displayName: 'Client ID',
51
+ name: 'clientId',
52
+ type: 'string',
53
+ default: '',
54
+ required: true,
55
+ },
56
+ {
57
+ displayName: 'Client Secret',
58
+ name: 'clientSecret',
59
+ type: 'string',
60
+ typeOptions: {
61
+ password: true,
62
+ },
63
+ default: '',
64
+ required: true,
65
+ },
66
+ ];
67
+ this.authenticate = {
68
+ type: 'generic',
69
+ properties: {
70
+ headers: {
71
+ Authorization: '={{$credentials.tokenType}} {{$credentials.accessToken}}',
72
+ },
73
+ },
74
+ };
75
+ this.test = {
76
+ request: {
77
+ baseURL: 'https://graph.microsoft.com/v1.0',
78
+ url: '/me',
79
+ },
80
+ };
81
+ }
82
+ }
83
+ exports.MicrosoftPlannerOAuth2Api = MicrosoftPlannerOAuth2Api;
@@ -0,0 +1,4 @@
1
+ import { IDataObject, IExecuteFunctions, IHookFunctions, IHttpRequestMethods, ILoadOptionsFunctions } from 'n8n-workflow';
2
+ export declare function microsoftApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, resource: string, body?: IDataObject, qs?: IDataObject, uri?: string, headers?: IDataObject): Promise<any>;
3
+ export declare function microsoftApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, query?: IDataObject): Promise<any>;
4
+ export declare function cleanETag(eTag: string): string;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.microsoftApiRequest = microsoftApiRequest;
4
+ exports.microsoftApiRequestAllItems = microsoftApiRequestAllItems;
5
+ exports.cleanETag = cleanETag;
6
+ const n8n_workflow_1 = require("n8n-workflow");
7
+ async function microsoftApiRequest(method, resource, body = {}, qs = {}, uri, headers = {}) {
8
+ const options = {
9
+ headers: {
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ method,
13
+ body,
14
+ qs,
15
+ url: uri || `https://graph.microsoft.com/v1.0${resource}`,
16
+ json: true,
17
+ };
18
+ try {
19
+ if (Object.keys(headers).length !== 0) {
20
+ options.headers = Object.assign({}, options.headers, headers);
21
+ }
22
+ if (Object.keys(body).length === 0) {
23
+ delete options.body;
24
+ }
25
+ return await this.helpers.requestOAuth2.call(this, 'microsoftPlannerOAuth2Api', options);
26
+ }
27
+ catch (error) {
28
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
29
+ }
30
+ }
31
+ async function microsoftApiRequestAllItems(propertyName, method, endpoint, body = {}, query = {}) {
32
+ const returnData = [];
33
+ let responseData;
34
+ let uri;
35
+ do {
36
+ responseData = await microsoftApiRequest.call(this, method, endpoint, body, query, uri);
37
+ uri = responseData['@odata.nextLink'];
38
+ returnData.push.apply(returnData, responseData[propertyName]);
39
+ } while (responseData['@odata.nextLink'] !== undefined);
40
+ return returnData;
41
+ }
42
+ function cleanETag(eTag) {
43
+ if (eTag.startsWith('W/"') || eTag.startsWith("W/'")) {
44
+ return eTag.substring(2);
45
+ }
46
+ return eTag;
47
+ }
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class MicrosoftPlanner implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MicrosoftPlanner = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const GenericFunctions_1 = require("./GenericFunctions");
6
+ const TaskDescription_1 = require("./TaskDescription");
7
+ class MicrosoftPlanner {
8
+ constructor() {
9
+ this.description = {
10
+ displayName: 'Microsoft Planner',
11
+ name: 'microsoftPlanner',
12
+ icon: 'file:planner.svg',
13
+ group: ['transform'],
14
+ version: 1,
15
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
16
+ description: 'Create and retrieve tasks in Microsoft Planner',
17
+ defaults: {
18
+ name: 'Microsoft Planner',
19
+ },
20
+ inputs: ['main'],
21
+ outputs: ['main'],
22
+ credentials: [
23
+ {
24
+ name: 'microsoftPlannerOAuth2Api',
25
+ required: true,
26
+ },
27
+ ],
28
+ properties: [
29
+ {
30
+ displayName: 'Resource',
31
+ name: 'resource',
32
+ type: 'options',
33
+ noDataExpression: true,
34
+ options: [
35
+ {
36
+ name: 'Task',
37
+ value: 'task',
38
+ },
39
+ ],
40
+ default: 'task',
41
+ },
42
+ ...TaskDescription_1.taskOperations,
43
+ ...TaskDescription_1.taskFields,
44
+ ],
45
+ };
46
+ }
47
+ async execute() {
48
+ const items = this.getInputData();
49
+ const returnData = [];
50
+ const resource = this.getNodeParameter('resource', 0);
51
+ const operation = this.getNodeParameter('operation', 0);
52
+ for (let i = 0; i < items.length; i++) {
53
+ try {
54
+ if (resource === 'task') {
55
+ // ----------------------------------
56
+ // task:create
57
+ // ----------------------------------
58
+ if (operation === 'create') {
59
+ const planId = this.getNodeParameter('planId', i);
60
+ const bucketId = this.getNodeParameter('bucketId', i);
61
+ const title = this.getNodeParameter('title', i);
62
+ const additionalFields = this.getNodeParameter('additionalFields', i);
63
+ const body = {
64
+ planId,
65
+ bucketId,
66
+ title,
67
+ };
68
+ if (additionalFields.priority !== undefined) {
69
+ body.priority = additionalFields.priority;
70
+ }
71
+ if (additionalFields.dueDateTime) {
72
+ body.dueDateTime = additionalFields.dueDateTime;
73
+ }
74
+ if (additionalFields.startDateTime) {
75
+ body.startDateTime = additionalFields.startDateTime;
76
+ }
77
+ if (additionalFields.percentComplete !== undefined) {
78
+ body.percentComplete = additionalFields.percentComplete;
79
+ }
80
+ const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'POST', '/planner/tasks', body);
81
+ // Add description if provided
82
+ if (additionalFields.description) {
83
+ const details = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${responseData.id}/details`);
84
+ const eTag = (0, GenericFunctions_1.cleanETag)(details['@odata.etag']);
85
+ await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${responseData.id}/details`, {
86
+ description: additionalFields.description,
87
+ }, {}, undefined, {
88
+ 'If-Match': eTag,
89
+ });
90
+ responseData.description = additionalFields.description;
91
+ }
92
+ returnData.push(responseData);
93
+ }
94
+ // ----------------------------------
95
+ // task:get
96
+ // ----------------------------------
97
+ if (operation === 'get') {
98
+ const taskId = this.getNodeParameter('taskId', i);
99
+ const additionalFields = this.getNodeParameter('additionalFields', i);
100
+ const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}`);
101
+ if (additionalFields.includeDetails) {
102
+ const details = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}/details`);
103
+ responseData.details = details;
104
+ }
105
+ returnData.push(responseData);
106
+ }
107
+ // ----------------------------------
108
+ // task:getAll
109
+ // ----------------------------------
110
+ if (operation === 'getAll') {
111
+ const returnAll = this.getNodeParameter('returnAll', i);
112
+ const filters = this.getNodeParameter('filters', i);
113
+ let endpoint = '';
114
+ if (filters.planId) {
115
+ endpoint = `/planner/plans/${filters.planId}/tasks`;
116
+ }
117
+ else if (filters.bucketId) {
118
+ endpoint = `/planner/buckets/${filters.bucketId}/tasks`;
119
+ }
120
+ else {
121
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'You must specify either a Plan ID or Bucket ID to retrieve tasks', { itemIndex: i });
122
+ }
123
+ if (returnAll) {
124
+ const responseData = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', endpoint);
125
+ returnData.push(...responseData);
126
+ }
127
+ else {
128
+ const limit = this.getNodeParameter('limit', i);
129
+ const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', endpoint, {}, {
130
+ $top: limit,
131
+ });
132
+ returnData.push(...responseData.value);
133
+ }
134
+ }
135
+ // ----------------------------------
136
+ // task:update
137
+ // ----------------------------------
138
+ if (operation === 'update') {
139
+ const taskId = this.getNodeParameter('taskId', i);
140
+ const updateFields = this.getNodeParameter('updateFields', i);
141
+ // Get current task to retrieve eTag
142
+ const currentTask = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}`);
143
+ const eTag = (0, GenericFunctions_1.cleanETag)(currentTask['@odata.etag']);
144
+ const body = {};
145
+ if (updateFields.title) {
146
+ body.title = updateFields.title;
147
+ }
148
+ if (updateFields.priority !== undefined) {
149
+ body.priority = updateFields.priority;
150
+ }
151
+ if (updateFields.dueDateTime) {
152
+ body.dueDateTime = updateFields.dueDateTime;
153
+ }
154
+ if (updateFields.startDateTime) {
155
+ body.startDateTime = updateFields.startDateTime;
156
+ }
157
+ if (updateFields.percentComplete !== undefined) {
158
+ body.percentComplete = updateFields.percentComplete;
159
+ }
160
+ if (updateFields.bucketId) {
161
+ body.bucketId = updateFields.bucketId;
162
+ }
163
+ const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}`, body, {}, undefined, {
164
+ 'If-Match': eTag,
165
+ });
166
+ // Update description if provided
167
+ if (updateFields.description) {
168
+ const details = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}/details`);
169
+ const detailsETag = (0, GenericFunctions_1.cleanETag)(details['@odata.etag']);
170
+ await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}/details`, {
171
+ description: updateFields.description,
172
+ }, {}, undefined, {
173
+ 'If-Match': detailsETag,
174
+ });
175
+ }
176
+ returnData.push(responseData);
177
+ }
178
+ // ----------------------------------
179
+ // task:delete
180
+ // ----------------------------------
181
+ if (operation === 'delete') {
182
+ const taskId = this.getNodeParameter('taskId', i);
183
+ // Get current task to retrieve eTag
184
+ const currentTask = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}`);
185
+ const eTag = (0, GenericFunctions_1.cleanETag)(currentTask['@odata.etag']);
186
+ await GenericFunctions_1.microsoftApiRequest.call(this, 'DELETE', `/planner/tasks/${taskId}`, {}, {}, undefined, {
187
+ 'If-Match': eTag,
188
+ });
189
+ returnData.push({ success: true, taskId });
190
+ }
191
+ }
192
+ }
193
+ catch (error) {
194
+ if (this.continueOnFail()) {
195
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
196
+ returnData.push({ error: errorMessage });
197
+ continue;
198
+ }
199
+ throw error;
200
+ }
201
+ }
202
+ return [this.helpers.returnJsonArray(returnData)];
203
+ }
204
+ }
205
+ exports.MicrosoftPlanner = MicrosoftPlanner;
@@ -0,0 +1,3 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const taskOperations: INodeProperties[];
3
+ export declare const taskFields: INodeProperties[];
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.taskFields = exports.taskOperations = void 0;
4
+ exports.taskOperations = [
5
+ {
6
+ displayName: 'Operation',
7
+ name: 'operation',
8
+ type: 'options',
9
+ noDataExpression: true,
10
+ displayOptions: {
11
+ show: {
12
+ resource: ['task'],
13
+ },
14
+ },
15
+ options: [
16
+ {
17
+ name: 'Create',
18
+ value: 'create',
19
+ description: 'Create a new task',
20
+ action: 'Create a task',
21
+ },
22
+ {
23
+ name: 'Get',
24
+ value: 'get',
25
+ description: 'Get a task',
26
+ action: 'Get a task',
27
+ },
28
+ {
29
+ name: 'Get Many',
30
+ value: 'getAll',
31
+ description: 'Get many tasks',
32
+ action: 'Get many tasks',
33
+ },
34
+ {
35
+ name: 'Update',
36
+ value: 'update',
37
+ description: 'Update a task',
38
+ action: 'Update a task',
39
+ },
40
+ {
41
+ name: 'Delete',
42
+ value: 'delete',
43
+ description: 'Delete a task',
44
+ action: 'Delete a task',
45
+ },
46
+ ],
47
+ default: 'create',
48
+ },
49
+ ];
50
+ exports.taskFields = [
51
+ // ----------------------------------
52
+ // task:create
53
+ // ----------------------------------
54
+ {
55
+ displayName: 'Plan ID',
56
+ name: 'planId',
57
+ type: 'string',
58
+ required: true,
59
+ displayOptions: {
60
+ show: {
61
+ resource: ['task'],
62
+ operation: ['create'],
63
+ },
64
+ },
65
+ default: '',
66
+ description: 'The ID of the plan to which the task belongs',
67
+ },
68
+ {
69
+ displayName: 'Bucket ID',
70
+ name: 'bucketId',
71
+ type: 'string',
72
+ required: true,
73
+ displayOptions: {
74
+ show: {
75
+ resource: ['task'],
76
+ operation: ['create'],
77
+ },
78
+ },
79
+ default: '',
80
+ description: 'The ID of the bucket to which the task belongs',
81
+ },
82
+ {
83
+ displayName: 'Title',
84
+ name: 'title',
85
+ type: 'string',
86
+ required: true,
87
+ displayOptions: {
88
+ show: {
89
+ resource: ['task'],
90
+ operation: ['create'],
91
+ },
92
+ },
93
+ default: '',
94
+ description: 'Title of the task',
95
+ },
96
+ {
97
+ displayName: 'Additional Fields',
98
+ name: 'additionalFields',
99
+ type: 'collection',
100
+ placeholder: 'Add Field',
101
+ default: {},
102
+ displayOptions: {
103
+ show: {
104
+ resource: ['task'],
105
+ operation: ['create'],
106
+ },
107
+ },
108
+ options: [
109
+ {
110
+ displayName: 'Description',
111
+ name: 'description',
112
+ type: 'string',
113
+ typeOptions: {
114
+ rows: 5,
115
+ },
116
+ default: '',
117
+ description: 'Description of the task',
118
+ },
119
+ {
120
+ displayName: 'Priority',
121
+ name: 'priority',
122
+ type: 'number',
123
+ default: 5,
124
+ description: 'Priority of the task (0-10, where 0 is most urgent)',
125
+ },
126
+ {
127
+ displayName: 'Due Date Time',
128
+ name: 'dueDateTime',
129
+ type: 'dateTime',
130
+ default: '',
131
+ description: 'Due date and time for the task',
132
+ },
133
+ {
134
+ displayName: 'Start Date Time',
135
+ name: 'startDateTime',
136
+ type: 'dateTime',
137
+ default: '',
138
+ description: 'Start date and time for the task',
139
+ },
140
+ {
141
+ displayName: 'Percent Complete',
142
+ name: 'percentComplete',
143
+ type: 'number',
144
+ default: 0,
145
+ description: 'Percentage of task completion (0-100)',
146
+ },
147
+ ],
148
+ },
149
+ // ----------------------------------
150
+ // task:get
151
+ // ----------------------------------
152
+ {
153
+ displayName: 'Task ID',
154
+ name: 'taskId',
155
+ type: 'string',
156
+ required: true,
157
+ displayOptions: {
158
+ show: {
159
+ resource: ['task'],
160
+ operation: ['get', 'delete', 'update'],
161
+ },
162
+ },
163
+ default: '',
164
+ description: 'The ID of the task',
165
+ },
166
+ {
167
+ displayName: 'Additional Fields',
168
+ name: 'additionalFields',
169
+ type: 'collection',
170
+ placeholder: 'Add Field',
171
+ default: {},
172
+ displayOptions: {
173
+ show: {
174
+ resource: ['task'],
175
+ operation: ['get'],
176
+ },
177
+ },
178
+ options: [
179
+ {
180
+ displayName: 'Include Details',
181
+ name: 'includeDetails',
182
+ type: 'boolean',
183
+ default: false,
184
+ description: 'Whether to include task details (description, checklist, etc.)',
185
+ },
186
+ ],
187
+ },
188
+ // ----------------------------------
189
+ // task:getAll
190
+ // ----------------------------------
191
+ {
192
+ displayName: 'Return All',
193
+ name: 'returnAll',
194
+ type: 'boolean',
195
+ displayOptions: {
196
+ show: {
197
+ resource: ['task'],
198
+ operation: ['getAll'],
199
+ },
200
+ },
201
+ default: false,
202
+ description: 'Whether to return all results or only up to a given limit',
203
+ },
204
+ {
205
+ displayName: 'Limit',
206
+ name: 'limit',
207
+ type: 'number',
208
+ displayOptions: {
209
+ show: {
210
+ resource: ['task'],
211
+ operation: ['getAll'],
212
+ returnAll: [false],
213
+ },
214
+ },
215
+ typeOptions: {
216
+ minValue: 1,
217
+ maxValue: 500,
218
+ },
219
+ default: 100,
220
+ description: 'Max number of results to return',
221
+ },
222
+ {
223
+ displayName: 'Filters',
224
+ name: 'filters',
225
+ type: 'collection',
226
+ placeholder: 'Add Filter',
227
+ default: {},
228
+ displayOptions: {
229
+ show: {
230
+ resource: ['task'],
231
+ operation: ['getAll'],
232
+ },
233
+ },
234
+ options: [
235
+ {
236
+ displayName: 'Plan ID',
237
+ name: 'planId',
238
+ type: 'string',
239
+ default: '',
240
+ description: 'Filter tasks by plan ID',
241
+ },
242
+ {
243
+ displayName: 'Bucket ID',
244
+ name: 'bucketId',
245
+ type: 'string',
246
+ default: '',
247
+ description: 'Filter tasks by bucket ID',
248
+ },
249
+ ],
250
+ },
251
+ // ----------------------------------
252
+ // task:update
253
+ // ----------------------------------
254
+ {
255
+ displayName: 'Update Fields',
256
+ name: 'updateFields',
257
+ type: 'collection',
258
+ placeholder: 'Add Field',
259
+ default: {},
260
+ displayOptions: {
261
+ show: {
262
+ resource: ['task'],
263
+ operation: ['update'],
264
+ },
265
+ },
266
+ options: [
267
+ {
268
+ displayName: 'Title',
269
+ name: 'title',
270
+ type: 'string',
271
+ default: '',
272
+ description: 'Title of the task',
273
+ },
274
+ {
275
+ displayName: 'Description',
276
+ name: 'description',
277
+ type: 'string',
278
+ typeOptions: {
279
+ rows: 5,
280
+ },
281
+ default: '',
282
+ description: 'Description of the task',
283
+ },
284
+ {
285
+ displayName: 'Priority',
286
+ name: 'priority',
287
+ type: 'number',
288
+ default: 5,
289
+ description: 'Priority of the task (0-10, where 0 is most urgent)',
290
+ },
291
+ {
292
+ displayName: 'Due Date Time',
293
+ name: 'dueDateTime',
294
+ type: 'dateTime',
295
+ default: '',
296
+ description: 'Due date and time for the task',
297
+ },
298
+ {
299
+ displayName: 'Start Date Time',
300
+ name: 'startDateTime',
301
+ type: 'dateTime',
302
+ default: '',
303
+ description: 'Start date and time for the task',
304
+ },
305
+ {
306
+ displayName: 'Percent Complete',
307
+ name: 'percentComplete',
308
+ type: 'number',
309
+ default: 0,
310
+ description: 'Percentage of task completion (0-100)',
311
+ },
312
+ {
313
+ displayName: 'Bucket ID',
314
+ name: 'bucketId',
315
+ type: 'string',
316
+ default: '',
317
+ description: 'Move task to a different bucket',
318
+ },
319
+ ],
320
+ },
321
+ ];
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <defs>
3
+ <linearGradient id="a" x1="16" y1="2.5" x2="16" y2="29.5" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#31ad5f"/>
5
+ <stop offset="1" stop-color="#1d6f42"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect x="2" y="2.5" width="28" height="27" rx="1.5" fill="url(#a)"/>
9
+ <path d="M7 9h7v2H7zm0 4h10v2H7zm0 4h8v2H7z" fill="#fff"/>
10
+ <circle cx="22" cy="10" r="2.5" fill="#fff"/>
11
+ <circle cx="22" cy="15" r="2.5" fill="#fff"/>
12
+ <circle cx="22" cy="20" r="2.5" fill="#fff"/>
13
+ </svg>
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@blickwerk/n8n-nodes-microsoft-planner",
3
+ "version": "1.0.0",
4
+ "description": "n8n node for Microsoft Planner - Create and retrieve tasks",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "microsoft",
9
+ "planner",
10
+ "tasks"
11
+ ],
12
+ "license": "MIT",
13
+ "homepage": "https://github.com/blickwerk/n8n-nodes-microsoft-planner",
14
+ "author": {
15
+ "name": "Blickwerk Media UG",
16
+ "email": "info@blickwerk-media.de"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/blickwerk/n8n-nodes-microsoft-planner.git"
21
+ },
22
+ "main": "index.js",
23
+ "scripts": {
24
+ "build": "tsc && gulp build:icons",
25
+ "dev": "tsc --watch",
26
+ "format": "prettier nodes credentials --write",
27
+ "lint": "eslint nodes credentials package.json",
28
+ "lintfix": "eslint nodes credentials package.json --fix",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "n8n": {
35
+ "n8nNodesApiVersion": 1,
36
+ "credentials": [
37
+ "dist/credentials/MicrosoftPlannerOAuth2Api.credentials.js"
38
+ ],
39
+ "nodes": [
40
+ "dist/nodes/MicrosoftPlanner/MicrosoftPlanner.node.js"
41
+ ]
42
+ },
43
+ "devDependencies": {
44
+ "@typescript-eslint/parser": "^5.59.0",
45
+ "eslint": "^8.40.0",
46
+ "eslint-plugin-n8n-nodes-base": "^1.12.0",
47
+ "gulp": "^4.0.2",
48
+ "n8n-workflow": "^1.0.0",
49
+ "prettier": "^2.8.8",
50
+ "typescript": "^5.0.4"
51
+ },
52
+ "dependencies": {
53
+ "n8n-core": "^1.0.0"
54
+ },
55
+ "peerDependencies": {
56
+ "n8n-workflow": "^1.0.0"
57
+ }
58
+ }