@nyaruka/temba-components 0.156.3 → 0.156.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/CHANGELOG.md +21 -0
- package/dist/temba-components.js +918 -807
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/flow/CanvasNode.ts +102 -20
- package/src/flow/Editor.ts +529 -543
- package/src/flow/EditorToolbar.ts +566 -0
- package/src/flow/StickyNote.ts +29 -5
- package/src/flow/actions/set_contact_language.ts +4 -13
- package/src/flow/utils.ts +11 -0
- package/src/form/select/Select.ts +1 -0
- package/src/list/SortableList.ts +6 -0
- package/temba-modules.ts +2 -0
package/package.json
CHANGED
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { ACTION_GROUP_METADATA, SPLIT_GROUP_METADATA } from './types';
|
|
|
5
5
|
import { Action, Exit, Node, NodeUI, Router } from '../store/flow-definition';
|
|
6
6
|
import { property } from 'lit/decorators.js';
|
|
7
7
|
import { RapidElement } from '../RapidElement';
|
|
8
|
-
import { getClasses } from '../utils';
|
|
8
|
+
import { generateUUID, getClasses } from '../utils';
|
|
9
|
+
import { SortableList } from '../list/SortableList';
|
|
9
10
|
import { isRightClick, localizeAction, renderClamped } from './utils';
|
|
10
11
|
import { Plumber } from './Plumber';
|
|
11
12
|
import { getStore } from '../store/Store';
|
|
@@ -107,6 +108,26 @@ export class CanvasNode extends RapidElement {
|
|
|
107
108
|
user-select: none;
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
.shift-held > temba-flow-node,
|
|
112
|
+
.shift-held > temba-flow-node * {
|
|
113
|
+
cursor: copy !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.shift-held > temba-flow-node .exit,
|
|
117
|
+
.shift-held > temba-flow-node .exit *,
|
|
118
|
+
.shift-held > temba-flow-node .linked-name,
|
|
119
|
+
.shift-held > temba-flow-node .linked-name *,
|
|
120
|
+
.shift-held > temba-flow-node .remove-button,
|
|
121
|
+
.shift-held > temba-flow-node .remove-button * {
|
|
122
|
+
cursor: pointer !important;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
temba-flow-node.drag-copy .node {
|
|
126
|
+
outline: 3px dashed var(--color-primary, #3b82f6);
|
|
127
|
+
outline-offset: 2px;
|
|
128
|
+
opacity: 0.7;
|
|
129
|
+
}
|
|
130
|
+
|
|
110
131
|
/* Flow start indicator */
|
|
111
132
|
temba-flow-node.flow-start .node::before {
|
|
112
133
|
content: 'FLOW START';
|
|
@@ -574,6 +595,8 @@ export class CanvasNode extends RapidElement {
|
|
|
574
595
|
this.handleExternalActionDragLeave.bind(this);
|
|
575
596
|
this.handleActionShowGhost = this.handleActionShowGhost.bind(this);
|
|
576
597
|
this.handleActionHideGhost = this.handleActionHideGhost.bind(this);
|
|
598
|
+
this.handleActionShowOriginal = this.handleActionShowOriginal.bind(this);
|
|
599
|
+
this.handleActionHideOriginal = this.handleActionHideOriginal.bind(this);
|
|
577
600
|
}
|
|
578
601
|
|
|
579
602
|
connectedCallback() {
|
|
@@ -600,6 +623,14 @@ export class CanvasNode extends RapidElement {
|
|
|
600
623
|
'action-hide-ghost',
|
|
601
624
|
this.handleActionHideGhost as EventListener
|
|
602
625
|
);
|
|
626
|
+
this.addEventListener(
|
|
627
|
+
'action-show-original',
|
|
628
|
+
this.handleActionShowOriginal as EventListener
|
|
629
|
+
);
|
|
630
|
+
this.addEventListener(
|
|
631
|
+
'action-hide-original',
|
|
632
|
+
this.handleActionHideOriginal as EventListener
|
|
633
|
+
);
|
|
603
634
|
|
|
604
635
|
// Observe size changes to revalidate plumbing connections
|
|
605
636
|
this.resizeObserver = new ResizeObserver(() => {
|
|
@@ -711,6 +742,14 @@ export class CanvasNode extends RapidElement {
|
|
|
711
742
|
'action-hide-ghost',
|
|
712
743
|
this.handleActionHideGhost as EventListener
|
|
713
744
|
);
|
|
745
|
+
this.removeEventListener(
|
|
746
|
+
'action-show-original',
|
|
747
|
+
this.handleActionShowOriginal as EventListener
|
|
748
|
+
);
|
|
749
|
+
this.removeEventListener(
|
|
750
|
+
'action-hide-original',
|
|
751
|
+
this.handleActionHideOriginal as EventListener
|
|
752
|
+
);
|
|
714
753
|
|
|
715
754
|
// Clear any pending exit removal timeouts
|
|
716
755
|
this.exitRemovalTimeouts.forEach((timeoutId) => {
|
|
@@ -1531,11 +1570,32 @@ export class CanvasNode extends RapidElement {
|
|
|
1531
1570
|
}
|
|
1532
1571
|
}
|
|
1533
1572
|
|
|
1573
|
+
private handleActionShowOriginal(_event: CustomEvent): void {
|
|
1574
|
+
const sortableList = this.querySelector(
|
|
1575
|
+
'temba-sortable-list'
|
|
1576
|
+
) as SortableList;
|
|
1577
|
+
sortableList?.setOriginalVisible(true);
|
|
1578
|
+
this.showLastActionPlaceholder = false;
|
|
1579
|
+
this.requestUpdate();
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
private handleActionHideOriginal(_event: CustomEvent): void {
|
|
1583
|
+
const sortableList = this.querySelector(
|
|
1584
|
+
'temba-sortable-list'
|
|
1585
|
+
) as SortableList;
|
|
1586
|
+
sortableList?.setOriginalVisible(false);
|
|
1587
|
+
// Restore the placeholder if this is the last action
|
|
1588
|
+
if (this.node.actions.length === 1) {
|
|
1589
|
+
this.showLastActionPlaceholder = true;
|
|
1590
|
+
}
|
|
1591
|
+
this.requestUpdate();
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1534
1594
|
private handleExternalActionDrop(event: CustomEvent): void {
|
|
1535
1595
|
// Only handle if this is an execute_actions node
|
|
1536
1596
|
if (this.ui.type !== 'execute_actions') return;
|
|
1537
1597
|
|
|
1538
|
-
const { action, sourceNodeUuid, actionIndex } = event.detail;
|
|
1598
|
+
const { action, sourceNodeUuid, actionIndex, isCopy } = event.detail;
|
|
1539
1599
|
|
|
1540
1600
|
// Don't accept drops from the same node
|
|
1541
1601
|
if (sourceNodeUuid === this.node.uuid) return;
|
|
@@ -1561,30 +1621,52 @@ export class CanvasNode extends RapidElement {
|
|
|
1561
1621
|
|
|
1562
1622
|
// IMPORTANT: Add the action to this node FIRST, before removing from source
|
|
1563
1623
|
// This ensures we don't lose the action if the source node gets deleted
|
|
1624
|
+
const droppedAction = isCopy
|
|
1625
|
+
? { ...action, uuid: generateUUID() }
|
|
1626
|
+
: action;
|
|
1564
1627
|
const newActions = [...this.node.actions];
|
|
1565
|
-
newActions.splice(dropIndex, 0,
|
|
1628
|
+
newActions.splice(dropIndex, 0, droppedAction);
|
|
1566
1629
|
|
|
1567
1630
|
const updatedNode = { ...this.node, actions: newActions };
|
|
1568
1631
|
getStore()?.getState().updateNode(this.node.uuid, updatedNode);
|
|
1569
1632
|
|
|
1570
|
-
//
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1633
|
+
// Copy localizations from the original action to the new one
|
|
1634
|
+
if (isCopy) {
|
|
1635
|
+
const localization = flowDefinition.localization;
|
|
1636
|
+
if (localization) {
|
|
1637
|
+
for (const langCode of Object.keys(localization)) {
|
|
1638
|
+
const entry = localization[langCode]?.[action.uuid];
|
|
1639
|
+
if (entry) {
|
|
1640
|
+
store.getState().updateLocalization(
|
|
1641
|
+
langCode,
|
|
1642
|
+
droppedAction.uuid,
|
|
1643
|
+
JSON.parse(JSON.stringify(entry))
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1574
1649
|
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1650
|
+
if (!isCopy) {
|
|
1651
|
+
// Remove the action from the source node
|
|
1652
|
+
const updatedSourceActions = sourceNode.actions.filter(
|
|
1653
|
+
(_a, idx) => idx !== actionIndex
|
|
1654
|
+
);
|
|
1655
|
+
|
|
1656
|
+
// If source node has no actions left, remove it
|
|
1657
|
+
if (updatedSourceActions.length === 0) {
|
|
1658
|
+
// Fire event to Editor so it can clean up jsPlumb connections properly
|
|
1659
|
+
this.fireCustomEvent(CustomEventType.NodeDeleted, {
|
|
1660
|
+
uuid: sourceNodeUuid
|
|
1661
|
+
});
|
|
1662
|
+
} else {
|
|
1663
|
+
// Update source node
|
|
1664
|
+
const updatedSourceNode = {
|
|
1665
|
+
...sourceNode,
|
|
1666
|
+
actions: updatedSourceActions
|
|
1667
|
+
};
|
|
1668
|
+
getStore()?.getState().updateNode(sourceNodeUuid, updatedSourceNode);
|
|
1669
|
+
}
|
|
1588
1670
|
}
|
|
1589
1671
|
|
|
1590
1672
|
// Request update and notify that this node's size changed
|