@nyaruka/temba-components 0.135.9 → 0.136.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/demo/components/webchat/example.html +4 -2
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +1351 -322
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +2 -1
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +2 -6
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +29 -1
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +229 -5
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +320 -1
- package/out-tsc/src/flow/Plumber.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/layout/FloatingWindow.js +30 -8
- package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +1861 -0
- package/out-tsc/src/simulator/Simulator.js.map +1 -0
- package/out-tsc/src/store/AppState.js +66 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/utils.js +48 -0
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-appstate-node-sorting.test.js +430 -0
- package/out-tsc/test/temba-appstate-node-sorting.test.js.map +1 -0
- package/out-tsc/test/temba-floating-tab.test.js +0 -9
- package/out-tsc/test/temba-floating-tab.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +262 -1
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js +3 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +3 -1
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +642 -0
- package/out-tsc/test/temba-simulator.test.js.map +1 -0
- package/out-tsc/test/utils.test.js +1 -1
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-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/floating-tab/gray.png +0 -0
- package/screenshots/truth/floating-tab/green.png +0 -0
- package/screenshots/truth/floating-tab/purple.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/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.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/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/screenshots/truth/simulator/after-message-sent.png +0 -0
- package/screenshots/truth/simulator/after-reset.png +0 -0
- package/screenshots/truth/simulator/attachment-menu.png +0 -0
- package/screenshots/truth/simulator/context-expanded.png +0 -0
- package/screenshots/truth/simulator/context-explorer-open.png +0 -0
- package/screenshots/truth/simulator/event-info.png +0 -0
- package/screenshots/truth/simulator/image-attachment.png +0 -0
- package/screenshots/truth/simulator/open-initial.png +0 -0
- package/screenshots/truth/simulator/quick-replies.png +0 -0
- package/src/Icons.ts +2 -1
- package/src/display/FloatingTab.ts +2 -7
- package/src/flow/CanvasNode.ts +30 -1
- package/src/flow/Editor.ts +246 -4
- package/src/flow/Plumber.ts +371 -2
- package/src/interfaces.ts +2 -1
- package/src/layout/FloatingWindow.ts +37 -12
- package/src/simulator/Simulator.ts +2061 -0
- package/src/store/AppState.ts +109 -0
- package/src/utils.ts +53 -0
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/route.svg +1 -0
- package/static/svg/work/used/route.svg +3 -0
- package/temba-modules.ts +2 -0
- package/test/temba-appstate-node-sorting.test.ts +506 -0
- package/test/temba-floating-tab.test.ts +0 -11
- package/test/temba-flow-editor.test.ts +298 -1
- package/test/temba-flow-plumber-connections.test.ts +4 -1
- package/test/temba-flow-plumber.test.ts +4 -1
- package/test/temba-simulator.test.ts +866 -0
- package/test/utils.test.ts +1 -1
|
@@ -169,6 +169,125 @@ export class Editor extends RapidElement {
|
|
|
169
169
|
z-index: 10;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/* Activity overlays on connections */
|
|
173
|
+
.jtk-overlay.activity-overlay {
|
|
174
|
+
background: #f3f3f3;
|
|
175
|
+
border: 1px solid #d9d9d9;
|
|
176
|
+
color: #333;
|
|
177
|
+
border-radius: 4px;
|
|
178
|
+
padding: 2px 4px;
|
|
179
|
+
font-size: 10px;
|
|
180
|
+
font-weight: 600;
|
|
181
|
+
line-height: 0.9;
|
|
182
|
+
cursor: pointer;
|
|
183
|
+
z-index: 500;
|
|
184
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Active contact count on nodes */
|
|
188
|
+
.active-count {
|
|
189
|
+
position: absolute;
|
|
190
|
+
background: #3498db;
|
|
191
|
+
border: 1px solid #2980b9;
|
|
192
|
+
border-radius: 12px;
|
|
193
|
+
padding: 3px 5px;
|
|
194
|
+
color: #fff;
|
|
195
|
+
font-weight: 500;
|
|
196
|
+
top: -10px;
|
|
197
|
+
left: -10px;
|
|
198
|
+
font-size: 13px;
|
|
199
|
+
min-width: 22px;
|
|
200
|
+
text-align: center;
|
|
201
|
+
z-index: 600;
|
|
202
|
+
line-height: 1;
|
|
203
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Recent contacts popup */
|
|
207
|
+
@keyframes popupBounceIn {
|
|
208
|
+
0% {
|
|
209
|
+
transform: scale(0.8);
|
|
210
|
+
opacity: 0;
|
|
211
|
+
}
|
|
212
|
+
50% {
|
|
213
|
+
transform: scale(1.05);
|
|
214
|
+
}
|
|
215
|
+
100% {
|
|
216
|
+
transform: scale(1);
|
|
217
|
+
opacity: 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.recent-contacts-popup {
|
|
222
|
+
display: none;
|
|
223
|
+
position: absolute;
|
|
224
|
+
width: 200px;
|
|
225
|
+
background: #f3f3f3;
|
|
226
|
+
border-radius: 10px;
|
|
227
|
+
box-shadow: 0 1px 3px 1px rgba(130, 130, 130, 0.2);
|
|
228
|
+
z-index: 1015;
|
|
229
|
+
transform-origin: top center;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.recent-contacts-popup.show {
|
|
233
|
+
display: block;
|
|
234
|
+
animation: popupBounceIn 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.recent-contacts-popup .popup-title {
|
|
238
|
+
background: #999;
|
|
239
|
+
color: #fff;
|
|
240
|
+
padding: 6px 0;
|
|
241
|
+
text-align: center;
|
|
242
|
+
border-top-left-radius: 10px;
|
|
243
|
+
border-top-right-radius: 10px;
|
|
244
|
+
font-size: 12px;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.recent-contacts-popup .no-contacts-message {
|
|
248
|
+
padding: 15px;
|
|
249
|
+
text-align: center;
|
|
250
|
+
color: #999;
|
|
251
|
+
font-size: 12px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.recent-contacts-popup .contact-row {
|
|
255
|
+
padding: 8px 10px;
|
|
256
|
+
border-top: 1px solid #e0e0e0;
|
|
257
|
+
text-align: left;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.recent-contacts-popup .contact-row:last-child {
|
|
261
|
+
border-bottom-left-radius: 10px;
|
|
262
|
+
border-bottom-right-radius: 10px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.recent-contacts-popup .contact-name {
|
|
266
|
+
display: block;
|
|
267
|
+
font-weight: 500;
|
|
268
|
+
font-size: 12px;
|
|
269
|
+
color: var(--color-link-primary, #1d4ed8);
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.recent-contacts-popup .contact-name:hover {
|
|
274
|
+
text-decoration: underline;
|
|
275
|
+
color: var(--color-link-primary, #1d4ed8);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.recent-contacts-popup .contact-operand {
|
|
279
|
+
padding-top: 3px;
|
|
280
|
+
font-size: 11px;
|
|
281
|
+
color: #666;
|
|
282
|
+
word-wrap: break-word;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.recent-contacts-popup .contact-time {
|
|
286
|
+
padding-top: 3px;
|
|
287
|
+
font-size: 10px;
|
|
288
|
+
color: #999;
|
|
289
|
+
}
|
|
290
|
+
|
|
172
291
|
/* Connection dragging feedback */
|
|
173
292
|
body svg.jtk-connector.jtk-dragging {
|
|
174
293
|
z-index: 99999 !important;
|
|
@@ -399,6 +518,8 @@ export class Editor extends RapidElement {
|
|
|
399
518
|
this.saveTimer = null;
|
|
400
519
|
this.flowType = 'message';
|
|
401
520
|
this.features = [];
|
|
521
|
+
this.activityTimer = null;
|
|
522
|
+
this.activityInterval = 100; // Start with 100ms interval for fast initial load
|
|
402
523
|
// Drag state
|
|
403
524
|
this.isDragging = false;
|
|
404
525
|
this.isMouseDown = false;
|
|
@@ -446,7 +567,7 @@ export class Editor extends RapidElement {
|
|
|
446
567
|
}
|
|
447
568
|
firstUpdated(changes) {
|
|
448
569
|
super.firstUpdated(changes);
|
|
449
|
-
this.plumber = new Plumber(this.querySelector('#canvas'));
|
|
570
|
+
this.plumber = new Plumber(this.querySelector('#canvas'), this);
|
|
450
571
|
this.setupGlobalEventListeners();
|
|
451
572
|
if (changes.has('flow')) {
|
|
452
573
|
getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
|
|
@@ -484,7 +605,7 @@ export class Editor extends RapidElement {
|
|
|
484
605
|
this.isValidTarget = true;
|
|
485
606
|
}
|
|
486
607
|
updated(changes) {
|
|
487
|
-
var _b, _c, _d;
|
|
608
|
+
var _b, _c, _d, _e;
|
|
488
609
|
super.updated(changes);
|
|
489
610
|
if (changes.has('canvasSize')) {
|
|
490
611
|
// console.log('Setting canvas size', this.canvasSize);
|
|
@@ -505,6 +626,27 @@ export class Editor extends RapidElement {
|
|
|
505
626
|
this.translationFilters = normalizedFilters;
|
|
506
627
|
}
|
|
507
628
|
this.translationCache.clear();
|
|
629
|
+
// Start fetching activity data when definition is loaded
|
|
630
|
+
if ((_e = this.definition) === null || _e === void 0 ? void 0 : _e.uuid) {
|
|
631
|
+
this.startActivityFetching();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (changes.has('simulatorActive')) {
|
|
635
|
+
if (this.simulatorActive) {
|
|
636
|
+
// Stop polling when simulator becomes active
|
|
637
|
+
this.stopActivityFetching();
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
// Resume polling and refresh activity when simulator closes
|
|
641
|
+
this.activityInterval = 100; // Reset to fast initial interval
|
|
642
|
+
this.startActivityFetching();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (changes.has('activityData')) {
|
|
646
|
+
// Update plumber with new activity data
|
|
647
|
+
if (this.plumber) {
|
|
648
|
+
this.plumber.setActivityData(this.activityData);
|
|
649
|
+
}
|
|
508
650
|
}
|
|
509
651
|
if (changes.has('dirtyDate')) {
|
|
510
652
|
if (this.dirtyDate) {
|
|
@@ -572,6 +714,46 @@ export class Editor extends RapidElement {
|
|
|
572
714
|
});
|
|
573
715
|
getStore().getState().setDirtyDate(null);
|
|
574
716
|
}
|
|
717
|
+
startActivityFetching() {
|
|
718
|
+
// Don't start if simulator is active
|
|
719
|
+
if (this.simulatorActive) {
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
// Fetch immediately
|
|
723
|
+
this.fetchActivityData();
|
|
724
|
+
}
|
|
725
|
+
stopActivityFetching() {
|
|
726
|
+
if (this.activityTimer !== null) {
|
|
727
|
+
clearTimeout(this.activityTimer);
|
|
728
|
+
this.activityTimer = null;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
fetchActivityData() {
|
|
732
|
+
var _b;
|
|
733
|
+
if (!((_b = this.definition) === null || _b === void 0 ? void 0 : _b.uuid)) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
// Don't fetch if simulator is active
|
|
737
|
+
if (this.simulatorActive) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const activityEndpoint = `/flow/activity/${this.definition.uuid}/`;
|
|
741
|
+
const store = getStore();
|
|
742
|
+
if (!store) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const state = store.getState();
|
|
746
|
+
state.fetchActivity(activityEndpoint).then(() => {
|
|
747
|
+
// Schedule next fetch with exponential backoff (max 5 minutes)
|
|
748
|
+
this.activityInterval = Math.min(60000 * 5, this.activityInterval + 100);
|
|
749
|
+
if (this.activityTimer !== null) {
|
|
750
|
+
clearTimeout(this.activityTimer);
|
|
751
|
+
}
|
|
752
|
+
this.activityTimer = window.setTimeout(() => {
|
|
753
|
+
this.fetchActivityData();
|
|
754
|
+
}, this.activityInterval);
|
|
755
|
+
});
|
|
756
|
+
}
|
|
575
757
|
handleLanguageChange(languageCode) {
|
|
576
758
|
zustand.getState().setLanguageCode(languageCode);
|
|
577
759
|
// Repaint connections after language change since node sizes can change
|
|
@@ -587,6 +769,10 @@ export class Editor extends RapidElement {
|
|
|
587
769
|
clearTimeout(this.saveTimer);
|
|
588
770
|
this.saveTimer = null;
|
|
589
771
|
}
|
|
772
|
+
if (this.activityTimer !== null) {
|
|
773
|
+
clearTimeout(this.activityTimer);
|
|
774
|
+
this.activityTimer = null;
|
|
775
|
+
}
|
|
590
776
|
document.removeEventListener('mousemove', this.boundMouseMove);
|
|
591
777
|
document.removeEventListener('mouseup', this.boundMouseUp);
|
|
592
778
|
document.removeEventListener('mousedown', this.boundGlobalMouseDown);
|
|
@@ -2100,7 +2286,7 @@ export class Editor extends RapidElement {
|
|
|
2100
2286
|
header="Translations"
|
|
2101
2287
|
.width=${360}
|
|
2102
2288
|
.maxHeight=${600}
|
|
2103
|
-
.top=${
|
|
2289
|
+
.top=${75}
|
|
2104
2290
|
color="#6b7280"
|
|
2105
2291
|
.hidden=${this.localizationWindowHidden}
|
|
2106
2292
|
@temba-dialog-hidden=${this.handleLocalizationWindowClosed}
|
|
@@ -2264,6 +2450,36 @@ export class Editor extends RapidElement {
|
|
|
2264
2450
|
></temba-floating-tab>
|
|
2265
2451
|
`;
|
|
2266
2452
|
}
|
|
2453
|
+
/**
|
|
2454
|
+
* Focus on a specific node by smoothly scrolling it to the center of the canvas
|
|
2455
|
+
*/
|
|
2456
|
+
focusNode(nodeUuid) {
|
|
2457
|
+
const nodeElement = this.querySelector(`temba-flow-node[uuid="${nodeUuid}"]`);
|
|
2458
|
+
if (!nodeElement) {
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
const editor = this.querySelector('#editor');
|
|
2462
|
+
if (!editor) {
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
// Get the editor's dimensions and scroll position
|
|
2466
|
+
const editorRect = editor.getBoundingClientRect();
|
|
2467
|
+
const editorCenterX = editorRect.width / 2;
|
|
2468
|
+
const editorCenterY = editorRect.height / 2;
|
|
2469
|
+
// Get node position relative to the editor's scroll container
|
|
2470
|
+
const nodeRect = nodeElement.getBoundingClientRect();
|
|
2471
|
+
const nodeCenterX = nodeElement.offsetLeft + nodeRect.width / 2;
|
|
2472
|
+
const nodeCenterY = nodeElement.offsetTop + nodeRect.height / 2;
|
|
2473
|
+
// Calculate the scroll position needed to center the node
|
|
2474
|
+
const targetScrollX = nodeCenterX - editorCenterX;
|
|
2475
|
+
const targetScrollY = nodeCenterY - editorCenterY;
|
|
2476
|
+
// Smooth scroll the editor container to the target position
|
|
2477
|
+
editor.scrollTo({
|
|
2478
|
+
left: Math.max(0, targetScrollX),
|
|
2479
|
+
top: Math.max(0, targetScrollY),
|
|
2480
|
+
behavior: 'smooth'
|
|
2481
|
+
});
|
|
2482
|
+
}
|
|
2267
2483
|
render() {
|
|
2268
2484
|
var _b, _c;
|
|
2269
2485
|
// we have to embed our own style since we are in light DOM
|
|
@@ -2282,7 +2498,7 @@ export class Editor extends RapidElement {
|
|
|
2282
2498
|
>
|
|
2283
2499
|
<div id="canvas">
|
|
2284
2500
|
${this.definition
|
|
2285
|
-
? repeat(this.definition.nodes, (node) => node.uuid, (node) => {
|
|
2501
|
+
? repeat(this.definition.nodes, (node) => node.uuid, (node, index) => {
|
|
2286
2502
|
var _b, _c, _d;
|
|
2287
2503
|
const position = ((_c = (_b = this.definition._ui) === null || _b === void 0 ? void 0 : _b.nodes[node.uuid]) === null || _c === void 0 ? void 0 : _c.position) || {
|
|
2288
2504
|
left: 0,
|
|
@@ -2291,10 +2507,12 @@ export class Editor extends RapidElement {
|
|
|
2291
2507
|
const dragging = this.isDragging &&
|
|
2292
2508
|
((_d = this.currentDragItem) === null || _d === void 0 ? void 0 : _d.uuid) === node.uuid;
|
|
2293
2509
|
const selected = this.selectedItems.has(node.uuid);
|
|
2510
|
+
// first node is the flow start (nodes are sorted by position)
|
|
2511
|
+
const isFlowStart = index === 0;
|
|
2294
2512
|
return html `<temba-flow-node
|
|
2295
2513
|
class="draggable ${dragging ? 'dragging' : ''} ${selected
|
|
2296
2514
|
? 'selected'
|
|
2297
|
-
: ''}"
|
|
2515
|
+
: ''} ${isFlowStart ? 'flow-start' : ''}"
|
|
2298
2516
|
@mousedown=${this.handleMouseDown.bind(this)}
|
|
2299
2517
|
uuid=${node.uuid}
|
|
2300
2518
|
data-node-uuid=${node.uuid}
|
|
@@ -2364,6 +2582,9 @@ __decorate([
|
|
|
2364
2582
|
__decorate([
|
|
2365
2583
|
fromStore(zustand, (state) => state.flowDefinition)
|
|
2366
2584
|
], Editor.prototype, "definition", void 0);
|
|
2585
|
+
__decorate([
|
|
2586
|
+
fromStore(zustand, (state) => state.simulatorActive)
|
|
2587
|
+
], Editor.prototype, "simulatorActive", void 0);
|
|
2367
2588
|
__decorate([
|
|
2368
2589
|
fromStore(zustand, (state) => state.canvasSize)
|
|
2369
2590
|
], Editor.prototype, "canvasSize", void 0);
|
|
@@ -2379,6 +2600,9 @@ __decorate([
|
|
|
2379
2600
|
__decorate([
|
|
2380
2601
|
fromStore(zustand, (state) => state.workspace)
|
|
2381
2602
|
], Editor.prototype, "workspace", void 0);
|
|
2603
|
+
__decorate([
|
|
2604
|
+
fromStore(zustand, (state) => state.getCurrentActivity())
|
|
2605
|
+
], Editor.prototype, "activityData", void 0);
|
|
2382
2606
|
__decorate([
|
|
2383
2607
|
state()
|
|
2384
2608
|
], Editor.prototype, "isDragging", void 0);
|