@hustleops/n8n-nodes-hustleops 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +293 -0
- package/dist/credentials/HustleOpsApi.credentials.d.ts +12 -0
- package/dist/credentials/HustleOpsApi.credentials.js +53 -0
- package/dist/nodes/HustleOps/GenericFunctions.d.ts +38 -0
- package/dist/nodes/HustleOps/GenericFunctions.js +366 -0
- package/dist/nodes/HustleOps/HustleOps.node.d.ts +29 -0
- package/dist/nodes/HustleOps/HustleOps.node.js +1594 -0
- package/dist/nodes/HustleOps/HustleOps.node.json +18 -0
- package/dist/nodes/HustleOps/commentDefinitions.d.ts +21 -0
- package/dist/nodes/HustleOps/commentDefinitions.js +254 -0
- package/dist/nodes/HustleOps/constants.d.ts +1 -0
- package/dist/nodes/HustleOps/constants.js +4 -0
- package/dist/nodes/HustleOps/customFieldDefinitions.d.ts +36 -0
- package/dist/nodes/HustleOps/customFieldDefinitions.js +447 -0
- package/dist/nodes/HustleOps/hustleops.dark.svg +7 -0
- package/dist/nodes/HustleOps/hustleops.svg +7 -0
- package/dist/nodes/HustleOps/payloadInputMode.d.ts +18 -0
- package/dist/nodes/HustleOps/payloadInputMode.js +56 -0
- package/dist/nodes/HustleOps/resourceDefinitions.d.ts +48 -0
- package/dist/nodes/HustleOps/resourceDefinitions.js +629 -0
- package/dist/nodes/HustleOps/structuredCoreFields.d.ts +7 -0
- package/dist/nodes/HustleOps/structuredCoreFields.js +29 -0
- package/dist/nodes/HustleOps/tagDefinitions.d.ts +15 -0
- package/dist/nodes/HustleOps/tagDefinitions.js +215 -0
- package/dist/package.json +69 -0
- package/package.json +69 -0
|
@@ -0,0 +1,1594 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HustleOps = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const GenericFunctions_1 = require("./GenericFunctions");
|
|
6
|
+
const commentDefinitions_1 = require("./commentDefinitions");
|
|
7
|
+
const customFieldDefinitions_1 = require("./customFieldDefinitions");
|
|
8
|
+
const resourceDefinitions_1 = require("./resourceDefinitions");
|
|
9
|
+
const tagDefinitions_1 = require("./tagDefinitions");
|
|
10
|
+
const structuredCoreFields_1 = require("./structuredCoreFields");
|
|
11
|
+
const payloadInputMode_1 = require("./payloadInputMode");
|
|
12
|
+
const LIVE_DESCRIPTION = 'Work with HustleOps incident response objects through the HustleOps API.';
|
|
13
|
+
const STRUCTURED_CORE_FIELDS_NODE = {
|
|
14
|
+
id: 'hustleops-structured-core-fields',
|
|
15
|
+
name: 'HustleOps',
|
|
16
|
+
type: 'hustleOps',
|
|
17
|
+
typeVersion: 1,
|
|
18
|
+
position: [0, 0],
|
|
19
|
+
parameters: {},
|
|
20
|
+
};
|
|
21
|
+
const OPERATIONS_WITH_ID = [
|
|
22
|
+
'get',
|
|
23
|
+
'update',
|
|
24
|
+
'setTags',
|
|
25
|
+
'addTags',
|
|
26
|
+
'removeTag',
|
|
27
|
+
];
|
|
28
|
+
const CORE_RESOURCE_VALUES = resourceDefinitions_1.CORE_RESOURCE_OPTIONS.map((option) => option.value);
|
|
29
|
+
const PAYLOAD_OPERATION_VALUES = [
|
|
30
|
+
'search',
|
|
31
|
+
'count',
|
|
32
|
+
'create',
|
|
33
|
+
'update',
|
|
34
|
+
'setTags',
|
|
35
|
+
'addTags',
|
|
36
|
+
'toggleReaction',
|
|
37
|
+
'updateColor',
|
|
38
|
+
'bulkUpdateColor',
|
|
39
|
+
'bulkDelete',
|
|
40
|
+
'searchDefinitions',
|
|
41
|
+
'createGroup',
|
|
42
|
+
'updateGroup',
|
|
43
|
+
'createDefinition',
|
|
44
|
+
'updateDefinition',
|
|
45
|
+
'bulkUpdateDefinitions',
|
|
46
|
+
'bulkDeleteDefinitions',
|
|
47
|
+
'batchGetValues',
|
|
48
|
+
'replaceValues',
|
|
49
|
+
'updateSelectedValuesSafely',
|
|
50
|
+
];
|
|
51
|
+
const HUSTLEOPS_RESOURCE_OPTIONS = [
|
|
52
|
+
...resourceDefinitions_1.CORE_RESOURCE_OPTIONS,
|
|
53
|
+
commentDefinitions_1.COMMENT_RESOURCE_OPTION,
|
|
54
|
+
tagDefinitions_1.TAG_RESOURCE_OPTION,
|
|
55
|
+
customFieldDefinitions_1.CUSTOM_FIELD_RESOURCE_OPTION,
|
|
56
|
+
];
|
|
57
|
+
const PICKLIST_LOAD_OPTIONS_METHODS = {
|
|
58
|
+
alertType: 'getAlertTypeOptions',
|
|
59
|
+
alertStatus: 'getAlertStatusOptions',
|
|
60
|
+
incidentStatus: 'getIncidentStatusOptions',
|
|
61
|
+
incidentCategory: 'getIncidentCategoryOptions',
|
|
62
|
+
observableType: 'getObservableTypeOptions',
|
|
63
|
+
threatLevel: 'getThreatLevelOptions',
|
|
64
|
+
criticality: 'getCriticalityOptions',
|
|
65
|
+
knowledgeType: 'getKnowledgeTypeOptions',
|
|
66
|
+
};
|
|
67
|
+
const CORE_OPERATION_OPTIONS = [
|
|
68
|
+
{
|
|
69
|
+
name: 'Search',
|
|
70
|
+
value: 'search',
|
|
71
|
+
description: 'Search HustleOps objects with filters, pagination, and sorting',
|
|
72
|
+
action: 'Search HustleOps objects',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Count',
|
|
76
|
+
value: 'count',
|
|
77
|
+
description: 'Count HustleOps objects matching a search request',
|
|
78
|
+
action: 'Count HustleOps objects',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'Get',
|
|
82
|
+
value: 'get',
|
|
83
|
+
description: 'Get a HustleOps object by ID',
|
|
84
|
+
action: 'Get a HustleOps object',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'Create',
|
|
88
|
+
value: 'create',
|
|
89
|
+
description: 'Create a HustleOps object',
|
|
90
|
+
action: 'Create a HustleOps object',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'Update',
|
|
94
|
+
value: 'update',
|
|
95
|
+
description: 'Update a HustleOps object',
|
|
96
|
+
action: 'Update a HustleOps object',
|
|
97
|
+
},
|
|
98
|
+
...tagDefinitions_1.ENTITY_TAG_OPERATION_OPTIONS,
|
|
99
|
+
];
|
|
100
|
+
function fieldDefaultValue(spec) {
|
|
101
|
+
if (spec.type === 'boolean') {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (spec.type === 'tags') {
|
|
105
|
+
return '[]';
|
|
106
|
+
}
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
function fieldType(spec) {
|
|
110
|
+
if (spec.picklistDomain) {
|
|
111
|
+
return 'options';
|
|
112
|
+
}
|
|
113
|
+
if (spec.type === 'string' || spec.type === 'uuid' || spec.type === 'url') {
|
|
114
|
+
return 'string';
|
|
115
|
+
}
|
|
116
|
+
if (spec.type === 'number') {
|
|
117
|
+
return 'number';
|
|
118
|
+
}
|
|
119
|
+
if (spec.type === 'boolean') {
|
|
120
|
+
return 'boolean';
|
|
121
|
+
}
|
|
122
|
+
if (spec.type === 'enum') {
|
|
123
|
+
return 'options';
|
|
124
|
+
}
|
|
125
|
+
if (spec.type === 'date-time') {
|
|
126
|
+
return 'dateTime';
|
|
127
|
+
}
|
|
128
|
+
if (spec.type === 'tags') {
|
|
129
|
+
return 'json';
|
|
130
|
+
}
|
|
131
|
+
if (spec.type === 'uuid[]') {
|
|
132
|
+
throw new n8n_workflow_1.NodeOperationError(STRUCTURED_CORE_FIELDS_NODE, 'Structured core fields do not yet support uuid[] field specs.');
|
|
133
|
+
}
|
|
134
|
+
const _exhaustive = spec.type;
|
|
135
|
+
throw new n8n_workflow_1.NodeOperationError(STRUCTURED_CORE_FIELDS_NODE, `Unsupported structured core field type: ${_exhaustive}`);
|
|
136
|
+
}
|
|
137
|
+
function enumOptionDisplayName(value) {
|
|
138
|
+
return (0, structuredCoreFields_1.fieldDisplayName)(value.toLowerCase().replace(/_/g, ' '));
|
|
139
|
+
}
|
|
140
|
+
function picklistLoadOptionsMethod(domain) {
|
|
141
|
+
const method = PICKLIST_LOAD_OPTIONS_METHODS[domain];
|
|
142
|
+
if (!method) {
|
|
143
|
+
throw new n8n_workflow_1.NodeOperationError(STRUCTURED_CORE_FIELDS_NODE, `Unsupported HustleOps picklist domain: ${domain}`);
|
|
144
|
+
}
|
|
145
|
+
return method;
|
|
146
|
+
}
|
|
147
|
+
function fieldDescription(definition, field, spec) {
|
|
148
|
+
const constraints = [];
|
|
149
|
+
if (spec.maxLength !== undefined) {
|
|
150
|
+
constraints.push(`Maximum ${spec.maxLength} characters.`);
|
|
151
|
+
}
|
|
152
|
+
if (spec.patternDescription) {
|
|
153
|
+
constraints.push(`${spec.patternDescription}.`);
|
|
154
|
+
}
|
|
155
|
+
if (spec.type === 'tags') {
|
|
156
|
+
return `${definition.displayName} ${(0, structuredCoreFields_1.fieldDisplayName)(field)} as a JSON array of tag names`;
|
|
157
|
+
}
|
|
158
|
+
if (spec.type === 'enum' && spec.allowedValues) {
|
|
159
|
+
constraints.push(`Supported values: ${spec.allowedValues.join(', ')}.`);
|
|
160
|
+
}
|
|
161
|
+
if (spec.picklistDomain) {
|
|
162
|
+
constraints.push(`Options load from the HustleOps ${spec.picklistDomain} picklist.`);
|
|
163
|
+
}
|
|
164
|
+
return [`${definition.displayName} ${(0, structuredCoreFields_1.fieldDisplayName)(field)}.`, spec.description, ...constraints]
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.join(' ');
|
|
167
|
+
}
|
|
168
|
+
function buildFieldProperty(definition, field, required, parameterName = field) {
|
|
169
|
+
const spec = definition.fieldSpecs[field];
|
|
170
|
+
const property = {
|
|
171
|
+
displayName: (0, structuredCoreFields_1.fieldDisplayName)(field),
|
|
172
|
+
name: parameterName,
|
|
173
|
+
type: fieldType(spec),
|
|
174
|
+
default: fieldDefaultValue(spec),
|
|
175
|
+
required,
|
|
176
|
+
description: fieldDescription(definition, field, spec),
|
|
177
|
+
};
|
|
178
|
+
if (spec.type === 'enum' && spec.allowedValues) {
|
|
179
|
+
property.options = spec.allowedValues.map((value) => ({
|
|
180
|
+
name: enumOptionDisplayName(value),
|
|
181
|
+
value,
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
if (spec.picklistDomain) {
|
|
185
|
+
property.typeOptions = {
|
|
186
|
+
loadOptionsMethod: picklistLoadOptionsMethod(spec.picklistDomain),
|
|
187
|
+
};
|
|
188
|
+
delete property.options;
|
|
189
|
+
}
|
|
190
|
+
return property;
|
|
191
|
+
}
|
|
192
|
+
function buildCoreCreateRequiredProperties() {
|
|
193
|
+
return Object.values(resourceDefinitions_1.CORE_RESOURCE_DEFINITIONS).flatMap((definition) => definition.requiredCreateFields.map((field) => ({
|
|
194
|
+
...buildFieldProperty(definition, field, true, (0, structuredCoreFields_1.structuredFieldParameterName)(definition.resource, 'create', field)),
|
|
195
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)([definition.resource], ['create'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
196
|
+
})));
|
|
197
|
+
}
|
|
198
|
+
function buildCoreCreateAdditionalProperties() {
|
|
199
|
+
return Object.values(resourceDefinitions_1.CORE_RESOURCE_DEFINITIONS).map((definition) => ({
|
|
200
|
+
displayName: 'Additional Fields',
|
|
201
|
+
name: (0, structuredCoreFields_1.createAdditionalFieldsParameterName)(definition.resource),
|
|
202
|
+
type: 'collection',
|
|
203
|
+
placeholder: 'Add Field',
|
|
204
|
+
default: {},
|
|
205
|
+
options: definition.createFields
|
|
206
|
+
.filter((field) => !definition.requiredCreateFields.includes(field))
|
|
207
|
+
.map((field) => buildFieldProperty(definition, field, false)),
|
|
208
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)([definition.resource], ['create'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
function buildCoreUpdateFieldProperties() {
|
|
212
|
+
return Object.values(resourceDefinitions_1.CORE_RESOURCE_DEFINITIONS).map((definition) => ({
|
|
213
|
+
displayName: 'Fields to Update',
|
|
214
|
+
name: (0, structuredCoreFields_1.updateFieldsParameterName)(definition.resource),
|
|
215
|
+
type: 'collection',
|
|
216
|
+
placeholder: 'Add Field',
|
|
217
|
+
default: {},
|
|
218
|
+
options: definition.updateFields.map((field) => buildFieldProperty(definition, field, false)),
|
|
219
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)([definition.resource], ['update'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
const CORE_CREATE_REQUIRED_PROPERTIES = buildCoreCreateRequiredProperties();
|
|
223
|
+
const CORE_CREATE_ADDITIONAL_PROPERTIES = buildCoreCreateAdditionalProperties();
|
|
224
|
+
const CORE_UPDATE_FIELD_PROPERTIES = buildCoreUpdateFieldProperties();
|
|
225
|
+
const JSON_OBJECT_PAYLOAD_OPERATIONS = {
|
|
226
|
+
alert: ['search', 'count', 'create', 'update', 'setTags', 'addTags'],
|
|
227
|
+
incident: ['search', 'count', 'create', 'update', 'setTags', 'addTags'],
|
|
228
|
+
observable: ['search', 'count', 'create', 'update', 'setTags', 'addTags'],
|
|
229
|
+
knowledge: ['search', 'count', 'create', 'update', 'setTags', 'addTags'],
|
|
230
|
+
comment: ['create', 'update', 'toggleReaction'],
|
|
231
|
+
tag: ['search', 'create', 'updateColor', 'bulkUpdateColor', 'bulkDelete'],
|
|
232
|
+
customField: [
|
|
233
|
+
'searchDefinitions',
|
|
234
|
+
'createGroup',
|
|
235
|
+
'updateGroup',
|
|
236
|
+
'createDefinition',
|
|
237
|
+
'updateDefinition',
|
|
238
|
+
'bulkUpdateDefinitions',
|
|
239
|
+
'bulkDeleteDefinitions',
|
|
240
|
+
'batchGetValues',
|
|
241
|
+
'replaceValues',
|
|
242
|
+
'updateSelectedValuesSafely',
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
function buildPayloadJsonObjectProperties() {
|
|
246
|
+
return Object.entries(JSON_OBJECT_PAYLOAD_OPERATIONS).flatMap(([resource, operations]) => operations.map((operation) => ({
|
|
247
|
+
displayName: `${(0, structuredCoreFields_1.fieldDisplayName)(resource)} ${(0, structuredCoreFields_1.fieldDisplayName)(operation)} JSON Object`,
|
|
248
|
+
name: (0, payloadInputMode_1.payloadJsonObjectParameterName)(resource, operation),
|
|
249
|
+
type: 'json',
|
|
250
|
+
default: '{}',
|
|
251
|
+
description: 'Complete JSON object to submit as the request body',
|
|
252
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)([resource], [operation], payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT),
|
|
253
|
+
})));
|
|
254
|
+
}
|
|
255
|
+
const PAYLOAD_JSON_OBJECT_PROPERTIES = buildPayloadJsonObjectProperties();
|
|
256
|
+
const SEARCH_FIELD_DISPLAY_OPTIONS = (0, payloadInputMode_1.modeDisplayOptions)([...CORE_RESOURCE_VALUES, 'tag', 'customField'], ['search', 'count', 'searchDefinitions'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS);
|
|
257
|
+
const TAG_SEARCH_REQUEST_DEFINITION = {
|
|
258
|
+
displayName: 'Tag',
|
|
259
|
+
defaultSortBy: 'value',
|
|
260
|
+
defaultSortOrder: 'asc',
|
|
261
|
+
searchFields: ['value', 'color', 'createdAt', 'updatedAt'],
|
|
262
|
+
sortFields: ['value', 'createdAt', 'updatedAt'],
|
|
263
|
+
};
|
|
264
|
+
const CUSTOM_FIELD_DEFINITION_SEARCH_REQUEST_DEFINITION = {
|
|
265
|
+
displayName: 'Custom Field Definition',
|
|
266
|
+
defaultSortBy: 'createdAt',
|
|
267
|
+
defaultSortOrder: 'desc',
|
|
268
|
+
searchFields: [
|
|
269
|
+
'name',
|
|
270
|
+
'description',
|
|
271
|
+
'fieldType',
|
|
272
|
+
'entityTypes',
|
|
273
|
+
'groupId',
|
|
274
|
+
'isRequired',
|
|
275
|
+
'createdAt',
|
|
276
|
+
'updatedAt',
|
|
277
|
+
],
|
|
278
|
+
sortFields: ['name', 'fieldType', 'createdAt', 'updatedAt'],
|
|
279
|
+
};
|
|
280
|
+
function shouldOmitStructuredValue(value) {
|
|
281
|
+
return value === undefined || value === null || value === '';
|
|
282
|
+
}
|
|
283
|
+
function normalizeStructuredFieldValue(context, spec, value, itemIndex) {
|
|
284
|
+
if (spec.type === 'tags') {
|
|
285
|
+
const tags = (0, tagDefinitions_1.parseTagValues)(context, value, (0, structuredCoreFields_1.fieldDisplayName)(spec.name), itemIndex, {
|
|
286
|
+
allowEmpty: true,
|
|
287
|
+
});
|
|
288
|
+
return tags.length === 0 ? undefined : tags;
|
|
289
|
+
}
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
function labelStructuredDtoError(context, error, fields, itemIndex) {
|
|
293
|
+
if (!(error instanceof Error)) {
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
let message = error.message;
|
|
297
|
+
for (const field of [...fields].sort((left, right) => right.length - left.length)) {
|
|
298
|
+
const displayLabel = `${(0, structuredCoreFields_1.fieldDisplayName)(field)} (${field})`;
|
|
299
|
+
message = message
|
|
300
|
+
.replace(`field ${field}`, `field ${displayLabel}`)
|
|
301
|
+
.replace(`field: ${field}`, `field: ${displayLabel}`)
|
|
302
|
+
.replace(`field ${field} `, `field ${displayLabel} `);
|
|
303
|
+
}
|
|
304
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), message, { itemIndex });
|
|
305
|
+
}
|
|
306
|
+
function assignStructuredField(context, body, structuredFields, definition, field, value, omitEmpty, itemIndex) {
|
|
307
|
+
const spec = definition.fieldSpecs[field];
|
|
308
|
+
if (omitEmpty && shouldOmitStructuredValue(value)) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const normalizedValue = normalizeStructuredFieldValue(context, spec, value, itemIndex);
|
|
312
|
+
if (omitEmpty && normalizedValue === undefined) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
body[field] = normalizedValue;
|
|
316
|
+
structuredFields.add(field);
|
|
317
|
+
}
|
|
318
|
+
function getStructuredCollectionValues(context, parameterName, label, itemIndex) {
|
|
319
|
+
return (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter(parameterName, itemIndex, {}), label, itemIndex);
|
|
320
|
+
}
|
|
321
|
+
function normalizeMergedDtoBody(context, body, definition, itemIndex) {
|
|
322
|
+
var _a;
|
|
323
|
+
if (((_a = definition.fieldSpecs.tags) === null || _a === void 0 ? void 0 : _a.type) === 'tags' &&
|
|
324
|
+
Object.prototype.hasOwnProperty.call(body, 'tags')) {
|
|
325
|
+
body.tags = (0, tagDefinitions_1.parseTagValues)(context, body.tags, 'Tags', itemIndex, {
|
|
326
|
+
allowEmpty: true,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return body;
|
|
330
|
+
}
|
|
331
|
+
function payloadMode(context, itemIndex) {
|
|
332
|
+
return context.getNodeParameter(payloadInputMode_1.PAYLOAD_INPUT_MODE_PARAMETER, itemIndex, payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS);
|
|
333
|
+
}
|
|
334
|
+
function optionalStringParameter(value) {
|
|
335
|
+
return typeof value === 'string' && value.trim() === ''
|
|
336
|
+
? undefined
|
|
337
|
+
: value;
|
|
338
|
+
}
|
|
339
|
+
function jsonObjectPayload(context, itemIndex, resource, operation, label) {
|
|
340
|
+
return (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter((0, payloadInputMode_1.payloadJsonObjectParameterName)(resource, operation), itemIndex, '{}'), label, itemIndex);
|
|
341
|
+
}
|
|
342
|
+
function buildStructuredDtoBody(context, itemIndex, definition, operation) {
|
|
343
|
+
const structuredBody = {};
|
|
344
|
+
const structuredFields = new Set();
|
|
345
|
+
if (operation === 'create') {
|
|
346
|
+
for (const field of definition.requiredCreateFields) {
|
|
347
|
+
assignStructuredField(context, structuredBody, structuredFields, definition, field, context.getNodeParameter((0, structuredCoreFields_1.structuredFieldParameterName)(definition.resource, 'create', field), itemIndex, ''), false, itemIndex);
|
|
348
|
+
}
|
|
349
|
+
const additionalFields = getStructuredCollectionValues(context, (0, structuredCoreFields_1.createAdditionalFieldsParameterName)(definition.resource), 'Additional Fields', itemIndex);
|
|
350
|
+
for (const field of definition.createFields) {
|
|
351
|
+
if (definition.requiredCreateFields.includes(field)) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
assignStructuredField(context, structuredBody, structuredFields, definition, field, additionalFields[field], true, itemIndex);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
const fieldsToUpdate = getStructuredCollectionValues(context, (0, structuredCoreFields_1.updateFieldsParameterName)(definition.resource), 'Fields to Update', itemIndex);
|
|
359
|
+
for (const field of definition.updateFields) {
|
|
360
|
+
assignStructuredField(context, structuredBody, structuredFields, definition, field, fieldsToUpdate[field], true, itemIndex);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const normalizedBody = normalizeMergedDtoBody(context, structuredBody, definition, itemIndex);
|
|
364
|
+
try {
|
|
365
|
+
return (0, resourceDefinitions_1.sanitizeDtoBody)(definition, operation, normalizedBody);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
labelStructuredDtoError(context, error, structuredFields, itemIndex);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function buildCoreDtoBody(context, itemIndex, definition, operation) {
|
|
372
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
373
|
+
const body = normalizeMergedDtoBody(context, jsonObjectPayload(context, itemIndex, definition.resource, operation, `${definition.displayName} ${operation} JSON Object`), definition, itemIndex);
|
|
374
|
+
return (0, resourceDefinitions_1.sanitizeDtoBody)(definition, operation, body);
|
|
375
|
+
}
|
|
376
|
+
return buildStructuredDtoBody(context, itemIndex, definition, operation);
|
|
377
|
+
}
|
|
378
|
+
function buildSearchFieldsBody(context, itemIndex) {
|
|
379
|
+
const filter = (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter('payloadSearchFilter', itemIndex, '{}'), 'Filter', itemIndex);
|
|
380
|
+
const excludeIds = (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadSearchExcludeIds', itemIndex, '[]'), 'Exclude IDs', itemIndex);
|
|
381
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
382
|
+
filter: Object.keys(filter).length === 0 ? undefined : filter,
|
|
383
|
+
excludeIds: excludeIds.length === 0 ? undefined : excludeIds,
|
|
384
|
+
pagination: {
|
|
385
|
+
page: context.getNodeParameter('payloadSearchPage', itemIndex, 1),
|
|
386
|
+
pageSize: context.getNodeParameter('payloadSearchPageSize', itemIndex, 25),
|
|
387
|
+
sortBy: optionalStringParameter(context.getNodeParameter('payloadSearchSortBy', itemIndex, '')),
|
|
388
|
+
sortOrder: optionalStringParameter(context.getNodeParameter('payloadSearchSortOrder', itemIndex, '')),
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function buildCoreSearchBody(context, itemIndex, definition, operation) {
|
|
393
|
+
const input = payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT
|
|
394
|
+
? jsonObjectPayload(context, itemIndex, definition.resource, operation, `${definition.displayName} ${operation} JSON Object`)
|
|
395
|
+
: buildSearchFieldsBody(context, itemIndex);
|
|
396
|
+
return (0, resourceDefinitions_1.buildSearchRequest)(definition, input);
|
|
397
|
+
}
|
|
398
|
+
function buildCommentPayload(context, itemIndex, operation) {
|
|
399
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
400
|
+
return jsonObjectPayload(context, itemIndex, 'comment', operation, 'Comment JSON Object');
|
|
401
|
+
}
|
|
402
|
+
if (operation === 'create') {
|
|
403
|
+
const attachmentIds = (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadCommentAttachmentIds', itemIndex, '[]'), 'Comment Attachment IDs', itemIndex);
|
|
404
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
405
|
+
content: optionalStringParameter(context.getNodeParameter('payloadCommentContent', itemIndex, '')),
|
|
406
|
+
parentId: optionalStringParameter(context.getNodeParameter('payloadCommentParentId', itemIndex, '')),
|
|
407
|
+
attachmentIds: attachmentIds.length === 0 ? undefined : attachmentIds,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (operation === 'update') {
|
|
411
|
+
return { content: context.getNodeParameter('payloadCommentContent', itemIndex, '') };
|
|
412
|
+
}
|
|
413
|
+
if (operation === 'toggleReaction') {
|
|
414
|
+
return { emoji: context.getNodeParameter('payloadCommentEmoji', itemIndex, '') };
|
|
415
|
+
}
|
|
416
|
+
return {};
|
|
417
|
+
}
|
|
418
|
+
function buildTagPayload(context, itemIndex, operation) {
|
|
419
|
+
if (operation === 'search') {
|
|
420
|
+
const input = payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT
|
|
421
|
+
? jsonObjectPayload(context, itemIndex, 'tag', operation, 'Tag JSON Object')
|
|
422
|
+
: buildSearchFieldsBody(context, itemIndex);
|
|
423
|
+
return (0, resourceDefinitions_1.buildGenericSearchRequest)(TAG_SEARCH_REQUEST_DEFINITION, input);
|
|
424
|
+
}
|
|
425
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
426
|
+
return jsonObjectPayload(context, itemIndex, 'tag', operation, 'Tag JSON Object');
|
|
427
|
+
}
|
|
428
|
+
if (operation === 'create') {
|
|
429
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
430
|
+
value: context.getNodeParameter('payloadTagValue', itemIndex, ''),
|
|
431
|
+
color: optionalStringParameter(context.getNodeParameter('payloadTagColor', itemIndex, '')),
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
if (operation === 'updateColor') {
|
|
435
|
+
return { color: context.getNodeParameter('payloadTagColor', itemIndex, '') };
|
|
436
|
+
}
|
|
437
|
+
if (operation === 'bulkUpdateColor') {
|
|
438
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
439
|
+
ids: (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadTagIds', itemIndex, '[]'), 'Tag IDs', itemIndex),
|
|
440
|
+
color: optionalStringParameter(context.getNodeParameter('payloadTagColor', itemIndex, '')),
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
if (operation === 'bulkDelete') {
|
|
444
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
445
|
+
ids: (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadTagIds', itemIndex, '[]'), 'Tag IDs', itemIndex),
|
|
446
|
+
force: context.getNodeParameter('payloadTagForce', itemIndex, undefined),
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return {};
|
|
450
|
+
}
|
|
451
|
+
function buildEntityTagBody(context, itemIndex, resource, operation) {
|
|
452
|
+
const operationLabel = operation === 'setTags' ? 'Set Tags' : 'Add Tags';
|
|
453
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
454
|
+
const body = jsonObjectPayload(context, itemIndex, resource, operation, `${operationLabel} JSON Object`);
|
|
455
|
+
for (const key of Object.keys(body)) {
|
|
456
|
+
if (key !== 'values') {
|
|
457
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Unsupported ${operationLabel} JSON Object field: ${key}`, { itemIndex });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return { values: (0, tagDefinitions_1.parseEntityTagValues)(context, body.values, operationLabel, itemIndex) };
|
|
461
|
+
}
|
|
462
|
+
return {
|
|
463
|
+
values: (0, tagDefinitions_1.parseEntityTagValues)(context, context.getNodeParameter('payloadEntityTagValues', itemIndex, '[]'), operationLabel, itemIndex),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function buildCustomFieldBodyPayload(context, itemIndex, operation) {
|
|
467
|
+
if (operation === 'searchDefinitions') {
|
|
468
|
+
const input = payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT
|
|
469
|
+
? jsonObjectPayload(context, itemIndex, 'customField', operation, 'Custom Field Definition Search JSON Object')
|
|
470
|
+
: buildSearchFieldsBody(context, itemIndex);
|
|
471
|
+
return (0, resourceDefinitions_1.buildGenericSearchRequest)(CUSTOM_FIELD_DEFINITION_SEARCH_REQUEST_DEFINITION, input);
|
|
472
|
+
}
|
|
473
|
+
if (operation === 'batchGetValues' &&
|
|
474
|
+
payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
475
|
+
return (0, customFieldDefinitions_1.customFieldBatchBody)(context, jsonObjectPayload(context, itemIndex, 'customField', operation, 'Custom Field Batch Get Values JSON Object'), itemIndex);
|
|
476
|
+
}
|
|
477
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
478
|
+
return jsonObjectPayload(context, itemIndex, 'customField', operation, 'Custom Field JSON Object');
|
|
479
|
+
}
|
|
480
|
+
if (operation === 'createGroup' || operation === 'updateGroup') {
|
|
481
|
+
return (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter('payloadCustomFieldGroupFields', itemIndex, '{}'), 'Custom Field Group Fields', itemIndex);
|
|
482
|
+
}
|
|
483
|
+
if (operation === 'createDefinition' || operation === 'updateDefinition') {
|
|
484
|
+
return (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter('payloadCustomFieldDefinitionFields', itemIndex, '{}'), 'Custom Field Definition Fields', itemIndex);
|
|
485
|
+
}
|
|
486
|
+
if (operation === 'bulkUpdateDefinitions') {
|
|
487
|
+
return (0, GenericFunctions_1.parseJsonObject)(context, context.getNodeParameter('payloadCustomFieldDefinitionBulkFields', itemIndex, '{}'), 'Custom Field Definition Bulk Fields', itemIndex);
|
|
488
|
+
}
|
|
489
|
+
if (operation === 'bulkDeleteDefinitions') {
|
|
490
|
+
return (0, GenericFunctions_1.compactObject)({
|
|
491
|
+
ids: (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadCustomFieldDefinitionIds', itemIndex, '[]'), 'Custom Field Definition IDs', itemIndex),
|
|
492
|
+
force: context.getNodeParameter('payloadCustomFieldDefinitionForce', itemIndex, undefined),
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (operation === 'batchGetValues') {
|
|
496
|
+
return (0, customFieldDefinitions_1.customFieldBatchBody)(context, {
|
|
497
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
498
|
+
entityIds: context.getNodeParameter('payloadCustomFieldEntityIds', itemIndex, '[]'),
|
|
499
|
+
}, itemIndex);
|
|
500
|
+
}
|
|
501
|
+
return {};
|
|
502
|
+
}
|
|
503
|
+
function customFieldPayloadRows(context, itemIndex, operation) {
|
|
504
|
+
if (payloadMode(context, itemIndex) === payloadInputMode_1.PAYLOAD_MODE_JSON_OBJECT) {
|
|
505
|
+
const body = jsonObjectPayload(context, itemIndex, 'customField', operation, 'Custom Field Values JSON Object');
|
|
506
|
+
if (!Array.isArray(body.values)) {
|
|
507
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Custom Field Values JSON Object must include a values array.', {
|
|
508
|
+
itemIndex,
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
return body.values;
|
|
512
|
+
}
|
|
513
|
+
return (0, GenericFunctions_1.parseJsonArray)(context, context.getNodeParameter('payloadCustomFieldValues', itemIndex, '[]'), 'Custom Field Values', itemIndex);
|
|
514
|
+
}
|
|
515
|
+
async function executeCommentOperation(context, itemIndex, operation, returnData) {
|
|
516
|
+
if (operation === 'list') {
|
|
517
|
+
const query = (0, commentDefinitions_1.buildCommentEntityQuery)(context, {
|
|
518
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
519
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
520
|
+
take: context.getNodeParameter('take', itemIndex, 50),
|
|
521
|
+
cursor: context.getNodeParameter('cursor', itemIndex, ''),
|
|
522
|
+
}, itemIndex);
|
|
523
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
524
|
+
const response = (0, commentDefinitions_1.assertCommentListResponse)(await client.request('GET', '/comments', undefined, query), 'Comment list response');
|
|
525
|
+
const includeMetadata = context.getNodeParameter('includeCommentPaginationMetadata', itemIndex, false);
|
|
526
|
+
if (includeMetadata) {
|
|
527
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
for (const row of response.items) {
|
|
531
|
+
returnData.push({ json: row, pairedItem: { item: itemIndex } });
|
|
532
|
+
}
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
if (operation === 'search') {
|
|
536
|
+
const query = (0, commentDefinitions_1.buildCommentSearchQuery)(context, {
|
|
537
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
538
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
539
|
+
q: context.getNodeParameter('q', itemIndex),
|
|
540
|
+
}, itemIndex);
|
|
541
|
+
const maxResults = (0, commentDefinitions_1.parseCommentMaxResults)(context, context.getNodeParameter('maxResults', itemIndex, 100), itemIndex);
|
|
542
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
543
|
+
const response = await client.request('GET', '/comments/search', undefined, query);
|
|
544
|
+
if (!Array.isArray(response)) {
|
|
545
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Comment search response must be an array.', {
|
|
546
|
+
itemIndex,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
for (const row of response.slice(0, maxResults)) {
|
|
550
|
+
returnData.push({ json: row, pairedItem: { item: itemIndex } });
|
|
551
|
+
}
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (operation === 'unreadCount') {
|
|
555
|
+
const query = (0, commentDefinitions_1.buildCommentEntityQuery)(context, {
|
|
556
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
557
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
558
|
+
}, itemIndex);
|
|
559
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
560
|
+
const response = await client.request('GET', '/comments/unread-count', undefined, query);
|
|
561
|
+
if (typeof response !== 'number') {
|
|
562
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Comment unread count response must be a number.', { itemIndex });
|
|
563
|
+
}
|
|
564
|
+
returnData.push({ json: { unreadCount: response }, pairedItem: { item: itemIndex } });
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (operation === 'create') {
|
|
568
|
+
const body = (0, commentDefinitions_1.sanitizeCreateComment)(context, {
|
|
569
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
570
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
571
|
+
}, buildCommentPayload(context, itemIndex, operation), itemIndex);
|
|
572
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
573
|
+
const response = await client.request('POST', '/comments', body);
|
|
574
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (operation === 'markRead') {
|
|
578
|
+
const body = (0, commentDefinitions_1.sanitizeMarkReadComment)(context, {
|
|
579
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
580
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
581
|
+
}, itemIndex);
|
|
582
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
583
|
+
await client.request('POST', '/comments/read', body);
|
|
584
|
+
returnData.push({ json: { success: true, ...body }, pairedItem: { item: itemIndex } });
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const commentId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('commentId', itemIndex), 'Comment ID');
|
|
588
|
+
if (operation === 'update') {
|
|
589
|
+
const body = (0, commentDefinitions_1.sanitizeUpdateComment)(context, buildCommentPayload(context, itemIndex, operation), itemIndex);
|
|
590
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
591
|
+
const response = await client.request('PATCH', `/comments/${commentId}`, body);
|
|
592
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (operation === 'delete') {
|
|
596
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
597
|
+
const response = await client.request('DELETE', `/comments/${commentId}`);
|
|
598
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (operation === 'toggleReaction') {
|
|
602
|
+
const body = (0, commentDefinitions_1.sanitizeToggleReaction)(context, buildCommentPayload(context, itemIndex, operation), itemIndex);
|
|
603
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
604
|
+
const response = await client.request('POST', `/comments/${commentId}/reactions`, body);
|
|
605
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
if (operation === 'togglePin') {
|
|
609
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
610
|
+
const response = await client.request('PATCH', `/comments/${commentId}/pin`);
|
|
611
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Unsupported Comment operation: ${operation}`, {
|
|
615
|
+
itemIndex,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
function pushResponse(returnData, response, itemIndex) {
|
|
619
|
+
if (Array.isArray(response)) {
|
|
620
|
+
for (const row of response) {
|
|
621
|
+
returnData.push({ json: row, pairedItem: { item: itemIndex } });
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
returnData.push({
|
|
626
|
+
json: (response !== null && response !== void 0 ? response : { success: true }),
|
|
627
|
+
pairedItem: { item: itemIndex },
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
function pushPaginatedRows(returnData, response, label, itemIndex) {
|
|
631
|
+
const page = (0, GenericFunctions_1.assertPaginatedResponse)(response, label);
|
|
632
|
+
for (const row of page.data) {
|
|
633
|
+
returnData.push({ json: row, pairedItem: { item: itemIndex } });
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function extractOptionRows(response) {
|
|
637
|
+
if (Array.isArray(response)) {
|
|
638
|
+
return response.filter((row) => !!row && typeof row === 'object' && !Array.isArray(row));
|
|
639
|
+
}
|
|
640
|
+
if (response && typeof response === 'object') {
|
|
641
|
+
const objectResponse = response;
|
|
642
|
+
for (const key of ['data', 'items', 'values']) {
|
|
643
|
+
const rows = objectResponse[key];
|
|
644
|
+
if (Array.isArray(rows)) {
|
|
645
|
+
return rows.filter((row) => !!row && typeof row === 'object' && !Array.isArray(row));
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
function optionFromRow(row, fallbackPrefix) {
|
|
652
|
+
var _a, _b, _c, _d, _e, _f;
|
|
653
|
+
const value = String((_c = (_b = (_a = row.id) !== null && _a !== void 0 ? _a : row.value) !== null && _b !== void 0 ? _b : row.name) !== null && _c !== void 0 ? _c : '');
|
|
654
|
+
const label = (_f = (_e = (_d = row.value) !== null && _d !== void 0 ? _d : row.name) !== null && _e !== void 0 ? _e : row.label) !== null && _f !== void 0 ? _f : value;
|
|
655
|
+
const name = String(label || fallbackPrefix);
|
|
656
|
+
return {
|
|
657
|
+
name,
|
|
658
|
+
value,
|
|
659
|
+
description: typeof row.description === 'string' ? row.description : undefined,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function hasOptionRows(response) {
|
|
663
|
+
if (Array.isArray(response)) {
|
|
664
|
+
return true;
|
|
665
|
+
}
|
|
666
|
+
if (response && typeof response === 'object') {
|
|
667
|
+
const objectResponse = response;
|
|
668
|
+
return ['data', 'items', 'values'].some((key) => Array.isArray(objectResponse[key]));
|
|
669
|
+
}
|
|
670
|
+
return false;
|
|
671
|
+
}
|
|
672
|
+
function picklistOptionFromRow(row, fallbackPrefix, valueTransform) {
|
|
673
|
+
if (typeof row.value !== 'string' || row.value.trim() === '') {
|
|
674
|
+
return undefined;
|
|
675
|
+
}
|
|
676
|
+
const value = valueTransform === 'uppercase' ? row.value.toUpperCase() : row.value;
|
|
677
|
+
const label = typeof row.label === 'string' && row.label.trim() !== ''
|
|
678
|
+
? row.label
|
|
679
|
+
: enumOptionDisplayName(value);
|
|
680
|
+
const name = String(label || fallbackPrefix);
|
|
681
|
+
return {
|
|
682
|
+
name,
|
|
683
|
+
value,
|
|
684
|
+
description: typeof row.description === 'string' ? row.description : undefined,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
async function loadOptionsFromPath(context, path, fallbackPrefix) {
|
|
688
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, 0);
|
|
689
|
+
const response = await client.request('GET', path);
|
|
690
|
+
return extractOptionRows(response)
|
|
691
|
+
.map((row) => optionFromRow(row, fallbackPrefix))
|
|
692
|
+
.filter((option) => option.value !== '');
|
|
693
|
+
}
|
|
694
|
+
async function loadPicklistOptions(context, domain, fallbackPrefix, valueTransform) {
|
|
695
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, 0);
|
|
696
|
+
const response = await client.request('GET', `/picklists/${domain}`);
|
|
697
|
+
if (!hasOptionRows(response)) {
|
|
698
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `HustleOps picklist ${domain} response must be an array or contain a data, items, or values array.`);
|
|
699
|
+
}
|
|
700
|
+
return extractOptionRows(response)
|
|
701
|
+
.map((row) => picklistOptionFromRow(row, fallbackPrefix, valueTransform))
|
|
702
|
+
.filter((option) => option !== undefined);
|
|
703
|
+
}
|
|
704
|
+
async function executeTagOperation(context, itemIndex, operation, returnData) {
|
|
705
|
+
if (operation === 'list') {
|
|
706
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
707
|
+
const response = await client.request('GET', '/tags', undefined, {
|
|
708
|
+
withCounts: context.getNodeParameter('withCounts', itemIndex, false),
|
|
709
|
+
});
|
|
710
|
+
pushResponse(returnData, response, itemIndex);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (operation === 'delete') {
|
|
714
|
+
const tagId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('tagId', itemIndex), 'Tag ID');
|
|
715
|
+
const force = context.getNodeParameter('force', itemIndex, false);
|
|
716
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
717
|
+
const response = await client.request('DELETE', `/tags/${tagId}`, undefined, {
|
|
718
|
+
force: force ? true : undefined,
|
|
719
|
+
});
|
|
720
|
+
pushResponse(returnData, response, itemIndex);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
const body = buildTagPayload(context, itemIndex, operation);
|
|
724
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
725
|
+
if (operation === 'search') {
|
|
726
|
+
const response = await client.request('POST', '/tags/search', body);
|
|
727
|
+
pushPaginatedRows(returnData, response, 'Tag search response', itemIndex);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (operation === 'create') {
|
|
731
|
+
const response = await client.request('POST', '/tags', (0, tagDefinitions_1.sanitizeTagBody)(context, operation, body, itemIndex));
|
|
732
|
+
pushResponse(returnData, response, itemIndex);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (operation === 'updateColor') {
|
|
736
|
+
const tagId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('tagId', itemIndex), 'Tag ID');
|
|
737
|
+
const response = await client.request('PATCH', `/tags/${tagId}`, (0, tagDefinitions_1.sanitizeTagBody)(context, operation, body, itemIndex));
|
|
738
|
+
pushResponse(returnData, response, itemIndex);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
if (operation === 'bulkUpdateColor') {
|
|
742
|
+
const response = await client.request('PATCH', '/tags/bulk', (0, tagDefinitions_1.sanitizeTagBody)(context, operation, body, itemIndex));
|
|
743
|
+
pushResponse(returnData, response, itemIndex);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (operation === 'bulkDelete') {
|
|
747
|
+
const response = await client.request('POST', '/tags/bulk-delete', (0, tagDefinitions_1.sanitizeTagBody)(context, operation, body, itemIndex));
|
|
748
|
+
pushResponse(returnData, response, itemIndex);
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Unsupported Tag operation: ${operation}`, {
|
|
752
|
+
itemIndex,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
async function executeEntityTagOperation(context, itemIndex, resource, operation, returnData) {
|
|
756
|
+
const definition = (0, resourceDefinitions_1.getCoreResourceDefinition)(resource);
|
|
757
|
+
const entityId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('id', itemIndex), `${definition.displayName} ID`);
|
|
758
|
+
if (operation === 'removeTag') {
|
|
759
|
+
const tagId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('tagId', itemIndex), 'Tag ID');
|
|
760
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
761
|
+
const response = await client.request('DELETE', `${definition.path}/${entityId}/tags/${tagId}`);
|
|
762
|
+
pushResponse(returnData, response, itemIndex);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const body = buildEntityTagBody(context, itemIndex, resource, operation);
|
|
766
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
767
|
+
const response = await client.request(operation === 'setTags' ? 'PUT' : 'POST', `${definition.path}/${entityId}/tags`, body);
|
|
768
|
+
pushResponse(returnData, response, itemIndex);
|
|
769
|
+
}
|
|
770
|
+
async function executeCustomFieldOperation(context, itemIndex, operation, returnData) {
|
|
771
|
+
if (operation === 'listGroups') {
|
|
772
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
773
|
+
pushResponse(returnData, await client.request('GET', '/custom-fields/groups'), itemIndex);
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
if (operation === 'listDefinitions') {
|
|
777
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
778
|
+
pushResponse(returnData, await client.request('GET', '/custom-fields/definitions'), itemIndex);
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (operation === 'deleteGroup') {
|
|
782
|
+
const groupId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('customFieldGroupId', itemIndex), 'Custom field group ID');
|
|
783
|
+
const force = context.getNodeParameter('force', itemIndex, false);
|
|
784
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
785
|
+
const response = await client.request('DELETE', `/custom-fields/groups/${groupId}`, undefined, { force: force ? true : undefined });
|
|
786
|
+
pushResponse(returnData, response, itemIndex);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (operation === 'deleteDefinition') {
|
|
790
|
+
const definitionId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('customFieldDefinitionId', itemIndex), 'Custom field definition ID');
|
|
791
|
+
const force = context.getNodeParameter('force', itemIndex, false);
|
|
792
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
793
|
+
const response = await client.request('DELETE', `/custom-fields/definitions/${definitionId}`, undefined, { force: force ? true : undefined });
|
|
794
|
+
pushResponse(returnData, response, itemIndex);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
if (operation === 'getValues' || operation === 'getAvailable') {
|
|
798
|
+
const scope = (0, customFieldDefinitions_1.customFieldEntityScope)(context, {
|
|
799
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
800
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
801
|
+
}, itemIndex);
|
|
802
|
+
const pathPrefix = operation === 'getValues' ? '/custom-fields/values' : '/custom-fields/available';
|
|
803
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
804
|
+
const response = await client.request('GET', `${pathPrefix}/${scope.entityType}/${(0, GenericFunctions_1.safePathSegment)(scope.entityId, 'Custom field entity ID')}`);
|
|
805
|
+
pushResponse(returnData, response, itemIndex);
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
if (operation === 'batchGetValues') {
|
|
809
|
+
const body = buildCustomFieldBodyPayload(context, itemIndex, operation);
|
|
810
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
811
|
+
const response = await client.request('POST', '/custom-fields/values/batch', body);
|
|
812
|
+
pushResponse(returnData, response, itemIndex);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (operation === 'replaceValues' || operation === 'updateSelectedValuesSafely') {
|
|
816
|
+
const scope = (0, customFieldDefinitions_1.customFieldEntityScope)(context, {
|
|
817
|
+
entityType: context.getNodeParameter('entityType', itemIndex),
|
|
818
|
+
entityId: context.getNodeParameter('entityId', itemIndex),
|
|
819
|
+
}, itemIndex);
|
|
820
|
+
const selectedValues = (0, customFieldDefinitions_1.parseCustomFieldValues)(context, customFieldPayloadRows(context, itemIndex, operation), itemIndex);
|
|
821
|
+
if (operation === 'updateSelectedValuesSafely' && selectedValues.length === 0) {
|
|
822
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), 'Update Selected Values Safely requires at least one custom field value.', { itemIndex });
|
|
823
|
+
}
|
|
824
|
+
const path = `/custom-fields/values/${scope.entityType}/${(0, GenericFunctions_1.safePathSegment)(scope.entityId, 'Custom field entity ID')}`;
|
|
825
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
826
|
+
const values = operation === 'replaceValues'
|
|
827
|
+
? selectedValues
|
|
828
|
+
: (0, customFieldDefinitions_1.mergeCustomFieldValues)((0, customFieldDefinitions_1.extractAttachedCustomFieldValues)(await client.request('GET', path)), selectedValues);
|
|
829
|
+
const response = await client.request('PATCH', path, { values });
|
|
830
|
+
pushResponse(returnData, response, itemIndex);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const body = buildCustomFieldBodyPayload(context, itemIndex, operation);
|
|
834
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(context, itemIndex);
|
|
835
|
+
if (operation === 'searchDefinitions') {
|
|
836
|
+
pushPaginatedRows(returnData, await client.request('POST', '/custom-fields/definitions/search', body), 'Custom field definition search response', itemIndex);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
if (operation === 'createGroup') {
|
|
840
|
+
const response = await client.request('POST', '/custom-fields/groups', (0, customFieldDefinitions_1.sanitizeCustomFieldGroupBody)(context, body, true, itemIndex));
|
|
841
|
+
pushResponse(returnData, response, itemIndex);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (operation === 'updateGroup') {
|
|
845
|
+
const groupId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('customFieldGroupId', itemIndex), 'Custom field group ID');
|
|
846
|
+
const response = await client.request('PATCH', `/custom-fields/groups/${groupId}`, (0, customFieldDefinitions_1.sanitizeCustomFieldGroupBody)(context, body, false, itemIndex));
|
|
847
|
+
pushResponse(returnData, response, itemIndex);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (operation === 'createDefinition') {
|
|
851
|
+
const response = await client.request('POST', '/custom-fields/definitions', (0, customFieldDefinitions_1.sanitizeCustomFieldDefinitionBody)(context, body, 'create', itemIndex));
|
|
852
|
+
pushResponse(returnData, response, itemIndex);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (operation === 'updateDefinition') {
|
|
856
|
+
const definitionId = (0, GenericFunctions_1.safePathSegment)(context.getNodeParameter('customFieldDefinitionId', itemIndex), 'Custom field definition ID');
|
|
857
|
+
const response = await client.request('PATCH', `/custom-fields/definitions/${definitionId}`, (0, customFieldDefinitions_1.sanitizeCustomFieldDefinitionBody)(context, body, 'update', itemIndex));
|
|
858
|
+
pushResponse(returnData, response, itemIndex);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (operation === 'bulkUpdateDefinitions') {
|
|
862
|
+
const response = await client.request('PATCH', '/custom-fields/definitions/bulk', (0, customFieldDefinitions_1.sanitizeCustomFieldDefinitionBulkUpdate)(context, body, itemIndex));
|
|
863
|
+
pushResponse(returnData, response, itemIndex);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (operation === 'bulkDeleteDefinitions') {
|
|
867
|
+
const response = await client.request('POST', '/custom-fields/definitions/bulk-delete', (0, customFieldDefinitions_1.sanitizeCustomFieldDefinitionBulkDelete)(context, body, itemIndex));
|
|
868
|
+
pushResponse(returnData, response, itemIndex);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
throw new n8n_workflow_1.NodeOperationError(context.getNode(), `Unsupported Custom Field operation: ${operation}`, { itemIndex });
|
|
872
|
+
}
|
|
873
|
+
class HustleOps {
|
|
874
|
+
constructor() {
|
|
875
|
+
this.description = {
|
|
876
|
+
displayName: 'HustleOps',
|
|
877
|
+
name: 'hustleOps',
|
|
878
|
+
icon: { light: 'file:hustleops.svg', dark: 'file:hustleops.dark.svg' },
|
|
879
|
+
group: ['transform'],
|
|
880
|
+
version: [1],
|
|
881
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
882
|
+
description: LIVE_DESCRIPTION,
|
|
883
|
+
defaults: {
|
|
884
|
+
name: 'HustleOps',
|
|
885
|
+
},
|
|
886
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
887
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
888
|
+
usableAsTool: true,
|
|
889
|
+
credentials: [
|
|
890
|
+
{
|
|
891
|
+
name: 'hustleOpsApi',
|
|
892
|
+
required: true,
|
|
893
|
+
testedBy: 'hustleOps',
|
|
894
|
+
},
|
|
895
|
+
],
|
|
896
|
+
properties: [
|
|
897
|
+
{
|
|
898
|
+
displayName: 'Resource',
|
|
899
|
+
name: 'resource',
|
|
900
|
+
type: 'options',
|
|
901
|
+
noDataExpression: true,
|
|
902
|
+
default: 'incident',
|
|
903
|
+
options: HUSTLEOPS_RESOURCE_OPTIONS,
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
displayName: 'Operation',
|
|
907
|
+
name: 'operation',
|
|
908
|
+
type: 'options',
|
|
909
|
+
noDataExpression: true,
|
|
910
|
+
default: 'search',
|
|
911
|
+
options: CORE_OPERATION_OPTIONS,
|
|
912
|
+
displayOptions: {
|
|
913
|
+
show: {
|
|
914
|
+
resource: CORE_RESOURCE_VALUES,
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
displayName: 'Operation',
|
|
920
|
+
name: 'operation',
|
|
921
|
+
type: 'options',
|
|
922
|
+
noDataExpression: true,
|
|
923
|
+
default: 'list',
|
|
924
|
+
options: commentDefinitions_1.COMMENT_OPERATION_OPTIONS,
|
|
925
|
+
displayOptions: {
|
|
926
|
+
show: {
|
|
927
|
+
resource: ['comment'],
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
displayName: 'Operation',
|
|
933
|
+
name: 'operation',
|
|
934
|
+
type: 'options',
|
|
935
|
+
noDataExpression: true,
|
|
936
|
+
default: 'list',
|
|
937
|
+
options: tagDefinitions_1.TAG_OPERATION_OPTIONS,
|
|
938
|
+
displayOptions: {
|
|
939
|
+
show: {
|
|
940
|
+
resource: ['tag'],
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
displayName: 'Operation',
|
|
946
|
+
name: 'operation',
|
|
947
|
+
type: 'options',
|
|
948
|
+
noDataExpression: true,
|
|
949
|
+
default: 'listDefinitions',
|
|
950
|
+
options: customFieldDefinitions_1.CUSTOM_FIELD_OPERATION_OPTIONS,
|
|
951
|
+
displayOptions: {
|
|
952
|
+
show: {
|
|
953
|
+
resource: ['customField'],
|
|
954
|
+
},
|
|
955
|
+
},
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
displayName: 'ID',
|
|
959
|
+
name: 'id',
|
|
960
|
+
type: 'string',
|
|
961
|
+
default: '',
|
|
962
|
+
required: true,
|
|
963
|
+
description: 'HustleOps object ID',
|
|
964
|
+
displayOptions: {
|
|
965
|
+
show: {
|
|
966
|
+
resource: CORE_RESOURCE_VALUES,
|
|
967
|
+
operation: OPERATIONS_WITH_ID,
|
|
968
|
+
},
|
|
969
|
+
},
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
displayName: 'Input Mode',
|
|
973
|
+
name: payloadInputMode_1.PAYLOAD_INPUT_MODE_PARAMETER,
|
|
974
|
+
type: 'options',
|
|
975
|
+
default: payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS,
|
|
976
|
+
options: [...payloadInputMode_1.PAYLOAD_INPUT_MODE_OPTIONS],
|
|
977
|
+
displayOptions: (0, payloadInputMode_1.payloadModeDisplayOptions)([...CORE_RESOURCE_VALUES, 'comment', 'tag', 'customField'], PAYLOAD_OPERATION_VALUES),
|
|
978
|
+
},
|
|
979
|
+
...CORE_CREATE_REQUIRED_PROPERTIES,
|
|
980
|
+
...CORE_CREATE_ADDITIONAL_PROPERTIES,
|
|
981
|
+
...CORE_UPDATE_FIELD_PROPERTIES,
|
|
982
|
+
...PAYLOAD_JSON_OBJECT_PROPERTIES,
|
|
983
|
+
{
|
|
984
|
+
displayName: 'Filter',
|
|
985
|
+
name: 'payloadSearchFilter',
|
|
986
|
+
type: 'json',
|
|
987
|
+
default: '{}',
|
|
988
|
+
description: 'Optional search filter object. Leave {} to omit the filter.',
|
|
989
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
displayName: 'Page',
|
|
993
|
+
name: 'payloadSearchPage',
|
|
994
|
+
type: 'number',
|
|
995
|
+
typeOptions: {
|
|
996
|
+
minValue: 1,
|
|
997
|
+
},
|
|
998
|
+
default: 1,
|
|
999
|
+
description: 'Search result page to request',
|
|
1000
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
displayName: 'Page Size',
|
|
1004
|
+
name: 'payloadSearchPageSize',
|
|
1005
|
+
type: 'number',
|
|
1006
|
+
typeOptions: {
|
|
1007
|
+
minValue: 1,
|
|
1008
|
+
maxValue: 100,
|
|
1009
|
+
},
|
|
1010
|
+
default: 25,
|
|
1011
|
+
description: 'Number of search rows to request per page',
|
|
1012
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
displayName: 'Sort By',
|
|
1016
|
+
name: 'payloadSearchSortBy',
|
|
1017
|
+
type: 'string',
|
|
1018
|
+
default: '',
|
|
1019
|
+
description: 'Optional sort field. Leave empty to use the resource default.',
|
|
1020
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
displayName: 'Sort Order',
|
|
1024
|
+
name: 'payloadSearchSortOrder',
|
|
1025
|
+
type: 'options',
|
|
1026
|
+
default: '',
|
|
1027
|
+
options: [
|
|
1028
|
+
{
|
|
1029
|
+
name: 'Ascending',
|
|
1030
|
+
value: 'asc',
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
name: 'Default',
|
|
1034
|
+
value: '',
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
name: 'Descending',
|
|
1038
|
+
value: 'desc',
|
|
1039
|
+
},
|
|
1040
|
+
],
|
|
1041
|
+
description: 'Optional sort direction. Leave empty to use the resource default.',
|
|
1042
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
displayName: 'Exclude IDs',
|
|
1046
|
+
name: 'payloadSearchExcludeIds',
|
|
1047
|
+
type: 'json',
|
|
1048
|
+
default: '[]',
|
|
1049
|
+
description: 'Optional JSON array of entity UUIDs to exclude from search results',
|
|
1050
|
+
displayOptions: SEARCH_FIELD_DISPLAY_OPTIONS,
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
displayName: 'Return All',
|
|
1054
|
+
name: 'returnAll',
|
|
1055
|
+
type: 'boolean',
|
|
1056
|
+
default: false,
|
|
1057
|
+
description: 'Whether to return all results or only up to a given limit',
|
|
1058
|
+
displayOptions: {
|
|
1059
|
+
show: {
|
|
1060
|
+
resource: CORE_RESOURCE_VALUES,
|
|
1061
|
+
operation: ['search'],
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1065
|
+
{
|
|
1066
|
+
displayName: 'Max Items',
|
|
1067
|
+
name: 'maxItems',
|
|
1068
|
+
type: 'number',
|
|
1069
|
+
typeOptions: {
|
|
1070
|
+
minValue: 1,
|
|
1071
|
+
},
|
|
1072
|
+
default: 1000,
|
|
1073
|
+
description: 'Maximum number of search rows to return when Return All is enabled',
|
|
1074
|
+
displayOptions: {
|
|
1075
|
+
show: {
|
|
1076
|
+
resource: CORE_RESOURCE_VALUES,
|
|
1077
|
+
operation: ['search'],
|
|
1078
|
+
returnAll: [true],
|
|
1079
|
+
},
|
|
1080
|
+
},
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
displayName: 'Max Pages',
|
|
1084
|
+
name: 'maxPages',
|
|
1085
|
+
type: 'number',
|
|
1086
|
+
typeOptions: {
|
|
1087
|
+
minValue: 1,
|
|
1088
|
+
},
|
|
1089
|
+
default: 100,
|
|
1090
|
+
description: 'Maximum number of pages to fetch when Return All is enabled',
|
|
1091
|
+
displayOptions: {
|
|
1092
|
+
show: {
|
|
1093
|
+
resource: CORE_RESOURCE_VALUES,
|
|
1094
|
+
operation: ['search'],
|
|
1095
|
+
returnAll: [true],
|
|
1096
|
+
},
|
|
1097
|
+
},
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
displayName: 'Include Pagination Metadata',
|
|
1101
|
+
name: 'includePaginationMetadata',
|
|
1102
|
+
type: 'boolean',
|
|
1103
|
+
default: false,
|
|
1104
|
+
description: 'Whether Search should return the raw paginated response with data, total, page, pageSize, and totalPages instead of only data rows',
|
|
1105
|
+
displayOptions: {
|
|
1106
|
+
show: {
|
|
1107
|
+
resource: CORE_RESOURCE_VALUES,
|
|
1108
|
+
operation: ['search'],
|
|
1109
|
+
returnAll: [false],
|
|
1110
|
+
},
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
displayName: 'With Counts',
|
|
1115
|
+
name: 'withCounts',
|
|
1116
|
+
type: 'boolean',
|
|
1117
|
+
default: false,
|
|
1118
|
+
description: 'Whether to request tag usage counts. Counts require the HustleOps Admin role.',
|
|
1119
|
+
displayOptions: {
|
|
1120
|
+
show: {
|
|
1121
|
+
resource: ['tag'],
|
|
1122
|
+
operation: ['list'],
|
|
1123
|
+
},
|
|
1124
|
+
},
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
displayName: 'Tag Values',
|
|
1128
|
+
name: 'payloadEntityTagValues',
|
|
1129
|
+
type: 'json',
|
|
1130
|
+
default: '[]',
|
|
1131
|
+
description: 'JSON array of tag values. Set Tags accepts an empty array to clear all tags; Add Tags requires at least one value.',
|
|
1132
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(CORE_RESOURCE_VALUES, ['setTags', 'addTags'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
displayName: 'Tag Value',
|
|
1136
|
+
name: 'payloadTagValue',
|
|
1137
|
+
type: 'string',
|
|
1138
|
+
default: '',
|
|
1139
|
+
required: true,
|
|
1140
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['tag'], ['create'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
displayName: 'Tag Color',
|
|
1144
|
+
name: 'payloadTagColor',
|
|
1145
|
+
type: 'color',
|
|
1146
|
+
default: '',
|
|
1147
|
+
description: 'Optional tag color',
|
|
1148
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['tag'], ['create', 'updateColor', 'bulkUpdateColor'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
displayName: 'Tag IDs',
|
|
1152
|
+
name: 'payloadTagIds',
|
|
1153
|
+
type: 'json',
|
|
1154
|
+
default: '[]',
|
|
1155
|
+
description: 'JSON array of tag UUIDs',
|
|
1156
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['tag'], ['bulkUpdateColor', 'bulkDelete'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1157
|
+
},
|
|
1158
|
+
{
|
|
1159
|
+
displayName: 'Force',
|
|
1160
|
+
name: 'payloadTagForce',
|
|
1161
|
+
type: 'boolean',
|
|
1162
|
+
default: false,
|
|
1163
|
+
description: 'Whether to force bulk deletion',
|
|
1164
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['tag'], ['bulkDelete'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
displayName: 'Tag Name or ID',
|
|
1168
|
+
name: 'tagId',
|
|
1169
|
+
type: 'options',
|
|
1170
|
+
default: '',
|
|
1171
|
+
required: true,
|
|
1172
|
+
typeOptions: {
|
|
1173
|
+
loadOptionsMethod: 'getTagOptions',
|
|
1174
|
+
},
|
|
1175
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1176
|
+
displayOptions: {
|
|
1177
|
+
show: {
|
|
1178
|
+
resource: [...CORE_RESOURCE_VALUES, 'tag'],
|
|
1179
|
+
operation: ['updateColor', 'delete', 'removeTag'],
|
|
1180
|
+
},
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
displayName: 'Force',
|
|
1185
|
+
name: 'force',
|
|
1186
|
+
type: 'boolean',
|
|
1187
|
+
default: false,
|
|
1188
|
+
description: 'Whether to force deletion. Single deletes send force as a query parameter.',
|
|
1189
|
+
displayOptions: {
|
|
1190
|
+
show: {
|
|
1191
|
+
resource: ['tag', 'customField'],
|
|
1192
|
+
operation: ['delete', 'deleteGroup', 'deleteDefinition'],
|
|
1193
|
+
},
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
displayName: 'Custom Field Group Fields',
|
|
1198
|
+
name: 'payloadCustomFieldGroupFields',
|
|
1199
|
+
type: 'json',
|
|
1200
|
+
default: '{}',
|
|
1201
|
+
description: 'Custom field group fields as a JSON object',
|
|
1202
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['createGroup', 'updateGroup'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1203
|
+
},
|
|
1204
|
+
{
|
|
1205
|
+
displayName: 'Custom Field Definition Fields',
|
|
1206
|
+
name: 'payloadCustomFieldDefinitionFields',
|
|
1207
|
+
type: 'json',
|
|
1208
|
+
default: '{}',
|
|
1209
|
+
description: 'Custom field definition fields as a JSON object',
|
|
1210
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['createDefinition', 'updateDefinition'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
displayName: 'Custom Field Definition Bulk Fields',
|
|
1214
|
+
name: 'payloadCustomFieldDefinitionBulkFields',
|
|
1215
|
+
type: 'json',
|
|
1216
|
+
default: '{}',
|
|
1217
|
+
description: 'Custom field definition bulk update fields as a JSON object',
|
|
1218
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['bulkUpdateDefinitions'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
displayName: 'Custom Field Definition IDs',
|
|
1222
|
+
name: 'payloadCustomFieldDefinitionIds',
|
|
1223
|
+
type: 'json',
|
|
1224
|
+
default: '[]',
|
|
1225
|
+
description: 'JSON array of custom field definition UUIDs',
|
|
1226
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['bulkDeleteDefinitions'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
displayName: 'Force',
|
|
1230
|
+
name: 'payloadCustomFieldDefinitionForce',
|
|
1231
|
+
type: 'boolean',
|
|
1232
|
+
default: false,
|
|
1233
|
+
description: 'Whether to force bulk deletion of custom field definitions',
|
|
1234
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['bulkDeleteDefinitions'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
displayName: 'Custom Field Values',
|
|
1238
|
+
name: 'payloadCustomFieldValues',
|
|
1239
|
+
type: 'json',
|
|
1240
|
+
default: '[]',
|
|
1241
|
+
description: 'JSON array of { fieldId, value, fieldType? } objects. Array values are serialized as MULTI_SELECT JSON strings before sending.',
|
|
1242
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['replaceValues', 'updateSelectedValuesSafely'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
displayName: 'Entity IDs',
|
|
1246
|
+
name: 'payloadCustomFieldEntityIds',
|
|
1247
|
+
type: 'json',
|
|
1248
|
+
default: '[]',
|
|
1249
|
+
required: true,
|
|
1250
|
+
description: 'JSON array of up to 100 entity UUIDs for batch custom field values',
|
|
1251
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['customField'], ['batchGetValues'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1252
|
+
},
|
|
1253
|
+
{
|
|
1254
|
+
displayName: 'Custom Field Group ID',
|
|
1255
|
+
name: 'customFieldGroupId',
|
|
1256
|
+
type: 'string',
|
|
1257
|
+
default: '',
|
|
1258
|
+
required: true,
|
|
1259
|
+
description: 'Custom field group UUID',
|
|
1260
|
+
displayOptions: {
|
|
1261
|
+
show: {
|
|
1262
|
+
resource: ['customField'],
|
|
1263
|
+
operation: ['updateGroup', 'deleteGroup'],
|
|
1264
|
+
},
|
|
1265
|
+
},
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
displayName: 'Custom Field Definition Name or ID',
|
|
1269
|
+
name: 'customFieldDefinitionId',
|
|
1270
|
+
type: 'options',
|
|
1271
|
+
default: '',
|
|
1272
|
+
required: true,
|
|
1273
|
+
typeOptions: {
|
|
1274
|
+
loadOptionsMethod: 'getCustomFieldDefinitionOptions',
|
|
1275
|
+
},
|
|
1276
|
+
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
|
|
1277
|
+
displayOptions: {
|
|
1278
|
+
show: {
|
|
1279
|
+
resource: ['customField'],
|
|
1280
|
+
operation: ['updateDefinition', 'deleteDefinition'],
|
|
1281
|
+
},
|
|
1282
|
+
},
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
displayName: 'Entity Type',
|
|
1286
|
+
name: 'entityType',
|
|
1287
|
+
type: 'options',
|
|
1288
|
+
default: 'INCIDENT',
|
|
1289
|
+
required: true,
|
|
1290
|
+
description: 'Type of HustleOps entity for the comment or custom field operation',
|
|
1291
|
+
options: commentDefinitions_1.COMMENT_ENTITY_TYPE_OPTIONS,
|
|
1292
|
+
displayOptions: {
|
|
1293
|
+
show: {
|
|
1294
|
+
resource: ['comment', 'customField'],
|
|
1295
|
+
operation: [
|
|
1296
|
+
'list',
|
|
1297
|
+
'search',
|
|
1298
|
+
'unreadCount',
|
|
1299
|
+
'create',
|
|
1300
|
+
'markRead',
|
|
1301
|
+
'getValues',
|
|
1302
|
+
'getAvailable',
|
|
1303
|
+
'batchGetValues',
|
|
1304
|
+
'replaceValues',
|
|
1305
|
+
'updateSelectedValuesSafely',
|
|
1306
|
+
],
|
|
1307
|
+
},
|
|
1308
|
+
},
|
|
1309
|
+
},
|
|
1310
|
+
{
|
|
1311
|
+
displayName: 'Entity ID',
|
|
1312
|
+
name: 'entityId',
|
|
1313
|
+
type: 'string',
|
|
1314
|
+
default: '',
|
|
1315
|
+
required: true,
|
|
1316
|
+
description: 'HustleOps entity UUID for the comment or custom field operation',
|
|
1317
|
+
displayOptions: {
|
|
1318
|
+
show: {
|
|
1319
|
+
resource: ['comment', 'customField'],
|
|
1320
|
+
operation: [
|
|
1321
|
+
'list',
|
|
1322
|
+
'search',
|
|
1323
|
+
'unreadCount',
|
|
1324
|
+
'create',
|
|
1325
|
+
'markRead',
|
|
1326
|
+
'getValues',
|
|
1327
|
+
'getAvailable',
|
|
1328
|
+
'replaceValues',
|
|
1329
|
+
'updateSelectedValuesSafely',
|
|
1330
|
+
],
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
displayName: 'Comment ID',
|
|
1336
|
+
name: 'commentId',
|
|
1337
|
+
type: 'string',
|
|
1338
|
+
default: '',
|
|
1339
|
+
required: true,
|
|
1340
|
+
description: 'Comment UUID',
|
|
1341
|
+
displayOptions: {
|
|
1342
|
+
show: {
|
|
1343
|
+
resource: ['comment'],
|
|
1344
|
+
operation: ['update', 'delete', 'toggleReaction', 'togglePin'],
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
displayName: 'Take',
|
|
1350
|
+
name: 'take',
|
|
1351
|
+
type: 'number',
|
|
1352
|
+
typeOptions: {
|
|
1353
|
+
minValue: 1,
|
|
1354
|
+
maxValue: 100,
|
|
1355
|
+
},
|
|
1356
|
+
default: 50,
|
|
1357
|
+
description: 'Number of comments to request, from 1 to 100',
|
|
1358
|
+
displayOptions: {
|
|
1359
|
+
show: {
|
|
1360
|
+
resource: ['comment'],
|
|
1361
|
+
operation: ['list'],
|
|
1362
|
+
},
|
|
1363
|
+
},
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
displayName: 'Cursor',
|
|
1367
|
+
name: 'cursor',
|
|
1368
|
+
type: 'string',
|
|
1369
|
+
default: '',
|
|
1370
|
+
description: 'Optional comment UUID cursor returned as nextCursor by a previous list response',
|
|
1371
|
+
displayOptions: {
|
|
1372
|
+
show: {
|
|
1373
|
+
resource: ['comment'],
|
|
1374
|
+
operation: ['list'],
|
|
1375
|
+
},
|
|
1376
|
+
},
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
displayName: 'Search Query',
|
|
1380
|
+
name: 'q',
|
|
1381
|
+
type: 'string',
|
|
1382
|
+
default: '',
|
|
1383
|
+
required: true,
|
|
1384
|
+
description: 'Text to search for within the entity comment thread. Keep search text at or below 500 characters.',
|
|
1385
|
+
displayOptions: {
|
|
1386
|
+
show: {
|
|
1387
|
+
resource: ['comment'],
|
|
1388
|
+
operation: ['search'],
|
|
1389
|
+
},
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
{
|
|
1393
|
+
displayName: 'Max Results',
|
|
1394
|
+
name: 'maxResults',
|
|
1395
|
+
type: 'number',
|
|
1396
|
+
typeOptions: {
|
|
1397
|
+
minValue: 1,
|
|
1398
|
+
maxValue: 100,
|
|
1399
|
+
},
|
|
1400
|
+
default: 100,
|
|
1401
|
+
description: 'Maximum number of comment search results to emit',
|
|
1402
|
+
displayOptions: {
|
|
1403
|
+
show: {
|
|
1404
|
+
resource: ['comment'],
|
|
1405
|
+
operation: ['search'],
|
|
1406
|
+
},
|
|
1407
|
+
},
|
|
1408
|
+
},
|
|
1409
|
+
{
|
|
1410
|
+
displayName: 'Content',
|
|
1411
|
+
name: 'payloadCommentContent',
|
|
1412
|
+
type: 'string',
|
|
1413
|
+
default: '',
|
|
1414
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['comment'], ['create', 'update'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
displayName: 'Parent ID',
|
|
1418
|
+
name: 'payloadCommentParentId',
|
|
1419
|
+
type: 'string',
|
|
1420
|
+
default: '',
|
|
1421
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['comment'], ['create'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1422
|
+
},
|
|
1423
|
+
{
|
|
1424
|
+
displayName: 'Attachment IDs',
|
|
1425
|
+
name: 'payloadCommentAttachmentIds',
|
|
1426
|
+
type: 'json',
|
|
1427
|
+
default: '[]',
|
|
1428
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['comment'], ['create'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1429
|
+
},
|
|
1430
|
+
{
|
|
1431
|
+
displayName: 'Emoji',
|
|
1432
|
+
name: 'payloadCommentEmoji',
|
|
1433
|
+
type: 'string',
|
|
1434
|
+
default: '',
|
|
1435
|
+
displayOptions: (0, payloadInputMode_1.modeDisplayOptions)(['comment'], ['toggleReaction'], payloadInputMode_1.PAYLOAD_MODE_INDIVIDUAL_FIELDS),
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
displayName: 'Include Cursor Metadata',
|
|
1439
|
+
name: 'includeCommentPaginationMetadata',
|
|
1440
|
+
type: 'boolean',
|
|
1441
|
+
default: false,
|
|
1442
|
+
description: 'Whether List should return the raw response with items and nextCursor instead of one output item per comment',
|
|
1443
|
+
displayOptions: {
|
|
1444
|
+
show: {
|
|
1445
|
+
resource: ['comment'],
|
|
1446
|
+
operation: ['list'],
|
|
1447
|
+
},
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
],
|
|
1451
|
+
};
|
|
1452
|
+
this.methods = {
|
|
1453
|
+
credentialTest: {
|
|
1454
|
+
async hustleOps(credential) {
|
|
1455
|
+
var _a;
|
|
1456
|
+
try {
|
|
1457
|
+
await (0, GenericFunctions_1.testHustleOpsApiCredentials)(this, (_a = credential.data) !== null && _a !== void 0 ? _a : {});
|
|
1458
|
+
return {
|
|
1459
|
+
status: 'OK',
|
|
1460
|
+
message: 'HustleOps API credentials are valid.',
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
catch (error) {
|
|
1464
|
+
return {
|
|
1465
|
+
status: 'Error',
|
|
1466
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
},
|
|
1470
|
+
},
|
|
1471
|
+
loadOptions: {
|
|
1472
|
+
async getTagOptions() {
|
|
1473
|
+
return loadOptionsFromPath(this, '/tags', 'Tag');
|
|
1474
|
+
},
|
|
1475
|
+
async getCustomFieldDefinitionOptions() {
|
|
1476
|
+
return loadOptionsFromPath(this, '/custom-fields/definitions', 'Custom Field');
|
|
1477
|
+
},
|
|
1478
|
+
async getAlertTypeOptions() {
|
|
1479
|
+
return loadPicklistOptions(this, 'alertType', 'Alert Type');
|
|
1480
|
+
},
|
|
1481
|
+
async getAlertStatusOptions() {
|
|
1482
|
+
return loadPicklistOptions(this, 'alertStatus', 'Alert Status');
|
|
1483
|
+
},
|
|
1484
|
+
async getIncidentStatusOptions() {
|
|
1485
|
+
return loadPicklistOptions(this, 'incidentStatus', 'Incident Status');
|
|
1486
|
+
},
|
|
1487
|
+
async getIncidentCategoryOptions() {
|
|
1488
|
+
return loadPicklistOptions(this, 'incidentCategory', 'Incident Category');
|
|
1489
|
+
},
|
|
1490
|
+
async getObservableTypeOptions() {
|
|
1491
|
+
return loadPicklistOptions(this, 'observableType', 'Observable Type');
|
|
1492
|
+
},
|
|
1493
|
+
async getThreatLevelOptions() {
|
|
1494
|
+
return loadPicklistOptions(this, 'threatLevel', 'Threat Level', 'uppercase');
|
|
1495
|
+
},
|
|
1496
|
+
async getCriticalityOptions() {
|
|
1497
|
+
return loadPicklistOptions(this, 'criticality', 'Criticality', 'uppercase');
|
|
1498
|
+
},
|
|
1499
|
+
async getKnowledgeTypeOptions() {
|
|
1500
|
+
return loadPicklistOptions(this, 'knowledgeType', 'Knowledge Type');
|
|
1501
|
+
},
|
|
1502
|
+
},
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
async execute() {
|
|
1506
|
+
const items = this.getInputData();
|
|
1507
|
+
const returnData = [];
|
|
1508
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
1509
|
+
try {
|
|
1510
|
+
const resource = this.getNodeParameter('resource', itemIndex);
|
|
1511
|
+
const operation = this.getNodeParameter('operation', itemIndex);
|
|
1512
|
+
if (resource === 'comment') {
|
|
1513
|
+
await executeCommentOperation(this, itemIndex, operation, returnData);
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
if (resource === 'tag') {
|
|
1517
|
+
await executeTagOperation(this, itemIndex, operation, returnData);
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
if (resource === 'customField') {
|
|
1521
|
+
await executeCustomFieldOperation(this, itemIndex, operation, returnData);
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1524
|
+
if (operation === 'setTags' || operation === 'addTags' || operation === 'removeTag') {
|
|
1525
|
+
await executeEntityTagOperation(this, itemIndex, resource, operation, returnData);
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
const definition = (0, resourceDefinitions_1.getCoreResourceDefinition)(resource);
|
|
1529
|
+
const coreOperation = operation;
|
|
1530
|
+
if (coreOperation === 'get') {
|
|
1531
|
+
const id = this.getNodeParameter('id', itemIndex);
|
|
1532
|
+
const entityId = (0, GenericFunctions_1.safePathSegment)(id, `${definition.displayName} ID`);
|
|
1533
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(this, itemIndex);
|
|
1534
|
+
const response = await client.request('GET', `${definition.path}/${entityId}`);
|
|
1535
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (coreOperation === 'create') {
|
|
1539
|
+
const body = buildCoreDtoBody(this, itemIndex, definition, 'create');
|
|
1540
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(this, itemIndex);
|
|
1541
|
+
const response = await client.request('POST', definition.path, body);
|
|
1542
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
if (coreOperation === 'update') {
|
|
1546
|
+
const id = this.getNodeParameter('id', itemIndex);
|
|
1547
|
+
const entityId = (0, GenericFunctions_1.safePathSegment)(id, `${definition.displayName} ID`);
|
|
1548
|
+
const body = buildCoreDtoBody(this, itemIndex, definition, 'update');
|
|
1549
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(this, itemIndex);
|
|
1550
|
+
const response = await client.request('PATCH', `${definition.path}/${entityId}`, body);
|
|
1551
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
1552
|
+
continue;
|
|
1553
|
+
}
|
|
1554
|
+
const searchRequestBody = buildCoreSearchBody(this, itemIndex, definition, coreOperation);
|
|
1555
|
+
const client = await (0, GenericFunctions_1.createHustleOpsApiClient)(this, itemIndex);
|
|
1556
|
+
if (coreOperation === 'count') {
|
|
1557
|
+
const response = await client.request('POST', `${definition.path}/count`, searchRequestBody);
|
|
1558
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
const returnAll = this.getNodeParameter('returnAll', itemIndex, false);
|
|
1562
|
+
if (returnAll) {
|
|
1563
|
+
const maxItems = (0, GenericFunctions_1.parsePositiveInteger)(this, this.getNodeParameter('maxItems', itemIndex, 1000), 'Max Items', itemIndex);
|
|
1564
|
+
const maxPages = (0, GenericFunctions_1.parsePositiveInteger)(this, this.getNodeParameter('maxPages', itemIndex, 100), 'Max Pages', itemIndex);
|
|
1565
|
+
await client.requestEachPage(`${definition.path}/search`, searchRequestBody, { maxItems, maxPages }, (row) => returnData.push({ json: row, pairedItem: { item: itemIndex } }));
|
|
1566
|
+
continue;
|
|
1567
|
+
}
|
|
1568
|
+
const response = (0, GenericFunctions_1.assertPaginatedResponse)(await client.request('POST', `${definition.path}/search`, searchRequestBody), `${definition.displayName} search response`);
|
|
1569
|
+
const includePaginationMetadata = this.getNodeParameter('includePaginationMetadata', itemIndex, false);
|
|
1570
|
+
if (includePaginationMetadata) {
|
|
1571
|
+
returnData.push({ json: response, pairedItem: { item: itemIndex } });
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
for (const row of response.data) {
|
|
1575
|
+
returnData.push({ json: row, pairedItem: { item: itemIndex } });
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
catch (error) {
|
|
1579
|
+
const nodeError = error instanceof n8n_workflow_1.NodeOperationError
|
|
1580
|
+
? error
|
|
1581
|
+
: new n8n_workflow_1.NodeOperationError(this.getNode(), error instanceof Error ? error.message : String(error), { itemIndex });
|
|
1582
|
+
if (!this.continueOnFail()) {
|
|
1583
|
+
throw nodeError;
|
|
1584
|
+
}
|
|
1585
|
+
returnData.push({
|
|
1586
|
+
json: { error: nodeError.message },
|
|
1587
|
+
pairedItem: { item: itemIndex },
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
return [returnData];
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
exports.HustleOps = HustleOps;
|