@belmontdigitalmarketing/n8n-nodes-flowlu 0.2.1 → 0.3.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.
|
@@ -9,10 +9,9 @@ async function getFlowluCredentials(context) {
|
|
|
9
9
|
const credentials = await context.getCredentials('flowluApi');
|
|
10
10
|
const subdomain = credentials.subdomain;
|
|
11
11
|
const apiKey = credentials.apiKey;
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return { baseUrl, apiKey };
|
|
12
|
+
const defaultOwnerId = (credentials.defaultOwnerId || '').trim();
|
|
13
|
+
const baseUrl = subdomain.endsWith('.flowlu.com') ? `https://${subdomain}` : `https://${subdomain}.flowlu.com`;
|
|
14
|
+
return { baseUrl, apiKey, defaultOwnerId };
|
|
16
15
|
}
|
|
17
16
|
async function flowluApiRequest(method, baseUrl, endpoint, apiKey, body, queryParams) {
|
|
18
17
|
const qs = { api_key: apiKey };
|
|
@@ -31,6 +30,59 @@ async function flowluApiRequest(method, baseUrl, endpoint, apiKey, body, queryPa
|
|
|
31
30
|
const response = await this.helpers.request(requestOptions);
|
|
32
31
|
return typeof response === 'string' ? JSON.parse(response) : response;
|
|
33
32
|
}
|
|
33
|
+
// Detect Flowlu's rate-limit signal in either a thrown error or a returned body.
|
|
34
|
+
function isFlowluRateLimit(value) {
|
|
35
|
+
const text = value instanceof Error ? value.message : typeof value === 'string' ? value : JSON.stringify(value ?? '');
|
|
36
|
+
return /limit exceeded|too many requests|\b429\b/i.test(text);
|
|
37
|
+
}
|
|
38
|
+
// GET wrapper that retries through Flowlu's rate limit with linear backoff. If it
|
|
39
|
+
// never succeeds it throws, so callers surface the real cause instead of silently
|
|
40
|
+
// returning no data (which previously masqueraded as "No fields found").
|
|
41
|
+
async function flowluApiGetWithRetry(baseUrl, endpoint, apiKey, queryParams, maxRetries = 3) {
|
|
42
|
+
let lastMessage = 'Flowlu request failed';
|
|
43
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
44
|
+
try {
|
|
45
|
+
const response = await flowluApiRequest.call(this, 'GET', baseUrl, endpoint, apiKey, undefined, queryParams);
|
|
46
|
+
if (!isFlowluRateLimit(response?.error ?? response)) {
|
|
47
|
+
return response;
|
|
48
|
+
}
|
|
49
|
+
lastMessage = String(response?.error ?? 'Flowlu request limit exceeded');
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (!isFlowluRateLimit(error)) {
|
|
53
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Flowlu API error: ${error.message}`);
|
|
54
|
+
}
|
|
55
|
+
lastMessage = error.message || 'Flowlu request limit exceeded';
|
|
56
|
+
}
|
|
57
|
+
// linear backoff before the next attempt (no wait after the final one)
|
|
58
|
+
if (attempt < maxRetries) {
|
|
59
|
+
await new Promise((resolve) => {
|
|
60
|
+
setTimeout(resolve, 1500 * (attempt + 1));
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Flowlu API rate limit reached while loading data (${lastMessage}). Wait a moment and click Retry.`);
|
|
65
|
+
}
|
|
66
|
+
// Fetch every page of a Flowlu list endpoint. The API caps responses at 50 items
|
|
67
|
+
// per page, so a single call silently truncates larger result sets.
|
|
68
|
+
async function flowluListAll(baseUrl, endpoint, apiKey, queryParams) {
|
|
69
|
+
const items = [];
|
|
70
|
+
const maxPages = 100; // safety bound
|
|
71
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
72
|
+
const response = await flowluApiGetWithRetry.call(this, baseUrl, endpoint, apiKey, {
|
|
73
|
+
...(queryParams ?? {}),
|
|
74
|
+
page: String(page),
|
|
75
|
+
});
|
|
76
|
+
const pageItems = response?.response?.items;
|
|
77
|
+
if (!Array.isArray(pageItems) || pageItems.length === 0)
|
|
78
|
+
break;
|
|
79
|
+
items.push(...pageItems);
|
|
80
|
+
const total = Number(response.response.total ?? items.length);
|
|
81
|
+
if (items.length >= total)
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
return items;
|
|
85
|
+
}
|
|
34
86
|
function appendWorkflowFooter(target, contentKey = 'description') {
|
|
35
87
|
const { id } = this.getWorkflow();
|
|
36
88
|
const footer = `<hr><em>Generated via n8n:</em> <a href="${this.getInstanceBaseUrl()}workflow/${id}">View Workflow</a>`;
|
|
@@ -52,49 +104,27 @@ function applyResourceMapperFields(context, body, paramName, itemIndex) {
|
|
|
52
104
|
// No custom fields set - ignore
|
|
53
105
|
}
|
|
54
106
|
}
|
|
55
|
-
// Helper to load custom fields
|
|
107
|
+
// Helper to load an entity's custom fields as name/value options.
|
|
56
108
|
async function loadCustomFieldsForEntity(context, moduleFilter, modelFilter) {
|
|
109
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(context);
|
|
110
|
+
let fieldsets;
|
|
111
|
+
let allFields;
|
|
57
112
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const fieldsetsResponse = await flowluApiRequest.call(context, 'GET', baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
61
|
-
const fieldsetIds = [];
|
|
62
|
-
if (fieldsetsResponse?.response?.items) {
|
|
63
|
-
for (const fs of fieldsetsResponse.response.items) {
|
|
64
|
-
if (fs.module === moduleFilter && fs.model === modelFilter) {
|
|
65
|
-
fieldsetIds.push(fs.id.toString());
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// Get all custom fields
|
|
70
|
-
const fieldsResponse = await flowluApiRequest.call(context, 'GET', baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
71
|
-
if (fieldsResponse?.response?.items) {
|
|
72
|
-
let fields = fieldsResponse.response.items;
|
|
73
|
-
// Filter by fieldset if we found matching fieldsets
|
|
74
|
-
if (fieldsetIds.length > 0) {
|
|
75
|
-
fields = fields.filter((f) => fieldsetIds.includes(f.fieldset_id?.toString()));
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
// Fallback: filter by module/model directly on the field
|
|
79
|
-
fields = fields.filter((f) => f.module === moduleFilter && f.model === modelFilter);
|
|
80
|
-
}
|
|
81
|
-
return fields
|
|
82
|
-
.filter((f) => f.active !== 0)
|
|
83
|
-
.map((f) => {
|
|
84
|
-
const cfKey = (f.api_use_alias && f.alias)
|
|
85
|
-
? `cf_${f.alias}`
|
|
86
|
-
: `cf_${f.id}`;
|
|
87
|
-
return {
|
|
88
|
-
name: f.name || cfKey,
|
|
89
|
-
value: cfKey,
|
|
90
|
-
};
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return [];
|
|
113
|
+
fieldsets = await flowluListAll.call(context, baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
114
|
+
allFields = await flowluListAll.call(context, baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
94
115
|
}
|
|
95
116
|
catch (error) {
|
|
96
|
-
|
|
117
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Could not load Flowlu custom fields: ${error.message}. If this is a rate limit, wait a moment and try again.`);
|
|
97
118
|
}
|
|
119
|
+
// Fields don't reliably carry module/model, so match via their fieldset.
|
|
120
|
+
const matchingFieldsetIds = new Set(fieldsets.filter((fs) => fs.module === moduleFilter && fs.model === modelFilter).map((fs) => String(fs.id)));
|
|
121
|
+
return allFields
|
|
122
|
+
.filter((f) => f.active !== 0)
|
|
123
|
+
.filter((f) => matchingFieldsetIds.has(String(f.fieldset_id)) || (f.module === moduleFilter && f.model === modelFilter))
|
|
124
|
+
.map((f) => {
|
|
125
|
+
const cfKey = f.api_use_alias && f.alias ? `cf_${f.alias}` : `cf_${f.id}`;
|
|
126
|
+
return { name: f.name || cfKey, value: cfKey };
|
|
127
|
+
});
|
|
98
128
|
}
|
|
99
129
|
// ============================================================
|
|
100
130
|
// Reusable custom field option definitions
|
|
@@ -103,27 +133,16 @@ async function loadCustomFieldsForEntity(context, moduleFilter, modelFilter) {
|
|
|
103
133
|
async function loadEntityCustomFieldColumns(moduleFilter, modelFilter) {
|
|
104
134
|
try {
|
|
105
135
|
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
const fieldsResponse = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
116
|
-
if (!fieldsResponse?.response?.items)
|
|
117
|
-
return { fields: [] };
|
|
118
|
-
let filtered = fieldsResponse.response.items.filter((f) => f.active !== 0);
|
|
119
|
-
if (fieldsetIds.length > 0) {
|
|
120
|
-
filtered = filtered.filter((f) => fieldsetIds.includes(f.fieldset_id?.toString()));
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
filtered = filtered.filter((f) => f.module === moduleFilter && f.model === modelFilter);
|
|
124
|
-
}
|
|
136
|
+
const fieldsets = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
137
|
+
const allFields = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
138
|
+
// Fields don't reliably carry module/model, so match via their fieldset.
|
|
139
|
+
const matchingFieldsetIds = new Set(fieldsets
|
|
140
|
+
.filter((fs) => fs.module === moduleFilter && fs.model === modelFilter)
|
|
141
|
+
.map((fs) => String(fs.id)));
|
|
142
|
+
const filtered = allFields.filter((f) => f.active !== 0 &&
|
|
143
|
+
(matchingFieldsetIds.has(String(f.fieldset_id)) || (f.module === moduleFilter && f.model === modelFilter)));
|
|
125
144
|
const fields = filtered.map((f) => {
|
|
126
|
-
const cfKey =
|
|
145
|
+
const cfKey = f.api_use_alias && f.alias ? `cf_${f.alias}` : `cf_${f.id}`;
|
|
127
146
|
let fieldType = 'string';
|
|
128
147
|
if (f.type === 'int')
|
|
129
148
|
fieldType = 'number';
|
|
@@ -145,7 +164,9 @@ async function loadEntityCustomFieldColumns(moduleFilter, modelFilter) {
|
|
|
145
164
|
.filter((o) => o.value)
|
|
146
165
|
.map((o) => ({ name: o.value, value: o.id?.toString() || o.value }));
|
|
147
166
|
}
|
|
148
|
-
catch {
|
|
167
|
+
catch {
|
|
168
|
+
/* ignore */
|
|
169
|
+
}
|
|
149
170
|
}
|
|
150
171
|
const field = {
|
|
151
172
|
id: cfKey,
|
|
@@ -163,7 +184,9 @@ async function loadEntityCustomFieldColumns(moduleFilter, modelFilter) {
|
|
|
163
184
|
return { fields };
|
|
164
185
|
}
|
|
165
186
|
catch (error) {
|
|
166
|
-
|
|
187
|
+
if (error instanceof n8n_workflow_1.NodeOperationError)
|
|
188
|
+
throw error;
|
|
189
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not load Flowlu custom fields: ${error.message}. If this is a rate limit, wait a moment and click Retry.`);
|
|
167
190
|
}
|
|
168
191
|
}
|
|
169
192
|
function makeCustomFieldsOption(loadMethod) {
|
|
@@ -251,7 +274,12 @@ class Flowlu {
|
|
|
251
274
|
displayOptions: { show: { resource: ['tag'] } },
|
|
252
275
|
options: [
|
|
253
276
|
{ name: 'Add', value: 'add', description: 'Add a tag to an entity', action: 'Add a tag' },
|
|
254
|
-
{
|
|
277
|
+
{
|
|
278
|
+
name: 'Get Many',
|
|
279
|
+
value: 'getAll',
|
|
280
|
+
description: 'Get many tags on an entity',
|
|
281
|
+
action: 'Get tags on entity',
|
|
282
|
+
},
|
|
255
283
|
{ name: 'List All', value: 'listAll', description: 'List all tags in your account', action: 'List all tags' },
|
|
256
284
|
{ name: 'Remove', value: 'remove', description: 'Remove a tag from an entity', action: 'Remove a tag' },
|
|
257
285
|
],
|
|
@@ -268,7 +296,12 @@ class Flowlu {
|
|
|
268
296
|
displayOptions: { show: { resource: ['comment'] } },
|
|
269
297
|
options: [
|
|
270
298
|
{ name: 'Create', value: 'create', description: 'Create a comment on an entity', action: 'Create a comment' },
|
|
271
|
-
{
|
|
299
|
+
{
|
|
300
|
+
name: 'Get Many',
|
|
301
|
+
value: 'getAll',
|
|
302
|
+
description: 'Get many comments on an entity',
|
|
303
|
+
action: 'Get comments on entity',
|
|
304
|
+
},
|
|
272
305
|
],
|
|
273
306
|
default: 'create',
|
|
274
307
|
},
|
|
@@ -303,7 +336,12 @@ class Flowlu {
|
|
|
303
336
|
{ name: 'Create', value: 'create', description: 'Create a new opportunity', action: 'Create an opportunity' },
|
|
304
337
|
{ name: 'Delete', value: 'delete', description: 'Delete an opportunity', action: 'Delete an opportunity' },
|
|
305
338
|
{ name: 'Get', value: 'get', description: 'Get an opportunity by ID', action: 'Get an opportunity' },
|
|
306
|
-
{
|
|
339
|
+
{
|
|
340
|
+
name: 'Get Many',
|
|
341
|
+
value: 'getAll',
|
|
342
|
+
description: 'Get many opportunities',
|
|
343
|
+
action: 'Get many opportunities',
|
|
344
|
+
},
|
|
307
345
|
{ name: 'Update', value: 'update', description: 'Update an opportunity', action: 'Update an opportunity' },
|
|
308
346
|
],
|
|
309
347
|
default: 'create',
|
|
@@ -432,7 +470,14 @@ class Flowlu {
|
|
|
432
470
|
{ displayName: 'Instagram', name: 'social_network_link_6', type: 'string', default: '' },
|
|
433
471
|
{ displayName: 'LinkedIn', name: 'social_network_link_5', type: 'string', default: '' },
|
|
434
472
|
{ displayName: 'Middle Name', name: 'middle_name', type: 'string', default: '' },
|
|
435
|
-
{
|
|
473
|
+
{
|
|
474
|
+
displayName: 'Owner Name or ID',
|
|
475
|
+
name: 'owner_id',
|
|
476
|
+
type: 'options',
|
|
477
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
478
|
+
default: '',
|
|
479
|
+
description: 'Assigned user for this contact. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
480
|
+
},
|
|
436
481
|
{ displayName: 'Personal Email', name: 'email_personal', type: 'string', default: '' },
|
|
437
482
|
{ displayName: 'Phone 2', name: 'phone2', type: 'string', default: '' },
|
|
438
483
|
{ displayName: 'Phone 3', name: 'phone3', type: 'string', default: '' },
|
|
@@ -491,7 +536,14 @@ class Flowlu {
|
|
|
491
536
|
{ displayName: 'Last Name', name: 'last_name', type: 'string', default: '' },
|
|
492
537
|
{ displayName: 'LinkedIn', name: 'social_network_link_5', type: 'string', default: '' },
|
|
493
538
|
{ displayName: 'Middle Name', name: 'middle_name', type: 'string', default: '' },
|
|
494
|
-
{
|
|
539
|
+
{
|
|
540
|
+
displayName: 'Owner Name or ID',
|
|
541
|
+
name: 'owner_id',
|
|
542
|
+
type: 'options',
|
|
543
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
544
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
545
|
+
default: '',
|
|
546
|
+
},
|
|
495
547
|
{ displayName: 'Personal Email', name: 'email_personal', type: 'string', default: '' },
|
|
496
548
|
{ displayName: 'Phone', name: 'phone', type: 'string', default: '' },
|
|
497
549
|
{ displayName: 'Phone 2', name: 'phone2', type: 'string', default: '' },
|
|
@@ -541,10 +593,23 @@ class Flowlu {
|
|
|
541
593
|
displayOptions: { show: { resource: ['contact'], operation: ['getAll'] } },
|
|
542
594
|
options: [
|
|
543
595
|
{ displayName: 'Name', name: 'name', type: 'string', default: '', description: 'Filter by contact name' },
|
|
544
|
-
{
|
|
545
|
-
|
|
596
|
+
{
|
|
597
|
+
displayName: 'Email',
|
|
598
|
+
name: 'email',
|
|
599
|
+
type: 'string',
|
|
600
|
+
placeholder: 'name@email.com',
|
|
601
|
+
default: '',
|
|
602
|
+
description: 'Filter by email address',
|
|
603
|
+
},
|
|
546
604
|
{ displayName: 'Phone', name: 'phone', type: 'string', default: '', description: 'Filter by phone number' },
|
|
547
|
-
{
|
|
605
|
+
{
|
|
606
|
+
displayName: 'Owner Name or ID',
|
|
607
|
+
name: 'owner_id',
|
|
608
|
+
type: 'options',
|
|
609
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
610
|
+
default: '',
|
|
611
|
+
description: 'Filter by assigned owner. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
612
|
+
},
|
|
548
613
|
],
|
|
549
614
|
},
|
|
550
615
|
// ========================================
|
|
@@ -606,11 +671,23 @@ class Flowlu {
|
|
|
606
671
|
default: {},
|
|
607
672
|
displayOptions: { show: { resource: ['opportunity'], operation: ['create'] } },
|
|
608
673
|
options: [
|
|
609
|
-
{
|
|
674
|
+
{
|
|
675
|
+
displayName: 'Budget',
|
|
676
|
+
name: 'budget',
|
|
677
|
+
type: 'number',
|
|
678
|
+
default: 0,
|
|
679
|
+
description: 'Opportunity value/amount',
|
|
680
|
+
},
|
|
610
681
|
{ displayName: 'Contact Company', name: 'contact_company', type: 'string', default: '' },
|
|
611
682
|
{ displayName: 'Contact Email', name: 'contact_email', type: 'string', default: '' },
|
|
612
683
|
{ displayName: 'Contact Mobile', name: 'contact_mobile', type: 'string', default: '' },
|
|
613
|
-
{
|
|
684
|
+
{
|
|
685
|
+
displayName: 'Contact Name',
|
|
686
|
+
name: 'contact_name',
|
|
687
|
+
type: 'string',
|
|
688
|
+
default: '',
|
|
689
|
+
description: 'Quick-add contact name (if not linking to existing contact)',
|
|
690
|
+
},
|
|
614
691
|
{ displayName: 'Contact Phone', name: 'contact_phone', type: 'string', default: '' },
|
|
615
692
|
{ displayName: 'Contact Position', name: 'contact_position', type: 'string', default: '' },
|
|
616
693
|
{ displayName: 'Contact Website', name: 'contact_web', type: 'string', default: '' },
|
|
@@ -622,10 +699,31 @@ class Flowlu {
|
|
|
622
699
|
default: false,
|
|
623
700
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the opportunity description, linking back to this workflow',
|
|
624
701
|
},
|
|
625
|
-
{
|
|
626
|
-
|
|
702
|
+
{
|
|
703
|
+
displayName: 'Link to Account Name or ID',
|
|
704
|
+
name: 'link_account_id',
|
|
705
|
+
type: 'options',
|
|
706
|
+
typeOptions: { loadOptionsMethod: 'getAccounts' },
|
|
707
|
+
default: '',
|
|
708
|
+
description: 'Link this opportunity to an existing CRM account (organization). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
displayName: 'Link to Contact Name or ID',
|
|
712
|
+
name: 'link_contact_id',
|
|
713
|
+
type: 'options',
|
|
714
|
+
typeOptions: { loadOptionsMethod: 'getContacts' },
|
|
715
|
+
default: '',
|
|
716
|
+
description: 'Link this opportunity to an existing CRM contact. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
717
|
+
},
|
|
627
718
|
{ displayName: 'Planned Close Date', name: 'deadline', type: 'dateTime', default: '' },
|
|
628
|
-
{
|
|
719
|
+
{
|
|
720
|
+
displayName: 'Source Name or ID',
|
|
721
|
+
name: 'source_id',
|
|
722
|
+
type: 'options',
|
|
723
|
+
typeOptions: { loadOptionsMethod: 'getOpportunitySources' },
|
|
724
|
+
default: '',
|
|
725
|
+
description: 'Where this opportunity came from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
726
|
+
},
|
|
629
727
|
{ displayName: 'Start Date', name: 'start_date', type: 'dateTime', default: '' },
|
|
630
728
|
],
|
|
631
729
|
},
|
|
@@ -655,9 +753,22 @@ class Flowlu {
|
|
|
655
753
|
default: {},
|
|
656
754
|
displayOptions: { show: { resource: ['opportunity'], operation: ['update'] } },
|
|
657
755
|
options: [
|
|
658
|
-
{
|
|
756
|
+
{
|
|
757
|
+
displayName: 'Assignee Name or ID',
|
|
758
|
+
name: 'assignee_id',
|
|
759
|
+
type: 'options',
|
|
760
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
761
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
762
|
+
default: '',
|
|
763
|
+
},
|
|
659
764
|
{ displayName: 'Budget', name: 'budget', type: 'number', default: 0 },
|
|
660
|
-
{
|
|
765
|
+
{
|
|
766
|
+
displayName: 'Closing Comment',
|
|
767
|
+
name: 'closing_comment',
|
|
768
|
+
type: 'string',
|
|
769
|
+
default: '',
|
|
770
|
+
description: 'Reason for win/loss',
|
|
771
|
+
},
|
|
661
772
|
{ displayName: 'Contact Email', name: 'contact_email', type: 'string', default: '' },
|
|
662
773
|
{ displayName: 'Contact Name', name: 'contact_name', type: 'string', default: '' },
|
|
663
774
|
{ displayName: 'Contact Phone', name: 'contact_phone', type: 'string', default: '' },
|
|
@@ -669,11 +780,39 @@ class Flowlu {
|
|
|
669
780
|
default: false,
|
|
670
781
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the opportunity description, linking back to this workflow. Requires Description to be set.',
|
|
671
782
|
},
|
|
672
|
-
{
|
|
673
|
-
|
|
783
|
+
{
|
|
784
|
+
displayName: 'Link to Account Name or ID',
|
|
785
|
+
name: 'link_account_id',
|
|
786
|
+
type: 'options',
|
|
787
|
+
typeOptions: { loadOptionsMethod: 'getAccounts' },
|
|
788
|
+
default: '',
|
|
789
|
+
description: 'Link this opportunity to a CRM account. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
displayName: 'Link to Contact Name or ID',
|
|
793
|
+
name: 'link_contact_id',
|
|
794
|
+
type: 'options',
|
|
795
|
+
typeOptions: { loadOptionsMethod: 'getContacts' },
|
|
796
|
+
default: '',
|
|
797
|
+
description: 'Link this opportunity to a CRM contact. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
798
|
+
},
|
|
674
799
|
{ displayName: 'Name', name: 'name', type: 'string', default: '' },
|
|
675
|
-
{
|
|
676
|
-
|
|
800
|
+
{
|
|
801
|
+
displayName: 'Pipeline Name or ID',
|
|
802
|
+
name: 'pipeline_id',
|
|
803
|
+
type: 'options',
|
|
804
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
805
|
+
typeOptions: { loadOptionsMethod: 'getPipelines' },
|
|
806
|
+
default: '',
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
displayName: 'Pipeline Stage Name or ID',
|
|
810
|
+
name: 'pipeline_stage_id',
|
|
811
|
+
type: 'options',
|
|
812
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
813
|
+
typeOptions: { loadOptionsMethod: 'getPipelineStages' },
|
|
814
|
+
default: '',
|
|
815
|
+
},
|
|
677
816
|
{ displayName: 'Planned Close Date', name: 'deadline', type: 'dateTime', default: '' },
|
|
678
817
|
{ displayName: 'Start Date', name: 'start_date', type: 'dateTime', default: '' },
|
|
679
818
|
{
|
|
@@ -748,8 +887,22 @@ class Flowlu {
|
|
|
748
887
|
displayOptions: { show: { resource: ['opportunity'], operation: ['getAll'] } },
|
|
749
888
|
options: [
|
|
750
889
|
{ displayName: 'Name', name: 'name', type: 'string', default: '', description: 'Filter by opportunity name' },
|
|
751
|
-
{
|
|
752
|
-
|
|
890
|
+
{
|
|
891
|
+
displayName: 'Assignee Name or ID',
|
|
892
|
+
name: 'assignee_id',
|
|
893
|
+
type: 'options',
|
|
894
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
895
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
896
|
+
default: '',
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
displayName: 'Account / Contact Name or ID',
|
|
900
|
+
name: 'company_id',
|
|
901
|
+
type: 'options',
|
|
902
|
+
typeOptions: { loadOptionsMethod: 'getAllCrmAccounts' },
|
|
903
|
+
default: '',
|
|
904
|
+
description: 'Filter by linked company or contact (note: Flowlu may not support this filter). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
905
|
+
},
|
|
753
906
|
{
|
|
754
907
|
displayName: 'Status',
|
|
755
908
|
name: 'active',
|
|
@@ -823,8 +976,22 @@ class Flowlu {
|
|
|
823
976
|
default: 0,
|
|
824
977
|
},
|
|
825
978
|
{ displayName: 'Contract Sum (Revenue)', name: 'estimated_revenue', type: 'number', default: 0 },
|
|
826
|
-
{
|
|
827
|
-
|
|
979
|
+
{
|
|
980
|
+
displayName: 'Customer (Company ID) Name or ID',
|
|
981
|
+
name: 'customer_id',
|
|
982
|
+
type: 'options',
|
|
983
|
+
typeOptions: { loadOptionsMethod: 'getContacts' },
|
|
984
|
+
default: '',
|
|
985
|
+
description: 'CRM company linked to this project. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
displayName: 'Customer Contact Name or ID',
|
|
989
|
+
name: 'customer_crm_contact_id',
|
|
990
|
+
type: 'options',
|
|
991
|
+
typeOptions: { loadOptionsMethod: 'getContacts' },
|
|
992
|
+
default: '',
|
|
993
|
+
description: 'CRM contact linked to this project. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
994
|
+
},
|
|
828
995
|
{ displayName: 'End Date', name: 'enddate', type: 'dateTime', default: '' },
|
|
829
996
|
{ displayName: 'Expense Sum', name: 'estimated_expenses', type: 'number', default: 0 },
|
|
830
997
|
{
|
|
@@ -834,8 +1001,21 @@ class Flowlu {
|
|
|
834
1001
|
default: false,
|
|
835
1002
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the project description, linking back to this workflow',
|
|
836
1003
|
},
|
|
837
|
-
{
|
|
838
|
-
|
|
1004
|
+
{
|
|
1005
|
+
displayName: 'Opportunity',
|
|
1006
|
+
name: 'crm_lead_id',
|
|
1007
|
+
type: 'number',
|
|
1008
|
+
default: 0,
|
|
1009
|
+
description: 'ID of a linked CRM opportunity',
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
displayName: 'Portfolio Name or ID',
|
|
1013
|
+
name: 'briefcase_id',
|
|
1014
|
+
type: 'options',
|
|
1015
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1016
|
+
typeOptions: { loadOptionsMethod: 'getPortfolios' },
|
|
1017
|
+
default: '',
|
|
1018
|
+
},
|
|
839
1019
|
{
|
|
840
1020
|
displayName: 'Priority',
|
|
841
1021
|
name: 'priority',
|
|
@@ -847,9 +1027,23 @@ class Flowlu {
|
|
|
847
1027
|
],
|
|
848
1028
|
default: 2,
|
|
849
1029
|
},
|
|
850
|
-
{
|
|
1030
|
+
{
|
|
1031
|
+
displayName: 'Project Stage Name or ID',
|
|
1032
|
+
name: 'stage_id',
|
|
1033
|
+
type: 'options',
|
|
1034
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1035
|
+
typeOptions: { loadOptionsMethod: 'getProjectStages' },
|
|
1036
|
+
default: '',
|
|
1037
|
+
},
|
|
851
1038
|
{ displayName: 'Start Date', name: 'startdate', type: 'dateTime', default: '' },
|
|
852
|
-
{
|
|
1039
|
+
{
|
|
1040
|
+
displayName: 'Task Workflow Name or ID',
|
|
1041
|
+
name: 'tasks_workflow_id',
|
|
1042
|
+
type: 'options',
|
|
1043
|
+
typeOptions: { loadOptionsMethod: 'getTaskWorkflows' },
|
|
1044
|
+
default: '',
|
|
1045
|
+
description: 'Default task workflow for tasks in this project. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1046
|
+
},
|
|
853
1047
|
],
|
|
854
1048
|
},
|
|
855
1049
|
{
|
|
@@ -895,7 +1089,14 @@ class Flowlu {
|
|
|
895
1089
|
default: false,
|
|
896
1090
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the project description, linking back to this workflow. Requires Description to be set.',
|
|
897
1091
|
},
|
|
898
|
-
{
|
|
1092
|
+
{
|
|
1093
|
+
displayName: 'Manager Name or ID',
|
|
1094
|
+
name: 'manager_id',
|
|
1095
|
+
type: 'options',
|
|
1096
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1097
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1098
|
+
default: '',
|
|
1099
|
+
},
|
|
899
1100
|
{
|
|
900
1101
|
displayName: 'Priority',
|
|
901
1102
|
name: 'priority',
|
|
@@ -908,7 +1109,14 @@ class Flowlu {
|
|
|
908
1109
|
default: 2,
|
|
909
1110
|
},
|
|
910
1111
|
{ displayName: 'Project Name', name: 'name', type: 'string', default: '' },
|
|
911
|
-
{
|
|
1112
|
+
{
|
|
1113
|
+
displayName: 'Project Stage Name or ID',
|
|
1114
|
+
name: 'stage_id',
|
|
1115
|
+
type: 'options',
|
|
1116
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1117
|
+
typeOptions: { loadOptionsMethod: 'getProjectStages' },
|
|
1118
|
+
default: '',
|
|
1119
|
+
},
|
|
912
1120
|
{ displayName: 'Start Date', name: 'startdate', type: 'dateTime', default: '' },
|
|
913
1121
|
],
|
|
914
1122
|
},
|
|
@@ -950,8 +1158,22 @@ class Flowlu {
|
|
|
950
1158
|
displayOptions: { show: { resource: ['project'], operation: ['getAll'] } },
|
|
951
1159
|
options: [
|
|
952
1160
|
{ displayName: 'Name', name: 'name', type: 'string', default: '', description: 'Filter by project name' },
|
|
953
|
-
{
|
|
954
|
-
|
|
1161
|
+
{
|
|
1162
|
+
displayName: 'Manager Name or ID',
|
|
1163
|
+
name: 'manager_id',
|
|
1164
|
+
type: 'options',
|
|
1165
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1166
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1167
|
+
default: '',
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
displayName: 'Customer Name or ID',
|
|
1171
|
+
name: 'customer_id',
|
|
1172
|
+
type: 'options',
|
|
1173
|
+
typeOptions: { loadOptionsMethod: 'getAccounts' },
|
|
1174
|
+
default: '',
|
|
1175
|
+
description: 'Filter by linked company. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1176
|
+
},
|
|
955
1177
|
{
|
|
956
1178
|
displayName: 'Include Archived',
|
|
957
1179
|
name: 'is_archive',
|
|
@@ -1046,7 +1268,13 @@ class Flowlu {
|
|
|
1046
1268
|
default: {},
|
|
1047
1269
|
displayOptions: { show: { resource: ['recordList'], operation: ['getAll'] } },
|
|
1048
1270
|
options: [
|
|
1049
|
-
{
|
|
1271
|
+
{
|
|
1272
|
+
displayName: 'Search',
|
|
1273
|
+
name: 'search',
|
|
1274
|
+
type: 'string',
|
|
1275
|
+
default: '',
|
|
1276
|
+
description: 'Search records by name/content',
|
|
1277
|
+
},
|
|
1050
1278
|
],
|
|
1051
1279
|
},
|
|
1052
1280
|
// ========================================
|
|
@@ -1088,6 +1316,59 @@ class Flowlu {
|
|
|
1088
1316
|
default: '',
|
|
1089
1317
|
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1090
1318
|
},
|
|
1319
|
+
{
|
|
1320
|
+
displayName: 'Owner Name or ID',
|
|
1321
|
+
name: 'owner_id',
|
|
1322
|
+
type: 'options',
|
|
1323
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1324
|
+
default: '',
|
|
1325
|
+
description: 'The user who owns this task. If left blank, the credential\'s Default Task Owner is used. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1326
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
displayName: 'Priority',
|
|
1330
|
+
name: 'priority',
|
|
1331
|
+
type: 'options',
|
|
1332
|
+
options: [
|
|
1333
|
+
{ name: 'Low', value: 1 },
|
|
1334
|
+
{ name: 'Medium', value: 2 },
|
|
1335
|
+
{ name: 'High', value: 3 },
|
|
1336
|
+
],
|
|
1337
|
+
default: 2,
|
|
1338
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
displayName: 'Contact Name or ID',
|
|
1342
|
+
name: 'contact_id',
|
|
1343
|
+
type: 'options',
|
|
1344
|
+
typeOptions: { loadOptionsMethod: 'getContacts' },
|
|
1345
|
+
default: '',
|
|
1346
|
+
description: 'The contact this task is related to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1347
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
displayName: 'Project Name or ID',
|
|
1351
|
+
name: 'model_id',
|
|
1352
|
+
type: 'options',
|
|
1353
|
+
typeOptions: { loadOptionsMethod: 'getProjects' },
|
|
1354
|
+
default: '',
|
|
1355
|
+
description: 'The project this task belongs to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1356
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
displayName: 'Start Date',
|
|
1360
|
+
name: 'plan_start_date',
|
|
1361
|
+
type: 'dateTime',
|
|
1362
|
+
default: '',
|
|
1363
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
displayName: 'End Date',
|
|
1367
|
+
name: 'deadline',
|
|
1368
|
+
type: 'dateTime',
|
|
1369
|
+
default: '',
|
|
1370
|
+
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1371
|
+
},
|
|
1091
1372
|
// Task Create: Additional Fields
|
|
1092
1373
|
{
|
|
1093
1374
|
displayName: 'Additional Fields',
|
|
@@ -1098,8 +1379,6 @@ class Flowlu {
|
|
|
1098
1379
|
displayOptions: { show: { resource: ['task'], operation: ['create'] } },
|
|
1099
1380
|
options: [
|
|
1100
1381
|
{ displayName: 'Allow End Date Change', name: 'deadline_allowchange', type: 'boolean', default: true },
|
|
1101
|
-
{ displayName: 'Contact Name or ID', name: 'contact_id', type: 'options', typeOptions: { loadOptionsMethod: 'getContacts' }, default: '', description: 'The contact this task is related to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.' },
|
|
1102
|
-
{ displayName: 'End Date', name: 'deadline', type: 'dateTime', default: '' },
|
|
1103
1382
|
{
|
|
1104
1383
|
displayName: 'Include Link to Workflow',
|
|
1105
1384
|
name: 'includeLinkToWorkflow',
|
|
@@ -1107,24 +1386,16 @@ class Flowlu {
|
|
|
1107
1386
|
default: false,
|
|
1108
1387
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the task description, linking back to this workflow',
|
|
1109
1388
|
},
|
|
1110
|
-
{ displayName: 'Owner Name or ID', name: 'owner_id', type: 'options', typeOptions: { loadOptionsMethod: 'getUsers' }, description: 'The user who owns/created this task. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.', default: '' },
|
|
1111
|
-
{ displayName: 'Parent Task ID', name: 'parent_id', type: 'number', default: 0, description: 'ID of the parent task (for subtasks)' },
|
|
1112
|
-
{ displayName: 'Planned Cost', name: 'cost', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
1113
|
-
{ displayName: 'Planned Income', name: 'price', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
1114
1389
|
{
|
|
1115
|
-
displayName: '
|
|
1116
|
-
name: '
|
|
1117
|
-
type: '
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
{ name: 'Medium', value: 2 },
|
|
1121
|
-
{ name: 'High', value: 3 },
|
|
1122
|
-
],
|
|
1123
|
-
default: 2,
|
|
1390
|
+
displayName: 'Parent Task ID',
|
|
1391
|
+
name: 'parent_id',
|
|
1392
|
+
type: 'number',
|
|
1393
|
+
default: 0,
|
|
1394
|
+
description: 'ID of the parent task (for subtasks)',
|
|
1124
1395
|
},
|
|
1125
|
-
{ displayName: '
|
|
1396
|
+
{ displayName: 'Planned Cost', name: 'cost', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
1397
|
+
{ displayName: 'Planned Income', name: 'price', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
1126
1398
|
{ displayName: 'Reviewed by Owner', name: 'task_checkbyowner', type: 'boolean', default: false },
|
|
1127
|
-
{ displayName: 'Start Date', name: 'plan_start_date', type: 'dateTime', default: '' },
|
|
1128
1399
|
{
|
|
1129
1400
|
displayName: 'Status',
|
|
1130
1401
|
name: 'status',
|
|
@@ -1137,9 +1408,29 @@ class Flowlu {
|
|
|
1137
1408
|
],
|
|
1138
1409
|
default: 1,
|
|
1139
1410
|
},
|
|
1140
|
-
{
|
|
1141
|
-
|
|
1142
|
-
|
|
1411
|
+
{
|
|
1412
|
+
displayName: 'Time Estimate (Minutes)',
|
|
1413
|
+
name: 'time_estimate',
|
|
1414
|
+
type: 'number',
|
|
1415
|
+
default: 0,
|
|
1416
|
+
typeOptions: { minValue: 0 },
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
displayName: 'Workflow Name or ID',
|
|
1420
|
+
name: 'workflow_id',
|
|
1421
|
+
type: 'options',
|
|
1422
|
+
typeOptions: { loadOptionsMethod: 'getTaskWorkflows' },
|
|
1423
|
+
default: '',
|
|
1424
|
+
description: 'The task workflow to use (defaults to the first workflow if not set). Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
displayName: 'Workflow Stage Name or ID',
|
|
1428
|
+
name: 'workflow_stage_id',
|
|
1429
|
+
type: 'options',
|
|
1430
|
+
typeOptions: { loadOptionsMethod: 'getTaskWorkflowStages' },
|
|
1431
|
+
default: '',
|
|
1432
|
+
description: 'The starting stage within the workflow. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
|
|
1433
|
+
},
|
|
1143
1434
|
],
|
|
1144
1435
|
},
|
|
1145
1436
|
{
|
|
@@ -1168,7 +1459,14 @@ class Flowlu {
|
|
|
1168
1459
|
default: {},
|
|
1169
1460
|
displayOptions: { show: { resource: ['task'], operation: ['update'] } },
|
|
1170
1461
|
options: [
|
|
1171
|
-
{
|
|
1462
|
+
{
|
|
1463
|
+
displayName: 'Assignee Name or ID',
|
|
1464
|
+
name: 'responsible_id',
|
|
1465
|
+
type: 'options',
|
|
1466
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1467
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1468
|
+
default: '',
|
|
1469
|
+
},
|
|
1172
1470
|
{ displayName: 'Description', name: 'description', type: 'string', typeOptions: { rows: 4 }, default: '' },
|
|
1173
1471
|
{ displayName: 'End Date', name: 'deadline', type: 'dateTime', default: '' },
|
|
1174
1472
|
{
|
|
@@ -1178,7 +1476,14 @@ class Flowlu {
|
|
|
1178
1476
|
default: false,
|
|
1179
1477
|
description: 'Whether to append a "Generated via n8n: View Workflow" footer to the task description, linking back to this workflow. Requires Description to be set.',
|
|
1180
1478
|
},
|
|
1181
|
-
{
|
|
1479
|
+
{
|
|
1480
|
+
displayName: 'Owner Name or ID',
|
|
1481
|
+
name: 'owner_id',
|
|
1482
|
+
type: 'options',
|
|
1483
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1484
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1485
|
+
default: '',
|
|
1486
|
+
},
|
|
1182
1487
|
{ displayName: 'Parent Task ID', name: 'parent_id', type: 'number', default: 0 },
|
|
1183
1488
|
{ displayName: 'Planned Cost', name: 'cost', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
1184
1489
|
{ displayName: 'Planned Income', name: 'price', type: 'number', default: 0, typeOptions: { minValue: 0 } },
|
|
@@ -1193,7 +1498,14 @@ class Flowlu {
|
|
|
1193
1498
|
],
|
|
1194
1499
|
default: 2,
|
|
1195
1500
|
},
|
|
1196
|
-
{
|
|
1501
|
+
{
|
|
1502
|
+
displayName: 'Project Name or ID',
|
|
1503
|
+
name: 'model_id',
|
|
1504
|
+
type: 'options',
|
|
1505
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1506
|
+
typeOptions: { loadOptionsMethod: 'getProjects' },
|
|
1507
|
+
default: '',
|
|
1508
|
+
},
|
|
1197
1509
|
{ displayName: 'Start Date', name: 'plan_start_date', type: 'dateTime', default: '' },
|
|
1198
1510
|
{
|
|
1199
1511
|
displayName: 'Status',
|
|
@@ -1208,9 +1520,29 @@ class Flowlu {
|
|
|
1208
1520
|
default: 1,
|
|
1209
1521
|
},
|
|
1210
1522
|
{ displayName: 'Task Name', name: 'name', type: 'string', default: '' },
|
|
1211
|
-
{
|
|
1212
|
-
|
|
1213
|
-
|
|
1523
|
+
{
|
|
1524
|
+
displayName: 'Time Estimate (Minutes)',
|
|
1525
|
+
name: 'time_estimate',
|
|
1526
|
+
type: 'number',
|
|
1527
|
+
default: 0,
|
|
1528
|
+
typeOptions: { minValue: 0 },
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
displayName: 'Workflow Name or ID',
|
|
1532
|
+
name: 'workflow_id',
|
|
1533
|
+
type: 'options',
|
|
1534
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1535
|
+
typeOptions: { loadOptionsMethod: 'getTaskWorkflows' },
|
|
1536
|
+
default: '',
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
displayName: 'Workflow Stage Name or ID',
|
|
1540
|
+
name: 'workflow_stage_id',
|
|
1541
|
+
type: 'options',
|
|
1542
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1543
|
+
typeOptions: { loadOptionsMethod: 'getTaskWorkflowStages' },
|
|
1544
|
+
default: '',
|
|
1545
|
+
},
|
|
1214
1546
|
],
|
|
1215
1547
|
},
|
|
1216
1548
|
{
|
|
@@ -1250,7 +1582,14 @@ class Flowlu {
|
|
|
1250
1582
|
default: {},
|
|
1251
1583
|
displayOptions: { show: { resource: ['task'], operation: ['getAll'] } },
|
|
1252
1584
|
options: [
|
|
1253
|
-
{
|
|
1585
|
+
{
|
|
1586
|
+
displayName: 'Assignee Name or ID',
|
|
1587
|
+
name: 'responsible_id',
|
|
1588
|
+
type: 'options',
|
|
1589
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1590
|
+
typeOptions: { loadOptionsMethod: 'getUsers' },
|
|
1591
|
+
default: '',
|
|
1592
|
+
},
|
|
1254
1593
|
{ displayName: 'Name', name: 'name', type: 'string', default: '', description: 'Filter by task name' },
|
|
1255
1594
|
{
|
|
1256
1595
|
displayName: 'Priority',
|
|
@@ -1263,7 +1602,14 @@ class Flowlu {
|
|
|
1263
1602
|
],
|
|
1264
1603
|
default: 2,
|
|
1265
1604
|
},
|
|
1266
|
-
{
|
|
1605
|
+
{
|
|
1606
|
+
displayName: 'Project Name or ID',
|
|
1607
|
+
name: 'model_id',
|
|
1608
|
+
type: 'options',
|
|
1609
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1610
|
+
typeOptions: { loadOptionsMethod: 'getProjects' },
|
|
1611
|
+
default: '',
|
|
1612
|
+
},
|
|
1267
1613
|
{
|
|
1268
1614
|
displayName: 'Status',
|
|
1269
1615
|
name: 'status',
|
|
@@ -1384,274 +1730,195 @@ class Flowlu {
|
|
|
1384
1730
|
this.methods = {
|
|
1385
1731
|
loadOptions: {
|
|
1386
1732
|
async getUsers() {
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
}
|
|
1395
|
-
catch (error) {
|
|
1396
|
-
return [];
|
|
1397
|
-
}
|
|
1733
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1734
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/core/user/list', apiKey, {
|
|
1735
|
+
'filter[role_login]': '1',
|
|
1736
|
+
});
|
|
1737
|
+
return items.map((user) => ({
|
|
1738
|
+
name: user.name || user.email || `User ${user.id}`,
|
|
1739
|
+
value: user.id.toString(),
|
|
1740
|
+
}));
|
|
1398
1741
|
},
|
|
1399
1742
|
async getAccounts() {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
}
|
|
1408
|
-
catch (error) {
|
|
1409
|
-
return [];
|
|
1410
|
-
}
|
|
1743
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1744
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/account/list', apiKey, {
|
|
1745
|
+
'filter[type]': '1',
|
|
1746
|
+
});
|
|
1747
|
+
return items.map((a) => ({
|
|
1748
|
+
name: a.name || `Account ${a.id}`,
|
|
1749
|
+
value: a.id.toString(),
|
|
1750
|
+
}));
|
|
1411
1751
|
},
|
|
1412
1752
|
async getContacts() {
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
}
|
|
1421
|
-
catch (error) {
|
|
1422
|
-
return [];
|
|
1423
|
-
}
|
|
1753
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1754
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/account/list', apiKey, {
|
|
1755
|
+
'filter[type]': '2',
|
|
1756
|
+
});
|
|
1757
|
+
return items.map((c) => ({
|
|
1758
|
+
name: c.name || `Contact ${c.id}`,
|
|
1759
|
+
value: c.id.toString(),
|
|
1760
|
+
}));
|
|
1424
1761
|
},
|
|
1425
1762
|
async getProjects() {
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
}
|
|
1434
|
-
catch (error) {
|
|
1435
|
-
return [];
|
|
1436
|
-
}
|
|
1763
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1764
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/st/projects/list', apiKey, {
|
|
1765
|
+
'filter[is_archive]': '0',
|
|
1766
|
+
});
|
|
1767
|
+
return items.map((p) => ({
|
|
1768
|
+
name: p.name || `Project ${p.id}`,
|
|
1769
|
+
value: p.id.toString(),
|
|
1770
|
+
}));
|
|
1437
1771
|
},
|
|
1438
1772
|
async getTaskWorkflows() {
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
return [];
|
|
1446
|
-
}
|
|
1447
|
-
catch (error) {
|
|
1448
|
-
return [];
|
|
1449
|
-
}
|
|
1773
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1774
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/task/workflows/list', apiKey);
|
|
1775
|
+
return items.map((wf) => ({
|
|
1776
|
+
name: wf.name || `Workflow ${wf.id}`,
|
|
1777
|
+
value: wf.id.toString(),
|
|
1778
|
+
}));
|
|
1450
1779
|
},
|
|
1451
1780
|
async getTaskWorkflowStages() {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
}
|
|
1460
|
-
catch (error) {
|
|
1461
|
-
return [];
|
|
1462
|
-
}
|
|
1781
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1782
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/task/stages/list', apiKey);
|
|
1783
|
+
return items.map((s) => ({
|
|
1784
|
+
name: s.name || `Stage ${s.id}`,
|
|
1785
|
+
value: s.id.toString(),
|
|
1786
|
+
description: `Workflow ID: ${s.workflow_id}`,
|
|
1787
|
+
}));
|
|
1463
1788
|
},
|
|
1464
1789
|
async getPipelines() {
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
return [];
|
|
1472
|
-
}
|
|
1473
|
-
catch (error) {
|
|
1474
|
-
return [];
|
|
1475
|
-
}
|
|
1790
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1791
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/pipeline/list', apiKey);
|
|
1792
|
+
return items.map((p) => ({
|
|
1793
|
+
name: p.name || `Pipeline ${p.id}`,
|
|
1794
|
+
value: p.id.toString(),
|
|
1795
|
+
}));
|
|
1476
1796
|
},
|
|
1477
1797
|
async getPipelineStages() {
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
}
|
|
1486
|
-
catch (error) {
|
|
1487
|
-
return [];
|
|
1488
|
-
}
|
|
1798
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1799
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/pipeline_stage/list', apiKey);
|
|
1800
|
+
return items.map((s) => ({
|
|
1801
|
+
name: s.name || `Stage ${s.id}`,
|
|
1802
|
+
value: s.id.toString(),
|
|
1803
|
+
description: `Pipeline ID: ${s.pipeline_id}`,
|
|
1804
|
+
}));
|
|
1489
1805
|
},
|
|
1490
1806
|
async getFilteredPipelineStages() {
|
|
1807
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1808
|
+
let pipelineId;
|
|
1491
1809
|
try {
|
|
1492
|
-
|
|
1493
|
-
let pipelineId;
|
|
1494
|
-
try {
|
|
1495
|
-
pipelineId = this.getNodeParameter('opportunityFilterPipeline');
|
|
1496
|
-
}
|
|
1497
|
-
catch { /* not set yet */ }
|
|
1498
|
-
const response = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/crm/pipeline_stage/list', apiKey);
|
|
1499
|
-
if (response?.response?.items) {
|
|
1500
|
-
let stages = response.response.items;
|
|
1501
|
-
if (pipelineId) {
|
|
1502
|
-
stages = stages.filter((s) => s.pipeline_id?.toString() === pipelineId);
|
|
1503
|
-
}
|
|
1504
|
-
return stages.map((s) => ({ name: s.name || `Stage ${s.id}`, value: s.id.toString() }));
|
|
1505
|
-
}
|
|
1506
|
-
return [];
|
|
1810
|
+
pipelineId = this.getNodeParameter('opportunityFilterPipeline');
|
|
1507
1811
|
}
|
|
1508
|
-
catch
|
|
1509
|
-
|
|
1812
|
+
catch {
|
|
1813
|
+
/* not set yet */
|
|
1510
1814
|
}
|
|
1815
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/pipeline_stage/list', apiKey);
|
|
1816
|
+
const stages = pipelineId
|
|
1817
|
+
? items.filter((s) => s.pipeline_id?.toString() === pipelineId)
|
|
1818
|
+
: items;
|
|
1819
|
+
return stages.map((s) => ({ name: s.name || `Stage ${s.id}`, value: s.id.toString() }));
|
|
1511
1820
|
},
|
|
1512
1821
|
async getAllCrmAccounts() {
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
return { name: `${a.name || `#${a.id}`} ${typeLabel}`.trim(), value: a.id.toString() };
|
|
1520
|
-
});
|
|
1521
|
-
}
|
|
1522
|
-
return [];
|
|
1523
|
-
}
|
|
1524
|
-
catch (error) {
|
|
1525
|
-
return [];
|
|
1526
|
-
}
|
|
1822
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1823
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/account/list', apiKey);
|
|
1824
|
+
return items.map((a) => {
|
|
1825
|
+
const typeLabel = a.type === 1 ? '(Company)' : a.type === 2 ? '(Contact)' : '';
|
|
1826
|
+
return { name: `${a.name || `#${a.id}`} ${typeLabel}`.trim(), value: a.id.toString() };
|
|
1827
|
+
});
|
|
1527
1828
|
},
|
|
1528
1829
|
async getOpportunitySources() {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
return [];
|
|
1536
|
-
}
|
|
1537
|
-
catch (error) {
|
|
1538
|
-
return [];
|
|
1539
|
-
}
|
|
1830
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1831
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/crm/source/list', apiKey);
|
|
1832
|
+
return items.map((s) => ({
|
|
1833
|
+
name: s.name || `Source ${s.id}`,
|
|
1834
|
+
value: s.id.toString(),
|
|
1835
|
+
}));
|
|
1540
1836
|
},
|
|
1541
1837
|
async getPortfolios() {
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
return [];
|
|
1549
|
-
}
|
|
1550
|
-
catch (error) {
|
|
1551
|
-
return [];
|
|
1552
|
-
}
|
|
1838
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1839
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/st/portfolio/list', apiKey);
|
|
1840
|
+
return items.map((p) => ({
|
|
1841
|
+
name: p.name || `Portfolio ${p.id}`,
|
|
1842
|
+
value: p.id.toString(),
|
|
1843
|
+
}));
|
|
1553
1844
|
},
|
|
1554
1845
|
async getProjectStages() {
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
return [];
|
|
1562
|
-
}
|
|
1563
|
-
catch (error) {
|
|
1564
|
-
return [];
|
|
1565
|
-
}
|
|
1846
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1847
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/st/stages/list', apiKey);
|
|
1848
|
+
return items.map((s) => ({
|
|
1849
|
+
name: s.name || `Stage ${s.id}`,
|
|
1850
|
+
value: s.id.toString(),
|
|
1851
|
+
}));
|
|
1566
1852
|
},
|
|
1567
1853
|
async getRecordLists() {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
return [];
|
|
1575
|
-
}
|
|
1576
|
-
catch (error) {
|
|
1577
|
-
return [];
|
|
1578
|
-
}
|
|
1854
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1855
|
+
const items = await flowluListAll.call(this, baseUrl, '/api/v1/module/customlists/lists/list', apiKey);
|
|
1856
|
+
return items.map((l) => ({
|
|
1857
|
+
name: l.name || `List ${l.id}`,
|
|
1858
|
+
value: l.id.toString(),
|
|
1859
|
+
}));
|
|
1579
1860
|
},
|
|
1580
1861
|
async getRecordListFields() {
|
|
1862
|
+
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
1863
|
+
// Get the selected list ID from the current node parameters
|
|
1864
|
+
let listId;
|
|
1581
1865
|
try {
|
|
1582
|
-
|
|
1583
|
-
// Get the selected list ID from the current node parameters
|
|
1584
|
-
let listId;
|
|
1585
|
-
try {
|
|
1586
|
-
listId = this.getNodeParameter('recordListId');
|
|
1587
|
-
}
|
|
1588
|
-
catch {
|
|
1589
|
-
return [];
|
|
1590
|
-
}
|
|
1591
|
-
if (!listId)
|
|
1592
|
-
return [];
|
|
1593
|
-
// Find the fieldset for this list (customlists/items with group_id matching list_id)
|
|
1594
|
-
const fieldsetsResponse = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
1595
|
-
const fieldsetIds = [];
|
|
1596
|
-
if (fieldsetsResponse?.response?.items) {
|
|
1597
|
-
for (const fs of fieldsetsResponse.response.items) {
|
|
1598
|
-
if (fs.module === 'customlists' && fs.model === 'items' && fs.group_id?.toString() === listId) {
|
|
1599
|
-
fieldsetIds.push(fs.id.toString());
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
if (fieldsetIds.length === 0)
|
|
1604
|
-
return [];
|
|
1605
|
-
// Get fields for those fieldsets
|
|
1606
|
-
const fieldsResponse = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
1607
|
-
if (fieldsResponse?.response?.items) {
|
|
1608
|
-
// Also fetch all fieldsets so we can resolve custom list link names
|
|
1609
|
-
const allFieldsets = fieldsetsResponse?.response?.items || [];
|
|
1610
|
-
return fieldsResponse.response.items
|
|
1611
|
-
.filter((f) => fieldsetIds.includes(f.fieldset_id?.toString()))
|
|
1612
|
-
.filter((f) => f.active !== 0)
|
|
1613
|
-
.map((f) => {
|
|
1614
|
-
const cfKey = (f.api_use_alias && f.alias) ? `cf_${f.alias}` : `cf_${f.id}`;
|
|
1615
|
-
let label = f.name || cfKey;
|
|
1616
|
-
let desc = '';
|
|
1617
|
-
// Detect link fields (model.any) and show what they link to
|
|
1618
|
-
if (f.type === 'model.any' && f.module && f.model) {
|
|
1619
|
-
const linkTargetMap = {
|
|
1620
|
-
'st/project': 'Project',
|
|
1621
|
-
'crm/company': 'Company',
|
|
1622
|
-
'crm/contact': 'Contact',
|
|
1623
|
-
'crm/client': 'Account',
|
|
1624
|
-
'crm/leads': 'Opportunity',
|
|
1625
|
-
'system/user': 'User',
|
|
1626
|
-
};
|
|
1627
|
-
const key = `${f.module}/${f.model}`;
|
|
1628
|
-
if (linkTargetMap[key]) {
|
|
1629
|
-
label = `${f.name} → ${linkTargetMap[key]}`;
|
|
1630
|
-
desc = `Enter the ${linkTargetMap[key]} ID`;
|
|
1631
|
-
}
|
|
1632
|
-
else if (f.module === 'customlists' && f.model === 'items' && f.group_id) {
|
|
1633
|
-
// Link to another custom list - find its name
|
|
1634
|
-
const targetList = allFieldsets.find((fs) => fs.module === 'customlists' && fs.model === 'items' && fs.group_id?.toString() === f.group_id.toString());
|
|
1635
|
-
const listName = targetList?.name || `List #${f.group_id}`;
|
|
1636
|
-
label = `${f.name} → ${listName}`;
|
|
1637
|
-
desc = `Enter the Record ID from "${listName}"`;
|
|
1638
|
-
}
|
|
1639
|
-
else {
|
|
1640
|
-
label = `${f.name} → ${f.module}/${f.model}`;
|
|
1641
|
-
desc = `Enter the linked record ID`;
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
const option = { name: label, value: cfKey };
|
|
1645
|
-
if (desc)
|
|
1646
|
-
option.description = desc;
|
|
1647
|
-
return option;
|
|
1648
|
-
});
|
|
1649
|
-
}
|
|
1650
|
-
return [];
|
|
1866
|
+
listId = this.getNodeParameter('recordListId');
|
|
1651
1867
|
}
|
|
1652
|
-
catch
|
|
1868
|
+
catch {
|
|
1653
1869
|
return [];
|
|
1654
1870
|
}
|
|
1871
|
+
if (!listId)
|
|
1872
|
+
return [];
|
|
1873
|
+
// Find the fieldset for this list (customlists/items with group_id matching list_id)
|
|
1874
|
+
const allFieldsets = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
1875
|
+
const fieldsetIds = new Set(allFieldsets
|
|
1876
|
+
.filter((fs) => fs.module === 'customlists' && fs.model === 'items' && fs.group_id?.toString() === listId)
|
|
1877
|
+
.map((fs) => fs.id.toString()));
|
|
1878
|
+
if (fieldsetIds.size === 0)
|
|
1879
|
+
return [];
|
|
1880
|
+
const allFields = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
1881
|
+
return allFields
|
|
1882
|
+
.filter((f) => fieldsetIds.has(f.fieldset_id?.toString()))
|
|
1883
|
+
.filter((f) => f.active !== 0)
|
|
1884
|
+
.map((f) => {
|
|
1885
|
+
const cfKey = f.api_use_alias && f.alias ? `cf_${f.alias}` : `cf_${f.id}`;
|
|
1886
|
+
let label = f.name || cfKey;
|
|
1887
|
+
let desc = '';
|
|
1888
|
+
// Detect link fields (model.any) and show what they link to
|
|
1889
|
+
if (f.type === 'model.any' && f.module && f.model) {
|
|
1890
|
+
const linkTargetMap = {
|
|
1891
|
+
'st/project': 'Project',
|
|
1892
|
+
'crm/company': 'Company',
|
|
1893
|
+
'crm/contact': 'Contact',
|
|
1894
|
+
'crm/client': 'Account',
|
|
1895
|
+
'crm/leads': 'Opportunity',
|
|
1896
|
+
'system/user': 'User',
|
|
1897
|
+
};
|
|
1898
|
+
const key = `${f.module}/${f.model}`;
|
|
1899
|
+
if (linkTargetMap[key]) {
|
|
1900
|
+
label = `${f.name} → ${linkTargetMap[key]}`;
|
|
1901
|
+
desc = `Enter the ${linkTargetMap[key]} ID`;
|
|
1902
|
+
}
|
|
1903
|
+
else if (f.module === 'customlists' && f.model === 'items' && f.group_id) {
|
|
1904
|
+
// Link to another custom list - find its name
|
|
1905
|
+
const targetList = allFieldsets.find((fs) => fs.module === 'customlists' &&
|
|
1906
|
+
fs.model === 'items' &&
|
|
1907
|
+
fs.group_id?.toString() === f.group_id.toString());
|
|
1908
|
+
const listName = targetList?.name || `List #${f.group_id}`;
|
|
1909
|
+
label = `${f.name} → ${listName}`;
|
|
1910
|
+
desc = `Enter the Record ID from "${listName}"`;
|
|
1911
|
+
}
|
|
1912
|
+
else {
|
|
1913
|
+
label = `${f.name} → ${f.module}/${f.model}`;
|
|
1914
|
+
desc = `Enter the linked record ID`;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
const option = { name: label, value: cfKey };
|
|
1918
|
+
if (desc)
|
|
1919
|
+
option.description = desc;
|
|
1920
|
+
return option;
|
|
1921
|
+
});
|
|
1655
1922
|
},
|
|
1656
1923
|
async getTaskCustomFields() {
|
|
1657
1924
|
return loadCustomFieldsForEntity(this, 'task', 'task');
|
|
@@ -1692,8 +1959,7 @@ class Flowlu {
|
|
|
1692
1959
|
if (!listId)
|
|
1693
1960
|
return { fields: [] };
|
|
1694
1961
|
// Get fieldsets to find this list's fieldset
|
|
1695
|
-
const
|
|
1696
|
-
const allFieldsets = fieldsetsResponse?.response?.items || [];
|
|
1962
|
+
const allFieldsets = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fieldsets/list', apiKey);
|
|
1697
1963
|
const fieldsetIds = [];
|
|
1698
1964
|
for (const fs of allFieldsets) {
|
|
1699
1965
|
if (fs.module === 'customlists' && fs.model === 'items' && fs.group_id?.toString() === listId) {
|
|
@@ -1703,9 +1969,7 @@ class Flowlu {
|
|
|
1703
1969
|
if (fieldsetIds.length === 0)
|
|
1704
1970
|
return { fields: [] };
|
|
1705
1971
|
// Get all custom fields
|
|
1706
|
-
const
|
|
1707
|
-
if (!fieldsResponse?.response?.items)
|
|
1708
|
-
return { fields: [] };
|
|
1972
|
+
const allRecordFields = await flowluListAll.call(this, baseUrl, '/api/v1/module/customfields/fields/list', apiKey);
|
|
1709
1973
|
// Map of linked entity endpoints for fetching dropdown options
|
|
1710
1974
|
const linkEndpoints = {
|
|
1711
1975
|
'st/project': '/api/v1/module/st/projects/list',
|
|
@@ -1725,7 +1989,7 @@ class Flowlu {
|
|
|
1725
1989
|
};
|
|
1726
1990
|
// Pre-fetch linked record options for all link field types we encounter
|
|
1727
1991
|
const linkOptionsCache = {};
|
|
1728
|
-
const filteredFields =
|
|
1992
|
+
const filteredFields = allRecordFields
|
|
1729
1993
|
.filter((f) => fieldsetIds.includes(f.fieldset_id?.toString()))
|
|
1730
1994
|
.filter((f) => f.active !== 0);
|
|
1731
1995
|
for (const f of filteredFields) {
|
|
@@ -1742,8 +2006,8 @@ class Flowlu {
|
|
|
1742
2006
|
qs['filter[type]'] = '1';
|
|
1743
2007
|
if (key === 'system/user')
|
|
1744
2008
|
qs['filter[role_login]'] = '1';
|
|
1745
|
-
const
|
|
1746
|
-
linkOptionsCache[key] =
|
|
2009
|
+
const linked = await flowluListAll.call(this, baseUrl, linkEndpoints[key], apiKey, qs);
|
|
2010
|
+
linkOptionsCache[key] = linked.map((item) => ({
|
|
1747
2011
|
name: item.name || item.email || `#${item.id}`,
|
|
1748
2012
|
value: item.id,
|
|
1749
2013
|
}));
|
|
@@ -1757,13 +2021,11 @@ class Flowlu {
|
|
|
1757
2021
|
const clKey = `customlists/${f.group_id}`;
|
|
1758
2022
|
if (!linkOptionsCache[clKey]) {
|
|
1759
2023
|
try {
|
|
1760
|
-
const
|
|
1761
|
-
'filter[list_id]': f.group_id.toString(),
|
|
1762
|
-
});
|
|
2024
|
+
const linked = await flowluListAll.call(this, baseUrl, '/api/v1/module/customlists/items/list', apiKey, { 'filter[list_id]': f.group_id.toString() });
|
|
1763
2025
|
// Find the label field for this list
|
|
1764
2026
|
const labelFieldId = f.group_label_field_id;
|
|
1765
|
-
linkOptionsCache[clKey] =
|
|
1766
|
-
const label = labelFieldId ?
|
|
2027
|
+
linkOptionsCache[clKey] = linked.map((item) => {
|
|
2028
|
+
const label = labelFieldId ? item[`cf_${labelFieldId}`] || `#${item.id}` : `#${item.id}`;
|
|
1767
2029
|
return { name: label, value: item.id };
|
|
1768
2030
|
});
|
|
1769
2031
|
}
|
|
@@ -1775,7 +2037,7 @@ class Flowlu {
|
|
|
1775
2037
|
}
|
|
1776
2038
|
}
|
|
1777
2039
|
const fields = filteredFields.map((f) => {
|
|
1778
|
-
const cfKey =
|
|
2040
|
+
const cfKey = f.api_use_alias && f.alias ? `cf_${f.alias}` : `cf_${f.id}`;
|
|
1779
2041
|
let displayName = f.name || cfKey;
|
|
1780
2042
|
let fieldType = 'string';
|
|
1781
2043
|
let fieldOptions;
|
|
@@ -1797,7 +2059,9 @@ class Flowlu {
|
|
|
1797
2059
|
.filter((o) => o.value)
|
|
1798
2060
|
.map((o) => ({ name: o.value, value: o.id?.toString() || o.value }));
|
|
1799
2061
|
}
|
|
1800
|
-
catch {
|
|
2062
|
+
catch {
|
|
2063
|
+
/* ignore parse errors */
|
|
2064
|
+
}
|
|
1801
2065
|
}
|
|
1802
2066
|
// Link fields - use dropdown with fetched options
|
|
1803
2067
|
if (f.type === 'model.any' && f.module && f.model) {
|
|
@@ -1806,12 +2070,12 @@ class Flowlu {
|
|
|
1806
2070
|
displayName = `${f.name} → ${linkLabels[key]}`;
|
|
1807
2071
|
}
|
|
1808
2072
|
else if (f.module === 'customlists' && f.model === 'items' && f.group_id) {
|
|
1809
|
-
const targetList = allFieldsets.find((fs) => fs.module === 'customlists' &&
|
|
2073
|
+
const targetList = allFieldsets.find((fs) => fs.module === 'customlists' &&
|
|
2074
|
+
fs.model === 'items' &&
|
|
2075
|
+
fs.group_id?.toString() === f.group_id.toString());
|
|
1810
2076
|
displayName = `${f.name} → ${targetList?.name || `List #${f.group_id}`}`;
|
|
1811
2077
|
}
|
|
1812
|
-
const cacheKey =
|
|
1813
|
-
? `customlists/${f.group_id}`
|
|
1814
|
-
: key;
|
|
2078
|
+
const cacheKey = f.module === 'customlists' && f.model === 'items' && f.group_id ? `customlists/${f.group_id}` : key;
|
|
1815
2079
|
if (linkOptionsCache[cacheKey]?.length) {
|
|
1816
2080
|
fieldType = 'options';
|
|
1817
2081
|
fieldOptions = linkOptionsCache[cacheKey];
|
|
@@ -1836,7 +2100,9 @@ class Flowlu {
|
|
|
1836
2100
|
return { fields };
|
|
1837
2101
|
}
|
|
1838
2102
|
catch (error) {
|
|
1839
|
-
|
|
2103
|
+
if (error instanceof n8n_workflow_1.NodeOperationError)
|
|
2104
|
+
throw error;
|
|
2105
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not load Flowlu record-list fields: ${error.message}. If this is a rate limit, wait a moment and click Retry.`);
|
|
1840
2106
|
}
|
|
1841
2107
|
},
|
|
1842
2108
|
},
|
|
@@ -1849,7 +2115,7 @@ class Flowlu {
|
|
|
1849
2115
|
const operation = this.getNodeParameter('operation', 0);
|
|
1850
2116
|
for (let i = 0; i < items.length; i++) {
|
|
1851
2117
|
try {
|
|
1852
|
-
const { baseUrl, apiKey } = await getFlowluCredentials(this);
|
|
2118
|
+
const { baseUrl, apiKey, defaultOwnerId } = await getFlowluCredentials(this);
|
|
1853
2119
|
let responseData;
|
|
1854
2120
|
// ============================
|
|
1855
2121
|
// CONTACT
|
|
@@ -1869,15 +2135,32 @@ class Flowlu {
|
|
|
1869
2135
|
body.phone = phone;
|
|
1870
2136
|
const additional = this.getNodeParameter('contactAdditionalFields', i);
|
|
1871
2137
|
const contactSimpleFields = [
|
|
1872
|
-
'middle_name',
|
|
1873
|
-
'
|
|
1874
|
-
'
|
|
1875
|
-
'
|
|
1876
|
-
'
|
|
1877
|
-
'
|
|
1878
|
-
'
|
|
1879
|
-
'
|
|
1880
|
-
'
|
|
2138
|
+
'middle_name',
|
|
2139
|
+
'description',
|
|
2140
|
+
'owner_id',
|
|
2141
|
+
'web',
|
|
2142
|
+
'phone2',
|
|
2143
|
+
'phone3',
|
|
2144
|
+
'email_personal',
|
|
2145
|
+
'social_network_link_1',
|
|
2146
|
+
'social_network_link_2',
|
|
2147
|
+
'social_network_link_3',
|
|
2148
|
+
'social_network_link_4',
|
|
2149
|
+
'social_network_link_5',
|
|
2150
|
+
'social_network_link_6',
|
|
2151
|
+
'address',
|
|
2152
|
+
'shipping_address_line_1',
|
|
2153
|
+
'shipping_city',
|
|
2154
|
+
'shipping_state',
|
|
2155
|
+
'shipping_zip',
|
|
2156
|
+
'shipping_country',
|
|
2157
|
+
'billing_address_line_1',
|
|
2158
|
+
'billing_city',
|
|
2159
|
+
'billing_state',
|
|
2160
|
+
'billing_zip',
|
|
2161
|
+
'billing_country',
|
|
2162
|
+
'VAT',
|
|
2163
|
+
'timezone',
|
|
1881
2164
|
];
|
|
1882
2165
|
for (const field of contactSimpleFields) {
|
|
1883
2166
|
if (additional[field] !== undefined && additional[field] !== '') {
|
|
@@ -1910,7 +2193,7 @@ class Flowlu {
|
|
|
1910
2193
|
if (filters.owner_id)
|
|
1911
2194
|
qs['filter[owner_id]'] = filters.owner_id;
|
|
1912
2195
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/crm/account/list', apiKey, undefined, qs);
|
|
1913
|
-
for (const item of
|
|
2196
|
+
for (const item of responseData?.response?.items || []) {
|
|
1914
2197
|
returnData.push({ json: item });
|
|
1915
2198
|
}
|
|
1916
2199
|
continue;
|
|
@@ -1920,13 +2203,25 @@ class Flowlu {
|
|
|
1920
2203
|
const updateFields = this.getNodeParameter('contactUpdateFields', i);
|
|
1921
2204
|
const body = { id };
|
|
1922
2205
|
const contactUpdateSimpleFields = [
|
|
1923
|
-
'first_name',
|
|
1924
|
-
'
|
|
2206
|
+
'first_name',
|
|
2207
|
+
'last_name',
|
|
2208
|
+
'middle_name',
|
|
2209
|
+
'email',
|
|
2210
|
+
'phone',
|
|
2211
|
+
'phone2',
|
|
2212
|
+
'phone3',
|
|
2213
|
+
'description',
|
|
2214
|
+
'owner_id',
|
|
2215
|
+
'web',
|
|
1925
2216
|
'email_personal',
|
|
1926
|
-
'social_network_link_1',
|
|
1927
|
-
'
|
|
1928
|
-
'
|
|
1929
|
-
'
|
|
2217
|
+
'social_network_link_1',
|
|
2218
|
+
'social_network_link_2',
|
|
2219
|
+
'social_network_link_3',
|
|
2220
|
+
'social_network_link_4',
|
|
2221
|
+
'social_network_link_5',
|
|
2222
|
+
'social_network_link_6',
|
|
2223
|
+
'address',
|
|
2224
|
+
'VAT',
|
|
1930
2225
|
];
|
|
1931
2226
|
for (const field of contactUpdateSimpleFields) {
|
|
1932
2227
|
if (updateFields[field] !== undefined && updateFields[field] !== '') {
|
|
@@ -1962,9 +2257,16 @@ class Flowlu {
|
|
|
1962
2257
|
body.assignee_id = assignee;
|
|
1963
2258
|
const additional = this.getNodeParameter('opportunityAdditionalFields', i);
|
|
1964
2259
|
const oppSimpleFields = [
|
|
1965
|
-
'budget',
|
|
1966
|
-
'
|
|
1967
|
-
'
|
|
2260
|
+
'budget',
|
|
2261
|
+
'description',
|
|
2262
|
+
'contact_name',
|
|
2263
|
+
'contact_email',
|
|
2264
|
+
'contact_phone',
|
|
2265
|
+
'contact_mobile',
|
|
2266
|
+
'contact_company',
|
|
2267
|
+
'contact_position',
|
|
2268
|
+
'contact_web',
|
|
2269
|
+
'source_id',
|
|
1968
2270
|
];
|
|
1969
2271
|
for (const field of oppSimpleFields) {
|
|
1970
2272
|
if (additional[field] !== undefined && additional[field] !== '') {
|
|
@@ -2022,7 +2324,7 @@ class Flowlu {
|
|
|
2022
2324
|
if (filters.active !== undefined)
|
|
2023
2325
|
qs['filter[active]'] = filters.active.toString();
|
|
2024
2326
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/crm/lead/list', apiKey, undefined, qs);
|
|
2025
|
-
for (const item of
|
|
2327
|
+
for (const item of responseData?.response?.items || []) {
|
|
2026
2328
|
returnData.push({ json: item });
|
|
2027
2329
|
}
|
|
2028
2330
|
continue;
|
|
@@ -2032,9 +2334,17 @@ class Flowlu {
|
|
|
2032
2334
|
const updateFields = this.getNodeParameter('opportunityUpdateFields', i);
|
|
2033
2335
|
const body = { id };
|
|
2034
2336
|
const oppUpdateFields = [
|
|
2035
|
-
'name',
|
|
2036
|
-
'
|
|
2037
|
-
'
|
|
2337
|
+
'name',
|
|
2338
|
+
'pipeline_id',
|
|
2339
|
+
'pipeline_stage_id',
|
|
2340
|
+
'assignee_id',
|
|
2341
|
+
'budget',
|
|
2342
|
+
'description',
|
|
2343
|
+
'active',
|
|
2344
|
+
'closing_comment',
|
|
2345
|
+
'contact_name',
|
|
2346
|
+
'contact_email',
|
|
2347
|
+
'contact_phone',
|
|
2038
2348
|
];
|
|
2039
2349
|
for (const field of oppUpdateFields) {
|
|
2040
2350
|
if (updateFields[field] !== undefined && updateFields[field] !== '') {
|
|
@@ -2077,9 +2387,16 @@ class Flowlu {
|
|
|
2077
2387
|
body.description = desc;
|
|
2078
2388
|
const additional = this.getNodeParameter('projectAdditionalFields', i);
|
|
2079
2389
|
const projSimpleFields = [
|
|
2080
|
-
'priority',
|
|
2081
|
-
'
|
|
2082
|
-
'
|
|
2390
|
+
'priority',
|
|
2391
|
+
'estimated_revenue',
|
|
2392
|
+
'estimated_expenses',
|
|
2393
|
+
'customer_id',
|
|
2394
|
+
'customer_crm_contact_id',
|
|
2395
|
+
'briefcase_id',
|
|
2396
|
+
'stage_id',
|
|
2397
|
+
'tasks_workflow_id',
|
|
2398
|
+
'billing_type',
|
|
2399
|
+
'crm_lead_id',
|
|
2083
2400
|
];
|
|
2084
2401
|
for (const field of projSimpleFields) {
|
|
2085
2402
|
if (additional[field] !== undefined && additional[field] !== '' && additional[field] !== 0) {
|
|
@@ -2115,7 +2432,7 @@ class Flowlu {
|
|
|
2115
2432
|
if (!filters.is_archive)
|
|
2116
2433
|
qs['filter[is_archive]'] = '0';
|
|
2117
2434
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/st/projects/list', apiKey, undefined, qs);
|
|
2118
|
-
for (const item of
|
|
2435
|
+
for (const item of responseData?.response?.items || []) {
|
|
2119
2436
|
returnData.push({ json: item });
|
|
2120
2437
|
}
|
|
2121
2438
|
continue;
|
|
@@ -2125,8 +2442,13 @@ class Flowlu {
|
|
|
2125
2442
|
const updateFields = this.getNodeParameter('projectUpdateFields', i);
|
|
2126
2443
|
const body = { id };
|
|
2127
2444
|
const projUpdateFields = [
|
|
2128
|
-
'name',
|
|
2129
|
-
'
|
|
2445
|
+
'name',
|
|
2446
|
+
'description',
|
|
2447
|
+
'manager_id',
|
|
2448
|
+
'priority',
|
|
2449
|
+
'estimated_revenue',
|
|
2450
|
+
'estimated_expenses',
|
|
2451
|
+
'stage_id',
|
|
2130
2452
|
];
|
|
2131
2453
|
for (const field of projUpdateFields) {
|
|
2132
2454
|
if (updateFields[field] !== undefined && updateFields[field] !== '') {
|
|
@@ -2179,7 +2501,7 @@ class Flowlu {
|
|
|
2179
2501
|
if (filters.search)
|
|
2180
2502
|
qs['search'] = filters.search;
|
|
2181
2503
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/customlists/items/list', apiKey, undefined, qs);
|
|
2182
|
-
for (const item of
|
|
2504
|
+
for (const item of responseData?.response?.items || []) {
|
|
2183
2505
|
returnData.push({ json: item });
|
|
2184
2506
|
}
|
|
2185
2507
|
continue;
|
|
@@ -2215,19 +2537,27 @@ class Flowlu {
|
|
|
2215
2537
|
const additional = this.getNodeParameter('taskAdditionalFields', i);
|
|
2216
2538
|
body.workflow_id = additional.workflow_id || '1';
|
|
2217
2539
|
body.workflow_stage_id = additional.workflow_stage_id || '1';
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2540
|
+
// Owner/Priority/Contact/Project/Start/End moved to top-level fields; fall back to
|
|
2541
|
+
// Additional Fields so task-create nodes built before the move keep working.
|
|
2542
|
+
const ownerId = this.getNodeParameter('owner_id', i, '') || additional.owner_id || defaultOwnerId;
|
|
2543
|
+
if (ownerId)
|
|
2544
|
+
body.owner_id = ownerId;
|
|
2545
|
+
const contactId = this.getNodeParameter('contact_id', i, '') || additional.contact_id;
|
|
2546
|
+
if (contactId)
|
|
2547
|
+
body.crm_account_id = parseInt(contactId, 10);
|
|
2548
|
+
body.priority =
|
|
2549
|
+
additional.priority !== undefined
|
|
2550
|
+
? additional.priority
|
|
2551
|
+
: this.getNodeParameter('priority', i, 2);
|
|
2224
2552
|
if (additional.status !== undefined)
|
|
2225
2553
|
body.status = additional.status;
|
|
2226
|
-
|
|
2227
|
-
|
|
2554
|
+
const planStartDate = this.getNodeParameter('plan_start_date', i, '') || additional.plan_start_date;
|
|
2555
|
+
if (planStartDate) {
|
|
2556
|
+
body.plan_start_date = new Date(planStartDate).toISOString().split('T')[0];
|
|
2228
2557
|
}
|
|
2229
|
-
|
|
2230
|
-
|
|
2558
|
+
const deadline = this.getNodeParameter('deadline', i, '') || additional.deadline;
|
|
2559
|
+
if (deadline) {
|
|
2560
|
+
body.deadline = new Date(deadline).toISOString().split('T')[0];
|
|
2231
2561
|
}
|
|
2232
2562
|
if (additional.time_estimate && additional.time_estimate > 0) {
|
|
2233
2563
|
body.time_estimate = Math.round(additional.time_estimate * 60);
|
|
@@ -2245,8 +2575,9 @@ class Flowlu {
|
|
|
2245
2575
|
if (additional.parent_id && additional.parent_id > 0) {
|
|
2246
2576
|
body.parent_id = additional.parent_id;
|
|
2247
2577
|
}
|
|
2248
|
-
|
|
2249
|
-
|
|
2578
|
+
const modelId = this.getNodeParameter('model_id', i, '') || additional.model_id;
|
|
2579
|
+
if (modelId) {
|
|
2580
|
+
body.model_id = modelId;
|
|
2250
2581
|
body.model = 'project';
|
|
2251
2582
|
body.module = 'st';
|
|
2252
2583
|
}
|
|
@@ -2278,7 +2609,7 @@ class Flowlu {
|
|
|
2278
2609
|
if (filters.status !== undefined)
|
|
2279
2610
|
qs['filter[status]'] = filters.status.toString();
|
|
2280
2611
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/task/tasks/list', apiKey, undefined, qs);
|
|
2281
|
-
for (const item of
|
|
2612
|
+
for (const item of responseData?.response?.items || []) {
|
|
2282
2613
|
returnData.push({ json: item });
|
|
2283
2614
|
}
|
|
2284
2615
|
continue;
|
|
@@ -2349,14 +2680,14 @@ class Flowlu {
|
|
|
2349
2680
|
const entityType = this.getNodeParameter('tagEntityType', i);
|
|
2350
2681
|
const entityId = this.getNodeParameter('tagEntityId', i);
|
|
2351
2682
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, `/api/v1/module/${entityType}/${entityId}/global_tags/list`, apiKey);
|
|
2352
|
-
for (const item of
|
|
2683
|
+
for (const item of responseData?.response?.items || []) {
|
|
2353
2684
|
returnData.push({ json: item });
|
|
2354
2685
|
}
|
|
2355
2686
|
continue;
|
|
2356
2687
|
}
|
|
2357
2688
|
else if (operation === 'listAll') {
|
|
2358
2689
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, '/api/v1/module/core/tag/list', apiKey);
|
|
2359
|
-
for (const item of
|
|
2690
|
+
for (const item of responseData?.response?.items || []) {
|
|
2360
2691
|
returnData.push({ json: item });
|
|
2361
2692
|
}
|
|
2362
2693
|
continue;
|
|
@@ -2387,7 +2718,7 @@ class Flowlu {
|
|
|
2387
2718
|
const entityId = this.getNodeParameter('commentEntityId', i);
|
|
2388
2719
|
const limit = this.getNodeParameter('limit', i);
|
|
2389
2720
|
responseData = await flowluApiRequest.call(this, 'GET', baseUrl, `/api/v1/module/${entityType}/${entityId}/comments/list`, apiKey, undefined, { limit: limit.toString() });
|
|
2390
|
-
for (const item of
|
|
2721
|
+
for (const item of responseData?.response?.items || []) {
|
|
2391
2722
|
returnData.push({ json: item });
|
|
2392
2723
|
}
|
|
2393
2724
|
continue;
|