@nyaruka/temba-components 0.141.1 → 0.142.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +849 -655
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +3 -1
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/display/Button.js +2 -2
- package/out-tsc/src/display/Button.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +24 -1
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +7 -2
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +654 -66
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +8 -5
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +40 -28
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +2 -1
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/reflow.js +393 -0
- package/out-tsc/src/flow/reflow.js.map +1 -0
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +18 -3
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/Compose.js +5 -0
- package/out-tsc/src/form/Compose.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +1 -3
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +2 -0
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +39 -19
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/test/temba-canvas-menu.test.js +44 -0
- package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
- package/out-tsc/test/temba-flow-collision.test.js +25 -0
- package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-zoom.test.js +491 -0
- package/out-tsc/test/temba-flow-editor-zoom.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor.test.js +145 -1
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-node-drag.test.js +123 -0
- package/out-tsc/test/temba-flow-node-drag.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +31 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-flow-reflow.test.js +472 -0
- package/out-tsc/test/temba-flow-reflow.test.js.map +1 -0
- package/out-tsc/test/temba-sortable-list.test.js +93 -0
- package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.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/set_contact_channel/editor/sms-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
- package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/editor/many-recipients.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dragging.png +0 -0
- package/screenshots/truth/modax/simple.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.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/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/src/Icons.ts +3 -1
- package/src/display/Button.ts +2 -2
- package/src/display/FloatingTab.ts +1 -1
- package/src/flow/CanvasMenu.ts +28 -3
- package/src/flow/CanvasNode.ts +7 -2
- package/src/flow/Editor.ts +755 -75
- package/src/flow/NodeEditor.ts +8 -4
- package/src/flow/Plumber.ts +65 -35
- package/src/flow/actions/send_msg.ts +2 -1
- package/src/flow/nodes/wait_for_response.ts +1 -1
- package/src/flow/reflow.ts +534 -0
- package/src/flow/types.ts +1 -0
- package/src/flow/utils.ts +19 -3
- package/src/form/Compose.ts +5 -0
- package/src/form/FieldRenderer.ts +1 -3
- package/src/layout/Dialog.ts +2 -0
- package/src/list/SortableList.ts +40 -19
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/expand-06.svg +1 -0
- package/static/svg/work/used/expand-06.svg +3 -0
- package/test/temba-canvas-menu.test.ts +55 -0
- package/test/temba-flow-collision.test.ts +31 -0
- package/test/temba-flow-editor-zoom.test.ts +583 -0
- package/test/temba-flow-editor.test.ts +187 -1
- package/test/temba-flow-node-drag.test.ts +171 -0
- package/test/temba-flow-plumber.test.ts +38 -0
- package/test/temba-flow-reflow.test.ts +703 -0
- package/test/temba-sortable-list.test.ts +120 -0
- package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
- package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
- package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
- package/screenshots/truth/compose/attachments-with-failures.png +0 -0
- package/screenshots/truth/compose/attachments-with-files-and-failures.png +0 -0
- package/screenshots/truth/contacts/tickets-assignment.png +0 -0
- package/screenshots/truth/contacts/tickets.png +0 -0
- package/screenshots/truth/flow/editor-basic.png +0 -0
- package/screenshots/truth/formfield/markdown-errors.png +0 -0
- package/screenshots/truth/formfield/no-errors.png +0 -0
- package/screenshots/truth/formfield/plain-text-errors.png +0 -0
- package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/enabled-multi-selection.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value.png +0 -0
- package/screenshots/truth/select/initial-value.png +0 -0
- package/screenshots/truth/select/multi-reorder-final.png +0 -0
- package/screenshots/truth/select/multi-reorder-initial.png +0 -0
- package/screenshots/truth/select/selected-multi-test.png +0 -0
- package/screenshots/truth/select/value-initial.png +0 -0
- package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
- package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
- package/screenshots/truth/webchat/connecting-state.png +0 -0
package/src/flow/NodeEditor.ts
CHANGED
|
@@ -221,7 +221,7 @@ export class NodeEditor extends RapidElement {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
.form-group-content {
|
|
224
|
-
padding: 6px;
|
|
224
|
+
padding: var(--group-content-padding, 6px);
|
|
225
225
|
display: flex;
|
|
226
226
|
flex-direction: column;
|
|
227
227
|
gap: 15px;
|
|
@@ -233,8 +233,8 @@ export class NodeEditor extends RapidElement {
|
|
|
233
233
|
|
|
234
234
|
.form-group-content.collapsed {
|
|
235
235
|
max-height: 0;
|
|
236
|
-
padding-top: 0;
|
|
237
|
-
padding-bottom: 0;
|
|
236
|
+
padding-top: 0 !important;
|
|
237
|
+
padding-bottom: 0 !important;
|
|
238
238
|
opacity: 0;
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -335,7 +335,7 @@ export class NodeEditor extends RapidElement {
|
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
.gutter-fields temba-select {
|
|
338
|
-
min-width:
|
|
338
|
+
min-width: 150px;
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
.optional-field-link {
|
|
@@ -1770,6 +1770,7 @@ export class NodeEditor extends RapidElement {
|
|
|
1770
1770
|
collapsible = false,
|
|
1771
1771
|
collapsed = false,
|
|
1772
1772
|
helpText,
|
|
1773
|
+
contentPadding,
|
|
1773
1774
|
getGroupValueCount
|
|
1774
1775
|
} = groupConfig;
|
|
1775
1776
|
|
|
@@ -1887,6 +1888,9 @@ export class NodeEditor extends RapidElement {
|
|
|
1887
1888
|
</div>
|
|
1888
1889
|
<div
|
|
1889
1890
|
class="form-group-content ${isCollapsed ? 'collapsed' : 'expanded'}"
|
|
1891
|
+
style="${contentPadding
|
|
1892
|
+
? `--group-content-padding: ${contentPadding}`
|
|
1893
|
+
: ''}"
|
|
1890
1894
|
>
|
|
1891
1895
|
${items.map((item) =>
|
|
1892
1896
|
this.renderLayoutItem(item, config, renderedFields)
|
package/src/flow/Plumber.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isRightClick } from './utils';
|
|
2
|
+
|
|
1
3
|
export type TargetFace = 'top' | 'left' | 'right';
|
|
2
4
|
|
|
3
5
|
// Shared arrow/drag constants used by both Plumber and Editor
|
|
@@ -196,6 +198,7 @@ export class Plumber {
|
|
|
196
198
|
private showContactsTimeout: number | null = null;
|
|
197
199
|
|
|
198
200
|
public connectionDragging = false;
|
|
201
|
+
public zoom = 1.0;
|
|
199
202
|
|
|
200
203
|
constructor(canvas: HTMLElement, editor: any) {
|
|
201
204
|
this.canvas = canvas;
|
|
@@ -246,7 +249,7 @@ export class Plumber {
|
|
|
246
249
|
const DRAG_THRESHOLD = 5;
|
|
247
250
|
|
|
248
251
|
const onMouseDown = (e: MouseEvent) => {
|
|
249
|
-
if (e
|
|
252
|
+
if (isRightClick(e)) return;
|
|
250
253
|
|
|
251
254
|
// Don't start drag from exit if it already has a connection —
|
|
252
255
|
// existing connections are picked up from the arrowhead instead
|
|
@@ -356,15 +359,17 @@ export class Plumber {
|
|
|
356
359
|
|
|
357
360
|
// --- Anchor point distribution ---
|
|
358
361
|
|
|
362
|
+
/** Convert a viewport-to-canvas rect difference to canvas coordinates */
|
|
363
|
+
private toCanvas(viewportDiff: number): number {
|
|
364
|
+
return viewportDiff / this.zoom;
|
|
365
|
+
}
|
|
366
|
+
|
|
359
367
|
private determineTargetFace(
|
|
360
368
|
sourceX: number,
|
|
361
369
|
sourceY: number,
|
|
362
|
-
|
|
363
|
-
|
|
370
|
+
targetCenterX: number,
|
|
371
|
+
targetTop: number
|
|
364
372
|
): TargetFace {
|
|
365
|
-
const targetCenterX =
|
|
366
|
-
targetRect.left + targetRect.width / 2 - canvasRect.left;
|
|
367
|
-
const targetTop = targetRect.top - canvasRect.top;
|
|
368
373
|
const verticalGap = targetTop - sourceY;
|
|
369
374
|
|
|
370
375
|
// Top face requires enough vertical room for the exit stub, entry stub,
|
|
@@ -396,14 +401,23 @@ export class Plumber {
|
|
|
396
401
|
|
|
397
402
|
if (fromRect.width === 0 || toRect.width === 0) return null;
|
|
398
403
|
|
|
399
|
-
|
|
400
|
-
const
|
|
404
|
+
// All coordinates are converted to canvas space by dividing by zoom
|
|
405
|
+
const sourceX = this.toCanvas(
|
|
406
|
+
fromRect.left + fromRect.width / 2 - canvasRect.left
|
|
407
|
+
);
|
|
408
|
+
const sourceY = this.toCanvas(fromRect.bottom - canvasRect.top);
|
|
409
|
+
|
|
410
|
+
// Pre-compute target canvas-space values for determineTargetFace
|
|
411
|
+
const toCenterX = this.toCanvas(
|
|
412
|
+
toRect.left + toRect.width / 2 - canvasRect.left
|
|
413
|
+
);
|
|
414
|
+
const toTopCanvas = this.toCanvas(toRect.top - canvasRect.top);
|
|
401
415
|
|
|
402
416
|
const targetFace = this.determineTargetFace(
|
|
403
417
|
sourceX,
|
|
404
418
|
sourceY,
|
|
405
|
-
|
|
406
|
-
|
|
419
|
+
toCenterX,
|
|
420
|
+
toTopCanvas
|
|
407
421
|
);
|
|
408
422
|
|
|
409
423
|
// Find all connections targeting the same node, grouped by face
|
|
@@ -417,14 +431,17 @@ export class Plumber {
|
|
|
417
431
|
const connFromEl = document.getElementById(conn.fromId);
|
|
418
432
|
if (connFromEl) {
|
|
419
433
|
const connFromRect = connFromEl.getBoundingClientRect();
|
|
420
|
-
const connSourceX =
|
|
421
|
-
connFromRect.left + connFromRect.width / 2 - canvasRect.left
|
|
422
|
-
|
|
434
|
+
const connSourceX = this.toCanvas(
|
|
435
|
+
connFromRect.left + connFromRect.width / 2 - canvasRect.left
|
|
436
|
+
);
|
|
437
|
+
const connSourceY = this.toCanvas(
|
|
438
|
+
connFromRect.bottom - canvasRect.top
|
|
439
|
+
);
|
|
423
440
|
const face = this.determineTargetFace(
|
|
424
441
|
connSourceX,
|
|
425
442
|
connSourceY,
|
|
426
|
-
|
|
427
|
-
|
|
443
|
+
toCenterX,
|
|
444
|
+
toTopCanvas
|
|
428
445
|
);
|
|
429
446
|
if (!faceConnections.has(face)) {
|
|
430
447
|
faceConnections.set(face, []);
|
|
@@ -451,11 +468,11 @@ export class Plumber {
|
|
|
451
468
|
const index = faceGroup.findIndex((e) => e.fromId === fromId);
|
|
452
469
|
const count = faceGroup.length;
|
|
453
470
|
|
|
454
|
-
// Calculate anchor point on the chosen face
|
|
455
|
-
const targetLeft = toRect.left - canvasRect.left;
|
|
456
|
-
const targetTop =
|
|
457
|
-
const targetW = toRect.width;
|
|
458
|
-
const targetH = toRect.height;
|
|
471
|
+
// Calculate anchor point on the chosen face (all in canvas space)
|
|
472
|
+
const targetLeft = this.toCanvas(toRect.left - canvasRect.left);
|
|
473
|
+
const targetTop = toTopCanvas;
|
|
474
|
+
const targetW = this.toCanvas(toRect.width);
|
|
475
|
+
const targetH = this.toCanvas(toRect.height);
|
|
459
476
|
|
|
460
477
|
let targetX: number;
|
|
461
478
|
let targetY: number;
|
|
@@ -504,18 +521,27 @@ export class Plumber {
|
|
|
504
521
|
if (connFromEl && connToEl) {
|
|
505
522
|
const connFromRect = connFromEl.getBoundingClientRect();
|
|
506
523
|
const connToRect = connToEl.getBoundingClientRect();
|
|
507
|
-
const connSourceX =
|
|
508
|
-
connFromRect.left + connFromRect.width / 2 - canvasRect.left
|
|
509
|
-
|
|
524
|
+
const connSourceX = this.toCanvas(
|
|
525
|
+
connFromRect.left + connFromRect.width / 2 - canvasRect.left
|
|
526
|
+
);
|
|
527
|
+
const connSourceY = this.toCanvas(
|
|
528
|
+
connFromRect.bottom - canvasRect.top
|
|
529
|
+
);
|
|
530
|
+
const connToCenterX = this.toCanvas(
|
|
531
|
+
connToRect.left + connToRect.width / 2 - canvasRect.left
|
|
532
|
+
);
|
|
533
|
+
const connToTop = this.toCanvas(connToRect.top - canvasRect.top);
|
|
510
534
|
const connFace = this.determineTargetFace(
|
|
511
535
|
connSourceX,
|
|
512
536
|
connSourceY,
|
|
513
|
-
|
|
514
|
-
|
|
537
|
+
connToCenterX,
|
|
538
|
+
connToTop
|
|
515
539
|
);
|
|
516
540
|
if (connFace === 'top') {
|
|
517
|
-
const connTargetLeft =
|
|
518
|
-
|
|
541
|
+
const connTargetLeft = this.toCanvas(
|
|
542
|
+
connToRect.left - canvasRect.left
|
|
543
|
+
);
|
|
544
|
+
const connTargetW = this.toCanvas(connToRect.width);
|
|
519
545
|
siblings.push({
|
|
520
546
|
fromId: conn.fromId,
|
|
521
547
|
targetX: connTargetLeft + connTargetW / 2
|
|
@@ -689,7 +715,7 @@ export class Plumber {
|
|
|
689
715
|
// Make arrowhead draggable for picking up existing connections
|
|
690
716
|
const DRAG_THRESHOLD = 5;
|
|
691
717
|
const onArrowMouseDown = (e: MouseEvent) => {
|
|
692
|
-
if (e
|
|
718
|
+
if (isRightClick(e)) return;
|
|
693
719
|
e.stopPropagation();
|
|
694
720
|
|
|
695
721
|
const startX = e.clientX;
|
|
@@ -1195,8 +1221,10 @@ export class Plumber {
|
|
|
1195
1221
|
|
|
1196
1222
|
const canvasRect = this.canvas.getBoundingClientRect();
|
|
1197
1223
|
const exitRect = exitEl.getBoundingClientRect();
|
|
1198
|
-
const sourceX =
|
|
1199
|
-
|
|
1224
|
+
const sourceX = this.toCanvas(
|
|
1225
|
+
exitRect.left + exitRect.width / 2 - canvasRect.left
|
|
1226
|
+
);
|
|
1227
|
+
const sourceY = this.toCanvas(exitRect.bottom - canvasRect.top);
|
|
1200
1228
|
|
|
1201
1229
|
const aw = ARROW_HALF_WIDTH;
|
|
1202
1230
|
const al = ARROW_LENGTH;
|
|
@@ -1252,16 +1280,18 @@ export class Plumber {
|
|
|
1252
1280
|
}
|
|
1253
1281
|
};
|
|
1254
1282
|
|
|
1255
|
-
// Initial path to cursor
|
|
1256
|
-
const cursorX = e.clientX - canvasRect.left;
|
|
1257
|
-
const cursorY = e.clientY - canvasRect.top;
|
|
1283
|
+
// Initial path to cursor (convert viewport to canvas coordinates)
|
|
1284
|
+
const cursorX = this.toCanvas(e.clientX - canvasRect.left);
|
|
1285
|
+
const cursorY = this.toCanvas(e.clientY - canvasRect.top);
|
|
1258
1286
|
updateDragPath(cursorX, cursorY);
|
|
1259
1287
|
|
|
1260
1288
|
this.connectionDragging = true;
|
|
1261
1289
|
|
|
1262
1290
|
const onMove = (me: MouseEvent) => {
|
|
1263
|
-
|
|
1264
|
-
const
|
|
1291
|
+
// Re-read canvasRect each move since scroll may have changed
|
|
1292
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
1293
|
+
const cx = this.toCanvas(me.clientX - rect.left);
|
|
1294
|
+
const cy = this.toCanvas(me.clientY - rect.top);
|
|
1265
1295
|
updateDragPath(cx, cy);
|
|
1266
1296
|
};
|
|
1267
1297
|
|
|
@@ -63,7 +63,6 @@ export const send_msg: ActionConfig = {
|
|
|
63
63
|
},
|
|
64
64
|
runtime_attachments: {
|
|
65
65
|
type: 'array',
|
|
66
|
-
helpText: 'Add dynamic attachments using expressions',
|
|
67
66
|
itemLabel: 'Attachment',
|
|
68
67
|
sortable: true,
|
|
69
68
|
maxItems: 10,
|
|
@@ -73,6 +72,7 @@ export const send_msg: ActionConfig = {
|
|
|
73
72
|
itemConfig: {
|
|
74
73
|
type: {
|
|
75
74
|
type: 'select',
|
|
75
|
+
width: '140px',
|
|
76
76
|
options: [
|
|
77
77
|
{ value: 'image', name: 'Image' },
|
|
78
78
|
{ value: 'audio', name: 'Audio' },
|
|
@@ -113,6 +113,7 @@ export const send_msg: ActionConfig = {
|
|
|
113
113
|
collapsible: true,
|
|
114
114
|
collapsed: true,
|
|
115
115
|
helpText: 'Add dynamic attachments that are evaluated at runtime',
|
|
116
|
+
contentPadding: '12px',
|
|
116
117
|
getGroupValueCount: (formData: FormData) => {
|
|
117
118
|
return (
|
|
118
119
|
formData.runtime_attachments?.filter(
|