@nyaruka/temba-components 0.137.0 → 0.138.4
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/.devcontainer/Dockerfile +0 -9
- package/.devcontainer/devcontainer.json +8 -3
- package/.github/workflows/build.yml +6 -1
- package/.github/workflows/cla.yml +1 -1
- package/.github/workflows/publish.yml +6 -1
- package/CHANGELOG.md +42 -0
- package/dist/locales/es.js +5 -5
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +5 -5
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/locale-codes.js +11 -2
- package/dist/locales/locale-codes.js.map +1 -1
- package/dist/locales/pt.js +5 -5
- package/dist/locales/pt.js.map +1 -1
- package/dist/temba-components.js +445 -278
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +16 -8
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +33 -15
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +49 -24
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +583 -70
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +13 -11
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +110 -64
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +5 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/list/RunList.js +2 -1
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/list/TicketList.js +2 -1
- package/out-tsc/src/list/TicketList.js.map +1 -1
- package/out-tsc/src/locales/es.js +5 -5
- package/out-tsc/src/locales/es.js.map +1 -1
- package/out-tsc/src/locales/fr.js +5 -5
- package/out-tsc/src/locales/fr.js.map +1 -1
- package/out-tsc/src/locales/locale-codes.js +11 -2
- package/out-tsc/src/locales/locale-codes.js.map +1 -1
- package/out-tsc/src/locales/pt.js +5 -5
- package/out-tsc/src/locales/pt.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +11 -4
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +17 -2
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/test/temba-contact-fields.test.js +3 -3
- package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +3 -1
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-revisions.test.js +106 -0
- package/out-tsc/test/temba-flow-editor-revisions.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor.test.js +14 -10
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js +7 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +6 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +1 -0
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/package.json +1 -1
- 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/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.png +0 -0
- package/src/display/FloatingTab.ts +18 -8
- package/src/flow/CanvasMenu.ts +38 -16
- package/src/flow/CanvasNode.ts +62 -29
- package/src/flow/Editor.ts +699 -74
- package/src/flow/NodeTypeSelector.ts +13 -11
- package/src/flow/Plumber.ts +123 -69
- package/src/flow/actions/set_contact_field.ts +5 -1
- package/src/list/RunList.ts +2 -1
- package/src/list/TicketList.ts +2 -1
- package/src/locales/es.ts +18 -13
- package/src/locales/fr.ts +18 -13
- package/src/locales/locale-codes.ts +11 -2
- package/src/locales/pt.ts +18 -13
- package/src/simulator/Simulator.ts +11 -5
- package/src/store/AppState.ts +18 -2
- package/test/temba-contact-fields.test.ts +8 -3
- package/test/temba-flow-editor-node.test.ts +3 -1
- package/test/temba-flow-editor-revisions.test.ts +134 -0
- package/test/temba-flow-editor.test.ts +16 -10
- package/test/temba-flow-plumber-connections.test.ts +7 -1
- package/test/temba-flow-plumber.test.ts +6 -0
- package/test/temba-select.test.ts +1 -0
|
@@ -172,12 +172,13 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
172
172
|
|
|
173
173
|
.items-grid {
|
|
174
174
|
display: grid;
|
|
175
|
-
grid-template-columns: repeat(auto-fill, minmax(
|
|
175
|
+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
176
176
|
gap: 0.75em;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
.node-item {
|
|
180
|
-
padding:
|
|
180
|
+
padding: 0.5em;
|
|
181
|
+
padding-left: 1em;
|
|
181
182
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
182
183
|
border-radius: calc(var(--curvature) * 0.75);
|
|
183
184
|
cursor: pointer;
|
|
@@ -211,7 +212,6 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
211
212
|
font-weight: 500;
|
|
212
213
|
font-size: 1rem;
|
|
213
214
|
color: var(--color-text-dark);
|
|
214
|
-
margin-bottom: 0.25em;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
.node-item-type {
|
|
@@ -259,8 +259,14 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
259
259
|
this.open = true;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
public close() {
|
|
263
|
-
this.open
|
|
262
|
+
public close(fireCanceledEvent: boolean = true) {
|
|
263
|
+
if (this.open) {
|
|
264
|
+
this.open = false;
|
|
265
|
+
// Fire canceled event so parent can clean up, but only if not from a selection
|
|
266
|
+
if (fireCanceledEvent) {
|
|
267
|
+
this.fireCustomEvent(CustomEventType.Canceled, {});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
264
270
|
}
|
|
265
271
|
|
|
266
272
|
/**
|
|
@@ -297,7 +303,8 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
297
303
|
nodeType,
|
|
298
304
|
position: this.clickPosition
|
|
299
305
|
} as NodeTypeSelection);
|
|
300
|
-
|
|
306
|
+
// Close without firing canceled event since we made a selection
|
|
307
|
+
this.close(false);
|
|
301
308
|
}
|
|
302
309
|
|
|
303
310
|
private handleOverlayClick() {
|
|
@@ -549,7 +556,6 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
549
556
|
<div class="node-item-title">
|
|
550
557
|
${item.config.name}
|
|
551
558
|
</div>
|
|
552
|
-
<div class="node-item-type">${item.type}</div>
|
|
553
559
|
</div>
|
|
554
560
|
`
|
|
555
561
|
)}
|
|
@@ -587,9 +593,6 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
587
593
|
<div class="node-item-title">
|
|
588
594
|
${item.config.name}
|
|
589
595
|
</div>
|
|
590
|
-
<div class="node-item-type">
|
|
591
|
-
${item.type}
|
|
592
|
-
</div>
|
|
593
596
|
</div>
|
|
594
597
|
`
|
|
595
598
|
)}
|
|
@@ -622,7 +625,6 @@ export class NodeTypeSelector extends RapidElement {
|
|
|
622
625
|
<div class="node-item-title">
|
|
623
626
|
${item.config.name}
|
|
624
627
|
</div>
|
|
625
|
-
<div class="node-item-type">${item.type}</div>
|
|
626
628
|
</div>
|
|
627
629
|
`
|
|
628
630
|
)}
|
package/src/flow/Plumber.ts
CHANGED
|
@@ -89,50 +89,54 @@ export class Plumber {
|
|
|
89
89
|
private showContactsTimeout: number | null = null;
|
|
90
90
|
private editor: any;
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
this.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
connectionOverlays: OVERLAYS_DEFAULTS
|
|
103
|
-
});
|
|
92
|
+
initializeJSPlumb(canvas: HTMLElement) {
|
|
93
|
+
this.jsPlumb = newInstance({
|
|
94
|
+
container: canvas,
|
|
95
|
+
connectionsDetachable: true,
|
|
96
|
+
endpointStyle: {
|
|
97
|
+
fill: 'green'
|
|
98
|
+
},
|
|
99
|
+
connector: CONNECTOR_DEFAULTS,
|
|
100
|
+
connectionOverlays: OVERLAYS_DEFAULTS
|
|
101
|
+
});
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
// Bind to connection events
|
|
104
|
+
this.jsPlumb.bind(EVENT_CONNECTION, (info) => {
|
|
105
|
+
this.connectionDragging = false;
|
|
106
|
+
this.notifyListeners(EVENT_CONNECTION, info);
|
|
107
|
+
});
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
// Bind to connection drag events
|
|
110
|
+
this.jsPlumb.bind(EVENT_CONNECTION_DRAG, (info) => {
|
|
111
|
+
this.connectionDragging = true;
|
|
112
|
+
this.notifyListeners(EVENT_CONNECTION_DRAG, info);
|
|
113
|
+
});
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
this.jsPlumb.bind(EVENT_CONNECTION_ABORT, (info) => {
|
|
116
|
+
this.connectionDragging = false;
|
|
117
|
+
this.notifyListeners(EVENT_CONNECTION_ABORT, info);
|
|
118
|
+
});
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
this.jsPlumb.bind(EVENT_CONNECTION_DETACHED, (info) => {
|
|
121
|
+
this.connectionDragging = false;
|
|
122
|
+
this.notifyListeners(EVENT_CONNECTION_DETACHED, info);
|
|
123
|
+
});
|
|
126
124
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
this.jsPlumb.bind(EVENT_REVERT, (info) => {
|
|
126
|
+
this.notifyListeners(EVENT_REVERT, info);
|
|
127
|
+
});
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
this.jsPlumb.bind(INTERCEPT_BEFORE_DROP, () => {
|
|
130
|
+
// we always deny automatic connections
|
|
131
|
+
return false;
|
|
132
|
+
});
|
|
133
|
+
this.jsPlumb.bind(INTERCEPT_BEFORE_DETACH, () => {});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
constructor(canvas: HTMLElement, editor: any) {
|
|
137
|
+
this.editor = editor;
|
|
138
|
+
ready(() => {
|
|
139
|
+
this.initializeJSPlumb(canvas);
|
|
136
140
|
});
|
|
137
141
|
}
|
|
138
142
|
|
|
@@ -159,12 +163,14 @@ export class Plumber {
|
|
|
159
163
|
|
|
160
164
|
public makeTarget(uuid: string) {
|
|
161
165
|
const element = document.getElementById(uuid);
|
|
162
|
-
|
|
166
|
+
if (!element) return;
|
|
167
|
+
return this.jsPlumb.addEndpoint(element, TARGET_DEFAULTS);
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
public makeSource(uuid: string) {
|
|
166
171
|
const element = document.getElementById(uuid);
|
|
167
|
-
|
|
172
|
+
if (!element) return;
|
|
173
|
+
return this.jsPlumb.addEndpoint(element, SOURCE_DEFAULTS);
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
// we'll process our pending connections, but we want to debounce this
|
|
@@ -180,27 +186,40 @@ export class Plumber {
|
|
|
180
186
|
this.jsPlumb.batch(() => {
|
|
181
187
|
this.pendingConnections.forEach((connection) => {
|
|
182
188
|
const { scope, fromId, toId } = connection;
|
|
183
|
-
const fromElement = document.getElementById(fromId);
|
|
184
|
-
const toElement = document.getElementById(toId);
|
|
185
|
-
|
|
186
|
-
// delete any existing endpoints
|
|
187
|
-
this.jsPlumb.selectEndpoints({ source: fromId }).deleteAll();
|
|
188
|
-
|
|
189
|
-
const source = this.jsPlumb.addEndpoint(fromElement, {
|
|
190
|
-
...SOURCE_DEFAULTS,
|
|
191
|
-
endpoint: {
|
|
192
|
-
...SOURCE_DEFAULTS.endpoint,
|
|
193
|
-
options: {
|
|
194
|
-
...SOURCE_DEFAULTS.endpoint.options,
|
|
195
|
-
cssClass: 'plumb-source connected'
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
189
|
|
|
200
|
-
|
|
190
|
+
// sources and targets must exist
|
|
191
|
+
const source = document.getElementById(fromId);
|
|
192
|
+
// const target = document.getElementById(toId);
|
|
193
|
+
|
|
194
|
+
this.revalidate([fromId, toId]);
|
|
195
|
+
|
|
196
|
+
// we need to find the source endpoint
|
|
197
|
+
const sourceEndpoint = this.jsPlumb
|
|
198
|
+
.getEndpoints(source)
|
|
199
|
+
?.find((endpoint) =>
|
|
200
|
+
endpoint.elementId === fromId ? true : false
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// update endpoint have connect css class
|
|
204
|
+
if (sourceEndpoint) {
|
|
205
|
+
sourceEndpoint.addClass('connected');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// each connection needs its own target endpoint
|
|
209
|
+
const targetEndpoint = this.makeTarget(toId);
|
|
210
|
+
|
|
211
|
+
if (!source || !targetEndpoint) {
|
|
212
|
+
console.warn(
|
|
213
|
+
`Plumber: Cannot connect ${fromId} to ${toId}. Element(s) missing.`
|
|
214
|
+
);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// delete connections
|
|
219
|
+
this.jsPlumb.select({ source, targetEndpoint }).deleteAll();
|
|
201
220
|
this.jsPlumb.connect({
|
|
202
|
-
source,
|
|
203
|
-
target,
|
|
221
|
+
source: source,
|
|
222
|
+
target: targetEndpoint,
|
|
204
223
|
connector: {
|
|
205
224
|
...CONNECTOR_DEFAULTS,
|
|
206
225
|
options: { ...CONNECTOR_DEFAULTS.options, gap: [0, 5] }
|
|
@@ -212,7 +231,15 @@ export class Plumber {
|
|
|
212
231
|
});
|
|
213
232
|
this.pendingConnections = [];
|
|
214
233
|
});
|
|
215
|
-
|
|
234
|
+
|
|
235
|
+
// Force a repaint to ensure connections are positioned correctly
|
|
236
|
+
// especially after bulk updates or view switching
|
|
237
|
+
window.requestAnimationFrame(() => {
|
|
238
|
+
if (this.jsPlumb) {
|
|
239
|
+
this.jsPlumb.repaintEverything();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}, 0);
|
|
216
243
|
}
|
|
217
244
|
|
|
218
245
|
public connectIds(scope: string, fromId: string, toId: string) {
|
|
@@ -597,20 +624,44 @@ export class Plumber {
|
|
|
597
624
|
});
|
|
598
625
|
}
|
|
599
626
|
|
|
600
|
-
public
|
|
627
|
+
public reset() {
|
|
628
|
+
if (this.connectionWait) {
|
|
629
|
+
clearTimeout(this.connectionWait);
|
|
630
|
+
this.connectionWait = null;
|
|
631
|
+
}
|
|
632
|
+
this.pendingConnections = [];
|
|
633
|
+
this.jsPlumb.select().deleteAll();
|
|
634
|
+
this.jsPlumb._managedElements = {};
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
public forgetNode(nodeId: string) {
|
|
638
|
+
if (!this.jsPlumb) return;
|
|
639
|
+
const element = document.getElementById(nodeId);
|
|
640
|
+
if (!element) return;
|
|
641
|
+
|
|
642
|
+
this.jsPlumb.deleteConnectionsForElement(element);
|
|
643
|
+
this.jsPlumb.removeAllEndpoints(element);
|
|
644
|
+
this.jsPlumb.unmanage(element);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
public removeNodeConnections(nodeId: string, exitIds?: string[]) {
|
|
601
648
|
if (!this.jsPlumb) return;
|
|
602
649
|
|
|
603
650
|
const inbound = this.jsPlumb.select({ target: nodeId });
|
|
604
|
-
|
|
651
|
+
|
|
652
|
+
// Use provided exitIds or try to find them in DOM (fallback)
|
|
653
|
+
const exits =
|
|
654
|
+
exitIds ||
|
|
605
655
|
Array.from(
|
|
606
656
|
document.getElementById(nodeId)?.querySelectorAll('.exit') || []
|
|
607
657
|
).map((exit) => {
|
|
608
658
|
return exit.id;
|
|
609
|
-
}) ||
|
|
659
|
+
}) ||
|
|
660
|
+
[];
|
|
610
661
|
|
|
611
662
|
inbound.deleteAll();
|
|
612
|
-
this.jsPlumb.select({ source:
|
|
613
|
-
this.jsPlumb.selectEndpoints({ source:
|
|
663
|
+
this.jsPlumb.select({ source: exits }).deleteAll();
|
|
664
|
+
this.jsPlumb.selectEndpoints({ source: exits }).deleteAll();
|
|
614
665
|
}
|
|
615
666
|
|
|
616
667
|
public removeExitConnection(exitId: string) {
|
|
@@ -627,13 +678,16 @@ export class Plumber {
|
|
|
627
678
|
this.jsPlumb.deleteConnection(connection);
|
|
628
679
|
});
|
|
629
680
|
|
|
630
|
-
// Re-create the source endpoint (now without connection)
|
|
631
|
-
this.jsPlumb.removeAllEndpoints(exitElement);
|
|
632
|
-
this.makeSource(exitId);
|
|
633
|
-
|
|
634
681
|
return connections.length > 0;
|
|
635
682
|
}
|
|
636
683
|
|
|
684
|
+
public removeAllEndpoints(nodeId: string) {
|
|
685
|
+
if (!this.jsPlumb) return;
|
|
686
|
+
const element = document.getElementById(nodeId);
|
|
687
|
+
if (!element) return;
|
|
688
|
+
this.jsPlumb.removeAllEndpoints(element, true);
|
|
689
|
+
}
|
|
690
|
+
|
|
637
691
|
/**
|
|
638
692
|
* Set the removing state for an exit's connection
|
|
639
693
|
* @param exitId The ID of the exit whose connections should be marked as removing
|
|
@@ -29,7 +29,11 @@ export const set_contact_field: ActionConfig = {
|
|
|
29
29
|
endpoint: '/api/v2/fields.json',
|
|
30
30
|
helpText: 'Select the contact field to update',
|
|
31
31
|
allowCreate: true,
|
|
32
|
-
createArbitraryOption: (input: string) => ({
|
|
32
|
+
createArbitraryOption: (input: string) => ({
|
|
33
|
+
key: input,
|
|
34
|
+
name: input,
|
|
35
|
+
type: 'text'
|
|
36
|
+
})
|
|
33
37
|
},
|
|
34
38
|
value: {
|
|
35
39
|
type: 'text',
|
package/src/list/RunList.ts
CHANGED
|
@@ -179,7 +179,8 @@ export class RunList extends TembaList {
|
|
|
179
179
|
public getRefreshEndpoint() {
|
|
180
180
|
if (this.items.length > 0) {
|
|
181
181
|
const modifiedOn = this.items[0].modified_on;
|
|
182
|
-
|
|
182
|
+
const separator = this.endpoint.includes('?') ? '&' : '?';
|
|
183
|
+
return this.endpoint + separator + 'after=' + modifiedOn;
|
|
183
184
|
}
|
|
184
185
|
return this.endpoint;
|
|
185
186
|
}
|
package/src/list/TicketList.ts
CHANGED
|
@@ -11,8 +11,9 @@ export class TicketList extends TembaList {
|
|
|
11
11
|
public getRefreshEndpoint() {
|
|
12
12
|
if (this.items.length > 0) {
|
|
13
13
|
const lastActivity = this.items[0].ticket.last_activity_on;
|
|
14
|
+
const separator = this.endpoint.includes('?') ? '&' : '?';
|
|
14
15
|
return (
|
|
15
|
-
this.endpoint + '
|
|
16
|
+
this.endpoint + separator + 'after=' + new Date(lastActivity).getTime() * 1000
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
19
|
return this.endpoint;
|
package/src/locales/es.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
// Do not modify this file by hand!
|
|
3
|
+
// Re-generate this file by running lit-localize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
+
|
|
11
|
+
export const templates = {
|
|
12
|
+
'scf1453991c986b25': `Tab para completar, enter para seleccionar`,
|
|
13
|
+
's73b4d70c02f4b4e0': `No options`,
|
|
14
|
+
's8f02e3a18ffc083a': `Are not currently in a flow`,
|
|
15
|
+
's638236250662c6b3': `Have sent a message in the last`,
|
|
16
|
+
's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
|
|
17
|
+
};
|
|
18
|
+
|
package/src/locales/fr.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
// Do not modify this file by hand!
|
|
3
|
+
// Re-generate this file by running lit-localize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
+
|
|
11
|
+
export const templates = {
|
|
12
|
+
's73b4d70c02f4b4e0': `No options`,
|
|
13
|
+
'scf1453991c986b25': `Tab to complete, enter to select`,
|
|
14
|
+
's8f02e3a18ffc083a': `Are not currently in a flow`,
|
|
15
|
+
's638236250662c6b3': `Have sent a message in the last`,
|
|
16
|
+
's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
|
|
17
|
+
};
|
|
18
|
+
|
|
@@ -10,9 +10,18 @@ export const sourceLocale = `en`;
|
|
|
10
10
|
* The other locale codes that this application is localized into. Sorted
|
|
11
11
|
* lexicographically.
|
|
12
12
|
*/
|
|
13
|
-
export const targetLocales = [
|
|
13
|
+
export const targetLocales = [
|
|
14
|
+
`es`,
|
|
15
|
+
`fr`,
|
|
16
|
+
`pt`,
|
|
17
|
+
] as const;
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* All valid project locale codes. Sorted lexicographically.
|
|
17
21
|
*/
|
|
18
|
-
export const allLocales = [
|
|
22
|
+
export const allLocales = [
|
|
23
|
+
`en`,
|
|
24
|
+
`es`,
|
|
25
|
+
`fr`,
|
|
26
|
+
`pt`,
|
|
27
|
+
] as const;
|
package/src/locales/pt.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
// Do not modify this file by hand!
|
|
3
|
+
// Re-generate this file by running lit-localize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
+
|
|
11
|
+
export const templates = {
|
|
12
|
+
's73b4d70c02f4b4e0': `No options`,
|
|
13
|
+
'scf1453991c986b25': `Tab to complete, enter to select`,
|
|
14
|
+
's8f02e3a18ffc083a': `Are not currently in a flow`,
|
|
15
|
+
's638236250662c6b3': `Have sent a message in the last`,
|
|
16
|
+
's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
|
|
17
|
+
};
|
|
18
|
+
|
|
@@ -183,7 +183,6 @@ export class Simulator extends RapidElement {
|
|
|
183
183
|
backdrop-filter: blur(10px);
|
|
184
184
|
border-radius: 16px;
|
|
185
185
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
186
|
-
pointer-events: all;
|
|
187
186
|
}
|
|
188
187
|
.option-btn {
|
|
189
188
|
background: rgba(255, 255, 255, 0.1);
|
|
@@ -359,6 +358,10 @@ export class Simulator extends RapidElement {
|
|
|
359
358
|
pointer-events: auto;
|
|
360
359
|
}
|
|
361
360
|
|
|
361
|
+
.context-explorer.hidden {
|
|
362
|
+
pointer-events: none !important;
|
|
363
|
+
}
|
|
364
|
+
|
|
362
365
|
.context-item {
|
|
363
366
|
display: flex;
|
|
364
367
|
align-items: flex-start;
|
|
@@ -1319,8 +1322,6 @@ export class Simulator extends RapidElement {
|
|
|
1319
1322
|
const phoneWindow = this.shadowRoot.getElementById(
|
|
1320
1323
|
'phone-window'
|
|
1321
1324
|
) as FloatingWindow;
|
|
1322
|
-
// phoneWindow.hide();
|
|
1323
|
-
|
|
1324
1325
|
phoneWindow.handleClose();
|
|
1325
1326
|
this.isVisible = false;
|
|
1326
1327
|
getStore().getState().setSimulatorActive(false);
|
|
@@ -1753,7 +1754,9 @@ export class Simulator extends RapidElement {
|
|
|
1753
1754
|
>
|
|
1754
1755
|
<div class="phone-simulator" style="${styleVars}">
|
|
1755
1756
|
<div
|
|
1756
|
-
class="context-explorer ${this.contextExplorerOpen
|
|
1757
|
+
class="context-explorer ${this.contextExplorerOpen
|
|
1758
|
+
? 'open'
|
|
1759
|
+
: ''} ${this.isVisible ? 'visible' : 'hidden'}"
|
|
1757
1760
|
>
|
|
1758
1761
|
<div class="context-explorer-scroll">
|
|
1759
1762
|
${this.context
|
|
@@ -1884,7 +1887,10 @@ export class Simulator extends RapidElement {
|
|
|
1884
1887
|
</div>
|
|
1885
1888
|
</div>
|
|
1886
1889
|
</div>
|
|
1887
|
-
<div
|
|
1890
|
+
<div
|
|
1891
|
+
class="option-pane"
|
|
1892
|
+
style="pointer-events:${this.isVisible ? 'all' : 'none'}"
|
|
1893
|
+
>
|
|
1888
1894
|
<button class="option-btn" @click=${this.handleClose} title="Close">
|
|
1889
1895
|
<temba-icon name="x" size="1.5"></temba-icon>
|
|
1890
1896
|
</button>
|
package/src/store/AppState.ts
CHANGED
|
@@ -105,6 +105,7 @@ export interface AppState {
|
|
|
105
105
|
languageNames: { [code: string]: Language };
|
|
106
106
|
workspace: Workspace;
|
|
107
107
|
isTranslating: boolean;
|
|
108
|
+
viewingRevision: boolean;
|
|
108
109
|
|
|
109
110
|
dirtyDate: Date | null;
|
|
110
111
|
|
|
@@ -174,6 +175,7 @@ export const zustand = createStore<AppState>()(
|
|
|
174
175
|
flowDefinition: null,
|
|
175
176
|
flowInfo: null,
|
|
176
177
|
isTranslating: false,
|
|
178
|
+
viewingRevision: false,
|
|
177
179
|
dirtyDate: null,
|
|
178
180
|
activity: null,
|
|
179
181
|
simulatorActivity: null,
|
|
@@ -187,6 +189,7 @@ export const zustand = createStore<AppState>()(
|
|
|
187
189
|
},
|
|
188
190
|
|
|
189
191
|
fetchRevision: async (endpoint: string, id: string = null) => {
|
|
192
|
+
const viewingRevision = !!id && id !== 'latest';
|
|
190
193
|
if (!id) {
|
|
191
194
|
id = 'latest';
|
|
192
195
|
}
|
|
@@ -198,7 +201,11 @@ export const zustand = createStore<AppState>()(
|
|
|
198
201
|
throw new Error('Network response was not ok');
|
|
199
202
|
}
|
|
200
203
|
const data = (await response.json()) as FlowContents;
|
|
201
|
-
set({
|
|
204
|
+
set({
|
|
205
|
+
flowInfo: data.info,
|
|
206
|
+
flowDefinition: data.definition,
|
|
207
|
+
viewingRevision
|
|
208
|
+
});
|
|
202
209
|
},
|
|
203
210
|
|
|
204
211
|
fetchWorkspace: async (endpoint) => {
|
|
@@ -282,7 +289,11 @@ export const zustand = createStore<AppState>()(
|
|
|
282
289
|
setFlowContents: (flow: FlowContents) => {
|
|
283
290
|
set((state: AppState) => {
|
|
284
291
|
const flowLang = flow.definition.language;
|
|
285
|
-
|
|
292
|
+
// Clone to ensure mutable for sorting
|
|
293
|
+
state.flowDefinition = {
|
|
294
|
+
...flow.definition,
|
|
295
|
+
nodes: [...(flow.definition.nodes || [])]
|
|
296
|
+
};
|
|
286
297
|
state.flowInfo = flow.info;
|
|
287
298
|
// Reset to the flow's default language when loading a new flow
|
|
288
299
|
state.languageCode = flowLang;
|
|
@@ -473,6 +484,11 @@ export const zustand = createStore<AppState>()(
|
|
|
473
484
|
exitUuid: string,
|
|
474
485
|
destinationNodeUuid: string
|
|
475
486
|
) => {
|
|
487
|
+
/* console.log('Upating connection:', {
|
|
488
|
+
nodeUuid,
|
|
489
|
+
exitUuid,
|
|
490
|
+
destinationNodeUuid
|
|
491
|
+
});*/
|
|
476
492
|
set((state: AppState) => {
|
|
477
493
|
// Find the exit with this UUID
|
|
478
494
|
const node = state.flowDefinition.nodes.find(
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { assert, expect } from '@open-wc/testing';
|
|
2
2
|
import { ContactFields } from '../src/live/ContactFields';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getComponent,
|
|
5
|
+
loadStore,
|
|
6
|
+
mockPOST,
|
|
7
|
+
waitForCondition
|
|
8
|
+
} from './utils.test';
|
|
4
9
|
|
|
5
10
|
const TAG = 'temba-contact-fields';
|
|
6
11
|
const getFields = async (attrs: any = {}) => {
|
|
7
12
|
attrs['endpoint'] = '/test-assets/contacts/';
|
|
8
13
|
const fields = (await getComponent(TAG, attrs, '', 600)) as ContactFields;
|
|
9
14
|
|
|
10
|
-
// wait for our contact to load
|
|
11
|
-
await
|
|
15
|
+
// wait for our contact data to load
|
|
16
|
+
await waitForCondition(() => fields.data !== undefined);
|
|
12
17
|
|
|
13
18
|
return fields;
|
|
14
19
|
};
|
|
@@ -835,7 +835,9 @@ describe('EditorNode', () => {
|
|
|
835
835
|
makeTarget: stub(),
|
|
836
836
|
makeSource: stub(),
|
|
837
837
|
connectIds: stub(),
|
|
838
|
-
removeExitConnection: stub()
|
|
838
|
+
removeExitConnection: stub(),
|
|
839
|
+
forgetNode: stub(),
|
|
840
|
+
removeNodeConnections: stub()
|
|
839
841
|
};
|
|
840
842
|
editorNode['plumber'] = mockPlumber;
|
|
841
843
|
});
|