@nyaruka/temba-components 0.142.0 → 0.142.2
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/CHANGELOG.md +18 -0
- package/dist/temba-components.js +825 -654
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +1 -0
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +30 -35
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +13 -8
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +18 -5
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +346 -10
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +2 -0
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +3 -1
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +2 -6
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/enter_flow.js +2 -2
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +2 -1
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +2 -6
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +2 -6
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +52 -35
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +4 -5
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -3
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +3 -3
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +2 -2
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +4 -5
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +3 -8
- package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +2 -2
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +25 -33
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -0
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +68 -0
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +17 -2
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +1 -1
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/utils.js +5 -12
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/test/nodes/split_by_run_result.test.js +1 -2
- package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
- package/out-tsc/test/temba-canvas-menu.test.js +13 -9
- package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
- package/out-tsc/test/temba-flow-reflow.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +9 -10
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-node-type-selector.test.js +3 -3
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +2 -2
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +2 -2
- package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
- package/screenshots/truth/canvas-menu/open.png +0 -0
- package/screenshots/truth/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/src/Icons.ts +1 -0
- package/src/flow/CanvasMenu.ts +38 -39
- package/src/flow/CanvasNode.ts +16 -8
- package/src/flow/Editor.ts +33 -6
- package/src/flow/NodeEditor.ts +373 -10
- package/src/flow/NodeTypeSelector.ts +2 -0
- package/src/flow/Plumber.ts +3 -1
- package/src/flow/actions/add_contact_urn.ts +5 -6
- package/src/flow/actions/enter_flow.ts +2 -2
- package/src/flow/actions/say_msg.ts +2 -1
- package/src/flow/actions/send_broadcast.ts +2 -6
- package/src/flow/actions/send_email.ts +2 -6
- package/src/flow/actions/send_msg.ts +56 -38
- package/src/flow/actions/set_contact_channel.ts +5 -1
- package/src/flow/actions/set_contact_field.ts +10 -5
- package/src/flow/actions/set_contact_language.ts +6 -3
- package/src/flow/actions/set_contact_name.ts +5 -1
- package/src/flow/actions/set_contact_status.ts +5 -1
- package/src/flow/actions/set_run_result.ts +6 -3
- package/src/flow/actions/start_session.ts +2 -2
- package/src/flow/nodes/split_by_llm.ts +5 -5
- package/src/flow/nodes/split_by_resthook.ts +3 -8
- package/src/flow/nodes/split_by_subflow.ts +2 -2
- package/src/flow/nodes/split_by_webhook.ts +26 -34
- package/src/flow/nodes/wait_for_response.ts +1 -0
- package/src/flow/types.ts +25 -2
- package/src/flow/utils.ts +81 -1
- package/src/form/FieldRenderer.ts +32 -3
- package/src/interfaces.ts +1 -0
- package/src/simulator/Simulator.ts +1 -1
- package/src/utils.ts +5 -12
- package/test/nodes/split_by_run_result.test.ts +1 -2
- package/test/temba-canvas-menu.test.ts +13 -9
- package/test/temba-flow-reflow.test.ts +4 -2
- package/test/temba-node-editor.test.ts +9 -10
- package/test/temba-node-type-selector.test.ts +3 -3
- package/test/temba-simulator.test.ts +2 -2
|
@@ -150,6 +150,25 @@ export class NodeEditor extends RapidElement {
|
|
|
150
150
|
overflow: hidden;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
.form-group.no-border {
|
|
154
|
+
border: none;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.form-group.no-border > .form-group-header {
|
|
158
|
+
background: none;
|
|
159
|
+
border-bottom: none;
|
|
160
|
+
padding-left: 11px; /* 1px border + 10px padding to align with bordered groups */
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.form-group.no-border > .form-group-header:hover {
|
|
164
|
+
background: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.form-group.no-border > .form-group-content {
|
|
168
|
+
padding-left: 0;
|
|
169
|
+
padding-right: 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
153
172
|
.form-group.has-errors {
|
|
154
173
|
border-color: var(--color-error, tomato);
|
|
155
174
|
}
|
|
@@ -314,6 +333,135 @@ export class NodeEditor extends RapidElement {
|
|
|
314
333
|
align-items: center;
|
|
315
334
|
}
|
|
316
335
|
|
|
336
|
+
/* Accordion styles */
|
|
337
|
+
.accordion {
|
|
338
|
+
border: 1px solid #e0e0e0;
|
|
339
|
+
border-radius: 6px;
|
|
340
|
+
overflow: hidden;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.accordion-section {
|
|
344
|
+
border-bottom: 1px solid #e0e0e0;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.accordion-section:last-child {
|
|
348
|
+
border-bottom: none;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.accordion-header {
|
|
352
|
+
display: flex;
|
|
353
|
+
align-items: center;
|
|
354
|
+
justify-content: space-between;
|
|
355
|
+
padding: 6px 10px;
|
|
356
|
+
cursor: pointer;
|
|
357
|
+
user-select: none;
|
|
358
|
+
background: #f8f9fa;
|
|
359
|
+
transition: background 0.15s ease;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.accordion-header:hover {
|
|
363
|
+
background: #f0f1f2;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.accordion-section.expanded > .accordion-header {
|
|
367
|
+
border-bottom: 1px solid #e0e0e0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.accordion-title {
|
|
371
|
+
font-weight: 500;
|
|
372
|
+
font-size: 13px;
|
|
373
|
+
color: var(--color-label, #777);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.accordion-toggle-container {
|
|
377
|
+
position: relative;
|
|
378
|
+
display: flex;
|
|
379
|
+
align-items: center;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.accordion-toggle-icon {
|
|
383
|
+
color: #999;
|
|
384
|
+
transition:
|
|
385
|
+
transform 0.2s ease,
|
|
386
|
+
opacity 0.3s ease;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.accordion-toggle-icon.expanded {
|
|
390
|
+
transform: rotate(90deg);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.accordion-toggle-icon.faded {
|
|
394
|
+
opacity: 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.accordion-count-bubble {
|
|
398
|
+
border-radius: 50%;
|
|
399
|
+
display: flex;
|
|
400
|
+
align-items: center;
|
|
401
|
+
justify-content: center;
|
|
402
|
+
font-size: 10px;
|
|
403
|
+
font-weight: 600;
|
|
404
|
+
padding: 3px;
|
|
405
|
+
min-width: 10px;
|
|
406
|
+
min-height: 10px;
|
|
407
|
+
position: absolute;
|
|
408
|
+
top: 50%;
|
|
409
|
+
left: 50%;
|
|
410
|
+
transform: translate(-50%, -50%);
|
|
411
|
+
line-height: 0px;
|
|
412
|
+
opacity: 1;
|
|
413
|
+
transition: opacity 0.3s ease;
|
|
414
|
+
background: var(--color-bubble-bg, #fff);
|
|
415
|
+
border: 1px solid var(--color-bubble-border, #777);
|
|
416
|
+
color: var(--color-bubble-text, #000);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.accordion-count-bubble.hidden {
|
|
420
|
+
opacity: 0;
|
|
421
|
+
pointer-events: none;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.accordion-checkmark-icon {
|
|
425
|
+
position: absolute;
|
|
426
|
+
top: 50%;
|
|
427
|
+
left: 50%;
|
|
428
|
+
transform: translate(-50%, -50%);
|
|
429
|
+
opacity: 1;
|
|
430
|
+
transition: opacity 0.3s ease;
|
|
431
|
+
border-radius: 50%;
|
|
432
|
+
color: var(--color-bubble-text, #000);
|
|
433
|
+
background: var(--color-bubble-bg, #fff);
|
|
434
|
+
border: 1px solid var(--color-bubble-border, #777);
|
|
435
|
+
padding: 0.15em;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.accordion-checkmark-icon.hidden {
|
|
439
|
+
opacity: 0;
|
|
440
|
+
pointer-events: none;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.accordion-content {
|
|
444
|
+
padding: 8px 10px;
|
|
445
|
+
display: flex;
|
|
446
|
+
flex-direction: column;
|
|
447
|
+
gap: 8px;
|
|
448
|
+
overflow: hidden;
|
|
449
|
+
transition: all 0.2s ease-in-out;
|
|
450
|
+
opacity: 1;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.accordion-content.collapsed {
|
|
454
|
+
max-height: 0;
|
|
455
|
+
padding-top: 0;
|
|
456
|
+
padding-bottom: 0;
|
|
457
|
+
opacity: 0;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.accordion-error-icon {
|
|
461
|
+
color: var(--color-error, tomato);
|
|
462
|
+
margin-right: 6px;
|
|
463
|
+
}
|
|
464
|
+
|
|
317
465
|
.gutter-fields {
|
|
318
466
|
display: flex;
|
|
319
467
|
flex-direction: column;
|
|
@@ -1041,14 +1189,20 @@ export class NodeEditor extends RapidElement {
|
|
|
1041
1189
|
if (typeof item === 'object' && item.type === 'group') {
|
|
1042
1190
|
const { label, collapsed, collapsible } = item;
|
|
1043
1191
|
// Only update if the group is collapsible and has a function-based collapsed property
|
|
1192
|
+
// Skip reveal groups that have been expanded — they are one-way
|
|
1044
1193
|
if (collapsible && typeof collapsed === 'function') {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1194
|
+
if (item.reveal && this.groupCollapseState[label] === false) {
|
|
1195
|
+
// Reveal group was manually expanded — don't re-collapse
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
const newCollapsedState = collapsed(this.formData);
|
|
1199
|
+
// Only update if the state has changed to avoid unnecessary re-renders
|
|
1200
|
+
if (this.groupCollapseState[label] !== newCollapsedState) {
|
|
1201
|
+
this.groupCollapseState = {
|
|
1202
|
+
...this.groupCollapseState,
|
|
1203
|
+
[label]: newCollapsedState
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1052
1206
|
}
|
|
1053
1207
|
}
|
|
1054
1208
|
// Recursively check nested items
|
|
@@ -1058,6 +1212,22 @@ export class NodeEditor extends RapidElement {
|
|
|
1058
1212
|
// Recursively check items in rows
|
|
1059
1213
|
this.updateGroupCollapseStatesRecursive(item.items);
|
|
1060
1214
|
}
|
|
1215
|
+
else if (typeof item === 'object' && item.type === 'accordion') {
|
|
1216
|
+
// Check each accordion section
|
|
1217
|
+
item.sections.forEach((section) => {
|
|
1218
|
+
const stateKey = `accordion:${section.label}`;
|
|
1219
|
+
if (typeof section.collapsed === 'function') {
|
|
1220
|
+
const newCollapsedState = section.collapsed(this.formData);
|
|
1221
|
+
if (this.groupCollapseState[stateKey] !== newCollapsedState) {
|
|
1222
|
+
this.groupCollapseState = {
|
|
1223
|
+
...this.groupCollapseState,
|
|
1224
|
+
[stateKey]: newCollapsedState
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
this.updateGroupCollapseStatesRecursive(section.items);
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1061
1231
|
});
|
|
1062
1232
|
}
|
|
1063
1233
|
updateComputedFields(changedFieldName) {
|
|
@@ -1242,6 +1412,10 @@ export class NodeEditor extends RapidElement {
|
|
|
1242
1412
|
const url = ((_b = (_a = picker.attachments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url) || '';
|
|
1243
1413
|
this.handleNewFieldChange(fieldName, url);
|
|
1244
1414
|
}
|
|
1415
|
+
else if (fieldName && config.type === 'template-editor') {
|
|
1416
|
+
// Special handling for template editor (manages template + template_variables)
|
|
1417
|
+
this.handleTemplateEditorChange(fieldName, e);
|
|
1418
|
+
}
|
|
1245
1419
|
else {
|
|
1246
1420
|
// Default handling for most field types
|
|
1247
1421
|
this.handleFormFieldChange(fieldName, e);
|
|
@@ -1250,7 +1424,8 @@ export class NodeEditor extends RapidElement {
|
|
|
1250
1424
|
showLabel: true,
|
|
1251
1425
|
formData: this.formData,
|
|
1252
1426
|
additionalData: {
|
|
1253
|
-
attachments: this.formData.attachments || []
|
|
1427
|
+
attachments: this.formData.attachments || [],
|
|
1428
|
+
template_variables: this.formData.template_variables || []
|
|
1254
1429
|
}
|
|
1255
1430
|
});
|
|
1256
1431
|
}
|
|
@@ -1298,6 +1473,20 @@ export class NodeEditor extends RapidElement {
|
|
|
1298
1473
|
// Recursively check items in rows
|
|
1299
1474
|
this.expandGroupsWithErrorsRecursive(item.items, errorFields);
|
|
1300
1475
|
}
|
|
1476
|
+
else if (typeof item === 'object' && item.type === 'accordion') {
|
|
1477
|
+
// Check each accordion section for errors
|
|
1478
|
+
item.sections.forEach((section) => {
|
|
1479
|
+
const fieldsInSection = this.collectFieldsFromItems(section.items);
|
|
1480
|
+
const sectionHasErrors = fieldsInSection.some((fieldName) => errorFields.has(fieldName));
|
|
1481
|
+
if (sectionHasErrors) {
|
|
1482
|
+
this.groupCollapseState = {
|
|
1483
|
+
...this.groupCollapseState,
|
|
1484
|
+
[`accordion:${section.label}`]: false
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
this.expandGroupsWithErrorsRecursive(section.items, errorFields);
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1301
1490
|
});
|
|
1302
1491
|
}
|
|
1303
1492
|
renderLayoutItem(item, config, renderedFields) {
|
|
@@ -1321,6 +1510,8 @@ export class NodeEditor extends RapidElement {
|
|
|
1321
1510
|
return this.renderRow(item, config, renderedFields);
|
|
1322
1511
|
case 'group':
|
|
1323
1512
|
return this.renderGroup(item, config, renderedFields);
|
|
1513
|
+
case 'accordion':
|
|
1514
|
+
return this.renderAccordion(item, config, renderedFields);
|
|
1324
1515
|
case 'spacer':
|
|
1325
1516
|
return html ``;
|
|
1326
1517
|
case 'text':
|
|
@@ -1416,7 +1607,7 @@ export class NodeEditor extends RapidElement {
|
|
|
1416
1607
|
}
|
|
1417
1608
|
renderGroup(groupConfig, config, renderedFields) {
|
|
1418
1609
|
var _a, _b;
|
|
1419
|
-
const { label, items, collapsible = false, collapsed = false, helpText, contentPadding, getGroupValueCount } = groupConfig;
|
|
1610
|
+
const { label, items, collapsible = false, collapsed = false, helpText, contentPadding, bordered = true, reveal = false, getGroupValueCount } = groupConfig;
|
|
1420
1611
|
// Initialize collapse state if not set
|
|
1421
1612
|
if (collapsible && !(label in this.groupCollapseState)) {
|
|
1422
1613
|
// Evaluate collapsed property - can be boolean or function
|
|
@@ -1429,6 +1620,10 @@ export class NodeEditor extends RapidElement {
|
|
|
1429
1620
|
const isCollapsed = collapsible
|
|
1430
1621
|
? (_a = this.groupCollapseState[label]) !== null && _a !== void 0 ? _a : (typeof collapsed === 'function' ? collapsed(this.formData) : collapsed)
|
|
1431
1622
|
: false;
|
|
1623
|
+
// Reveal mode: once expanded, render items directly without any group wrapper
|
|
1624
|
+
if (reveal && !isCollapsed) {
|
|
1625
|
+
return html `${items.map((item) => this.renderLayoutItem(item, config, renderedFields))}`;
|
|
1626
|
+
}
|
|
1432
1627
|
// Check if any field in this group has errors
|
|
1433
1628
|
const fieldsInGroup = this.collectFieldsFromItems(items);
|
|
1434
1629
|
const groupHasErrors = fieldsInGroup.some((fieldName) => this.errors[fieldName]);
|
|
@@ -1463,7 +1658,7 @@ export class NodeEditor extends RapidElement {
|
|
|
1463
1658
|
? 'has-errors'
|
|
1464
1659
|
: ''} ${isCollapsed ? 'collapsed' : 'expanded'} ${hasValue
|
|
1465
1660
|
? 'has-bubble'
|
|
1466
|
-
: ''}"
|
|
1661
|
+
: ''} ${!bordered ? 'no-border' : ''}"
|
|
1467
1662
|
>
|
|
1468
1663
|
<div
|
|
1469
1664
|
class="form-group-header ${collapsible ? 'clickable' : ''}"
|
|
@@ -1528,6 +1723,129 @@ export class NodeEditor extends RapidElement {
|
|
|
1528
1723
|
</div>
|
|
1529
1724
|
`;
|
|
1530
1725
|
}
|
|
1726
|
+
renderAccordion(accordionConfig, config, renderedFields) {
|
|
1727
|
+
const { sections, multi = false } = accordionConfig;
|
|
1728
|
+
return html `
|
|
1729
|
+
<div class="accordion">
|
|
1730
|
+
${sections.map((section) => {
|
|
1731
|
+
var _a, _b;
|
|
1732
|
+
const { label, collapsed = true, getValueCount } = section;
|
|
1733
|
+
const stateKey = `accordion:${label}`;
|
|
1734
|
+
// Initialize collapse state if not set
|
|
1735
|
+
if (!(stateKey in this.groupCollapseState)) {
|
|
1736
|
+
const initialCollapsed = typeof collapsed === 'function'
|
|
1737
|
+
? collapsed(this.formData)
|
|
1738
|
+
: collapsed;
|
|
1739
|
+
this.groupCollapseState = {
|
|
1740
|
+
...this.groupCollapseState,
|
|
1741
|
+
[stateKey]: initialCollapsed
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
const isCollapsed = (_a = this.groupCollapseState[stateKey]) !== null && _a !== void 0 ? _a : true;
|
|
1745
|
+
const isHovered = (_b = this.groupHoverState[stateKey]) !== null && _b !== void 0 ? _b : false;
|
|
1746
|
+
// Check for errors in this section
|
|
1747
|
+
const fieldsInSection = this.collectFieldsFromItems(section.items);
|
|
1748
|
+
const sectionHasErrors = fieldsInSection.some((fieldName) => this.errors[fieldName]);
|
|
1749
|
+
// Value count / checkmark display
|
|
1750
|
+
let valueCount = 0;
|
|
1751
|
+
let showBubble = false;
|
|
1752
|
+
let showCheckmark = false;
|
|
1753
|
+
let hasValue = false;
|
|
1754
|
+
if (getValueCount) {
|
|
1755
|
+
try {
|
|
1756
|
+
const result = getValueCount(this.formData);
|
|
1757
|
+
if (typeof result === 'boolean') {
|
|
1758
|
+
hasValue = result;
|
|
1759
|
+
showCheckmark = result && isCollapsed && !isHovered;
|
|
1760
|
+
}
|
|
1761
|
+
else if (typeof result === 'number') {
|
|
1762
|
+
valueCount = result;
|
|
1763
|
+
hasValue = valueCount > 0;
|
|
1764
|
+
showBubble = valueCount > 0 && isCollapsed && !isHovered;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
catch (error) {
|
|
1768
|
+
// ignore
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
return html `
|
|
1772
|
+
<div
|
|
1773
|
+
class="accordion-section ${isCollapsed
|
|
1774
|
+
? 'collapsed'
|
|
1775
|
+
: 'expanded'} ${hasValue ? 'has-value' : ''}"
|
|
1776
|
+
>
|
|
1777
|
+
<div
|
|
1778
|
+
class="accordion-header"
|
|
1779
|
+
@click=${() => this.handleAccordionToggle(stateKey, sections, multi)}
|
|
1780
|
+
@mouseenter=${() => this.handleGroupMouseEnter(stateKey)}
|
|
1781
|
+
@mouseleave=${() => this.handleGroupMouseLeave(stateKey)}
|
|
1782
|
+
>
|
|
1783
|
+
<div class="accordion-title">${label}</div>
|
|
1784
|
+
${sectionHasErrors
|
|
1785
|
+
? html `<temba-icon
|
|
1786
|
+
name="alert_warning"
|
|
1787
|
+
class="accordion-error-icon"
|
|
1788
|
+
size="1.2"
|
|
1789
|
+
></temba-icon>`
|
|
1790
|
+
: html `<div class="accordion-toggle-container">
|
|
1791
|
+
<temba-icon
|
|
1792
|
+
name="arrow_right"
|
|
1793
|
+
size="1.2"
|
|
1794
|
+
class="accordion-toggle-icon ${isCollapsed
|
|
1795
|
+
? 'collapsed'
|
|
1796
|
+
: 'expanded'} ${showBubble || showCheckmark
|
|
1797
|
+
? 'faded'
|
|
1798
|
+
: ''}"
|
|
1799
|
+
></temba-icon>
|
|
1800
|
+
${showCheckmark
|
|
1801
|
+
? html `<temba-icon
|
|
1802
|
+
name="check"
|
|
1803
|
+
size="0.8"
|
|
1804
|
+
class="accordion-checkmark-icon"
|
|
1805
|
+
></temba-icon>`
|
|
1806
|
+
: showBubble
|
|
1807
|
+
? html `<div
|
|
1808
|
+
class="accordion-count-bubble ${!showBubble
|
|
1809
|
+
? 'hidden'
|
|
1810
|
+
: ''}"
|
|
1811
|
+
>
|
|
1812
|
+
${valueCount}
|
|
1813
|
+
</div>`
|
|
1814
|
+
: ''}
|
|
1815
|
+
</div>`}
|
|
1816
|
+
</div>
|
|
1817
|
+
<div
|
|
1818
|
+
class="accordion-content ${isCollapsed ? 'collapsed' : 'expanded'}"
|
|
1819
|
+
>
|
|
1820
|
+
${section.items.map((item) => this.renderLayoutItem(item, config, renderedFields))}
|
|
1821
|
+
</div>
|
|
1822
|
+
</div>
|
|
1823
|
+
`;
|
|
1824
|
+
})}
|
|
1825
|
+
</div>
|
|
1826
|
+
`;
|
|
1827
|
+
}
|
|
1828
|
+
handleAccordionToggle(stateKey, sections, multi) {
|
|
1829
|
+
var _a;
|
|
1830
|
+
const isCurrentlyCollapsed = (_a = this.groupCollapseState[stateKey]) !== null && _a !== void 0 ? _a : true;
|
|
1831
|
+
if (multi) {
|
|
1832
|
+
// Multi mode: just toggle this section
|
|
1833
|
+
this.groupCollapseState = {
|
|
1834
|
+
...this.groupCollapseState,
|
|
1835
|
+
[stateKey]: !isCurrentlyCollapsed
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
else {
|
|
1839
|
+
// Single mode: collapse all other sections, toggle this one
|
|
1840
|
+
const newState = { ...this.groupCollapseState };
|
|
1841
|
+
sections.forEach((section) => {
|
|
1842
|
+
const key = `accordion:${section.label}`;
|
|
1843
|
+
newState[key] = true; // collapse all
|
|
1844
|
+
});
|
|
1845
|
+
newState[stateKey] = !isCurrentlyCollapsed; // toggle clicked
|
|
1846
|
+
this.groupCollapseState = newState;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1531
1849
|
collectFieldsFromItems(items) {
|
|
1532
1850
|
const fields = [];
|
|
1533
1851
|
items.forEach((item) => {
|
|
@@ -1543,6 +1861,11 @@ export class NodeEditor extends RapidElement {
|
|
|
1543
1861
|
else if (item.type === 'group') {
|
|
1544
1862
|
fields.push(...this.collectFieldsFromItems(item.items));
|
|
1545
1863
|
}
|
|
1864
|
+
else if (item.type === 'accordion') {
|
|
1865
|
+
item.sections.forEach((section) => {
|
|
1866
|
+
fields.push(...this.collectFieldsFromItems(section.items));
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1546
1869
|
});
|
|
1547
1870
|
return fields;
|
|
1548
1871
|
}
|
|
@@ -1570,6 +1893,19 @@ export class NodeEditor extends RapidElement {
|
|
|
1570
1893
|
// Trigger re-render
|
|
1571
1894
|
this.requestUpdate();
|
|
1572
1895
|
}
|
|
1896
|
+
handleTemplateEditorChange(fieldName, event) {
|
|
1897
|
+
const customEvent = event;
|
|
1898
|
+
const detail = customEvent.detail;
|
|
1899
|
+
this.formData = {
|
|
1900
|
+
...this.formData,
|
|
1901
|
+
[fieldName]: detail.template
|
|
1902
|
+
? { uuid: detail.template.uuid, name: detail.template.name }
|
|
1903
|
+
: null,
|
|
1904
|
+
template_variables: detail.variables || []
|
|
1905
|
+
};
|
|
1906
|
+
this.updateGroupCollapseStates();
|
|
1907
|
+
this.requestUpdate();
|
|
1908
|
+
}
|
|
1573
1909
|
handleMessageEditorChange(fieldName, event) {
|
|
1574
1910
|
const target = event.target;
|
|
1575
1911
|
// Update both text and attachments from the message editor
|