@blickwerk/n8n-nodes-microsoft-planner 1.3.9 → 1.5.5
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 +21 -21
- package/README.md +459 -309
- package/dist/credentials/MicrosoftPlannerOAuth2Api.credentials.js +3 -2
- package/dist/nodes/MicrosoftPlanner/BucketDescription.d.ts +3 -0
- package/dist/nodes/MicrosoftPlanner/BucketDescription.js +173 -0
- package/dist/nodes/MicrosoftPlanner/CommentDescription.d.ts +3 -0
- package/dist/nodes/MicrosoftPlanner/CommentDescription.js +160 -0
- package/dist/nodes/MicrosoftPlanner/GenericFunctions.d.ts +18 -2
- package/dist/nodes/MicrosoftPlanner/GenericFunctions.js +74 -9
- package/dist/nodes/MicrosoftPlanner/MicrosoftPlanner.node.d.ts +3 -0
- package/dist/nodes/MicrosoftPlanner/MicrosoftPlanner.node.js +607 -42
- package/dist/nodes/MicrosoftPlanner/PlanDescription.d.ts +3 -0
- package/dist/nodes/MicrosoftPlanner/PlanDescription.js +285 -0
- package/dist/nodes/MicrosoftPlanner/TaskDescription.js +532 -81
- package/dist/nodes/MicrosoftPlanner/planner.svg +51 -13
- package/package.json +63 -58
|
@@ -6,6 +6,7 @@ class MicrosoftPlannerOAuth2Api {
|
|
|
6
6
|
this.name = 'microsoftPlannerOAuth2Api';
|
|
7
7
|
this.extends = ['oAuth2Api'];
|
|
8
8
|
this.displayName = 'Microsoft Planner OAuth2 API';
|
|
9
|
+
// eslint-disable-next-line n8n-nodes-base/cred-class-field-documentation-url-miscased
|
|
9
10
|
this.documentationUrl = 'https://docs.microsoft.com/en-us/graph/auth-v2-user';
|
|
10
11
|
this.properties = [
|
|
11
12
|
{
|
|
@@ -17,14 +18,14 @@ class MicrosoftPlannerOAuth2Api {
|
|
|
17
18
|
{
|
|
18
19
|
displayName: 'Authorization URL',
|
|
19
20
|
name: 'authUrl',
|
|
20
|
-
type: '
|
|
21
|
+
type: 'string',
|
|
21
22
|
default: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
|
|
22
23
|
required: true,
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
26
|
displayName: 'Access Token URL',
|
|
26
27
|
name: 'accessTokenUrl',
|
|
27
|
-
type: '
|
|
28
|
+
type: 'string',
|
|
28
29
|
default: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
|
29
30
|
required: true,
|
|
30
31
|
},
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bucketFields = exports.bucketOperations = void 0;
|
|
4
|
+
// ----------------------------------
|
|
5
|
+
// Bucket operations
|
|
6
|
+
// ----------------------------------
|
|
7
|
+
exports.bucketOperations = [
|
|
8
|
+
{
|
|
9
|
+
displayName: 'Operation',
|
|
10
|
+
name: 'operation',
|
|
11
|
+
type: 'options',
|
|
12
|
+
noDataExpression: true,
|
|
13
|
+
displayOptions: {
|
|
14
|
+
show: {
|
|
15
|
+
resource: ['bucket'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
options: [
|
|
19
|
+
{
|
|
20
|
+
name: 'Create',
|
|
21
|
+
value: 'create',
|
|
22
|
+
description: 'Create a new bucket in a plan',
|
|
23
|
+
action: 'Create a bucket',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Get',
|
|
27
|
+
value: 'get',
|
|
28
|
+
description: 'Get a bucket',
|
|
29
|
+
action: 'Get a bucket',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'Get Many',
|
|
33
|
+
value: 'getAll',
|
|
34
|
+
description: 'Get many buckets in a plan',
|
|
35
|
+
action: 'Get many buckets',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'Update',
|
|
39
|
+
value: 'update',
|
|
40
|
+
description: 'Update a bucket',
|
|
41
|
+
action: 'Update a bucket',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Delete',
|
|
45
|
+
value: 'delete',
|
|
46
|
+
description: 'Delete a bucket',
|
|
47
|
+
action: 'Delete a bucket',
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
default: 'getAll',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
// ----------------------------------
|
|
54
|
+
// Bucket fields
|
|
55
|
+
// ----------------------------------
|
|
56
|
+
exports.bucketFields = [
|
|
57
|
+
// ----------------------------------
|
|
58
|
+
// bucket:create
|
|
59
|
+
// ----------------------------------
|
|
60
|
+
{
|
|
61
|
+
displayName: 'Plan ID',
|
|
62
|
+
name: 'planId',
|
|
63
|
+
type: 'string',
|
|
64
|
+
required: true,
|
|
65
|
+
displayOptions: {
|
|
66
|
+
show: {
|
|
67
|
+
resource: ['bucket'],
|
|
68
|
+
operation: ['create', 'getAll'],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
default: '',
|
|
72
|
+
description: 'The ID of the plan this bucket belongs to',
|
|
73
|
+
},
|
|
74
|
+
// ----------------------------------
|
|
75
|
+
// bucket:getAll
|
|
76
|
+
// ----------------------------------
|
|
77
|
+
// No Return All / Limit options; Graph does not support $top/$limit for Planner.
|
|
78
|
+
{
|
|
79
|
+
displayName: 'Name',
|
|
80
|
+
name: 'name',
|
|
81
|
+
type: 'string',
|
|
82
|
+
required: true,
|
|
83
|
+
displayOptions: {
|
|
84
|
+
show: {
|
|
85
|
+
resource: ['bucket'],
|
|
86
|
+
operation: ['create'],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
default: '',
|
|
90
|
+
description: 'Name of the bucket',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
displayName: 'Upsert',
|
|
94
|
+
name: 'upsert',
|
|
95
|
+
type: 'boolean',
|
|
96
|
+
default: false,
|
|
97
|
+
displayOptions: {
|
|
98
|
+
show: {
|
|
99
|
+
resource: ['bucket'],
|
|
100
|
+
operation: ['create'],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
description: 'Whether to return the existing bucket if one with the same name already exists in the plan',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
displayName: 'Additional Fields',
|
|
107
|
+
name: 'additionalFields',
|
|
108
|
+
type: 'collection',
|
|
109
|
+
placeholder: 'Add Field',
|
|
110
|
+
default: {},
|
|
111
|
+
displayOptions: {
|
|
112
|
+
show: {
|
|
113
|
+
resource: ['bucket'],
|
|
114
|
+
operation: ['getAll'],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
options: [
|
|
118
|
+
{
|
|
119
|
+
displayName: 'Select Properties',
|
|
120
|
+
name: 'select',
|
|
121
|
+
type: 'string',
|
|
122
|
+
default: '',
|
|
123
|
+
description: 'Comma-separated list of properties to specify which fields to return (e.g. id,name)',
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
// ----------------------------------
|
|
128
|
+
// bucket:get / bucket:update / bucket:delete
|
|
129
|
+
// ----------------------------------
|
|
130
|
+
{
|
|
131
|
+
displayName: 'Bucket ID',
|
|
132
|
+
name: 'bucketId',
|
|
133
|
+
type: 'string',
|
|
134
|
+
required: true,
|
|
135
|
+
displayOptions: {
|
|
136
|
+
show: {
|
|
137
|
+
resource: ['bucket'],
|
|
138
|
+
operation: ['get', 'update', 'delete'],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
default: '',
|
|
142
|
+
description: 'The ID of the bucket',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
displayName: 'Update Fields',
|
|
146
|
+
name: 'updateFields',
|
|
147
|
+
type: 'collection',
|
|
148
|
+
placeholder: 'Add Field',
|
|
149
|
+
default: {},
|
|
150
|
+
displayOptions: {
|
|
151
|
+
show: {
|
|
152
|
+
resource: ['bucket'],
|
|
153
|
+
operation: ['update'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
options: [
|
|
157
|
+
{
|
|
158
|
+
displayName: 'Name',
|
|
159
|
+
name: 'name',
|
|
160
|
+
type: 'string',
|
|
161
|
+
default: '',
|
|
162
|
+
description: 'Name of the bucket',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
displayName: 'Order Hint',
|
|
166
|
+
name: 'orderHint',
|
|
167
|
+
type: 'string',
|
|
168
|
+
default: '',
|
|
169
|
+
description: 'Used to sort buckets in the plan',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
];
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.commentFields = exports.commentOperations = void 0;
|
|
4
|
+
// ----------------------------------
|
|
5
|
+
// Comment operations
|
|
6
|
+
// ----------------------------------
|
|
7
|
+
exports.commentOperations = [
|
|
8
|
+
{
|
|
9
|
+
displayName: 'Operation',
|
|
10
|
+
name: 'operation',
|
|
11
|
+
type: 'options',
|
|
12
|
+
noDataExpression: true,
|
|
13
|
+
displayOptions: {
|
|
14
|
+
show: {
|
|
15
|
+
resource: ['comment'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
options: [
|
|
19
|
+
{
|
|
20
|
+
name: 'Create',
|
|
21
|
+
value: 'create',
|
|
22
|
+
description: 'Create a new comment on a task',
|
|
23
|
+
action: 'Create a comment',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Get Many',
|
|
27
|
+
value: 'getAll',
|
|
28
|
+
description: 'Get all comments from a task',
|
|
29
|
+
action: 'Get many comments',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
default: 'create',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
// ----------------------------------
|
|
36
|
+
// Comment fields
|
|
37
|
+
// ----------------------------------
|
|
38
|
+
exports.commentFields = [
|
|
39
|
+
// ----------------------------------
|
|
40
|
+
// comment:create
|
|
41
|
+
// ----------------------------------
|
|
42
|
+
{
|
|
43
|
+
displayName: 'Task',
|
|
44
|
+
name: 'taskId',
|
|
45
|
+
type: 'resourceLocator',
|
|
46
|
+
default: { mode: 'id', value: '' },
|
|
47
|
+
required: true,
|
|
48
|
+
displayOptions: {
|
|
49
|
+
show: {
|
|
50
|
+
resource: ['comment'],
|
|
51
|
+
operation: ['create'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
modes: [
|
|
55
|
+
{
|
|
56
|
+
displayName: 'By ID',
|
|
57
|
+
name: 'id',
|
|
58
|
+
type: 'string',
|
|
59
|
+
placeholder: 'e.g. rz1EH6N_a0aLpRm-2QifxZgAF5OL',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
description: 'The task to comment on',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
displayName: 'Content',
|
|
66
|
+
name: 'content',
|
|
67
|
+
type: 'string',
|
|
68
|
+
typeOptions: {
|
|
69
|
+
rows: 5,
|
|
70
|
+
},
|
|
71
|
+
required: true,
|
|
72
|
+
displayOptions: {
|
|
73
|
+
show: {
|
|
74
|
+
resource: ['comment'],
|
|
75
|
+
operation: ['create'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
default: '',
|
|
79
|
+
description: 'The content of the comment',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
displayName: 'Additional Fields',
|
|
83
|
+
name: 'additionalFields',
|
|
84
|
+
type: 'collection',
|
|
85
|
+
placeholder: 'Add Field',
|
|
86
|
+
default: {},
|
|
87
|
+
displayOptions: {
|
|
88
|
+
show: {
|
|
89
|
+
resource: ['comment'],
|
|
90
|
+
operation: ['create'],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
options: [
|
|
94
|
+
{
|
|
95
|
+
displayName: 'Content Type',
|
|
96
|
+
name: 'contentType',
|
|
97
|
+
type: 'options',
|
|
98
|
+
options: [
|
|
99
|
+
{
|
|
100
|
+
name: 'HTML',
|
|
101
|
+
value: 'html',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'Text',
|
|
105
|
+
value: 'text',
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
default: 'text',
|
|
109
|
+
description: 'The format of the comment content',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
// ----------------------------------
|
|
114
|
+
// comment:getAll
|
|
115
|
+
// ----------------------------------
|
|
116
|
+
{
|
|
117
|
+
displayName: 'Task',
|
|
118
|
+
name: 'taskId',
|
|
119
|
+
type: 'resourceLocator',
|
|
120
|
+
default: { mode: 'id', value: '' },
|
|
121
|
+
required: true,
|
|
122
|
+
displayOptions: {
|
|
123
|
+
show: {
|
|
124
|
+
resource: ['comment'],
|
|
125
|
+
operation: ['getAll'],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
modes: [
|
|
129
|
+
{
|
|
130
|
+
displayName: 'By ID',
|
|
131
|
+
name: 'id',
|
|
132
|
+
type: 'string',
|
|
133
|
+
placeholder: 'e.g. rz1EH6N_a0aLpRm-2QifxZgAF5OL',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
description: 'The task to get comments from',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
displayName: 'Additional Fields',
|
|
140
|
+
name: 'additionalFields',
|
|
141
|
+
type: 'collection',
|
|
142
|
+
placeholder: 'Add Field',
|
|
143
|
+
default: {},
|
|
144
|
+
displayOptions: {
|
|
145
|
+
show: {
|
|
146
|
+
resource: ['comment'],
|
|
147
|
+
operation: ['getAll'],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
options: [
|
|
151
|
+
{
|
|
152
|
+
displayName: 'Select Properties',
|
|
153
|
+
name: 'select',
|
|
154
|
+
type: 'string',
|
|
155
|
+
default: '',
|
|
156
|
+
description: 'Comma-separated list of properties to specify which fields to return (e.g. id,content)',
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
];
|
|
@@ -3,6 +3,22 @@ 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
|
|
7
|
-
export declare function parseAssignments(
|
|
6
|
+
export declare function getUserIdByEmail(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, email: string): Promise<string>;
|
|
7
|
+
export declare function parseAssignments(assignments: string | string[]): string[];
|
|
8
8
|
export declare function createAssignmentsObject(userIds: string[]): IDataObject;
|
|
9
|
+
/**
|
|
10
|
+
* Encodes a URL for use as a key in plannerExternalReferences.
|
|
11
|
+
* OData requires keys in open types to be free of certain special characters like '.',
|
|
12
|
+
* which must be encoded.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodeReferenceKey(url: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generates a GUID/UUID v4.
|
|
17
|
+
* Useful for creating new ID keys for checklist items.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateGuid(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Formats comment content for Microsoft Graph API conversation posts.
|
|
22
|
+
* Wraps plain text in HTML paragraph tags if needed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatCommentContent(content: string, contentType?: string): IDataObject;
|
|
@@ -7,6 +7,9 @@ exports.formatDateTime = formatDateTime;
|
|
|
7
7
|
exports.getUserIdByEmail = getUserIdByEmail;
|
|
8
8
|
exports.parseAssignments = parseAssignments;
|
|
9
9
|
exports.createAssignmentsObject = createAssignmentsObject;
|
|
10
|
+
exports.encodeReferenceKey = encodeReferenceKey;
|
|
11
|
+
exports.generateGuid = generateGuid;
|
|
12
|
+
exports.formatCommentContent = formatCommentContent;
|
|
10
13
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
11
14
|
async function microsoftApiRequest(method, resource, body = {}, qs = {}, uri, headers = {}) {
|
|
12
15
|
const options = {
|
|
@@ -26,7 +29,7 @@ async function microsoftApiRequest(method, resource, body = {}, qs = {}, uri, he
|
|
|
26
29
|
if (Object.keys(body).length === 0) {
|
|
27
30
|
delete options.body;
|
|
28
31
|
}
|
|
29
|
-
return await this.helpers.
|
|
32
|
+
return await this.helpers.httpRequestWithAuthentication.call(this, 'microsoftPlannerOAuth2Api', options);
|
|
30
33
|
}
|
|
31
34
|
catch (error) {
|
|
32
35
|
throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
|
|
@@ -37,7 +40,8 @@ async function microsoftApiRequestAllItems(propertyName, method, endpoint, body
|
|
|
37
40
|
let responseData;
|
|
38
41
|
let uri;
|
|
39
42
|
do {
|
|
40
|
-
|
|
43
|
+
const activeQuery = uri ? {} : query;
|
|
44
|
+
responseData = await microsoftApiRequest.call(this, method, endpoint, body, activeQuery, uri);
|
|
41
45
|
uri = responseData['@odata.nextLink'];
|
|
42
46
|
returnData.push.apply(returnData, responseData[propertyName]);
|
|
43
47
|
} while (responseData['@odata.nextLink'] !== undefined);
|
|
@@ -65,21 +69,37 @@ function formatDateTime(dateTime) {
|
|
|
65
69
|
return date.toISOString();
|
|
66
70
|
}
|
|
67
71
|
async function getUserIdByEmail(email) {
|
|
72
|
+
// 1. Check if it's already a UUID
|
|
73
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(email)) {
|
|
74
|
+
return email;
|
|
75
|
+
}
|
|
68
76
|
try {
|
|
69
|
-
|
|
77
|
+
// 2. Try direct lookup (fastest)
|
|
78
|
+
const response = await microsoftApiRequest.call(this, 'GET', `/users/${encodeURIComponent(email)}`, {}, { $select: 'id' });
|
|
70
79
|
return response.id;
|
|
71
80
|
}
|
|
72
81
|
catch (error) {
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
// 3. Try filter lookup (handling UPN mismatch or restricted visibility)
|
|
83
|
+
try {
|
|
84
|
+
const users = await microsoftApiRequestAllItems.call(this, 'value', 'GET', '/users', {}, { $filter: `mail eq '${email}' or userPrincipalName eq '${email}'`, $select: 'id' });
|
|
85
|
+
if (users && users.length > 0) {
|
|
86
|
+
return users[0].id;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (filterError) {
|
|
90
|
+
// Ignore filter error, throw original or new error
|
|
91
|
+
}
|
|
92
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not find user with email/ID: ${email}`);
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
|
-
function parseAssignments(
|
|
79
|
-
if (
|
|
95
|
+
function parseAssignments(assignments) {
|
|
96
|
+
if (Array.isArray(assignments)) {
|
|
97
|
+
return assignments;
|
|
98
|
+
}
|
|
99
|
+
if (!assignments || assignments.trim() === '') {
|
|
80
100
|
return [];
|
|
81
101
|
}
|
|
82
|
-
return
|
|
102
|
+
return assignments
|
|
83
103
|
.split(',')
|
|
84
104
|
.map((email) => email.trim())
|
|
85
105
|
.filter((email) => email.length > 0);
|
|
@@ -94,3 +114,48 @@ function createAssignmentsObject(userIds) {
|
|
|
94
114
|
}
|
|
95
115
|
return assignments;
|
|
96
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Encodes a URL for use as a key in plannerExternalReferences.
|
|
119
|
+
* OData requires keys in open types to be free of certain special characters like '.',
|
|
120
|
+
* which must be encoded.
|
|
121
|
+
*/
|
|
122
|
+
function encodeReferenceKey(url) {
|
|
123
|
+
// Use encodeURI to handle spaces and % but preserve URI structure (/, ?, &, =)
|
|
124
|
+
let encoded = encodeURI(url);
|
|
125
|
+
// Manually replace OData forbidden characters that encodeURI preserves
|
|
126
|
+
// Forbidden: . : % @ #
|
|
127
|
+
// encodeURI handles % (encodes to %25 unless it's a valid escape sequence)
|
|
128
|
+
encoded = encoded
|
|
129
|
+
.replace(/\./g, '%2E')
|
|
130
|
+
.replace(/:/g, '%3A')
|
|
131
|
+
.replace(/@/g, '%40')
|
|
132
|
+
.replace(/#/g, '%23');
|
|
133
|
+
return encoded;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generates a GUID/UUID v4.
|
|
137
|
+
* Useful for creating new ID keys for checklist items.
|
|
138
|
+
*/
|
|
139
|
+
function generateGuid() {
|
|
140
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
141
|
+
const r = (Math.random() * 16) | 0;
|
|
142
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
143
|
+
return v.toString(16);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Formats comment content for Microsoft Graph API conversation posts.
|
|
148
|
+
* Wraps plain text in HTML paragraph tags if needed.
|
|
149
|
+
*/
|
|
150
|
+
function formatCommentContent(content, contentType = 'text') {
|
|
151
|
+
// When we wrap text in HTML tags, we need to set contentType to 'html'
|
|
152
|
+
// Otherwise the tags will be displayed as literal text in Planner
|
|
153
|
+
const isHtml = contentType === 'html';
|
|
154
|
+
const formattedContent = isHtml ? content : `<p>${content}</p>`;
|
|
155
|
+
return {
|
|
156
|
+
body: {
|
|
157
|
+
contentType: 'html', // Always use 'html' since we're wrapping in tags
|
|
158
|
+
content: formattedContent,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -9,6 +9,9 @@ export declare class MicrosoftPlanner implements INodeType {
|
|
|
9
9
|
getTasks(this: ILoadOptionsFunctions): Promise<{
|
|
10
10
|
results: any;
|
|
11
11
|
}>;
|
|
12
|
+
getGroups(this: ILoadOptionsFunctions): Promise<{
|
|
13
|
+
results: any;
|
|
14
|
+
}>;
|
|
12
15
|
};
|
|
13
16
|
};
|
|
14
17
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|