@nyaruka/temba-components 0.136.1 → 0.138.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 +19 -0
- package/demo/components/webchat/example.html +2 -2
- package/dist/temba-components.js +692 -622
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +123 -44
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +2 -2
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/events/eventRenderers.js +442 -0
- package/out-tsc/src/events/eventRenderers.js.map +1 -0
- package/out-tsc/src/flow/CanvasNode.js +45 -24
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +308 -18
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +0 -1
- package/out-tsc/src/flow/NodeEditor.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/list/ShortcutList.js +1 -1
- package/out-tsc/src/list/ShortcutList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +12 -321
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +439 -575
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +12 -2
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +2 -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-simulator.test.js +51 -32
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.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/display/Chat.ts +123 -44
- package/src/display/FloatingTab.ts +2 -2
- package/src/events/eventRenderers.ts +527 -0
- package/src/flow/CanvasNode.ts +54 -29
- package/src/flow/Editor.ts +360 -19
- package/src/flow/NodeEditor.ts +0 -1
- package/src/flow/Plumber.ts +123 -69
- package/src/list/ShortcutList.ts +1 -1
- package/src/live/ContactChat.ts +17 -376
- package/src/simulator/Simulator.ts +498 -617
- package/src/store/AppState.ts +13 -2
- package/test/temba-flow-editor-node.test.ts +2 -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-simulator.test.ts +64 -34
|
@@ -3,11 +3,11 @@ import { html } from 'lit-html';
|
|
|
3
3
|
import { css, unsafeCSS } from 'lit';
|
|
4
4
|
import { property, state } from 'lit/decorators.js';
|
|
5
5
|
import { getStore } from '../store/Store';
|
|
6
|
-
import { fromStore, zustand } from '../store/AppState';
|
|
6
|
+
import { fromStore, zustand, FLOW_SPEC_VERSION } from '../store/AppState';
|
|
7
7
|
import { RapidElement } from '../RapidElement';
|
|
8
8
|
import { repeat } from 'lit-html/directives/repeat.js';
|
|
9
9
|
import { CustomEventType } from '../interfaces';
|
|
10
|
-
import { generateUUID, postJSON } from '../utils';
|
|
10
|
+
import { generateUUID, postJSON, fetchResults, getClasses } from '../utils';
|
|
11
11
|
import { ACTION_CONFIG, NODE_CONFIG } from './config';
|
|
12
12
|
import { ACTION_GROUP_METADATA } from './types';
|
|
13
13
|
import { Plumber } from './Plumber';
|
|
@@ -90,6 +90,7 @@ export class Editor extends RapidElement {
|
|
|
90
90
|
background-position: 10px 10px;
|
|
91
91
|
width: 100%;
|
|
92
92
|
display: flex;
|
|
93
|
+
padding-top: 20px;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
#canvas {
|
|
@@ -109,6 +110,29 @@ export class Editor extends RapidElement {
|
|
|
109
110
|
transition: none !important;
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
#canvas.viewing-revision {
|
|
114
|
+
pointer-events: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#canvas.read-only svg {
|
|
118
|
+
pointer-events: none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#grid.viewing-revision {
|
|
122
|
+
background-color: #fff9fc;
|
|
123
|
+
background-image: radial-gradient(
|
|
124
|
+
circle,
|
|
125
|
+
rgba(166, 38, 164, 0.2) 1px,
|
|
126
|
+
transparent 1px
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#grid.viewing-revision temba-flow-node,
|
|
131
|
+
#grid.viewing-revision svg.jtk-connector,
|
|
132
|
+
#grid.viewing-revision .activity-overlay {
|
|
133
|
+
opacity: 0.5;
|
|
134
|
+
}
|
|
135
|
+
|
|
112
136
|
body .jtk-endpoint {
|
|
113
137
|
width: initial;
|
|
114
138
|
height: initial;
|
|
@@ -163,12 +187,28 @@ export class Editor extends RapidElement {
|
|
|
163
187
|
stroke-width: 3px;
|
|
164
188
|
}
|
|
165
189
|
|
|
190
|
+
body #canvas.read-only-connections svg.jtk-connector.jtk-hover path {
|
|
191
|
+
stroke: var(--color-connectors) !important;
|
|
192
|
+
}
|
|
193
|
+
|
|
166
194
|
body .plumb-connector.jtk-hover .plumb-arrow {
|
|
167
195
|
fill: var(--color-success) !important;
|
|
168
196
|
stroke-width: 0px;
|
|
169
197
|
z-index: 10;
|
|
170
198
|
}
|
|
171
199
|
|
|
200
|
+
body
|
|
201
|
+
#canvas.read-only-connections
|
|
202
|
+
.plumb-connector.jtk-hover
|
|
203
|
+
.plumb-arrow {
|
|
204
|
+
fill: var(--color-connectors) !important;
|
|
205
|
+
ponter-events: none;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
body #canvas.read-only-connections svg {
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
}
|
|
211
|
+
|
|
172
212
|
/* Activity overlays on connections */
|
|
173
213
|
.jtk-overlay.activity-overlay {
|
|
174
214
|
background: #f3f3f3;
|
|
@@ -190,13 +230,13 @@ export class Editor extends RapidElement {
|
|
|
190
230
|
background: #3498db;
|
|
191
231
|
border: 1px solid #2980b9;
|
|
192
232
|
border-radius: 12px;
|
|
193
|
-
padding: 3px
|
|
233
|
+
padding: 3px 6px;
|
|
194
234
|
color: #fff;
|
|
195
235
|
font-weight: 500;
|
|
196
236
|
top: -10px;
|
|
197
237
|
left: -10px;
|
|
198
238
|
font-size: 13px;
|
|
199
|
-
|
|
239
|
+
|
|
200
240
|
text-align: center;
|
|
201
241
|
z-index: 600;
|
|
202
242
|
line-height: 1;
|
|
@@ -457,6 +497,18 @@ export class Editor extends RapidElement {
|
|
|
457
497
|
width: 100%;
|
|
458
498
|
}
|
|
459
499
|
|
|
500
|
+
.revert-button {
|
|
501
|
+
background: var(--color-primary-dark);
|
|
502
|
+
border: none;
|
|
503
|
+
color: #fff;
|
|
504
|
+
padding: 6px 10px;
|
|
505
|
+
border-radius: var(--curvature);
|
|
506
|
+
font-size: 11px;
|
|
507
|
+
font-weight: 600;
|
|
508
|
+
cursor: pointer;
|
|
509
|
+
transition: opacity 0.2s ease;
|
|
510
|
+
}
|
|
511
|
+
|
|
460
512
|
.auto-translate-button {
|
|
461
513
|
background: var(--color-primary-dark);
|
|
462
514
|
border: none;
|
|
@@ -543,6 +595,11 @@ export class Editor extends RapidElement {
|
|
|
543
595
|
this.autoTranslating = false;
|
|
544
596
|
this.autoTranslateModel = null;
|
|
545
597
|
this.autoTranslateError = null;
|
|
598
|
+
this.revisionsWindowHidden = true;
|
|
599
|
+
this.revisions = [];
|
|
600
|
+
this.viewingRevision = null;
|
|
601
|
+
this.isLoadingRevisions = false;
|
|
602
|
+
this.preRevertState = null;
|
|
546
603
|
this.translationCache = new Map();
|
|
547
604
|
// NodeEditor state - handles both node and action editing
|
|
548
605
|
this.editingNode = null;
|
|
@@ -692,10 +749,11 @@ export class Editor extends RapidElement {
|
|
|
692
749
|
}
|
|
693
750
|
}, SAVE_QUIET_TIME);
|
|
694
751
|
}
|
|
695
|
-
saveChanges() {
|
|
752
|
+
saveChanges(definitionOverride) {
|
|
753
|
+
const definition = definitionOverride || this.definition;
|
|
696
754
|
// post the flow definition to the server
|
|
697
|
-
getStore()
|
|
698
|
-
.postJSON(`/flow/revisions/${this.flow}/`,
|
|
755
|
+
return getStore()
|
|
756
|
+
.postJSON(`/flow/revisions/${this.flow}/`, definition)
|
|
699
757
|
.then((response) => {
|
|
700
758
|
var _b;
|
|
701
759
|
// Update flow info and revision with the response data
|
|
@@ -707,6 +765,10 @@ export class Editor extends RapidElement {
|
|
|
707
765
|
if (((_b = response.json.revision) === null || _b === void 0 ? void 0 : _b.revision) !== undefined) {
|
|
708
766
|
state.setRevision(response.json.revision.revision);
|
|
709
767
|
}
|
|
768
|
+
// if the revisions window is open, refresh the list
|
|
769
|
+
if (!this.revisionsWindowHidden) {
|
|
770
|
+
this.fetchRevisions();
|
|
771
|
+
}
|
|
710
772
|
}
|
|
711
773
|
})
|
|
712
774
|
.catch((error) => {
|
|
@@ -750,7 +812,7 @@ export class Editor extends RapidElement {
|
|
|
750
812
|
clearTimeout(this.activityTimer);
|
|
751
813
|
}
|
|
752
814
|
this.activityTimer = window.setTimeout(() => {
|
|
753
|
-
this.fetchActivityData();
|
|
815
|
+
// this.fetchActivityData();
|
|
754
816
|
}, this.activityInterval);
|
|
755
817
|
});
|
|
756
818
|
}
|
|
@@ -831,6 +893,8 @@ export class Editor extends RapidElement {
|
|
|
831
893
|
// ignore right clicks
|
|
832
894
|
if (event.button !== 0)
|
|
833
895
|
return;
|
|
896
|
+
if (this.isReadOnly())
|
|
897
|
+
return;
|
|
834
898
|
const element = event.currentTarget;
|
|
835
899
|
// Only start dragging if clicking on the element itself, not on exits or other interactive elements
|
|
836
900
|
const target = event.target;
|
|
@@ -892,6 +956,8 @@ export class Editor extends RapidElement {
|
|
|
892
956
|
}
|
|
893
957
|
handleCanvasMouseDown(event) {
|
|
894
958
|
var _b;
|
|
959
|
+
if (this.isReadOnly())
|
|
960
|
+
return;
|
|
895
961
|
const target = event.target;
|
|
896
962
|
if (target.id === 'canvas' || target.id === 'grid') {
|
|
897
963
|
// Ignore clicks on exits
|
|
@@ -953,6 +1019,7 @@ export class Editor extends RapidElement {
|
|
|
953
1019
|
// Clean up jsPlumb connections for nodes before removing them
|
|
954
1020
|
uuids.forEach((uuid) => {
|
|
955
1021
|
this.plumber.removeNodeConnections(uuid);
|
|
1022
|
+
this.plumber.removeAllEndpoints(uuid);
|
|
956
1023
|
});
|
|
957
1024
|
// Now remove them from the definition
|
|
958
1025
|
if (uuids.length > 0 && this.plumber) {
|
|
@@ -1371,6 +1438,10 @@ export class Editor extends RapidElement {
|
|
|
1371
1438
|
store.getState().expandCanvas(maxWidth, maxHeight);
|
|
1372
1439
|
}
|
|
1373
1440
|
handleCanvasContextMenu(event) {
|
|
1441
|
+
if (this.isReadOnly()) {
|
|
1442
|
+
event.preventDefault();
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1374
1445
|
// Check if we right-clicked on empty canvas space
|
|
1375
1446
|
const target = event.target;
|
|
1376
1447
|
if (target.id !== 'canvas') {
|
|
@@ -2047,6 +2118,7 @@ export class Editor extends RapidElement {
|
|
|
2047
2118
|
return;
|
|
2048
2119
|
}
|
|
2049
2120
|
this.localizationWindowHidden = false;
|
|
2121
|
+
this.revisionsWindowHidden = true;
|
|
2050
2122
|
const alreadySelected = languages.some((lang) => lang.code === this.languageCode);
|
|
2051
2123
|
if (!alreadySelected) {
|
|
2052
2124
|
this.handleLanguageChange(languages[0].code);
|
|
@@ -2254,6 +2326,199 @@ export class Editor extends RapidElement {
|
|
|
2254
2326
|
}
|
|
2255
2327
|
this.autoTranslating = false;
|
|
2256
2328
|
}
|
|
2329
|
+
handleRevisionsTabClick() {
|
|
2330
|
+
if (this.revisionsWindowHidden) {
|
|
2331
|
+
this.fetchRevisions();
|
|
2332
|
+
this.revisionsWindowHidden = false;
|
|
2333
|
+
this.localizationWindowHidden = true; // Close other window
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
handleRevisionsWindowClosed() {
|
|
2337
|
+
this.resetRevisionsScroll();
|
|
2338
|
+
this.revisionsWindowHidden = true;
|
|
2339
|
+
if (this.viewingRevision) {
|
|
2340
|
+
this.handleCancelRevisionView();
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
resetRevisionsScroll() {
|
|
2344
|
+
var _b;
|
|
2345
|
+
const list = (_b = this.querySelector('#revisions-window').shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('.body');
|
|
2346
|
+
if (list) {
|
|
2347
|
+
list.scrollTop = 0;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
async fetchRevisions() {
|
|
2351
|
+
this.isLoadingRevisions = true;
|
|
2352
|
+
try {
|
|
2353
|
+
const results = await fetchResults(`/flow/revisions/${this.flow}/?version=${FLOW_SPEC_VERSION}`);
|
|
2354
|
+
this.revisions = results.slice(1);
|
|
2355
|
+
}
|
|
2356
|
+
catch (e) {
|
|
2357
|
+
console.error('Error fetching revisions', e);
|
|
2358
|
+
}
|
|
2359
|
+
finally {
|
|
2360
|
+
this.isLoadingRevisions = false;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
async handleRevisionClick(revision) {
|
|
2364
|
+
var _b, _c;
|
|
2365
|
+
if (((_b = this.viewingRevision) === null || _b === void 0 ? void 0 : _b.id) === revision.id) {
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
if (!this.viewingRevision) {
|
|
2369
|
+
// Save current state first
|
|
2370
|
+
this.preRevertState = {
|
|
2371
|
+
definition: this.definition,
|
|
2372
|
+
dirtyDate: this.dirtyDate
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
this.viewingRevision = revision;
|
|
2376
|
+
this.isLoadingRevisions = true;
|
|
2377
|
+
(_c = this.plumber) === null || _c === void 0 ? void 0 : _c.reset();
|
|
2378
|
+
try {
|
|
2379
|
+
await getStore()
|
|
2380
|
+
.getState()
|
|
2381
|
+
.fetchRevision(`/flow/revisions/${this.flow}`, revision.id.toString());
|
|
2382
|
+
}
|
|
2383
|
+
catch (e) {
|
|
2384
|
+
console.error('Error fetching revision details', e);
|
|
2385
|
+
this.handleCancelRevisionView();
|
|
2386
|
+
}
|
|
2387
|
+
finally {
|
|
2388
|
+
this.isLoadingRevisions = false;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
handleCancelRevisionView() {
|
|
2392
|
+
var _b;
|
|
2393
|
+
(_b = this.plumber) === null || _b === void 0 ? void 0 : _b.reset();
|
|
2394
|
+
if (this.preRevertState) {
|
|
2395
|
+
const currentInfo = getStore().getState().flowInfo;
|
|
2396
|
+
getStore().getState().setFlowContents({
|
|
2397
|
+
definition: this.preRevertState.definition,
|
|
2398
|
+
info: currentInfo
|
|
2399
|
+
});
|
|
2400
|
+
if (this.preRevertState.dirtyDate) {
|
|
2401
|
+
getStore().getState().setDirtyDate(this.preRevertState.dirtyDate);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
else {
|
|
2405
|
+
// Fallback if no pre-revert definition
|
|
2406
|
+
getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
|
|
2407
|
+
}
|
|
2408
|
+
this.viewingRevision = null;
|
|
2409
|
+
this.preRevertState = null;
|
|
2410
|
+
}
|
|
2411
|
+
async handleRevertClick() {
|
|
2412
|
+
var _b;
|
|
2413
|
+
if (!this.viewingRevision || !this.preRevertState)
|
|
2414
|
+
return;
|
|
2415
|
+
(_b = this.plumber) === null || _b === void 0 ? void 0 : _b.reset();
|
|
2416
|
+
// Use the content of the viewing revision (this.definition)
|
|
2417
|
+
// but the revision number of the current head (preRevertState)
|
|
2418
|
+
// so the server accepts it as a valid update
|
|
2419
|
+
const definitionToSave = {
|
|
2420
|
+
...this.definition,
|
|
2421
|
+
revision: this.preRevertState.definition.revision
|
|
2422
|
+
};
|
|
2423
|
+
await this.saveChanges(definitionToSave);
|
|
2424
|
+
this.viewingRevision = null;
|
|
2425
|
+
this.preRevertState = null;
|
|
2426
|
+
this.revisionsWindowHidden = true;
|
|
2427
|
+
const revisionsWindow = document.getElementById('revisions-window');
|
|
2428
|
+
revisionsWindow.handleClose();
|
|
2429
|
+
// Refresh revisions list to show the new one
|
|
2430
|
+
this.fetchRevisions();
|
|
2431
|
+
// Fetch the latest version of the flow to ensure the store is up to date
|
|
2432
|
+
getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
|
|
2433
|
+
}
|
|
2434
|
+
renderRevisionsTab() {
|
|
2435
|
+
return html `
|
|
2436
|
+
<temba-floating-tab
|
|
2437
|
+
id="revisions-tab"
|
|
2438
|
+
icon="revisions"
|
|
2439
|
+
label="Revisions"
|
|
2440
|
+
color="rgb(142, 94, 167)"
|
|
2441
|
+
top="105"
|
|
2442
|
+
.hidden=${!this.revisionsWindowHidden && this.localizationWindowHidden}
|
|
2443
|
+
@temba-button-clicked=${this.handleRevisionsTabClick}
|
|
2444
|
+
></temba-floating-tab>
|
|
2445
|
+
`;
|
|
2446
|
+
}
|
|
2447
|
+
renderRevisionsWindow() {
|
|
2448
|
+
return html `
|
|
2449
|
+
<temba-floating-window
|
|
2450
|
+
id="revisions-window"
|
|
2451
|
+
header="Revisions"
|
|
2452
|
+
.width=${360}
|
|
2453
|
+
.maxHeight=${600}
|
|
2454
|
+
.top=${75}
|
|
2455
|
+
color="rgb(142, 94, 167)"
|
|
2456
|
+
.hidden=${this.revisionsWindowHidden}
|
|
2457
|
+
@temba-dialog-hidden=${this.handleRevisionsWindowClosed}
|
|
2458
|
+
>
|
|
2459
|
+
<div class="localization-window-content">
|
|
2460
|
+
<div
|
|
2461
|
+
class="revisions-list"
|
|
2462
|
+
style="display:flex; flex-direction:column; gap:8px; overflow-y:auto; padding-bottom:10px;"
|
|
2463
|
+
>
|
|
2464
|
+
${this.isLoadingRevisions && !this.revisions.length
|
|
2465
|
+
? html `<temba-loading></temba-loading>`
|
|
2466
|
+
: this.revisions.map((rev) => {
|
|
2467
|
+
var _b;
|
|
2468
|
+
const isSelected = ((_b = this.viewingRevision) === null || _b === void 0 ? void 0 : _b.id) === rev.id;
|
|
2469
|
+
return html `
|
|
2470
|
+
<div
|
|
2471
|
+
class="revision-item ${isSelected ? 'selected' : ''}"
|
|
2472
|
+
style="padding:8px; border-radius:4px; cursor:pointer; background:${isSelected
|
|
2473
|
+
? '#f0f6ff' // Light blue bg for selected
|
|
2474
|
+
: '#f9fafb'}; border:1px solid ${isSelected ? '#a4cafe' : '#e5e7eb'}; transition: all 0.2s ease;"
|
|
2475
|
+
@click=${() => this.handleRevisionClick(rev)}
|
|
2476
|
+
>
|
|
2477
|
+
<div
|
|
2478
|
+
style="display:flex; justify-content:space-between; align-items:center;"
|
|
2479
|
+
>
|
|
2480
|
+
<div
|
|
2481
|
+
class="revision-header"
|
|
2482
|
+
style="margin-bottom: 2px;"
|
|
2483
|
+
>
|
|
2484
|
+
<div
|
|
2485
|
+
style="font-weight:600; font-size:13px; color:#111827;"
|
|
2486
|
+
>
|
|
2487
|
+
<temba-date value=${rev.created_on} display="duration"></temba-date>
|
|
2488
|
+
|
|
2489
|
+
</div>
|
|
2490
|
+
<div style="font-size:11px; color:#6b7280;">
|
|
2491
|
+
${rev.user.name || rev.user.username}
|
|
2492
|
+
</div>
|
|
2493
|
+
</div>
|
|
2494
|
+
${isSelected
|
|
2495
|
+
? html `<button
|
|
2496
|
+
class="revert-button"
|
|
2497
|
+
@click=${this.handleRevertClick}
|
|
2498
|
+
>
|
|
2499
|
+
Revert
|
|
2500
|
+
</button>`
|
|
2501
|
+
: html ``}
|
|
2502
|
+
|
|
2503
|
+
</button>
|
|
2504
|
+
</div>
|
|
2505
|
+
|
|
2506
|
+
${rev.comment
|
|
2507
|
+
? html `<div
|
|
2508
|
+
style="font-size:12px; color:#4b5563; margin-top:4px;"
|
|
2509
|
+
>
|
|
2510
|
+
${rev.comment}
|
|
2511
|
+
</div>`
|
|
2512
|
+
: ''}
|
|
2513
|
+
|
|
2514
|
+
</div>
|
|
2515
|
+
`;
|
|
2516
|
+
})}
|
|
2517
|
+
</div>
|
|
2518
|
+
</div>
|
|
2519
|
+
</temba-floating-window>
|
|
2520
|
+
`;
|
|
2521
|
+
}
|
|
2257
2522
|
renderLocalizationWindow() {
|
|
2258
2523
|
var _b, _c, _d;
|
|
2259
2524
|
const languages = this.getLocalizationLanguages();
|
|
@@ -2480,6 +2745,9 @@ export class Editor extends RapidElement {
|
|
|
2480
2745
|
behavior: 'smooth'
|
|
2481
2746
|
});
|
|
2482
2747
|
}
|
|
2748
|
+
isReadOnly() {
|
|
2749
|
+
return this.viewingRevision !== null || this.isTranslating;
|
|
2750
|
+
}
|
|
2483
2751
|
render() {
|
|
2484
2752
|
var _b, _c;
|
|
2485
2753
|
// we have to embed our own style since we are in light DOM
|
|
@@ -2488,17 +2756,24 @@ export class Editor extends RapidElement {
|
|
|
2488
2756
|
${unsafeCSS(CanvasNode.styles.cssText)}
|
|
2489
2757
|
</style>`;
|
|
2490
2758
|
const stickies = ((_c = (_b = this.definition) === null || _b === void 0 ? void 0 : _b._ui) === null || _c === void 0 ? void 0 : _c.stickies) || {};
|
|
2491
|
-
return html `${style} ${this.
|
|
2492
|
-
${this.renderAutoTranslateDialog()}
|
|
2759
|
+
return html `${style} ${this.renderRevisionsWindow()}
|
|
2760
|
+
${this.renderLocalizationWindow()} ${this.renderAutoTranslateDialog()}
|
|
2493
2761
|
<div id="editor">
|
|
2494
2762
|
<div
|
|
2495
2763
|
id="grid"
|
|
2764
|
+
class="${this.viewingRevision ? 'viewing-revision' : ''}"
|
|
2496
2765
|
style="min-width:100%;width:${this.canvasSize.width}px; height:${this
|
|
2497
2766
|
.canvasSize.height}px"
|
|
2498
2767
|
>
|
|
2499
|
-
<div
|
|
2768
|
+
<div
|
|
2769
|
+
id="canvas"
|
|
2770
|
+
class="${getClasses({
|
|
2771
|
+
'viewing-revision': !!this.viewingRevision,
|
|
2772
|
+
'read-only-connections': !!this.viewingRevision || this.isTranslating
|
|
2773
|
+
})}"
|
|
2774
|
+
>
|
|
2500
2775
|
${this.definition
|
|
2501
|
-
? repeat(this.definition.nodes, (node) => node.uuid, (node
|
|
2776
|
+
? repeat([...this.definition.nodes].sort((a, b) => a.uuid.localeCompare(b.uuid)), (node) => node.uuid, (node) => {
|
|
2502
2777
|
var _b, _c, _d;
|
|
2503
2778
|
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) || {
|
|
2504
2779
|
left: 0,
|
|
@@ -2508,7 +2783,8 @@ export class Editor extends RapidElement {
|
|
|
2508
2783
|
((_d = this.currentDragItem) === null || _d === void 0 ? void 0 : _d.uuid) === node.uuid;
|
|
2509
2784
|
const selected = this.selectedItems.has(node.uuid);
|
|
2510
2785
|
// first node is the flow start (nodes are sorted by position)
|
|
2511
|
-
const isFlowStart =
|
|
2786
|
+
const isFlowStart = this.definition.nodes.length > 0 &&
|
|
2787
|
+
this.definition.nodes[0].uuid === node.uuid;
|
|
2512
2788
|
return html `<temba-flow-node
|
|
2513
2789
|
class="draggable ${dragging ? 'dragging' : ''} ${selected
|
|
2514
2790
|
? 'selected'
|
|
@@ -2560,11 +2836,13 @@ export class Editor extends RapidElement {
|
|
|
2560
2836
|
: ''}
|
|
2561
2837
|
|
|
2562
2838
|
<temba-canvas-menu></temba-canvas-menu>
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2839
|
+
${!this.viewingRevision
|
|
2840
|
+
? html `<temba-node-type-selector
|
|
2841
|
+
.flowType=${this.flowType}
|
|
2842
|
+
.features=${this.features}
|
|
2843
|
+
></temba-node-type-selector>`
|
|
2844
|
+
: ''}
|
|
2845
|
+
${this.renderRevisionsTab()} ${this.renderLocalizationTab()} `;
|
|
2568
2846
|
}
|
|
2569
2847
|
}
|
|
2570
2848
|
__decorate([
|
|
@@ -2651,6 +2929,18 @@ __decorate([
|
|
|
2651
2929
|
__decorate([
|
|
2652
2930
|
state()
|
|
2653
2931
|
], Editor.prototype, "autoTranslateError", void 0);
|
|
2932
|
+
__decorate([
|
|
2933
|
+
state()
|
|
2934
|
+
], Editor.prototype, "revisionsWindowHidden", void 0);
|
|
2935
|
+
__decorate([
|
|
2936
|
+
state()
|
|
2937
|
+
], Editor.prototype, "revisions", void 0);
|
|
2938
|
+
__decorate([
|
|
2939
|
+
state()
|
|
2940
|
+
], Editor.prototype, "viewingRevision", void 0);
|
|
2941
|
+
__decorate([
|
|
2942
|
+
state()
|
|
2943
|
+
], Editor.prototype, "isLoadingRevisions", void 0);
|
|
2654
2944
|
__decorate([
|
|
2655
2945
|
state()
|
|
2656
2946
|
], Editor.prototype, "editingNode", void 0);
|