n8n-nodes-qlik-cloud 1.0.17 → 1.1.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.
@@ -1,5 +1,7 @@
1
1
  import type {
2
+ IDataObject,
2
3
  IExecuteFunctions,
4
+ IHttpRequestOptions,
3
5
  INodeExecutionData,
4
6
  INodeType,
5
7
  INodeTypeDescription,
@@ -13,6 +15,10 @@ import { auditDescription } from './resources/audits/index';
13
15
  import { itemDescription } from './resources/items/index';
14
16
 
15
17
  const DEFAULT_PAGE_SIZE = 100;
18
+ const BINARY_DOWNLOAD_OPTIONS: Partial<IHttpRequestOptions> = {
19
+ json: false,
20
+ encoding: 'arraybuffer',
21
+ };
16
22
 
17
23
  function extractPageItems(response: any): any[] {
18
24
  const payload = response?.data ?? response;
@@ -86,106 +92,471 @@ async function fetchPaginatedResults(
86
92
  return limit === undefined ? collected : collected.slice(0, limit);
87
93
  }
88
94
 
89
- async function handleAppsResource(operation: string, context: IExecuteFunctions): Promise<any> {
90
- if (operation === 'getAll') {
91
- const returnAll = context.getNodeParameter('returnAll', 0) as boolean;
92
- const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
93
- const options = context.getNodeParameter('options', 0) as any;
95
+ function encodeMediaPath(path: string): string {
96
+ return encodeURIComponent(path).replace(/%2F/g, '/');
97
+ }
94
98
 
95
- const qs: Record<string, any> = {};
96
- if (options.name) {
97
- qs.name = options.name;
99
+ async function handleAppsResource(
100
+ operation: string,
101
+ context: IExecuteFunctions,
102
+ itemIndex: number,
103
+ ): Promise<any> {
104
+ switch (operation) {
105
+ case 'getAll': {
106
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
107
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
108
+ const options = context.getNodeParameter('options', itemIndex) as any;
109
+
110
+ const qs: Record<string, any> = {};
111
+ if (options.name) {
112
+ qs.name = options.name;
113
+ }
114
+ if (options.spaceId) {
115
+ qs.spaceId = options.spaceId;
116
+ }
117
+
118
+ return await fetchPaginatedResults(context, '/api/v1/apps', qs, limit);
98
119
  }
99
- if (options.spaceId) {
100
- qs.spaceId = options.spaceId;
120
+ case 'get': {
121
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
122
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}`);
101
123
  }
124
+ case 'create': {
125
+ const name = context.getNodeParameter('name', itemIndex) as string;
126
+ const options = context.getNodeParameter('options', itemIndex) as any;
102
127
 
103
- return await fetchPaginatedResults(context, '/api/v1/apps', qs, limit);
104
- }
105
-
106
- if (operation === 'get') {
107
- const appId = context.getNodeParameter('appId', 0) as string;
108
- return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}`);
109
- }
110
-
111
- if (operation === 'create') {
112
- const name = context.getNodeParameter('name', 0) as string;
113
- const options = context.getNodeParameter('options', 0) as any;
128
+ const body = { attributes: { name } };
129
+ if (options.description) {
130
+ (body.attributes as any).description = options.description;
131
+ }
132
+ if (options.locale) {
133
+ (body.attributes as any).locale = options.locale;
134
+ }
135
+ if (options.spaceId) {
136
+ (body.attributes as any).spaceId = options.spaceId;
137
+ }
114
138
 
115
- const body = { attributes: { name } };
116
- if (options.description) {
117
- (body.attributes as any).description = options.description;
139
+ return await qlikApiRequest.call(context, 'POST', '/api/v1/apps', body);
118
140
  }
119
- if (options.locale) {
120
- (body.attributes as any).locale = options.locale;
141
+ case 'update': {
142
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
143
+ const body = context.getNodeParameter('body', itemIndex) as any;
144
+ return await qlikApiRequest.call(context, 'PUT', `/api/v1/apps/${appId}`, body);
121
145
  }
122
- if (options.spaceId) {
123
- (body.attributes as any).spaceId = options.spaceId;
146
+ case 'delete': {
147
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
148
+ await qlikApiRequest.call(context, 'DELETE', `/api/v1/apps/${appId}`);
149
+ return { success: true };
124
150
  }
151
+ case 'copy': {
152
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
153
+ const name = context.getNodeParameter('name', itemIndex) as string;
154
+ const options = context.getNodeParameter('options', itemIndex) as any;
155
+
156
+ const body = { attributes: { name } };
157
+ if (options.description) {
158
+ (body.attributes as any).description = options.description;
159
+ }
160
+ if (options.spaceId) {
161
+ (body.attributes as any).spaceId = options.spaceId;
162
+ }
125
163
 
126
- return await qlikApiRequest.call(context, 'POST', '/api/v1/apps', body);
127
- }
128
-
129
- if (operation === 'update') {
130
- const appId = context.getNodeParameter('appId', 0) as string;
131
- const body = context.getNodeParameter('body', 0) as any;
132
- return await qlikApiRequest.call(context, 'PUT', `/api/v1/apps/${appId}`, body);
133
- }
134
-
135
- if (operation === 'delete') {
136
- const appId = context.getNodeParameter('appId', 0) as string;
137
- await qlikApiRequest.call(context, 'DELETE', `/api/v1/apps/${appId}`);
138
- return { success: true };
139
- }
140
-
141
- if (operation === 'copy') {
142
- const appId = context.getNodeParameter('appId', 0) as string;
143
- const name = context.getNodeParameter('name', 0) as string;
144
- const options = context.getNodeParameter('options', 0) as any;
145
-
146
- const body = { attributes: { name } };
147
- if (options.description) {
148
- (body.attributes as any).description = options.description;
164
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/copy`, body);
149
165
  }
150
- if (options.spaceId) {
151
- (body.attributes as any).spaceId = options.spaceId;
166
+ case 'export': {
167
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
168
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/export`, {});
152
169
  }
170
+ case 'publish': {
171
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
172
+ const options = context.getNodeParameter('publishOptions', itemIndex) as any;
153
173
 
154
- return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/copy`, body);
155
- }
174
+ const body: any = {};
175
+ if (options.spaceId) {
176
+ body.spaceId = options.spaceId;
177
+ }
156
178
 
157
- if (operation === 'export') {
158
- const appId = context.getNodeParameter('appId', 0) as string;
159
- return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/export`, {});
160
- }
179
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/publish`, body);
180
+ }
181
+ case 'republish': {
182
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
183
+ const options = context.getNodeParameter('publishOptions', itemIndex) as any;
161
184
 
162
- if (operation === 'publish') {
163
- const appId = context.getNodeParameter('appId', 0) as string;
164
- const options = context.getNodeParameter('publishOptions', 0) as any;
185
+ const body: any = {};
186
+ if (options.spaceId) {
187
+ body.spaceId = options.spaceId;
188
+ }
165
189
 
166
- const body: any = {};
167
- if (options.spaceId) {
168
- body.spaceId = options.spaceId;
190
+ return await qlikApiRequest.call(context, 'PUT', `/api/v1/apps/${appId}/publish`, body);
169
191
  }
192
+ case 'dataLineage': {
193
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
194
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/data/lineage`);
195
+ }
196
+ case 'dataMetadata': {
197
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
198
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/data/metadata`);
199
+ }
200
+ case 'listInsights': {
201
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
202
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/insight-analyses`);
203
+ }
204
+ case 'recommendInsights': {
205
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
206
+ const body = context.getNodeParameter('body', itemIndex) as any;
207
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
208
+
209
+ return await qlikApiRequest.call(
210
+ context,
211
+ 'POST',
212
+ `/api/v1/apps/${appId}/insight-analyses/actions/recommend`,
213
+ payload,
214
+ );
215
+ }
216
+ case 'getInsightModel': {
217
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
218
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/insight-analyses/model`);
219
+ }
220
+ case 'mediaGetFile': {
221
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
222
+ const path = context.getNodeParameter('path', itemIndex) as string;
223
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
224
+
225
+ const response = await qlikApiRequest.call(
226
+ context,
227
+ 'GET',
228
+ `/api/v1/apps/${appId}/media/files/${encodeMediaPath(path)}`,
229
+ undefined,
230
+ undefined,
231
+ true,
232
+ BINARY_DOWNLOAD_OPTIONS,
233
+ );
234
+
235
+ const data = (response as any).body ?? response;
236
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data as any);
237
+ const binary = await context.helpers.prepareBinaryData(buffer, path);
238
+
239
+ return { json: {}, binary: { [binaryProperty]: binary } };
240
+ }
241
+ case 'mediaUploadFile': {
242
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
243
+ const path = context.getNodeParameter('path', itemIndex) as string;
244
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
245
+ const contentType = context.getNodeParameter('contentType', itemIndex) as string;
246
+ const buffer = await context.helpers.getBinaryDataBuffer(itemIndex, binaryProperty);
247
+
248
+ return await qlikApiRequest.call(
249
+ context,
250
+ 'PUT',
251
+ `/api/v1/apps/${appId}/media/files/${encodeMediaPath(path)}`,
252
+ buffer,
253
+ undefined,
254
+ false,
255
+ {
256
+ json: false,
257
+ headers: { 'Content-Type': contentType },
258
+ },
259
+ );
260
+ }
261
+ case 'mediaDeleteFile': {
262
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
263
+ const path = context.getNodeParameter('path', itemIndex) as string;
264
+ await qlikApiRequest.call(
265
+ context,
266
+ 'DELETE',
267
+ `/api/v1/apps/${appId}/media/files/${encodeMediaPath(path)}`,
268
+ );
269
+ return { success: true };
270
+ }
271
+ case 'mediaList': {
272
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
273
+ const path = context.getNodeParameter('path', itemIndex) as string;
274
+ return await qlikApiRequest.call(
275
+ context,
276
+ 'GET',
277
+ `/api/v1/apps/${appId}/media/list/${encodeMediaPath(path)}`,
278
+ );
279
+ }
280
+ case 'mediaThumbnail': {
281
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
282
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
283
+
284
+ const response = await qlikApiRequest.call(
285
+ context,
286
+ 'GET',
287
+ `/api/v1/apps/${appId}/media/thumbnail`,
288
+ undefined,
289
+ undefined,
290
+ true,
291
+ BINARY_DOWNLOAD_OPTIONS,
292
+ );
293
+ const data = (response as any).body ?? response;
294
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data as any);
295
+ const binary = await context.helpers.prepareBinaryData(buffer, 'thumbnail.png');
296
+
297
+ return { json: {}, binary: { [binaryProperty]: binary } };
298
+ }
299
+ case 'changeObjectOwner': {
300
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
301
+ const objectId = context.getNodeParameter('objectId', itemIndex) as string;
302
+ const ownerId = context.getNodeParameter('ownerId', itemIndex) as string;
303
+
304
+ return await qlikApiRequest.call(
305
+ context,
306
+ 'POST',
307
+ `/api/v1/apps/${appId}/objects/${objectId}/actions/change-owner`,
308
+ { ownerId },
309
+ );
310
+ }
311
+ case 'updateOwner': {
312
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
313
+ const ownerId = context.getNodeParameter('ownerId', itemIndex) as string;
314
+ return await qlikApiRequest.call(context, 'PUT', `/api/v1/apps/${appId}/owner`, { ownerId });
315
+ }
316
+ case 'reloadLogs': {
317
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
318
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
319
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
170
320
 
171
- return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/publish`, body);
172
- }
173
-
174
- if (operation === 'privileges') {
175
- return await qlikApiRequest.call(context, 'GET', '/api/v1/apps/privileges');
321
+ return await fetchPaginatedResults(context, `/api/v1/apps/${appId}/reloads/logs`, {}, limit);
322
+ }
323
+ case 'reloadLog': {
324
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
325
+ const reloadId = context.getNodeParameter('reloadId', itemIndex) as string;
326
+ return await qlikApiRequest.call(
327
+ context,
328
+ 'GET',
329
+ `/api/v1/apps/${appId}/reloads/logs/${reloadId}`,
330
+ );
331
+ }
332
+ case 'reloadMetadata': {
333
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
334
+ const reloadId = context.getNodeParameter('reloadId', itemIndex) as string;
335
+ return await qlikApiRequest.call(
336
+ context,
337
+ 'GET',
338
+ `/api/v1/apps/${appId}/reloads/metadata/${reloadId}`,
339
+ );
340
+ }
341
+ case 'reportFiltersGetAll': {
342
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
343
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
344
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
345
+ const options = context.getNodeParameter('options', itemIndex) as any;
346
+
347
+ const qs: Record<string, any> = {};
348
+ if (options.filter) qs.filter = options.filter;
349
+ if (options.filterTypes) qs.filterTypes = options.filterTypes;
350
+ if (options.page !== undefined) qs.page = options.page;
351
+ if (options.sort) qs.sort = options.sort;
352
+ if (!returnAll && limit !== undefined) qs.limit = limit;
353
+
354
+ return await fetchPaginatedResults(
355
+ context,
356
+ `/api/v1/apps/${appId}/report-filters`,
357
+ qs,
358
+ limit,
359
+ );
360
+ }
361
+ case 'reportFiltersCreate': {
362
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
363
+ const body = context.getNodeParameter('body', itemIndex) as any;
364
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
365
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/report-filters`, payload);
366
+ }
367
+ case 'reportFiltersGet': {
368
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
369
+ const filterId = context.getNodeParameter('filterId', itemIndex) as string;
370
+ return await qlikApiRequest.call(
371
+ context,
372
+ 'GET',
373
+ `/api/v1/apps/${appId}/report-filters/${filterId}`,
374
+ );
375
+ }
376
+ case 'reportFiltersUpdate': {
377
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
378
+ const filterId = context.getNodeParameter('filterId', itemIndex) as string;
379
+ const body = context.getNodeParameter('body', itemIndex) as any;
380
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
381
+
382
+ return await qlikApiRequest.call(
383
+ context,
384
+ 'PATCH',
385
+ `/api/v1/apps/${appId}/report-filters/${filterId}`,
386
+ payload,
387
+ );
388
+ }
389
+ case 'reportFiltersDelete': {
390
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
391
+ const filterId = context.getNodeParameter('filterId', itemIndex) as string;
392
+ await qlikApiRequest.call(context, 'DELETE', `/api/v1/apps/${appId}/report-filters/${filterId}`);
393
+ return { success: true };
394
+ }
395
+ case 'reportFiltersCount': {
396
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
397
+ const options = context.getNodeParameter('options', itemIndex) as any;
398
+ const qs: Record<string, any> = {};
399
+ if (options.filter) qs.filter = options.filter;
400
+ if (options.filterTypes) qs.filterTypes = options.filterTypes;
401
+ return await qlikApiRequest.call(
402
+ context,
403
+ 'GET',
404
+ `/api/v1/apps/${appId}/report-filters/actions/count`,
405
+ undefined,
406
+ qs,
407
+ );
408
+ }
409
+ case 'scriptsGetAll': {
410
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
411
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/scripts`);
412
+ }
413
+ case 'scriptsCreate': {
414
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
415
+ const body = context.getNodeParameter('body', itemIndex) as any;
416
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
417
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/scripts`, payload);
418
+ }
419
+ case 'scriptsGet': {
420
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
421
+ const scriptId = context.getNodeParameter('scriptId', itemIndex) as string;
422
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/scripts/${scriptId}`);
423
+ }
424
+ case 'scriptsUpdate': {
425
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
426
+ const scriptId = context.getNodeParameter('scriptId', itemIndex) as string;
427
+ const body = context.getNodeParameter('body', itemIndex) as any;
428
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
429
+ return await qlikApiRequest.call(
430
+ context,
431
+ 'PATCH',
432
+ `/api/v1/apps/${appId}/scripts/${scriptId}`,
433
+ payload,
434
+ );
435
+ }
436
+ case 'scriptsDelete': {
437
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
438
+ const scriptId = context.getNodeParameter('scriptId', itemIndex) as string;
439
+ await qlikApiRequest.call(context, 'DELETE', `/api/v1/apps/${appId}/scripts/${scriptId}`);
440
+ return { success: true };
441
+ }
442
+ case 'moveToSpace': {
443
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
444
+ const spaceId = context.getNodeParameter('spaceId', itemIndex) as string;
445
+ return await qlikApiRequest.call(context, 'PUT', `/api/v1/apps/${appId}/space`, { spaceId });
446
+ }
447
+ case 'removeFromSpace': {
448
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
449
+ await qlikApiRequest.call(context, 'DELETE', `/api/v1/apps/${appId}/space`);
450
+ return { success: true };
451
+ }
452
+ case 'evaluationsGetAll': {
453
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
454
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/${appId}/evaluations`);
455
+ }
456
+ case 'evaluationsCreate': {
457
+ const appId = context.getNodeParameter('appId', itemIndex) as string;
458
+ const body = context.getNodeParameter('body', itemIndex) as any;
459
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
460
+ return await qlikApiRequest.call(context, 'POST', `/api/v1/apps/${appId}/evaluations`, payload);
461
+ }
462
+ case 'evaluationsCompare': {
463
+ const baseEvaluationId = context.getNodeParameter('baseEvaluationId', itemIndex) as string;
464
+ const comparisonEvaluationId = context.getNodeParameter('comparisonEvaluationId', itemIndex) as string;
465
+ return await qlikApiRequest.call(
466
+ context,
467
+ 'GET',
468
+ `/api/v1/apps/evaluations/${baseEvaluationId}/actions/compare/${comparisonEvaluationId}`,
469
+ );
470
+ }
471
+ case 'evaluationsDownloadCompare': {
472
+ const baseEvaluationId = context.getNodeParameter('baseEvaluationId', itemIndex) as string;
473
+ const comparisonEvaluationId = context.getNodeParameter('comparisonEvaluationId', itemIndex) as string;
474
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
475
+
476
+ const response = await qlikApiRequest.call(
477
+ context,
478
+ 'GET',
479
+ `/api/v1/apps/evaluations/${baseEvaluationId}/actions/compare/${comparisonEvaluationId}/actions/download`,
480
+ undefined,
481
+ undefined,
482
+ true,
483
+ BINARY_DOWNLOAD_OPTIONS,
484
+ );
485
+ const data = (response as any).body ?? response;
486
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data as any);
487
+ const binary = await context.helpers.prepareBinaryData(buffer, 'comparison');
488
+
489
+ return { json: {}, binary: { [binaryProperty]: binary } };
490
+ }
491
+ case 'evaluationGet': {
492
+ const evaluationId = context.getNodeParameter('evaluationId', itemIndex) as string;
493
+ return await qlikApiRequest.call(context, 'GET', `/api/v1/apps/evaluations/${evaluationId}`);
494
+ }
495
+ case 'evaluationDownload': {
496
+ const evaluationId = context.getNodeParameter('evaluationId', itemIndex) as string;
497
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
498
+
499
+ const response = await qlikApiRequest.call(
500
+ context,
501
+ 'GET',
502
+ `/api/v1/apps/evaluations/${evaluationId}/actions/download`,
503
+ undefined,
504
+ undefined,
505
+ true,
506
+ BINARY_DOWNLOAD_OPTIONS,
507
+ );
508
+ const data = (response as any).body ?? response;
509
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data as any);
510
+ const binary = await context.helpers.prepareBinaryData(buffer, 'evaluation');
511
+
512
+ return { json: {}, binary: { [binaryProperty]: binary } };
513
+ }
514
+ case 'importApp': {
515
+ const binaryProperty = context.getNodeParameter('binaryProperty', itemIndex) as string;
516
+ const options = context.getNodeParameter('options', itemIndex) as any;
517
+ const qs: Record<string, any> = {};
518
+ if (options.name) qs.name = options.name;
519
+ if (options.spaceId) qs.spaceId = options.spaceId;
520
+
521
+ const buffer = await context.helpers.getBinaryDataBuffer(itemIndex, binaryProperty);
522
+
523
+ return await qlikApiRequest.call(
524
+ context,
525
+ 'POST',
526
+ '/api/v1/apps/import',
527
+ buffer,
528
+ qs,
529
+ false,
530
+ { json: false, headers: { 'Content-Type': 'application/octet-stream' } },
531
+ );
532
+ }
533
+ case 'validateScript': {
534
+ const body = context.getNodeParameter('body', itemIndex) as any;
535
+ const payload = typeof body === 'string' ? JSON.parse(body) : body;
536
+ return await qlikApiRequest.call(context, 'POST', '/api/v1/apps/validatescript', payload);
537
+ }
538
+ case 'privileges': {
539
+ const options = context.getNodeParameter('options', itemIndex) as any;
540
+ const qs: Record<string, any> = {};
541
+ if (options.role) qs.role = options.role;
542
+ return await qlikApiRequest.call(context, 'GET', '/api/v1/apps/privileges', undefined, qs);
543
+ }
544
+ default:
545
+ throw new NodeOperationError(context.getNode(), `Unknown operation: ${operation}`);
176
546
  }
177
-
178
- throw new NodeOperationError(context.getNode(), `Unknown operation: ${operation}`);
179
547
  }
180
548
 
181
- async function handleAssistantsResource(operation: string, context: IExecuteFunctions): Promise<any> {
549
+ async function handleAssistantsResource(
550
+ operation: string,
551
+ context: IExecuteFunctions,
552
+ itemIndex: number,
553
+ ): Promise<any> {
182
554
  if (operation === 'getAll') {
183
- const options = context.getNodeParameter('options', 0) as any;
555
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
556
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
557
+ const options = context.getNodeParameter('options', itemIndex) as any;
184
558
 
185
559
  const qs: any = {};
186
- if (options.limit) {
187
- qs.limit = options.limit;
188
- }
189
560
  if (options.next) {
190
561
  qs.next = options.next;
191
562
  }
@@ -196,20 +567,24 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
196
567
  qs.sort = options.sort;
197
568
  }
198
569
 
199
- return await qlikApiRequest.call(context, 'GET', '/api/v1/assistants', undefined, qs);
570
+ if (!returnAll && options.limit) {
571
+ qs.limit = options.limit;
572
+ }
573
+
574
+ return await fetchPaginatedResults(context, '/api/v1/assistants', qs, limit);
200
575
  }
201
576
 
202
577
  if (operation === 'get') {
203
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
578
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
204
579
  return await qlikApiRequest.call(context, 'GET', `/api/v1/assistants/${assistantId}`);
205
580
  }
206
581
 
207
582
  if (operation === 'create') {
208
- const name = context.getNodeParameter('name', 0) as string;
209
- const title = context.getNodeParameter('title', 0) as string;
210
- const description = context.getNodeParameter('description', 0) as string;
211
- const spaceId = context.getNodeParameter('spaceId', 0) as string;
212
- const options = context.getNodeParameter('options', 0) as any;
583
+ const name = context.getNodeParameter('name', itemIndex) as string;
584
+ const title = context.getNodeParameter('title', itemIndex) as string;
585
+ const description = context.getNodeParameter('description', itemIndex) as string;
586
+ const spaceId = context.getNodeParameter('spaceId', itemIndex) as string;
587
+ const options = context.getNodeParameter('options', itemIndex) as any;
213
588
 
214
589
  const body: any = { name, title, description, spaceId };
215
590
  if (options.tags) {
@@ -231,8 +606,8 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
231
606
  }
232
607
 
233
608
  if (operation === 'update') {
234
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
235
- const body = context.getNodeParameter('body', 0) as any;
609
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
610
+ const body = context.getNodeParameter('body', itemIndex) as any;
236
611
 
237
612
  const patchOps = typeof body === 'string' ? JSON.parse(body) : body;
238
613
 
@@ -245,9 +620,9 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
245
620
  }
246
621
 
247
622
  if (operation === 'search') {
248
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
249
- const query = context.getNodeParameter('query', 0) as string;
250
- const options = context.getNodeParameter('options', 0) as any;
623
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
624
+ const query = context.getNodeParameter('query', itemIndex) as string;
625
+ const options = context.getNodeParameter('options', itemIndex) as any;
251
626
 
252
627
  const body: any = { text: query };
253
628
  if (options.topN) {
@@ -266,13 +641,13 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
266
641
  }
267
642
 
268
643
  if (operation === 'getFeedback') {
269
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
644
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
270
645
  return await qlikApiRequest.call(context, 'GET', `/api/v1/assistants/${assistantId}/feedback`);
271
646
  }
272
647
 
273
648
  if (operation === 'bulkSearchSources') {
274
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
275
- const chunkIds = context.getNodeParameter('chunkIds', 0) as any;
649
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
650
+ const chunkIds = context.getNodeParameter('chunkIds', itemIndex) as any;
276
651
 
277
652
  const body = typeof chunkIds === 'string' ? JSON.parse(chunkIds) : chunkIds;
278
653
 
@@ -285,8 +660,8 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
285
660
  }
286
661
 
287
662
  if (operation === 'listStarters') {
288
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
289
- const options = context.getNodeParameter('options', 0) as any;
663
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
664
+ const options = context.getNodeParameter('options', itemIndex) as any;
290
665
 
291
666
  const qs: any = {};
292
667
  if (options.limit) {
@@ -297,9 +672,9 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
297
672
  }
298
673
 
299
674
  if (operation === 'createStarter') {
300
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
301
- const question = context.getNodeParameter('question', 0) as string;
302
- const options = context.getNodeParameter('options', 0) as any;
675
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
676
+ const question = context.getNodeParameter('question', itemIndex) as string;
677
+ const options = context.getNodeParameter('options', itemIndex) as any;
303
678
 
304
679
  const body: any = { question };
305
680
  if (options.followups) {
@@ -320,8 +695,8 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
320
695
  }
321
696
 
322
697
  if (operation === 'listThreads') {
323
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
324
- const options = context.getNodeParameter('options', 0) as any;
698
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
699
+ const options = context.getNodeParameter('options', itemIndex) as any;
325
700
 
326
701
  const qs: any = {};
327
702
  if (options.limit) {
@@ -335,8 +710,8 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
335
710
  }
336
711
 
337
712
  if (operation === 'createThread') {
338
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
339
- const name = context.getNodeParameter('name', 0) as string;
713
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
714
+ const name = context.getNodeParameter('name', itemIndex) as string;
340
715
 
341
716
  const body: any = { name };
342
717
 
@@ -349,10 +724,10 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
349
724
  }
350
725
 
351
726
  if (operation === 'streamThread') {
352
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
353
- const threadId = context.getNodeParameter('threadId', 0) as string;
354
- const messages = context.getNodeParameter('messages', 0) as any;
355
- const options = context.getNodeParameter('options', 0) as any;
727
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
728
+ const threadId = context.getNodeParameter('threadId', itemIndex) as string;
729
+ const messages = context.getNodeParameter('messages', itemIndex) as any;
730
+ const options = context.getNodeParameter('options', itemIndex) as any;
356
731
 
357
732
  const body: any = {
358
733
  messages: typeof messages === 'string' ? JSON.parse(messages) : messages,
@@ -372,9 +747,9 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
372
747
  }
373
748
 
374
749
  if (operation === 'invokeThread') {
375
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
376
- const threadId = context.getNodeParameter('threadId', 0) as string;
377
- const message = context.getNodeParameter('message', 0) as string;
750
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
751
+ const threadId = context.getNodeParameter('threadId', itemIndex) as string;
752
+ const message = context.getNodeParameter('message', itemIndex) as string;
378
753
 
379
754
  const body = { message };
380
755
 
@@ -387,7 +762,7 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
387
762
  }
388
763
 
389
764
  if (operation === 'delete') {
390
- const assistantId = context.getNodeParameter('assistantId', 0) as string;
765
+ const assistantId = context.getNodeParameter('assistantId', itemIndex) as string;
391
766
  await qlikApiRequest.call(context, 'DELETE', `/api/v1/assistants/${assistantId}`);
392
767
  return { success: true };
393
768
  }
@@ -395,11 +770,15 @@ async function handleAssistantsResource(operation: string, context: IExecuteFunc
395
770
  throw new NodeOperationError(context.getNode(), `Unknown operation: ${operation}`);
396
771
  }
397
772
 
398
- async function handleAuditsResource(operation: string, context: IExecuteFunctions): Promise<any> {
773
+ async function handleAuditsResource(
774
+ operation: string,
775
+ context: IExecuteFunctions,
776
+ itemIndex: number,
777
+ ): Promise<any> {
399
778
  if (operation === 'getAll') {
400
- const returnAll = context.getNodeParameter('returnAll', 0) as boolean;
401
- const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
402
- const options = context.getNodeParameter('options', 0) as any;
779
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
780
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
781
+ const options = context.getNodeParameter('options', itemIndex) as any;
403
782
 
404
783
  const qs: Record<string, any> = {};
405
784
  if (options.eventType) {
@@ -422,7 +801,7 @@ async function handleAuditsResource(operation: string, context: IExecuteFunction
422
801
  }
423
802
 
424
803
  if (operation === 'get') {
425
- const auditId = context.getNodeParameter('auditId', 0) as string;
804
+ const auditId = context.getNodeParameter('auditId', itemIndex) as string;
426
805
  return await qlikApiRequest.call(context, 'GET', `/api/v1/audits/${auditId}`);
427
806
  }
428
807
 
@@ -444,11 +823,15 @@ async function handleAuditsResource(operation: string, context: IExecuteFunction
444
823
  throw new NodeOperationError(context.getNode(), `Unknown operation: ${operation}`);
445
824
  }
446
825
 
447
- async function handleItemsResource(operation: string, context: IExecuteFunctions): Promise<any> {
826
+ async function handleItemsResource(
827
+ operation: string,
828
+ context: IExecuteFunctions,
829
+ itemIndex: number,
830
+ ): Promise<any> {
448
831
  if (operation === 'getAll') {
449
- const returnAll = context.getNodeParameter('returnAll', 0) as boolean;
450
- const limit = returnAll ? undefined : (context.getNodeParameter('limit', 0) as number);
451
- const options = context.getNodeParameter('options', 0) as any;
832
+ const returnAll = context.getNodeParameter('returnAll', itemIndex) as boolean;
833
+ const limit = returnAll ? undefined : (context.getNodeParameter('limit', itemIndex) as number);
834
+ const options = context.getNodeParameter('options', itemIndex) as any;
452
835
 
453
836
  const qs: Record<string, any> = {};
454
837
  if (options.name) {
@@ -471,25 +854,25 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
471
854
  }
472
855
 
473
856
  if (operation === 'get') {
474
- const itemId = context.getNodeParameter('itemId', 0) as string;
857
+ const itemId = context.getNodeParameter('itemId', itemIndex) as string;
475
858
  return await qlikApiRequest.call(context, 'GET', `/api/v1/items/${itemId}`);
476
859
  }
477
860
 
478
861
  if (operation === 'update') {
479
- const itemId = context.getNodeParameter('itemId', 0) as string;
480
- const body = context.getNodeParameter('body', 0) as any;
862
+ const itemId = context.getNodeParameter('itemId', itemIndex) as string;
863
+ const body = context.getNodeParameter('body', itemIndex) as any;
481
864
  return await qlikApiRequest.call(context, 'PUT', `/api/v1/items/${itemId}`, body);
482
865
  }
483
866
 
484
867
  if (operation === 'delete') {
485
- const itemId = context.getNodeParameter('itemId', 0) as string;
868
+ const itemId = context.getNodeParameter('itemId', itemIndex) as string;
486
869
  await qlikApiRequest.call(context, 'DELETE', `/api/v1/items/${itemId}`);
487
870
  return { success: true };
488
871
  }
489
872
 
490
873
  if (operation === 'collections') {
491
- const itemId = context.getNodeParameter('itemId', 0) as string;
492
- const options = context.getNodeParameter('options', 0) as any;
874
+ const itemId = context.getNodeParameter('itemId', itemIndex) as string;
875
+ const options = context.getNodeParameter('options', itemIndex) as any;
493
876
 
494
877
  const qs: any = {};
495
878
  if (options.limit) {
@@ -507,8 +890,8 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
507
890
  }
508
891
 
509
892
  if (operation === 'publishedItems') {
510
- const itemId = context.getNodeParameter('itemId', 0) as string;
511
- const options = context.getNodeParameter('options', 0) as any;
893
+ const itemId = context.getNodeParameter('itemId', itemIndex) as string;
894
+ const options = context.getNodeParameter('options', itemIndex) as any;
512
895
 
513
896
  const qs: any = {};
514
897
  if (options.limit) {
@@ -526,7 +909,7 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
526
909
  }
527
910
 
528
911
  if (operation === 'settings') {
529
- const settingsOperation = context.getNodeParameter('settingsOperation', 0) as string;
912
+ const settingsOperation = context.getNodeParameter('settingsOperation', itemIndex) as string;
530
913
 
531
914
  if (settingsOperation === 'get') {
532
915
  const response = await qlikApiRequest.call(context, 'GET', '/api/v1/items/settings');
@@ -534,7 +917,7 @@ async function handleItemsResource(operation: string, context: IExecuteFunctions
534
917
  }
535
918
 
536
919
  if (settingsOperation === 'patch') {
537
- const body = context.getNodeParameter('body', 0) as any;
920
+ const body = context.getNodeParameter('body', itemIndex) as any;
538
921
  const response = await qlikApiRequest.call(context, 'PATCH', '/api/v1/items/settings', body);
539
922
  return response.data || response;
540
923
  }
@@ -611,19 +994,30 @@ export class QlikCloud implements INodeType {
611
994
  for (let i = 0; i < items.length; i++) {
612
995
  try {
613
996
  if (resource === 'apps') {
614
- responseData = await handleAppsResource(operation, this);
997
+ responseData = await handleAppsResource(operation, this, i);
615
998
  } else if (resource === 'assistants') {
616
- responseData = await handleAssistantsResource(operation, this);
999
+ responseData = await handleAssistantsResource(operation, this, i);
617
1000
  } else if (resource === 'audits') {
618
- responseData = await handleAuditsResource(operation, this);
1001
+ responseData = await handleAuditsResource(operation, this, i);
619
1002
  } else if (resource === 'items') {
620
- responseData = await handleItemsResource(operation, this);
1003
+ responseData = await handleItemsResource(operation, this, i);
621
1004
  }
622
1005
 
623
- const executionData = this.helpers.constructExecutionMetaData(
624
- this.helpers.returnJsonArray(Array.isArray(responseData) ? responseData : [responseData]),
625
- { itemData: { item: i } },
626
- );
1006
+ const responses = Array.isArray(responseData) ? responseData : [responseData];
1007
+ const executionItems: INodeExecutionData[] = responses.map((data) => {
1008
+ if ((data as INodeExecutionData).binary !== undefined || (data as INodeExecutionData).json !== undefined) {
1009
+ const asItem = data as INodeExecutionData;
1010
+ if (asItem.json === undefined) {
1011
+ asItem.json = {};
1012
+ }
1013
+ return asItem;
1014
+ }
1015
+ return { json: data as IDataObject };
1016
+ });
1017
+
1018
+ const executionData = this.helpers.constructExecutionMetaData(executionItems, {
1019
+ itemData: { item: i },
1020
+ });
627
1021
  returnData.push(...executionData);
628
1022
  } catch (error) {
629
1023
  if (this.continueOnFail()) {