@blickwerk/n8n-nodes-microsoft-planner 1.3.2 → 1.3.4

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
@@ -86,7 +86,7 @@ Configure the Microsoft Planner OAuth2 API credentials in n8n:
86
86
 
87
87
  ## Features
88
88
 
89
- - **Dynamic Dropdowns**: Automatically loads and displays your Plans, Buckets, and Tasks - no need to manually copy IDs!
89
+ - **Resource Locator UI**: Choose between "From List" (dropdown) or "By ID" (manual input) for Buckets
90
90
  - **User Assignment**: Assign tasks to users by email address
91
91
  - **Priority Management**: Easy-to-use priority dropdown (Urgent, Important, Medium, Low)
92
92
  - **Full CRUD Operations**: Create, Read, Update, and Delete tasks
@@ -125,17 +125,18 @@ Optional fields:
125
125
  ### Getting Tasks
126
126
 
127
127
  **Get a single task:**
128
- - Select the task from the dropdown (automatically loaded from your plans)
128
+ - Enter the **Task ID** manually (no dropdown available for single task lookups)
129
129
 
130
130
  **Get many tasks:**
131
- - Filter by **Plan** (select from dropdown)
132
- - Or filter by **Bucket** (select from dropdown)
131
+ - Choose filter type: **Plan** or **Bucket**
132
+ - Enter the **Plan ID**
133
+ - If filtering by Bucket: Select bucket from dropdown or enter Bucket ID manually
133
134
  - Set a limit or return all tasks
134
135
 
135
136
  ### Updating a Task
136
137
 
137
138
  To update a task:
138
- 1. Select the **Task** from the dropdown
139
+ 1. Enter the **Task ID** manually
139
140
  2. Update any of these fields:
140
141
  - Title
141
142
  - Description
@@ -161,13 +162,13 @@ You can find your Plan ID in several ways:
161
162
  - Run: `GET /me/planner/plans`
162
163
  - Copy the `id` field from the plan you want
163
164
 
164
- ### Dynamic Dropdowns
165
+ ### Resource Locator (From List / By ID)
165
166
 
166
- Once you enter a Plan ID:
167
- - **Buckets**: Automatically load for that plan
168
- - **Tasks**: Load based on selected Plan/Bucket
167
+ When creating tasks or filtering by bucket:
168
+ - **From List**: Select from dropdown (automatically loads based on Plan ID)
169
+ - **By ID**: Manually enter the ID if you already know it
169
170
 
170
- You can also manually enter Bucket IDs and Task IDs if needed.
171
+ For Get/Update/Delete operations, you need to manually enter the Task ID.
171
172
 
172
173
  ## Compatibility
173
174
 
@@ -181,6 +182,19 @@ Tested with n8n version 1.0.0 and above.
181
182
 
182
183
  ## Version History
183
184
 
185
+ ### 1.3.3
186
+ - **Restructured Get Many Tasks for better UX**
187
+ - Added "Filter By" dropdown to choose between Plan or Bucket filtering
188
+ - Plan ID and Bucket are now separate fields (not in collection)
189
+ - Bucket dropdown now properly loads when Plan ID is entered
190
+ - Simplified Get/Update/Delete Task to use "By ID" only (no dropdown)
191
+ - Resource Locator UI for buckets with "From List" / "By ID" toggle
192
+
193
+ ### 1.3.0 - 1.3.2
194
+ - Added resource locator UI for Buckets and Tasks
195
+ - Converted from loadOptions to listSearch methods
196
+ - Various fixes for dropdown loading issues
197
+
184
198
  ### 1.2.4
185
199
  - **Fixed Bucket and Task dropdowns not showing!**
186
200
  - Changed field type from 'string' back to 'options' for proper dropdown display
@@ -47,21 +47,7 @@ class MicrosoftPlanner {
47
47
  listSearch: {
48
48
  async getBuckets() {
49
49
  try {
50
- // Try to get planId from main parameter or from filters collection
51
- let planId = '';
52
- try {
53
- planId = this.getNodeParameter('planId', 0);
54
- }
55
- catch (error) {
56
- // If not found in main parameters, try filters
57
- try {
58
- const filters = this.getNodeParameter('filters', 0);
59
- planId = filters.planId;
60
- }
61
- catch (e) {
62
- // planId not found anywhere
63
- }
64
- }
50
+ const planId = this.getNodeParameter('planId', 0);
65
51
  if (!planId) {
66
52
  return { results: [] };
67
53
  }
@@ -141,7 +127,6 @@ class MicrosoftPlanner {
141
127
  if (operation === 'create') {
142
128
  const planId = this.getNodeParameter('planId', i);
143
129
  const bucketIdParam = this.getNodeParameter('bucketId', i);
144
- // Extract bucketId value from resourceLocator object or string
145
130
  const bucketId = typeof bucketIdParam === 'string'
146
131
  ? bucketIdParam
147
132
  : bucketIdParam.value;
@@ -219,15 +204,17 @@ class MicrosoftPlanner {
219
204
  // ----------------------------------
220
205
  if (operation === 'getAll') {
221
206
  const returnAll = this.getNodeParameter('returnAll', i);
222
- const filters = this.getNodeParameter('filters', i);
207
+ const filterBy = this.getNodeParameter('filterBy', i);
208
+ const planId = this.getNodeParameter('planId', i);
223
209
  let endpoint = '';
224
- if (filters.planId) {
225
- endpoint = `/planner/plans/${filters.planId}/tasks`;
210
+ if (filterBy === 'plan') {
211
+ endpoint = `/planner/plans/${planId}/tasks`;
226
212
  }
227
- else if (filters.bucketId) {
228
- const bucketIdValue = typeof filters.bucketId === 'string'
229
- ? filters.bucketId
230
- : filters.bucketId.value;
213
+ else if (filterBy === 'bucket') {
214
+ const bucketIdParam = this.getNodeParameter('bucketId', i);
215
+ const bucketIdValue = typeof bucketIdParam === 'string'
216
+ ? bucketIdParam
217
+ : bucketIdParam.value;
231
218
  endpoint = `/planner/buckets/${bucketIdValue}/tasks`;
232
219
  }
233
220
  else {
@@ -296,9 +283,13 @@ class MicrosoftPlanner {
296
283
  console.warn('No valid user IDs found for assignment. Check if User.Read.All permission is granted.');
297
284
  }
298
285
  }
299
- const responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}`, body, {}, undefined, {
300
- 'If-Match': eTag,
301
- });
286
+ let responseData = currentTask;
287
+ // Only send PATCH request if there are fields to update (excluding description)
288
+ if (Object.keys(body).length > 0) {
289
+ responseData = await GenericFunctions_1.microsoftApiRequest.call(this, 'PATCH', `/planner/tasks/${taskId}`, body, {}, undefined, {
290
+ 'If-Match': eTag,
291
+ });
292
+ }
302
293
  // Update description if provided
303
294
  if (updateFields.description) {
304
295
  const details = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/planner/tasks/${taskId}/details`);
@@ -197,7 +197,7 @@ exports.taskFields = [
197
197
  displayName: 'Task',
198
198
  name: 'taskId',
199
199
  type: 'resourceLocator',
200
- default: { mode: 'list', value: '' },
200
+ default: { mode: 'id', value: '' },
201
201
  required: true,
202
202
  displayOptions: {
203
203
  show: {
@@ -206,15 +206,6 @@ exports.taskFields = [
206
206
  },
207
207
  },
208
208
  modes: [
209
- {
210
- displayName: 'From List',
211
- name: 'list',
212
- type: 'list',
213
- typeOptions: {
214
- searchListMethod: 'getTasks',
215
- searchable: true,
216
- },
217
- },
218
209
  {
219
210
  displayName: 'By ID',
220
211
  name: 'id',
@@ -281,11 +272,9 @@ exports.taskFields = [
281
272
  description: 'Max number of results to return',
282
273
  },
283
274
  {
284
- displayName: 'Filters',
285
- name: 'filters',
286
- type: 'collection',
287
- placeholder: 'Add Filter',
288
- default: {},
275
+ displayName: 'Filter By',
276
+ name: 'filterBy',
277
+ type: 'options',
289
278
  displayOptions: {
290
279
  show: {
291
280
  resource: ['task'],
@@ -294,36 +283,62 @@ exports.taskFields = [
294
283
  },
295
284
  options: [
296
285
  {
297
- displayName: 'Plan ID',
298
- name: 'planId',
299
- type: 'string',
300
- default: '',
301
- description: 'Filter tasks by Plan ID',
302
- placeholder: 'Enter Plan ID',
286
+ name: 'Plan',
287
+ value: 'plan',
303
288
  },
304
289
  {
305
- displayName: 'Bucket',
306
- name: 'bucketId',
307
- type: 'resourceLocator',
308
- default: { mode: 'list', value: '' },
309
- description: 'Filter tasks by bucket',
310
- modes: [
311
- {
312
- displayName: 'From List',
313
- name: 'list',
314
- type: 'list',
315
- typeOptions: {
316
- searchListMethod: 'getBuckets',
317
- searchable: true,
318
- },
319
- },
320
- {
321
- displayName: 'By ID',
322
- name: 'id',
323
- type: 'string',
324
- placeholder: 'e.g. FTmIDbes6UyAjh1k0suR3JgACHty',
325
- },
326
- ],
290
+ name: 'Bucket',
291
+ value: 'bucket',
292
+ },
293
+ ],
294
+ default: 'plan',
295
+ description: 'Choose whether to filter by Plan or Bucket',
296
+ },
297
+ {
298
+ displayName: 'Plan ID',
299
+ name: 'planId',
300
+ type: 'string',
301
+ displayOptions: {
302
+ show: {
303
+ resource: ['task'],
304
+ operation: ['getAll'],
305
+ filterBy: ['plan', 'bucket'],
306
+ },
307
+ },
308
+ default: '',
309
+ required: true,
310
+ description: 'The Plan ID to filter tasks',
311
+ placeholder: 'Enter Plan ID',
312
+ },
313
+ {
314
+ displayName: 'Bucket',
315
+ name: 'bucketId',
316
+ type: 'resourceLocator',
317
+ displayOptions: {
318
+ show: {
319
+ resource: ['task'],
320
+ operation: ['getAll'],
321
+ filterBy: ['bucket'],
322
+ },
323
+ },
324
+ default: { mode: 'list', value: '' },
325
+ required: true,
326
+ description: 'The Bucket to filter tasks',
327
+ modes: [
328
+ {
329
+ displayName: 'From List',
330
+ name: 'list',
331
+ type: 'list',
332
+ typeOptions: {
333
+ searchListMethod: 'getBuckets',
334
+ searchable: true,
335
+ },
336
+ },
337
+ {
338
+ displayName: 'By ID',
339
+ name: 'id',
340
+ type: 'string',
341
+ placeholder: 'e.g. FTmIDbes6UyAjh1k0suR3JgACHty',
327
342
  },
328
343
  ],
329
344
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blickwerk/n8n-nodes-microsoft-planner",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "n8n node for Microsoft Planner - Create and retrieve tasks",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",