@blickwerk/n8n-nodes-microsoft-planner 1.2.1 → 1.2.3

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
@@ -106,8 +106,8 @@ Configure the Microsoft Planner OAuth2 API credentials in n8n:
106
106
  ### Creating a Task
107
107
 
108
108
  To create a task:
109
- 1. Select a **Plan** from the dropdown (automatically loaded from your Microsoft 365)
110
- 2. Select a **Bucket** from the dropdown (loads buckets from the selected plan)
109
+ 1. Enter the **Plan ID** (you can find this in Microsoft Planner URL or via Graph Explorer)
110
+ 2. Select a **Bucket** from the dropdown (loads automatically based on the Plan ID)
111
111
  3. Enter the **Title** of the task
112
112
 
113
113
  Optional fields:
@@ -146,14 +146,28 @@ To update a task:
146
146
  - Percent Complete
147
147
  - Move to different bucket
148
148
 
149
- ### How Dynamic Dropdowns Work
149
+ ### How to Find Plan IDs
150
150
 
151
- The node automatically fetches your data from Microsoft 365:
152
- - **Plans**: Loaded from your account when you open the Plan dropdown
153
- - **Buckets**: Dynamically loaded based on the selected Plan
154
- - **Tasks**: Loaded from the selected Plan or Bucket
151
+ You can find your Plan ID in several ways:
155
152
 
156
- No need to manually look up IDs anymore! Just select from the dropdown menus.
153
+ 1. **From Planner URL**: Open Microsoft Planner in browser, the URL contains the Plan ID:
154
+ ```
155
+ https://tasks.office.com/.../ planId=YOUR_PLAN_ID_HERE /...
156
+ ```
157
+
158
+ 2. **Via Microsoft Graph Explorer**:
159
+ - Go to https://developer.microsoft.com/graph/graph-explorer
160
+ - Sign in
161
+ - Run: `GET /me/planner/plans`
162
+ - Copy the `id` field from the plan you want
163
+
164
+ ### Dynamic Dropdowns
165
+
166
+ Once you enter a Plan ID:
167
+ - **Buckets**: Automatically load for that plan
168
+ - **Tasks**: Load based on selected Plan/Bucket
169
+
170
+ You can also manually enter Bucket IDs and Task IDs if needed.
157
171
 
158
172
  ## Compatibility
159
173
 
@@ -167,6 +181,17 @@ Tested with n8n version 1.0.0 and above.
167
181
 
168
182
  ## Version History
169
183
 
184
+ ### 1.2.3
185
+ - Improved error handling for Buckets and Tasks loading
186
+ - Better fallback values when data cannot be loaded
187
+ - Added console logging for debugging dropdown issues
188
+
189
+ ### 1.2.2
190
+ - Removed Plan dropdown (Plans cannot be loaded via API)
191
+ - Plan ID is now manual input only
192
+ - Buckets and Tasks still have dynamic dropdowns
193
+ - Simplified and more reliable plan selection
194
+
170
195
  ### 1.2.1
171
196
  - Fixed Plans not loading (improved API endpoint to fetch from groups)
172
197
  - Allow manual ID input in all dropdown fields
@@ -3,10 +3,6 @@ export declare class MicrosoftPlanner implements INodeType {
3
3
  description: INodeTypeDescription;
4
4
  methods: {
5
5
  loadOptions: {
6
- getPlans(this: ILoadOptionsFunctions): Promise<{
7
- name: any;
8
- value: any;
9
- }[]>;
10
6
  getBuckets(this: ILoadOptionsFunctions): Promise<any>;
11
7
  getTasks(this: ILoadOptionsFunctions): Promise<any>;
12
8
  };
@@ -45,62 +45,53 @@ class MicrosoftPlanner {
45
45
  };
46
46
  this.methods = {
47
47
  loadOptions: {
48
- async getPlans() {
48
+ async getBuckets() {
49
49
  try {
50
- // Try to get plans from groups the user is member of
51
- const groups = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', '/me/memberOf/microsoft.graph.group?$filter=groupTypes/any(c:c+eq+%27Unified%27)');
52
- const plans = [];
53
- for (const group of groups) {
54
- try {
55
- const groupPlans = await GenericFunctions_1.microsoftApiRequest.call(this, 'GET', `/groups/${group.id}/planner/plans`);
56
- if (groupPlans.value && groupPlans.value.length > 0) {
57
- plans.push(...groupPlans.value);
58
- }
59
- }
60
- catch (error) {
61
- // Skip groups without plans
62
- continue;
63
- }
50
+ const planId = this.getNodeParameter('planId', 0);
51
+ if (!planId) {
52
+ return [];
53
+ }
54
+ const buckets = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', `/planner/plans/${planId}/buckets`);
55
+ if (!buckets || buckets.length === 0) {
56
+ return [];
64
57
  }
65
- return plans.map((plan) => ({
66
- name: plan.title || plan.id,
67
- value: plan.id,
58
+ return buckets.map((bucket) => ({
59
+ name: bucket.name || bucket.id,
60
+ value: bucket.id,
68
61
  }));
69
62
  }
70
63
  catch (error) {
71
- console.error('Error loading plans:', error);
64
+ console.error('Error loading buckets:', error);
72
65
  return [];
73
66
  }
74
67
  },
75
- async getBuckets() {
76
- const planId = this.getNodeParameter('planId', 0);
77
- if (!planId) {
78
- return [];
79
- }
80
- const buckets = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', `/planner/plans/${planId}/buckets`);
81
- return buckets.map((bucket) => ({
82
- name: bucket.name,
83
- value: bucket.id,
84
- }));
85
- },
86
68
  async getTasks() {
87
- const planId = this.getNodeParameter('planId', 0);
88
- const bucketId = this.getNodeParameter('bucketId', 0);
89
- let endpoint = '';
90
- if (bucketId) {
91
- endpoint = `/planner/buckets/${bucketId}/tasks`;
92
- }
93
- else if (planId) {
94
- endpoint = `/planner/plans/${planId}/tasks`;
69
+ try {
70
+ const planId = this.getNodeParameter('planId', 0);
71
+ const bucketId = this.getNodeParameter('bucketId', 0);
72
+ let endpoint = '';
73
+ if (bucketId) {
74
+ endpoint = `/planner/buckets/${bucketId}/tasks`;
75
+ }
76
+ else if (planId) {
77
+ endpoint = `/planner/plans/${planId}/tasks`;
78
+ }
79
+ else {
80
+ return [];
81
+ }
82
+ const tasks = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', endpoint);
83
+ if (!tasks || tasks.length === 0) {
84
+ return [];
85
+ }
86
+ return tasks.map((task) => ({
87
+ name: task.title || task.id,
88
+ value: task.id,
89
+ }));
95
90
  }
96
- else {
91
+ catch (error) {
92
+ console.error('Error loading tasks:', error);
97
93
  return [];
98
94
  }
99
- const tasks = await GenericFunctions_1.microsoftApiRequestAllItems.call(this, 'value', 'GET', endpoint);
100
- return tasks.map((task) => ({
101
- name: task.title,
102
- value: task.id,
103
- }));
104
95
  },
105
96
  },
106
97
  };
@@ -52,12 +52,9 @@ exports.taskFields = [
52
52
  // task:create
53
53
  // ----------------------------------
54
54
  {
55
- displayName: 'Plan',
55
+ displayName: 'Plan ID',
56
56
  name: 'planId',
57
57
  type: 'string',
58
- typeOptions: {
59
- loadOptionsMethod: 'getPlans',
60
- },
61
58
  required: true,
62
59
  displayOptions: {
63
60
  show: {
@@ -66,8 +63,8 @@ exports.taskFields = [
66
63
  },
67
64
  },
68
65
  default: '',
69
- description: 'The plan to which the task belongs. Choose from the dropdown or enter a Plan ID manually.',
70
- placeholder: 'Select from dropdown or paste Plan ID',
66
+ description: 'The ID of the plan to which the task belongs',
67
+ placeholder: 'Enter Plan ID',
71
68
  },
72
69
  {
73
70
  displayName: 'Bucket',
@@ -271,15 +268,12 @@ exports.taskFields = [
271
268
  },
272
269
  options: [
273
270
  {
274
- displayName: 'Plan',
271
+ displayName: 'Plan ID',
275
272
  name: 'planId',
276
273
  type: 'string',
277
- typeOptions: {
278
- loadOptionsMethod: 'getPlans',
279
- },
280
274
  default: '',
281
- description: 'Filter tasks by plan. Choose from the dropdown or enter a Plan ID manually.',
282
- placeholder: 'Select from dropdown or paste Plan ID',
275
+ description: 'Filter tasks by Plan ID',
276
+ placeholder: 'Enter Plan ID',
283
277
  },
284
278
  {
285
279
  displayName: 'Bucket',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blickwerk/n8n-nodes-microsoft-planner",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "n8n node for Microsoft Planner - Create and retrieve tasks",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",