@blickwerk/n8n-nodes-microsoft-planner 1.0.1 → 1.1.1

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/README.md CHANGED
@@ -14,7 +14,7 @@ Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes
14
14
 
15
15
  1. Go to **Settings > Community Nodes** in your n8n instance
16
16
  2. Select **Install**
17
- 3. Enter `n8n-nodes-microsoft-planner` in **Enter npm package name**
17
+ 3. Enter `@blickwerk/n8n-nodes-microsoft-planner` in **Enter npm package name**
18
18
  4. Agree to the [risks](https://docs.n8n.io/integrations/community-nodes/risks/) of using community nodes
19
19
  5. Select **Install**
20
20
 
@@ -22,10 +22,10 @@ After installing the node, you can use it like any other node in your workflows.
22
22
 
23
23
  ### Manual Installation
24
24
 
25
- To install manually from source:
25
+ To install manually:
26
26
 
27
27
  ```bash
28
- npm install n8n-nodes-microsoft-planner
28
+ npm install @blickwerk/n8n-nodes-microsoft-planner
29
29
  ```
30
30
 
31
31
  ## Prerequisites
@@ -36,6 +36,7 @@ You need to have:
36
36
  - Azure AD App Registration with the following API permissions:
37
37
  - `Tasks.ReadWrite` - Read and write tasks
38
38
  - `Group.ReadWrite.All` - Read and write all groups (required for Planner)
39
+ - `User.Read.All` - Read all users (required for user assignment by email)
39
40
 
40
41
  ## Setting up Azure AD App
41
42
 
@@ -54,10 +55,13 @@ You need to have:
54
55
  3. Select **Microsoft Graph**
55
56
  4. Select **Delegated permissions**
56
57
  5. Add the following permissions:
57
- - `Tasks.ReadWrite`
58
- - `Group.ReadWrite.All`
58
+ - `Tasks.ReadWrite` - Read and write tasks
59
+ - `Group.ReadWrite.All` - Read and write all groups (required for Planner)
60
+ - `User.Read.All` - Read all users' basic profiles (required for user assignment)
59
61
  6. Click **Grant admin consent**
60
62
 
63
+ **Note**: The `User.Read.All` permission is required if you want to assign tasks to users by email address.
64
+
61
65
  ### Create Client Secret
62
66
 
63
67
  1. Go to **Certificates & secrets**
@@ -100,11 +104,16 @@ To create a task, you need:
100
104
  - **Title**: The task title
101
105
 
102
106
  Optional fields:
103
- - Description
104
- - Priority (0-10, where 0 is most urgent)
105
- - Due Date Time
106
- - Start Date Time
107
- - Percent Complete
107
+ - **Description**: Detailed task description
108
+ - **Priority**: Select from dropdown
109
+ - Urgent (highest priority)
110
+ - Important
111
+ - Medium (default)
112
+ - Low
113
+ - **Assigned To**: Comma-separated list of user emails (e.g., `user1@domain.com, user2@domain.com`)
114
+ - **Due Date Time**: When the task should be completed
115
+ - **Start Date Time**: When work on the task should begin
116
+ - **Percent Complete**: Task completion percentage (0-100)
108
117
 
109
118
  ### Getting Tasks
110
119
 
@@ -115,7 +124,15 @@ You can retrieve tasks by:
115
124
 
116
125
  ### Updating a Task
117
126
 
118
- To update a task, provide the Task ID and the fields you want to update.
127
+ To update a task, provide the Task ID and the fields you want to update. You can update:
128
+ - Title
129
+ - Description
130
+ - Priority (via dropdown)
131
+ - Assigned users (via email list)
132
+ - Due Date Time
133
+ - Start Date Time
134
+ - Percent Complete
135
+ - Move to different bucket
119
136
 
120
137
  ### Finding Plan and Bucket IDs
121
138
 
@@ -139,10 +156,20 @@ Tested with n8n version 1.0.0 and above.
139
156
 
140
157
  ## Version History
141
158
 
159
+ ### 1.1.0
160
+ - Added priority dropdown (Urgent, Important, Medium, Low) instead of number input
161
+ - Added user assignment functionality (assign tasks by email)
162
+ - Improved user experience with better field descriptions
163
+
164
+ ### 1.0.1
165
+ - Fixed DateTime format handling (automatic conversion to ISO 8601)
166
+ - Improved error handling for invalid date formats
167
+
142
168
  ### 1.0.0
143
169
  - Initial release
144
170
  - Support for creating and retrieving Planner tasks
145
171
  - OAuth2 authentication
172
+ - CRUD operations (Create, Read, Update, Delete)
146
173
 
147
174
  ## License
148
175
 
@@ -3,3 +3,6 @@ export declare function microsoftApiRequest(this: IHookFunctions | IExecuteFunct
3
3
  export declare function microsoftApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, query?: IDataObject): Promise<any>;
4
4
  export declare function cleanETag(eTag: string): string;
5
5
  export declare function formatDateTime(dateTime: string | undefined): string | undefined;
6
+ export declare function getUserIdByEmail(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, email: string): Promise<string | null>;
7
+ export declare function parseAssignments(assignmentsString: string): string[];
8
+ export declare function createAssignmentsObject(userIds: string[]): IDataObject;
@@ -4,6 +4,9 @@ exports.microsoftApiRequest = microsoftApiRequest;
4
4
  exports.microsoftApiRequestAllItems = microsoftApiRequestAllItems;
5
5
  exports.cleanETag = cleanETag;
6
6
  exports.formatDateTime = formatDateTime;
7
+ exports.getUserIdByEmail = getUserIdByEmail;
8
+ exports.parseAssignments = parseAssignments;
9
+ exports.createAssignmentsObject = createAssignmentsObject;
7
10
  const n8n_workflow_1 = require("n8n-workflow");
8
11
  async function microsoftApiRequest(method, resource, body = {}, qs = {}, uri, headers = {}) {
9
12
  const options = {
@@ -61,3 +64,33 @@ function formatDateTime(dateTime) {
61
64
  }
62
65
  return date.toISOString();
63
66
  }
67
+ async function getUserIdByEmail(email) {
68
+ try {
69
+ const response = await microsoftApiRequest.call(this, 'GET', `/users/${encodeURIComponent(email)}`);
70
+ return response.id;
71
+ }
72
+ catch (error) {
73
+ // Log error for debugging
74
+ console.error(`Failed to get user ID for email ${email}:`, error.message || error);
75
+ return null;
76
+ }
77
+ }
78
+ function parseAssignments(assignmentsString) {
79
+ if (!assignmentsString || assignmentsString.trim() === '') {
80
+ return [];
81
+ }
82
+ return assignmentsString
83
+ .split(',')
84
+ .map((email) => email.trim())
85
+ .filter((email) => email.length > 0);
86
+ }
87
+ function createAssignmentsObject(userIds) {
88
+ const assignments = {};
89
+ for (const userId of userIds) {
90
+ assignments[userId] = {
91
+ '@odata.type': '#microsoft.graph.plannerAssignment',
92
+ orderHint: ' !',
93
+ };
94
+ }
95
+ return assignments;
96
+ }
@@ -68,15 +68,37 @@ class MicrosoftPlanner {
68
68
  if (additionalFields.priority !== undefined) {
69
69
  body.priority = additionalFields.priority;
70
70
  }
71
- if (additionalFields.dueDateTime) {
72
- body.dueDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.dueDateTime);
71
+ const formattedDueDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.dueDateTime);
72
+ if (formattedDueDateTime) {
73
+ body.dueDateTime = formattedDueDateTime;
73
74
  }
74
- if (additionalFields.startDateTime) {
75
- body.startDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.startDateTime);
75
+ const formattedStartDateTime = (0, GenericFunctions_1.formatDateTime)(additionalFields.startDateTime);
76
+ if (formattedStartDateTime) {
77
+ body.startDateTime = formattedStartDateTime;
76
78
  }
77
79
  if (additionalFields.percentComplete !== undefined) {
78
80
  body.percentComplete = additionalFields.percentComplete;
79
81
  }
82
+ // Handle assignments
83
+ if (additionalFields.assignments) {
84
+ const emails = (0, GenericFunctions_1.parseAssignments)(additionalFields.assignments);
85
+ const userIds = [];
86
+ for (const email of emails) {
87
+ const userId = await GenericFunctions_1.getUserIdByEmail.call(this, email);
88
+ if (userId) {
89
+ userIds.push(userId);
90
+ }
91
+ else {
92
+ console.warn(`Could not find user ID for email: ${email}`);
93
+ }
94
+ }
95
+ if (userIds.length > 0) {
96
+ body.assignments = (0, GenericFunctions_1.createAssignmentsObject)(userIds);
97
+ }
98
+ else if (emails.length > 0) {
99
+ console.warn('No valid user IDs found for assignment. Check if User.Read.All permission is granted.');
100
+ }
101
+ }
80
102
  const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'POST', '/planner/tasks', body);
81
103
  // Add description if provided
82
104
  if (additionalFields.description) {
@@ -148,11 +170,13 @@ class MicrosoftPlanner {
148
170
  if (updateFields.priority !== undefined) {
149
171
  body.priority = updateFields.priority;
150
172
  }
151
- if (updateFields.dueDateTime) {
152
- body.dueDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.dueDateTime);
173
+ const formattedDueDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.dueDateTime);
174
+ if (formattedDueDateTime) {
175
+ body.dueDateTime = formattedDueDateTime;
153
176
  }
154
- if (updateFields.startDateTime) {
155
- body.startDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.startDateTime);
177
+ const formattedStartDateTime = (0, GenericFunctions_1.formatDateTime)(updateFields.startDateTime);
178
+ if (formattedStartDateTime) {
179
+ body.startDateTime = formattedStartDateTime;
156
180
  }
157
181
  if (updateFields.percentComplete !== undefined) {
158
182
  body.percentComplete = updateFields.percentComplete;
@@ -160,6 +184,26 @@ class MicrosoftPlanner {
160
184
  if (updateFields.bucketId) {
161
185
  body.bucketId = updateFields.bucketId;
162
186
  }
187
+ // Handle assignments
188
+ if (updateFields.assignments) {
189
+ const emails = (0, GenericFunctions_1.parseAssignments)(updateFields.assignments);
190
+ const userIds = [];
191
+ for (const email of emails) {
192
+ const userId = await GenericFunctions_1.getUserIdByEmail.call(this, email);
193
+ if (userId) {
194
+ userIds.push(userId);
195
+ }
196
+ else {
197
+ console.warn(`Could not find user ID for email: ${email}`);
198
+ }
199
+ }
200
+ if (userIds.length > 0) {
201
+ body.assignments = (0, GenericFunctions_1.createAssignmentsObject)(userIds);
202
+ }
203
+ else if (emails.length > 0) {
204
+ console.warn('No valid user IDs found for assignment. Check if User.Read.All permission is granted.');
205
+ }
206
+ }
163
207
  const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}`, body, {}, undefined, {
164
208
  'If-Match': eTag,
165
209
  });
@@ -119,9 +119,35 @@ exports.taskFields = [
119
119
  {
120
120
  displayName: 'Priority',
121
121
  name: 'priority',
122
- type: 'number',
122
+ type: 'options',
123
+ options: [
124
+ {
125
+ name: 'Urgent',
126
+ value: 0,
127
+ },
128
+ {
129
+ name: 'Important',
130
+ value: 1,
131
+ },
132
+ {
133
+ name: 'Medium',
134
+ value: 5,
135
+ },
136
+ {
137
+ name: 'Low',
138
+ value: 9,
139
+ },
140
+ ],
123
141
  default: 5,
124
- description: 'Priority of the task (0-10, where 0 is most urgent)',
142
+ description: 'Priority of the task',
143
+ },
144
+ {
145
+ displayName: 'Assigned To (User IDs)',
146
+ name: 'assignments',
147
+ type: 'string',
148
+ default: '',
149
+ placeholder: 'user1@domain.com, user2@domain.com',
150
+ description: 'Comma-separated list of user emails or IDs to assign the task to',
125
151
  },
126
152
  {
127
153
  displayName: 'Due Date Time',
@@ -284,9 +310,35 @@ exports.taskFields = [
284
310
  {
285
311
  displayName: 'Priority',
286
312
  name: 'priority',
287
- type: 'number',
313
+ type: 'options',
314
+ options: [
315
+ {
316
+ name: 'Urgent',
317
+ value: 0,
318
+ },
319
+ {
320
+ name: 'Important',
321
+ value: 1,
322
+ },
323
+ {
324
+ name: 'Medium',
325
+ value: 5,
326
+ },
327
+ {
328
+ name: 'Low',
329
+ value: 9,
330
+ },
331
+ ],
288
332
  default: 5,
289
- description: 'Priority of the task (0-10, where 0 is most urgent)',
333
+ description: 'Priority of the task',
334
+ },
335
+ {
336
+ displayName: 'Assigned To (User IDs)',
337
+ name: 'assignments',
338
+ type: 'string',
339
+ default: '',
340
+ placeholder: 'user1@domain.com, user2@domain.com',
341
+ description: 'Comma-separated list of user emails or IDs to assign the task to',
290
342
  },
291
343
  {
292
344
  displayName: 'Due Date Time',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blickwerk/n8n-nodes-microsoft-planner",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "n8n node for Microsoft Planner - Create and retrieve tasks",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",