@vitaliy.ustymenko/n8n-node-appsheet 0.6.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/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/credentials/AppSheetApi.credentials.d.ts +6 -0
- package/dist/credentials/AppSheetApi.credentials.js +25 -0
- package/dist/nodes/AppSheet/AIAgentAppSheet.node.d.ts +5 -0
- package/dist/nodes/AppSheet/AIAgentAppSheet.node.js +1123 -0
- package/dist/nodes/AppSheet/AppSheet.node.d.ts +5 -0
- package/dist/nodes/AppSheet/AppSheet.node.js +1123 -0
- package/dist/nodes/AppSheet/AppSheet.node.json +7 -0
- package/dist/nodes/AppSheet/appsheet.png +0 -0
- package/package.json +52 -0
|
@@ -0,0 +1,1123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AIAgentAppSheet = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
class AIAgentAppSheet {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'AppSheet (AI Agent Tool)',
|
|
9
|
+
name: 'aiAgentAppSheet',
|
|
10
|
+
icon: 'file:appsheet.png',
|
|
11
|
+
group: ['transform'], // Use a safe built-in group to satisfy NodeGroupType
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
14
|
+
description: 'This node exposes the AppSheet API as a tool for AI agents. It supports the same operations as the standard AppSheet node (create, read, update, delete, and invoke actions) but is intended for use by n8n AI agents.',
|
|
15
|
+
defaults: {
|
|
16
|
+
name: 'AI Agent AppSheet',
|
|
17
|
+
},
|
|
18
|
+
inputs: [
|
|
19
|
+
{
|
|
20
|
+
name: 'main',
|
|
21
|
+
type: 'main',
|
|
22
|
+
default: '',
|
|
23
|
+
description: 'Input data',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
outputs: [
|
|
27
|
+
{
|
|
28
|
+
name: 'main',
|
|
29
|
+
type: 'main',
|
|
30
|
+
default: '',
|
|
31
|
+
description: 'Output data',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
credentials: [
|
|
35
|
+
{
|
|
36
|
+
name: 'appSheetApi',
|
|
37
|
+
required: true,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
properties: [
|
|
41
|
+
{
|
|
42
|
+
displayName: 'Region',
|
|
43
|
+
name: 'region',
|
|
44
|
+
type: 'options',
|
|
45
|
+
options: [
|
|
46
|
+
{ name: 'Global (www.appsheet.com)', value: 'www.appsheet.com' },
|
|
47
|
+
{ name: 'EU (eu.appsheet.com)', value: 'eu.appsheet.com' },
|
|
48
|
+
],
|
|
49
|
+
default: 'www.appsheet.com',
|
|
50
|
+
description: 'The AppSheet region domain to use in the API URL.',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
displayName: 'Operation',
|
|
54
|
+
name: 'operation',
|
|
55
|
+
type: 'options',
|
|
56
|
+
options: [
|
|
57
|
+
{ name: 'Create Record', value: 'create' },
|
|
58
|
+
{ name: 'Find Record', value: 'read' },
|
|
59
|
+
{ name: 'If Exists', value: 'exists' },
|
|
60
|
+
{ name: 'Upsert Records', value: 'upsert' },
|
|
61
|
+
{ name: 'Update Record', value: 'update' },
|
|
62
|
+
{ name: 'Delete Record', value: 'delete' },
|
|
63
|
+
{ name: 'Invoke Action', value: 'invoke' },
|
|
64
|
+
],
|
|
65
|
+
default: 'create',
|
|
66
|
+
noDataExpression: false, // Allows using expressions for dynamic operation selection.
|
|
67
|
+
description: 'Action to perform against the selected AppSheet table',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
displayName: 'Table Name',
|
|
71
|
+
name: 'tableName',
|
|
72
|
+
type: 'string',
|
|
73
|
+
required: true,
|
|
74
|
+
default: '',
|
|
75
|
+
description: 'Name of the AppSheet table (URL-encoded if needed).',
|
|
76
|
+
},
|
|
77
|
+
// READ-specific parameters
|
|
78
|
+
{
|
|
79
|
+
displayName: 'Selector (for Read)',
|
|
80
|
+
name: 'selector',
|
|
81
|
+
type: 'string',
|
|
82
|
+
displayOptions: {
|
|
83
|
+
show: {
|
|
84
|
+
operation: ['read'],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
default: '',
|
|
88
|
+
description: 'Enter a valid AppSheet selector expression (e.g., FILTER(People, [Age]>=21)). If provided, the "Records" input is ignored.',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
displayName: 'Combine With',
|
|
92
|
+
name: 'existsCombine',
|
|
93
|
+
type: 'options',
|
|
94
|
+
displayOptions: {
|
|
95
|
+
show: {
|
|
96
|
+
operation: ['exists'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
options: [
|
|
100
|
+
{ name: 'AND', value: 'and' },
|
|
101
|
+
{ name: 'OR', value: 'or' },
|
|
102
|
+
],
|
|
103
|
+
default: 'and',
|
|
104
|
+
description: 'How to combine multiple conditions',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
displayName: 'Conditions',
|
|
108
|
+
name: 'existsConditions',
|
|
109
|
+
type: 'fixedCollection',
|
|
110
|
+
typeOptions: {
|
|
111
|
+
multipleValues: true,
|
|
112
|
+
},
|
|
113
|
+
displayOptions: {
|
|
114
|
+
show: {
|
|
115
|
+
operation: ['exists'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
default: {},
|
|
119
|
+
options: [
|
|
120
|
+
{
|
|
121
|
+
displayName: 'Condition',
|
|
122
|
+
name: 'condition',
|
|
123
|
+
values: [
|
|
124
|
+
{
|
|
125
|
+
displayName: 'Field',
|
|
126
|
+
name: 'field',
|
|
127
|
+
type: 'string',
|
|
128
|
+
default: '',
|
|
129
|
+
description: 'Column name in the AppSheet table',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
displayName: 'Operator',
|
|
133
|
+
name: 'operator',
|
|
134
|
+
type: 'options',
|
|
135
|
+
options: [
|
|
136
|
+
{ name: 'Equals', value: 'equals' },
|
|
137
|
+
{ name: 'Not Equals', value: 'notEquals' },
|
|
138
|
+
{ name: 'Contains', value: 'contains' },
|
|
139
|
+
{ name: 'Not Contains', value: 'notContains' },
|
|
140
|
+
{ name: 'Starts With', value: 'startsWith' },
|
|
141
|
+
{ name: 'Ends With', value: 'endsWith' },
|
|
142
|
+
{ name: 'Greater Than', value: 'greaterThan' },
|
|
143
|
+
{ name: 'Greater Than or Equal', value: 'greaterThanOrEqual' },
|
|
144
|
+
{ name: 'Less Than', value: 'lessThan' },
|
|
145
|
+
{ name: 'Less Than or Equal', value: 'lessThanOrEqual' },
|
|
146
|
+
{ name: 'In', value: 'in' },
|
|
147
|
+
{ name: 'Not In', value: 'notIn' },
|
|
148
|
+
{ name: 'Is Blank', value: 'isBlank' },
|
|
149
|
+
{ name: 'Is Not Blank', value: 'isNotBlank' },
|
|
150
|
+
{ name: 'Expression', value: 'expression' },
|
|
151
|
+
],
|
|
152
|
+
default: 'equals',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
displayName: 'Value Type',
|
|
156
|
+
name: 'valueType',
|
|
157
|
+
type: 'options',
|
|
158
|
+
displayOptions: {
|
|
159
|
+
show: {
|
|
160
|
+
operator: [
|
|
161
|
+
'equals',
|
|
162
|
+
'notEquals',
|
|
163
|
+
'contains',
|
|
164
|
+
'notContains',
|
|
165
|
+
'startsWith',
|
|
166
|
+
'endsWith',
|
|
167
|
+
'greaterThan',
|
|
168
|
+
'greaterThanOrEqual',
|
|
169
|
+
'lessThan',
|
|
170
|
+
'lessThanOrEqual',
|
|
171
|
+
'in',
|
|
172
|
+
'notIn',
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
options: [
|
|
177
|
+
{ name: 'String', value: 'string' },
|
|
178
|
+
{ name: 'Number', value: 'number' },
|
|
179
|
+
{ name: 'Date & Time', value: 'dateTime' },
|
|
180
|
+
{ name: 'Boolean', value: 'boolean' },
|
|
181
|
+
{ name: 'Array', value: 'array' },
|
|
182
|
+
{ name: 'Object', value: 'object' },
|
|
183
|
+
],
|
|
184
|
+
default: 'string',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
displayName: 'Value',
|
|
188
|
+
name: 'value',
|
|
189
|
+
type: 'string',
|
|
190
|
+
displayOptions: {
|
|
191
|
+
show: {
|
|
192
|
+
operator: [
|
|
193
|
+
'equals',
|
|
194
|
+
'notEquals',
|
|
195
|
+
'contains',
|
|
196
|
+
'notContains',
|
|
197
|
+
'startsWith',
|
|
198
|
+
'endsWith',
|
|
199
|
+
'greaterThan',
|
|
200
|
+
'greaterThanOrEqual',
|
|
201
|
+
'lessThan',
|
|
202
|
+
'lessThanOrEqual',
|
|
203
|
+
'in',
|
|
204
|
+
'notIn',
|
|
205
|
+
'expression',
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
default: '',
|
|
210
|
+
description: 'Use n8n expressions if needed',
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
description: 'Conditions used to check if a record exists',
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
displayName: 'Records',
|
|
219
|
+
name: 'records',
|
|
220
|
+
type: 'fixedCollection',
|
|
221
|
+
typeOptions: {
|
|
222
|
+
multipleValues: true,
|
|
223
|
+
},
|
|
224
|
+
displayOptions: {
|
|
225
|
+
show: {
|
|
226
|
+
operation: ['read'],
|
|
227
|
+
selector: [''],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
default: {},
|
|
231
|
+
options: [
|
|
232
|
+
{
|
|
233
|
+
displayName: 'Record',
|
|
234
|
+
name: 'record',
|
|
235
|
+
values: [
|
|
236
|
+
{
|
|
237
|
+
displayName: 'Key',
|
|
238
|
+
name: 'key',
|
|
239
|
+
type: 'string',
|
|
240
|
+
default: '',
|
|
241
|
+
description: 'Column name in the AppSheet table',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
displayName: 'Value',
|
|
245
|
+
name: 'value',
|
|
246
|
+
type: 'string',
|
|
247
|
+
default: '',
|
|
248
|
+
description: 'Value for the specified column',
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
description: 'Record must include the key field values of the record to read',
|
|
254
|
+
},
|
|
255
|
+
// CREATE-specific parameter
|
|
256
|
+
{
|
|
257
|
+
displayName: 'Records',
|
|
258
|
+
name: 'records',
|
|
259
|
+
type: 'fixedCollection',
|
|
260
|
+
typeOptions: {
|
|
261
|
+
multipleValues: true,
|
|
262
|
+
},
|
|
263
|
+
displayOptions: {
|
|
264
|
+
show: {
|
|
265
|
+
operation: ['create'],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
default: {},
|
|
269
|
+
options: [
|
|
270
|
+
{
|
|
271
|
+
displayName: 'Record',
|
|
272
|
+
name: 'record',
|
|
273
|
+
values: [
|
|
274
|
+
{
|
|
275
|
+
displayName: 'Key',
|
|
276
|
+
name: 'key',
|
|
277
|
+
type: 'string',
|
|
278
|
+
default: '',
|
|
279
|
+
description: 'Column name in the AppSheet table',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
displayName: 'Value',
|
|
283
|
+
name: 'value',
|
|
284
|
+
type: 'string',
|
|
285
|
+
default: '',
|
|
286
|
+
description: 'Value for the specified column',
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
description: 'Record must include the key field values required by your table',
|
|
292
|
+
},
|
|
293
|
+
// UPDATE-specific parameter
|
|
294
|
+
{
|
|
295
|
+
displayName: 'Records',
|
|
296
|
+
name: 'records',
|
|
297
|
+
type: 'fixedCollection',
|
|
298
|
+
typeOptions: {
|
|
299
|
+
multipleValues: true,
|
|
300
|
+
},
|
|
301
|
+
displayOptions: {
|
|
302
|
+
show: {
|
|
303
|
+
operation: ['update'],
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
default: {},
|
|
307
|
+
options: [
|
|
308
|
+
{
|
|
309
|
+
displayName: 'Record',
|
|
310
|
+
name: 'record',
|
|
311
|
+
values: [
|
|
312
|
+
{
|
|
313
|
+
displayName: 'Key',
|
|
314
|
+
name: 'key',
|
|
315
|
+
type: 'string',
|
|
316
|
+
default: '',
|
|
317
|
+
description: 'Column name in the AppSheet table',
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
displayName: 'Value',
|
|
321
|
+
name: 'value',
|
|
322
|
+
type: 'string',
|
|
323
|
+
default: '',
|
|
324
|
+
description: 'Value for the specified column',
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
description: 'Record must include the key field values and fields to update',
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
displayName: 'Records',
|
|
333
|
+
name: 'upsertRecords',
|
|
334
|
+
type: 'fixedCollection',
|
|
335
|
+
typeOptions: {
|
|
336
|
+
multipleValues: true,
|
|
337
|
+
},
|
|
338
|
+
displayOptions: {
|
|
339
|
+
show: {
|
|
340
|
+
operation: ['upsert'],
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
default: {},
|
|
344
|
+
options: [
|
|
345
|
+
{
|
|
346
|
+
displayName: 'Record',
|
|
347
|
+
name: 'record',
|
|
348
|
+
values: [
|
|
349
|
+
{
|
|
350
|
+
displayName: 'Fields',
|
|
351
|
+
name: 'fields',
|
|
352
|
+
type: 'fixedCollection',
|
|
353
|
+
typeOptions: {
|
|
354
|
+
multipleValues: true,
|
|
355
|
+
},
|
|
356
|
+
default: {},
|
|
357
|
+
options: [
|
|
358
|
+
{
|
|
359
|
+
displayName: 'Field',
|
|
360
|
+
name: 'field',
|
|
361
|
+
values: [
|
|
362
|
+
{
|
|
363
|
+
displayName: 'Key',
|
|
364
|
+
name: 'key',
|
|
365
|
+
type: 'string',
|
|
366
|
+
default: '',
|
|
367
|
+
description: 'Column name in the AppSheet table',
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
displayName: 'Value',
|
|
371
|
+
name: 'value',
|
|
372
|
+
type: 'string',
|
|
373
|
+
default: '',
|
|
374
|
+
description: 'Value for the specified column',
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
],
|
|
383
|
+
description: 'Records to upsert',
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
displayName: 'Key Fields',
|
|
387
|
+
name: 'upsertKeyFields',
|
|
388
|
+
type: 'fixedCollection',
|
|
389
|
+
typeOptions: {
|
|
390
|
+
multipleValues: true,
|
|
391
|
+
},
|
|
392
|
+
displayOptions: {
|
|
393
|
+
show: {
|
|
394
|
+
operation: ['upsert'],
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
default: {},
|
|
398
|
+
options: [
|
|
399
|
+
{
|
|
400
|
+
displayName: 'Field',
|
|
401
|
+
name: 'field',
|
|
402
|
+
values: [
|
|
403
|
+
{
|
|
404
|
+
displayName: 'Field Name',
|
|
405
|
+
name: 'fieldName',
|
|
406
|
+
type: 'string',
|
|
407
|
+
default: '',
|
|
408
|
+
description: 'Column name that uniquely identifies a record',
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
description: 'Field names that uniquely identify a record',
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
displayName: 'Batch Size',
|
|
417
|
+
name: 'upsertBatchSize',
|
|
418
|
+
type: 'number',
|
|
419
|
+
displayOptions: {
|
|
420
|
+
show: {
|
|
421
|
+
operation: ['upsert'],
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
default: 0,
|
|
425
|
+
description: 'Number of records per request. Set to 0 to send all at once',
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
displayName: 'Dry Run',
|
|
429
|
+
name: 'upsertDryRun',
|
|
430
|
+
type: 'boolean',
|
|
431
|
+
displayOptions: {
|
|
432
|
+
show: {
|
|
433
|
+
operation: ['upsert'],
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
default: false,
|
|
437
|
+
description: 'Whether to only calculate what would be created or updated',
|
|
438
|
+
},
|
|
439
|
+
// DELETE-specific parameter
|
|
440
|
+
{
|
|
441
|
+
displayName: 'Records',
|
|
442
|
+
name: 'records',
|
|
443
|
+
type: 'fixedCollection',
|
|
444
|
+
typeOptions: {
|
|
445
|
+
multipleValues: true,
|
|
446
|
+
},
|
|
447
|
+
displayOptions: {
|
|
448
|
+
show: {
|
|
449
|
+
operation: ['delete'],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
default: {},
|
|
453
|
+
options: [
|
|
454
|
+
{
|
|
455
|
+
displayName: 'Record',
|
|
456
|
+
name: 'record',
|
|
457
|
+
values: [
|
|
458
|
+
{
|
|
459
|
+
displayName: 'Key',
|
|
460
|
+
name: 'key',
|
|
461
|
+
type: 'string',
|
|
462
|
+
default: '',
|
|
463
|
+
description: 'Column name in the AppSheet table',
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
displayName: 'Value',
|
|
467
|
+
name: 'value',
|
|
468
|
+
type: 'string',
|
|
469
|
+
default: '',
|
|
470
|
+
description: 'Value for the specified column',
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
description: 'Record must include the key field values of the record to delete',
|
|
476
|
+
},
|
|
477
|
+
// INVOKE-specific parameters
|
|
478
|
+
{
|
|
479
|
+
displayName: 'Action Name',
|
|
480
|
+
name: 'actionName',
|
|
481
|
+
type: 'string',
|
|
482
|
+
displayOptions: {
|
|
483
|
+
show: {
|
|
484
|
+
operation: ['invoke'],
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
default: '',
|
|
488
|
+
description: 'The name of the action to invoke. For example, "IncrementCountAction".',
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
displayName: 'Records',
|
|
492
|
+
name: 'invokeRecords',
|
|
493
|
+
type: 'fixedCollection',
|
|
494
|
+
typeOptions: {
|
|
495
|
+
multipleValues: true,
|
|
496
|
+
},
|
|
497
|
+
displayOptions: {
|
|
498
|
+
show: {
|
|
499
|
+
operation: ['invoke'],
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
default: {},
|
|
503
|
+
options: [
|
|
504
|
+
{
|
|
505
|
+
displayName: 'Record',
|
|
506
|
+
name: 'record',
|
|
507
|
+
values: [
|
|
508
|
+
{
|
|
509
|
+
displayName: 'Key',
|
|
510
|
+
name: 'key',
|
|
511
|
+
type: 'string',
|
|
512
|
+
default: '',
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
displayName: 'Value',
|
|
516
|
+
name: 'value',
|
|
517
|
+
type: 'string',
|
|
518
|
+
default: '',
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
},
|
|
522
|
+
],
|
|
523
|
+
description: 'Record must include the key field values of the record to apply an action to',
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
displayName: 'Options',
|
|
527
|
+
name: 'options',
|
|
528
|
+
type: 'fixedCollection',
|
|
529
|
+
typeOptions: {
|
|
530
|
+
multipleValues: true,
|
|
531
|
+
},
|
|
532
|
+
default: {},
|
|
533
|
+
description: 'Optional settings that apply to AppSheet requests',
|
|
534
|
+
options: [
|
|
535
|
+
{
|
|
536
|
+
displayName: 'Locale',
|
|
537
|
+
name: 'locale',
|
|
538
|
+
values: [
|
|
539
|
+
{
|
|
540
|
+
displayName: 'Locale',
|
|
541
|
+
name: 'locale',
|
|
542
|
+
type: 'string',
|
|
543
|
+
default: 'en-US',
|
|
544
|
+
description: 'Locale used for formatting dates and numbers (e.g., en-US)',
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
displayName: 'Location',
|
|
550
|
+
name: 'location',
|
|
551
|
+
values: [
|
|
552
|
+
{
|
|
553
|
+
displayName: 'Location',
|
|
554
|
+
name: 'location',
|
|
555
|
+
type: 'string',
|
|
556
|
+
default: '47.623098, -122.330184',
|
|
557
|
+
description: 'Geographical coordinates (e.g., 47.623098, -122.330184)',
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
displayName: 'Timezone',
|
|
563
|
+
name: 'timezone',
|
|
564
|
+
values: [
|
|
565
|
+
{
|
|
566
|
+
displayName: 'Timezone',
|
|
567
|
+
name: 'timezone',
|
|
568
|
+
type: 'string',
|
|
569
|
+
default: 'Pacific Standard Time',
|
|
570
|
+
description: 'Timezone used for date/time formatting',
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
displayName: 'Action Properties',
|
|
576
|
+
name: 'actionProperties',
|
|
577
|
+
displayOptions: {
|
|
578
|
+
show: {
|
|
579
|
+
operation: ['invoke'],
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
values: [
|
|
583
|
+
{
|
|
584
|
+
displayName: 'Action Properties',
|
|
585
|
+
name: 'actionProperties',
|
|
586
|
+
type: 'json',
|
|
587
|
+
default: '',
|
|
588
|
+
description: 'Optional: Enter additional properties for the action as a JSON object',
|
|
589
|
+
},
|
|
590
|
+
],
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
displayName: 'Run as User Email',
|
|
594
|
+
name: 'runAsUserEmail',
|
|
595
|
+
displayOptions: {
|
|
596
|
+
show: {
|
|
597
|
+
operation: ['invoke'],
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
values: [
|
|
601
|
+
{
|
|
602
|
+
displayName: 'Run as User Email',
|
|
603
|
+
name: 'runAsUserEmail',
|
|
604
|
+
type: 'string',
|
|
605
|
+
default: '',
|
|
606
|
+
description: 'The user email address of the person taking the action. If empty, the action runs as the application owner',
|
|
607
|
+
},
|
|
608
|
+
],
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
displayName: 'User Settings',
|
|
612
|
+
name: 'userSettings',
|
|
613
|
+
displayOptions: {
|
|
614
|
+
show: {
|
|
615
|
+
operation: ['invoke'],
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
values: [
|
|
619
|
+
{
|
|
620
|
+
displayName: 'User Settings',
|
|
621
|
+
name: 'userSettings',
|
|
622
|
+
type: 'fixedCollection',
|
|
623
|
+
typeOptions: {
|
|
624
|
+
multipleValues: true,
|
|
625
|
+
},
|
|
626
|
+
default: {},
|
|
627
|
+
options: [
|
|
628
|
+
{
|
|
629
|
+
displayName: 'Setting',
|
|
630
|
+
name: 'setting',
|
|
631
|
+
values: [
|
|
632
|
+
{
|
|
633
|
+
displayName: 'Setting Option Name',
|
|
634
|
+
name: 'settingOptionName',
|
|
635
|
+
type: 'string',
|
|
636
|
+
default: '',
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
displayName: 'Setting Option Value',
|
|
640
|
+
name: 'settingOptionValue',
|
|
641
|
+
type: 'string',
|
|
642
|
+
default: '',
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
},
|
|
646
|
+
],
|
|
647
|
+
description: 'User settings to use when performing the action. Leave empty to use no user settings',
|
|
648
|
+
},
|
|
649
|
+
],
|
|
650
|
+
},
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
// Common properties for all operations
|
|
654
|
+
],
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
async execute() {
|
|
658
|
+
const items = this.getInputData();
|
|
659
|
+
const returnData = [];
|
|
660
|
+
const credentials = await this.getCredentials('appSheetApi');
|
|
661
|
+
// Retrieve the region parameter:
|
|
662
|
+
const region = this.getNodeParameter('region', 0);
|
|
663
|
+
for (let i = 0; i < items.length; i++) {
|
|
664
|
+
const options = this.getNodeParameter('options', i, {});
|
|
665
|
+
const localeOption = options.locale?.[0];
|
|
666
|
+
const locationOption = options.location?.[0];
|
|
667
|
+
const timezoneOption = options.timezone?.[0];
|
|
668
|
+
const commonProperties = {
|
|
669
|
+
Locale: localeOption?.locale || 'en-US',
|
|
670
|
+
Location: locationOption?.location || '47.623098, -122.330184',
|
|
671
|
+
Timezone: timezoneOption?.timezone || 'Pacific Standard Time',
|
|
672
|
+
};
|
|
673
|
+
const operation = this.getNodeParameter('operation', i);
|
|
674
|
+
const tableName = this.getNodeParameter('tableName', i);
|
|
675
|
+
const recordsParam = this.getNodeParameter('records', i, {});
|
|
676
|
+
const buildRowsFromRecords = (param) => {
|
|
677
|
+
const recordItems = param.record || [];
|
|
678
|
+
if (!recordItems.length) {
|
|
679
|
+
return [];
|
|
680
|
+
}
|
|
681
|
+
const record = {};
|
|
682
|
+
for (const item of recordItems) {
|
|
683
|
+
const key = item.key;
|
|
684
|
+
if (key && key.trim() !== '') {
|
|
685
|
+
record[key] = item.value;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return Object.keys(record).length ? [record] : [];
|
|
689
|
+
};
|
|
690
|
+
const buildRowsFromUpsertRecords = (param) => {
|
|
691
|
+
const recordItems = param.record || [];
|
|
692
|
+
const rows = [];
|
|
693
|
+
for (const recordItem of recordItems) {
|
|
694
|
+
const fields = recordItem.fields || {};
|
|
695
|
+
const fieldItems = fields.field || [];
|
|
696
|
+
const record = {};
|
|
697
|
+
for (const fieldItem of fieldItems) {
|
|
698
|
+
const key = fieldItem.key;
|
|
699
|
+
if (key && key.trim() !== '') {
|
|
700
|
+
record[key] = fieldItem.value;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (Object.keys(record).length) {
|
|
704
|
+
rows.push(record);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return rows;
|
|
708
|
+
};
|
|
709
|
+
const chunk = (rows, size) => {
|
|
710
|
+
if (!size || size <= 0) {
|
|
711
|
+
return [rows];
|
|
712
|
+
}
|
|
713
|
+
const batches = [];
|
|
714
|
+
for (let index = 0; index < rows.length; index += size) {
|
|
715
|
+
batches.push(rows.slice(index, index + size));
|
|
716
|
+
}
|
|
717
|
+
return batches;
|
|
718
|
+
};
|
|
719
|
+
const buildSelectorForExists = () => {
|
|
720
|
+
const combineWith = this.getNodeParameter('existsCombine', i);
|
|
721
|
+
const conditionsParam = this.getNodeParameter('existsConditions', i, {});
|
|
722
|
+
const conditions = conditionsParam.condition || [];
|
|
723
|
+
const expressions = [];
|
|
724
|
+
for (const condition of conditions) {
|
|
725
|
+
const operator = condition.operator;
|
|
726
|
+
const field = condition.field || '';
|
|
727
|
+
if (operator === 'expression') {
|
|
728
|
+
const expression = condition.value || '';
|
|
729
|
+
if (expression.trim()) {
|
|
730
|
+
expressions.push(expression.trim());
|
|
731
|
+
}
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
if (!field.trim()) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
const rawValue = condition.value || '';
|
|
738
|
+
const valueType = condition.valueType || 'string';
|
|
739
|
+
const safeValue = String(rawValue).replace(/"/g, '\\"');
|
|
740
|
+
const formatListValues = (values) => values
|
|
741
|
+
.map((value) => {
|
|
742
|
+
if (valueType === 'number') {
|
|
743
|
+
return Number.isNaN(Number(value)) ? '0' : String(value);
|
|
744
|
+
}
|
|
745
|
+
if (valueType === 'boolean') {
|
|
746
|
+
return String(value).toLowerCase() === 'true' ? 'TRUE' : 'FALSE';
|
|
747
|
+
}
|
|
748
|
+
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
749
|
+
})
|
|
750
|
+
.join(', ');
|
|
751
|
+
const formattedValue = (() => {
|
|
752
|
+
if (valueType === 'number') {
|
|
753
|
+
return Number.isNaN(Number(rawValue)) ? '0' : String(rawValue);
|
|
754
|
+
}
|
|
755
|
+
if (valueType === 'boolean') {
|
|
756
|
+
return String(rawValue).toLowerCase() === 'true' ? 'TRUE' : 'FALSE';
|
|
757
|
+
}
|
|
758
|
+
if (valueType === 'array') {
|
|
759
|
+
const trimmed = String(rawValue).trim();
|
|
760
|
+
if (trimmed.startsWith('LIST(')) {
|
|
761
|
+
return trimmed;
|
|
762
|
+
}
|
|
763
|
+
try {
|
|
764
|
+
const parsed = JSON.parse(trimmed);
|
|
765
|
+
if (Array.isArray(parsed)) {
|
|
766
|
+
return `LIST(${formatListValues(parsed.map(String))})`;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
catch {
|
|
770
|
+
// fall through
|
|
771
|
+
}
|
|
772
|
+
const values = trimmed.split(',').map((value) => value.trim()).filter(Boolean);
|
|
773
|
+
return `LIST(${formatListValues(values)})`;
|
|
774
|
+
}
|
|
775
|
+
if (valueType === 'object') {
|
|
776
|
+
return String(rawValue).trim();
|
|
777
|
+
}
|
|
778
|
+
return `"${safeValue}"`;
|
|
779
|
+
})();
|
|
780
|
+
const buildListExpression = () => {
|
|
781
|
+
const trimmed = String(rawValue).trim();
|
|
782
|
+
if (valueType === 'array' && trimmed.startsWith('LIST(')) {
|
|
783
|
+
return trimmed;
|
|
784
|
+
}
|
|
785
|
+
try {
|
|
786
|
+
const parsed = JSON.parse(trimmed);
|
|
787
|
+
if (Array.isArray(parsed)) {
|
|
788
|
+
return `LIST(${formatListValues(parsed.map(String))})`;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
// fall through
|
|
793
|
+
}
|
|
794
|
+
const values = trimmed.split(',').map((value) => value.trim()).filter(Boolean);
|
|
795
|
+
return `LIST(${formatListValues(values)})`;
|
|
796
|
+
};
|
|
797
|
+
let expr = '';
|
|
798
|
+
switch (operator) {
|
|
799
|
+
case 'contains':
|
|
800
|
+
expr = `CONTAINS([${field}], ${formattedValue})`;
|
|
801
|
+
break;
|
|
802
|
+
case 'notContains':
|
|
803
|
+
expr = `NOT(CONTAINS([${field}], ${formattedValue}))`;
|
|
804
|
+
break;
|
|
805
|
+
case 'startsWith':
|
|
806
|
+
expr = `STARTSWITH([${field}], ${formattedValue})`;
|
|
807
|
+
break;
|
|
808
|
+
case 'endsWith':
|
|
809
|
+
expr = `ENDSWITH([${field}], ${formattedValue})`;
|
|
810
|
+
break;
|
|
811
|
+
case 'greaterThan':
|
|
812
|
+
expr = `[${field}] > ${formattedValue}`;
|
|
813
|
+
break;
|
|
814
|
+
case 'greaterThanOrEqual':
|
|
815
|
+
expr = `[${field}] >= ${formattedValue}`;
|
|
816
|
+
break;
|
|
817
|
+
case 'lessThan':
|
|
818
|
+
expr = `[${field}] < ${formattedValue}`;
|
|
819
|
+
break;
|
|
820
|
+
case 'lessThanOrEqual':
|
|
821
|
+
expr = `[${field}] <= ${formattedValue}`;
|
|
822
|
+
break;
|
|
823
|
+
case 'in':
|
|
824
|
+
expr = `IN([${field}], ${buildListExpression()})`;
|
|
825
|
+
break;
|
|
826
|
+
case 'notIn':
|
|
827
|
+
expr = `NOT(IN([${field}], ${buildListExpression()}))`;
|
|
828
|
+
break;
|
|
829
|
+
case 'isBlank':
|
|
830
|
+
expr = `ISBLANK([${field}])`;
|
|
831
|
+
break;
|
|
832
|
+
case 'isNotBlank':
|
|
833
|
+
expr = `ISNOTBLANK([${field}])`;
|
|
834
|
+
break;
|
|
835
|
+
case 'notEquals':
|
|
836
|
+
expr = `[${field}] <> ${formattedValue}`;
|
|
837
|
+
break;
|
|
838
|
+
case 'equals':
|
|
839
|
+
default:
|
|
840
|
+
expr = `[${field}] = ${formattedValue}`;
|
|
841
|
+
break;
|
|
842
|
+
}
|
|
843
|
+
expressions.push(expr);
|
|
844
|
+
}
|
|
845
|
+
if (!expressions.length) {
|
|
846
|
+
return '';
|
|
847
|
+
}
|
|
848
|
+
const combined = expressions.length === 1
|
|
849
|
+
? expressions[0]
|
|
850
|
+
: `${combineWith === 'or' ? 'OR' : 'AND'}(${expressions.join(', ')})`;
|
|
851
|
+
const trimmed = combined.trim();
|
|
852
|
+
if (/^(FILTER|SELECT)\(/i.test(trimmed)) {
|
|
853
|
+
return trimmed;
|
|
854
|
+
}
|
|
855
|
+
return `FILTER(${tableName}, ${combined})`;
|
|
856
|
+
};
|
|
857
|
+
let body = {
|
|
858
|
+
AppID: credentials.appId,
|
|
859
|
+
TableName: tableName,
|
|
860
|
+
Properties: commonProperties,
|
|
861
|
+
};
|
|
862
|
+
switch (operation) {
|
|
863
|
+
case 'create': {
|
|
864
|
+
const rows = buildRowsFromRecords(recordsParam);
|
|
865
|
+
if (!rows.length) {
|
|
866
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Records are required for create.');
|
|
867
|
+
}
|
|
868
|
+
body.Rows = rows;
|
|
869
|
+
body.Action = 'Add';
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
case 'read': {
|
|
873
|
+
body.Action = 'Find';
|
|
874
|
+
const selector = this.getNodeParameter('selector', i);
|
|
875
|
+
if (selector.trim() !== '') {
|
|
876
|
+
body.Properties = { ...commonProperties, Selector: selector };
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
const rows = buildRowsFromRecords(recordsParam);
|
|
880
|
+
if (!rows.length) {
|
|
881
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Records are required for read when Selector is empty.');
|
|
882
|
+
}
|
|
883
|
+
body.Rows = rows;
|
|
884
|
+
}
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
case 'exists': {
|
|
888
|
+
body.Action = 'Find';
|
|
889
|
+
const selector = buildSelectorForExists();
|
|
890
|
+
if (!selector) {
|
|
891
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one condition is required.');
|
|
892
|
+
}
|
|
893
|
+
body.Properties = { ...commonProperties, Selector: selector };
|
|
894
|
+
break;
|
|
895
|
+
}
|
|
896
|
+
case 'update': {
|
|
897
|
+
const rows = buildRowsFromRecords(recordsParam);
|
|
898
|
+
if (!rows.length) {
|
|
899
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Records are required for update.');
|
|
900
|
+
}
|
|
901
|
+
body.Rows = rows;
|
|
902
|
+
body.Action = 'Edit';
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
case 'upsert': {
|
|
906
|
+
const upsertRecordsParam = this.getNodeParameter('upsertRecords', i, {});
|
|
907
|
+
const rows = buildRowsFromUpsertRecords(upsertRecordsParam);
|
|
908
|
+
if (!rows.length) {
|
|
909
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Records are required for upsert.');
|
|
910
|
+
}
|
|
911
|
+
const keyFieldsParam = this.getNodeParameter('upsertKeyFields', i, {});
|
|
912
|
+
const keyFields = (keyFieldsParam.field || [])
|
|
913
|
+
.map((item) => item.fieldName || '')
|
|
914
|
+
.filter((field) => field.trim() !== '');
|
|
915
|
+
if (!keyFields.length) {
|
|
916
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Key Fields are required for upsert.');
|
|
917
|
+
}
|
|
918
|
+
const keyRows = rows.map((row) => {
|
|
919
|
+
const keyRow = {};
|
|
920
|
+
for (const field of keyFields) {
|
|
921
|
+
keyRow[field] = row[field];
|
|
922
|
+
}
|
|
923
|
+
return keyRow;
|
|
924
|
+
});
|
|
925
|
+
const findOptions = {
|
|
926
|
+
headers: {
|
|
927
|
+
'Content-Type': 'application/json',
|
|
928
|
+
'ApplicationAccessKey': credentials.apiKey,
|
|
929
|
+
},
|
|
930
|
+
body: {
|
|
931
|
+
AppID: credentials.appId,
|
|
932
|
+
TableName: tableName,
|
|
933
|
+
Properties: commonProperties,
|
|
934
|
+
Action: 'Find',
|
|
935
|
+
Rows: keyRows,
|
|
936
|
+
},
|
|
937
|
+
method: 'POST',
|
|
938
|
+
url: `https://${region}/api/v2/apps/${credentials.appId}/tables/${encodeURIComponent(tableName)}/Action`,
|
|
939
|
+
};
|
|
940
|
+
const findResponse = await this.helpers.httpRequest(findOptions);
|
|
941
|
+
const foundRows = Array.isArray(findResponse)
|
|
942
|
+
? findResponse
|
|
943
|
+
: Array.isArray(findResponse.Rows)
|
|
944
|
+
? findResponse.Rows
|
|
945
|
+
: [];
|
|
946
|
+
const keySignature = (row) => keyFields.map((field) => String(row[field] ?? '')).join('|');
|
|
947
|
+
const existingKeys = new Set(foundRows.map(keySignature));
|
|
948
|
+
const toCreate = rows.filter((row) => !existingKeys.has(keySignature(row)));
|
|
949
|
+
const toUpdate = rows.filter((row) => existingKeys.has(keySignature(row)));
|
|
950
|
+
const batchSize = this.getNodeParameter('upsertBatchSize', i);
|
|
951
|
+
const dryRun = this.getNodeParameter('upsertDryRun', i);
|
|
952
|
+
const createdResponses = [];
|
|
953
|
+
const updatedResponses = [];
|
|
954
|
+
if (dryRun) {
|
|
955
|
+
returnData.push({
|
|
956
|
+
dryRun: true,
|
|
957
|
+
created: toCreate.length,
|
|
958
|
+
updated: toUpdate.length,
|
|
959
|
+
createdRecords: toCreate,
|
|
960
|
+
updatedRecords: toUpdate,
|
|
961
|
+
});
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
for (const batchRows of chunk(toCreate, batchSize)) {
|
|
965
|
+
if (!batchRows.length) {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
const createOptions = {
|
|
969
|
+
headers: {
|
|
970
|
+
'Content-Type': 'application/json',
|
|
971
|
+
'ApplicationAccessKey': credentials.apiKey,
|
|
972
|
+
},
|
|
973
|
+
body: {
|
|
974
|
+
AppID: credentials.appId,
|
|
975
|
+
TableName: tableName,
|
|
976
|
+
Properties: commonProperties,
|
|
977
|
+
Action: 'Add',
|
|
978
|
+
Rows: batchRows,
|
|
979
|
+
},
|
|
980
|
+
method: 'POST',
|
|
981
|
+
url: `https://${region}/api/v2/apps/${credentials.appId}/tables/${encodeURIComponent(tableName)}/Action`,
|
|
982
|
+
};
|
|
983
|
+
const createResponse = await this.helpers.httpRequest(createOptions);
|
|
984
|
+
if (Array.isArray(createResponse)) {
|
|
985
|
+
createdResponses.push(...createResponse);
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
createdResponses.push(createResponse);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
for (const batchRows of chunk(toUpdate, batchSize)) {
|
|
992
|
+
if (!batchRows.length) {
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
const updateOptions = {
|
|
996
|
+
headers: {
|
|
997
|
+
'Content-Type': 'application/json',
|
|
998
|
+
'ApplicationAccessKey': credentials.apiKey,
|
|
999
|
+
},
|
|
1000
|
+
body: {
|
|
1001
|
+
AppID: credentials.appId,
|
|
1002
|
+
TableName: tableName,
|
|
1003
|
+
Properties: commonProperties,
|
|
1004
|
+
Action: 'Edit',
|
|
1005
|
+
Rows: batchRows,
|
|
1006
|
+
},
|
|
1007
|
+
method: 'POST',
|
|
1008
|
+
url: `https://${region}/api/v2/apps/${credentials.appId}/tables/${encodeURIComponent(tableName)}/Action`,
|
|
1009
|
+
};
|
|
1010
|
+
const updateResponse = await this.helpers.httpRequest(updateOptions);
|
|
1011
|
+
if (Array.isArray(updateResponse)) {
|
|
1012
|
+
updatedResponses.push(...updateResponse);
|
|
1013
|
+
}
|
|
1014
|
+
else {
|
|
1015
|
+
updatedResponses.push(updateResponse);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
returnData.push({
|
|
1019
|
+
created: createdResponses.length,
|
|
1020
|
+
updated: updatedResponses.length,
|
|
1021
|
+
createdRecords: createdResponses,
|
|
1022
|
+
updatedRecords: updatedResponses,
|
|
1023
|
+
});
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
case 'delete': {
|
|
1027
|
+
const rows = buildRowsFromRecords(recordsParam);
|
|
1028
|
+
if (!rows.length) {
|
|
1029
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Records are required for delete.');
|
|
1030
|
+
}
|
|
1031
|
+
body.Rows = rows;
|
|
1032
|
+
body.Action = 'Delete';
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
case 'invoke': {
|
|
1036
|
+
const actionName = this.getNodeParameter('actionName', i);
|
|
1037
|
+
body.Action = actionName || '';
|
|
1038
|
+
let properties = { ...commonProperties };
|
|
1039
|
+
const actionPropsOption = options.actionProperties?.[0];
|
|
1040
|
+
const actionProps = actionPropsOption?.actionProperties || '';
|
|
1041
|
+
if (actionProps.trim() !== '') {
|
|
1042
|
+
try {
|
|
1043
|
+
properties = { ...properties, ...JSON.parse(actionProps) };
|
|
1044
|
+
}
|
|
1045
|
+
catch (error) {
|
|
1046
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid JSON in Action Properties. Must be a JSON object.');
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
const invokeRecords = this.getNodeParameter('invokeRecords', i, {});
|
|
1050
|
+
const recordItems = invokeRecords.record || [];
|
|
1051
|
+
if (recordItems.length) {
|
|
1052
|
+
const record = {};
|
|
1053
|
+
for (const item of recordItems) {
|
|
1054
|
+
const key = item.key;
|
|
1055
|
+
if (key && key.trim() !== '') {
|
|
1056
|
+
record[key] = item.value;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (Object.keys(record).length) {
|
|
1060
|
+
body.Rows = [record];
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
const runAsUserEmailOption = options.runAsUserEmail?.[0];
|
|
1064
|
+
const runAsUserEmail = runAsUserEmailOption?.runAsUserEmail || '';
|
|
1065
|
+
if (runAsUserEmail.trim() !== '') {
|
|
1066
|
+
properties = { ...properties, UserId: runAsUserEmail };
|
|
1067
|
+
}
|
|
1068
|
+
const userSettingsOption = options.userSettings?.[0];
|
|
1069
|
+
const userSettingsParam = userSettingsOption?.userSettings || {};
|
|
1070
|
+
const settingsItems = userSettingsParam.setting || [];
|
|
1071
|
+
if (settingsItems.length) {
|
|
1072
|
+
const settings = {};
|
|
1073
|
+
for (const item of settingsItems) {
|
|
1074
|
+
const settingName = item.settingOptionName;
|
|
1075
|
+
if (settingName && settingName.trim() !== '') {
|
|
1076
|
+
settings[settingName] = item.settingOptionValue;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (Object.keys(settings).length) {
|
|
1080
|
+
properties = { ...properties, UserSettings: settings };
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
body.Properties = properties;
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
default:
|
|
1087
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Operation "${operation}" not supported!`);
|
|
1088
|
+
}
|
|
1089
|
+
const requestOptions = {
|
|
1090
|
+
headers: {
|
|
1091
|
+
'Content-Type': 'application/json',
|
|
1092
|
+
'ApplicationAccessKey': credentials.apiKey,
|
|
1093
|
+
},
|
|
1094
|
+
body,
|
|
1095
|
+
method: 'POST',
|
|
1096
|
+
url: `https://${region}/api/v2/apps/${credentials.appId}/tables/${encodeURIComponent(tableName)}/Action`,
|
|
1097
|
+
};
|
|
1098
|
+
const response = await this.helpers.httpRequest(requestOptions);
|
|
1099
|
+
if (operation === 'exists') {
|
|
1100
|
+
let records = [];
|
|
1101
|
+
if (Array.isArray(response)) {
|
|
1102
|
+
records = response;
|
|
1103
|
+
}
|
|
1104
|
+
else if (response && Array.isArray(response.Rows)) {
|
|
1105
|
+
records = response.Rows;
|
|
1106
|
+
}
|
|
1107
|
+
returnData.push({
|
|
1108
|
+
exists: records.length > 0,
|
|
1109
|
+
count: records.length,
|
|
1110
|
+
records,
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
else if (Array.isArray(response)) {
|
|
1114
|
+
returnData.push(...response);
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
returnData.push(response);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return [this.helpers.returnJsonArray(returnData)];
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
exports.AIAgentAppSheet = AIAgentAppSheet;
|