@nyaruka/temba-components 0.137.0 → 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 +9 -0
- package/dist/temba-components.js +392 -258
- package/dist/temba-components.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/flow/CanvasNode.js +45 -24
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +305 -16
- package/out-tsc/src/flow/Editor.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/simulator/Simulator.js +11 -4
- 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/package.json +1 -1
- package/src/display/FloatingTab.ts +2 -2
- package/src/flow/CanvasNode.ts +54 -29
- package/src/flow/Editor.ts +357 -17
- package/src/flow/Plumber.ts +123 -69
- package/src/simulator/Simulator.ts +11 -5
- 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
|
@@ -87,11 +87,11 @@ export class FloatingTab extends RapidElement {
|
|
|
87
87
|
// auto-calculate position based on index
|
|
88
88
|
const index = FloatingTab.allTabs.indexOf(this);
|
|
89
89
|
if (index === -1) {
|
|
90
|
-
this.top =
|
|
90
|
+
this.top = 150; // default fallback
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
93
93
|
// start at 100px and stack with 10px gap between tabs
|
|
94
|
-
this.top =
|
|
94
|
+
this.top = 150 + index * (FloatingTab.TAB_HEIGHT + 0);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
updated(changes) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 4998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 50; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top =
|
|
1
|
+
{"version":3,"file":"FloatingTab.js","sourceRoot":"","sources":["../../../src/display/FloatingTab.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAoC,MAAM,KAAK,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,OAAO,WAAY,SAAQ,YAAY;IAA7C;;QAsEE,UAAK,GAAG,SAAS,CAAC;QAGlB,QAAG,GAAG,CAAC,CAAC,CAAC,CAAC,mCAAmC;QAG7C,WAAM,GAAG,KAAK,CAAC;IAsFjB,CAAC;IAjKC,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuDT,CAAC;IACJ,CAAC;IAoBD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,oBAAoB;QAClB,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;YACf,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACvC,CAAC;QACD,qCAAqC;QACrC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;IAC7D,CAAC;IAEO,cAAc;QACpB,yCAAyC;QACzC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,mBAAmB;QACrC,CAAC;aAAM,CAAC;YACN,sDAAsD;YACtD,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,GAAG,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAEM,OAAO,CACZ,OAA0D;QAE1D,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,WAAW;QACjB,oCAAoC;QACpC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,aAAa,EAAE;YAClD,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAEM,MAAM,CAAC,WAAW;QACvB,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,MAAM,CAAC,WAAW;QACvB,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAClC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,MAAM;QACX,MAAM,QAAQ,GAAG;0BACK,IAAI,CAAC,KAAK;aACvB,IAAI,CAAC,GAAG;KAChB,CAAC;QAEF,MAAM,OAAO,GAAG,UAAU,CAAC;YACzB,GAAG,EAAE,IAAI;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAA;oBACK,OAAO,YAAY,QAAQ,YAAY,IAAI,CAAC,WAAW;;YAE/D,IAAI,CAAC,IAAI;YACT,CAAC,CAAC,IAAI,CAAA,gCAAgC,IAAI,CAAC,IAAI,iBAAiB;YAChE,CAAC,CAAC,EAAE;;6BAEa,IAAI,CAAC,KAAK;;KAElC,CAAC;IACJ,CAAC;;AArGM,sBAAU,GAAG,EAAE,AAAL,CAAM,CAAC,kCAAkC;AACnD,mBAAO,GAAkB,EAAE,AAApB,CAAqB;AAGnC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCACd;AAGb;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CACb;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CACT;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAClB;AAGT;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;2CACb","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { CustomEventType } from '../interfaces';\nimport { getClasses } from '../utils';\n\nexport class FloatingTab extends RapidElement {\n static get styles() {\n return css`\n .tab.hidden {\n transform: translateX(100%);\n }\n .tab {\n position: fixed;\n right: 0;\n z-index: 4998;\n transition: transform var(--transition-duration, 300ms) ease-in-out;\n display: flex;\n align-items: center;\n padding: 12px;\n border-top-left-radius: 8px;\n border-bottom-left-radius: 8px;\n cursor: pointer;\n box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);\n transition: all calc(var(--transition-duration, 300ms) * 0.7)\n ease-in-out;\n user-select: none;\n }\n\n .tab:hover {\n padding-right: 16px;\n box-shadow: -4px 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .icon-container {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n }\n\n temba-icon {\n --icon-color: white;\n }\n\n .label {\n color: white;\n font-weight: 500;\n font-size: 16px;\n max-width: 0;\n overflow: hidden;\n white-space: nowrap;\n margin-left: 0;\n opacity: 0;\n transition: all var(--transition-duration, 300ms) ease-in-out;\n }\n\n .tab:hover .label {\n max-width: 200px;\n margin-left: 12px;\n opacity: 1;\n }\n `;\n }\n\n static TAB_HEIGHT = 50; // height of tab for auto-stacking\n static allTabs: FloatingTab[] = [];\n\n @property({ type: String })\n icon: string;\n\n @property({ type: String })\n label: string;\n\n @property({ type: String })\n color = '#6B7280';\n\n @property({ type: Number })\n top = -1; // -1 means auto-calculate position\n\n @property({ type: Boolean })\n hidden = false;\n\n connectedCallback() {\n super.connectedCallback();\n FloatingTab.allTabs.push(this);\n this.updatePosition();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n const index = FloatingTab.allTabs.indexOf(this);\n if (index > -1) {\n FloatingTab.allTabs.splice(index, 1);\n }\n // update positions of remaining tabs\n FloatingTab.allTabs.forEach((tab) => tab.updatePosition());\n }\n\n private updatePosition() {\n // auto-calculate position based on index\n const index = FloatingTab.allTabs.indexOf(this);\n if (index === -1) {\n this.top = 150; // default fallback\n } else {\n // start at 100px and stack with 10px gap between tabs\n this.top = 150 + index * (FloatingTab.TAB_HEIGHT + 0);\n }\n }\n\n public updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('hidden')) {\n this.classList.toggle('hidden', this.hidden);\n }\n if (changes.has('top')) {\n this.updatePosition();\n }\n }\n\n private handleClick() {\n // hide all tabs when one is clicked\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n\n this.fireCustomEvent(CustomEventType.ButtonClicked, {\n action: 'toggle'\n });\n }\n\n public static showAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = false;\n });\n }\n\n public static hideAllTabs() {\n FloatingTab.allTabs.forEach((tab) => {\n tab.hidden = true;\n });\n }\n\n public render(): TemplateResult {\n const tabStyle = `\n background-color: ${this.color};\n top: ${this.top}px;\n `;\n\n const classes = getClasses({\n tab: true,\n hidden: this.hidden\n });\n\n return html`\n <div class=\"${classes}\" style=\"${tabStyle}\" @click=${this.handleClick}>\n <div class=\"icon-container\">\n ${this.icon\n ? html`<temba-icon size=\"1.5\" name=\"${this.icon}\"></temba-icon>`\n : ''}\n </div>\n <div class=\"label\">${this.label}</div>\n </div>\n `;\n }\n}\n"]}
|
|
@@ -22,11 +22,8 @@ export class CanvasNode extends RapidElement {
|
|
|
22
22
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
|
23
23
|
min-width: 200px;
|
|
24
24
|
border-radius: var(--curvature);
|
|
25
|
-
|
|
26
25
|
color: #333;
|
|
27
|
-
cursor: move;
|
|
28
26
|
user-select: none;
|
|
29
|
-
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
/* Flow start indicator */
|
|
@@ -109,7 +106,7 @@ export class CanvasNode extends RapidElement {
|
|
|
109
106
|
opacity: 1;
|
|
110
107
|
}
|
|
111
108
|
|
|
112
|
-
.
|
|
109
|
+
.read-only-hidden {
|
|
113
110
|
visibility: hidden !important;
|
|
114
111
|
pointer-events: none !important;
|
|
115
112
|
}
|
|
@@ -304,6 +301,12 @@ export class CanvasNode extends RapidElement {
|
|
|
304
301
|
.exit.connected:hover {
|
|
305
302
|
background-color: var(--color-connectors, #e6e6e6);
|
|
306
303
|
}
|
|
304
|
+
|
|
305
|
+
.exit.connected.read-only, .exit.connected.read-only:hover {
|
|
306
|
+
background-color: #fff;
|
|
307
|
+
pointer-events: none !important;
|
|
308
|
+
cursor: default;
|
|
309
|
+
}
|
|
307
310
|
|
|
308
311
|
.exit.removing, .exit.removing:hover {
|
|
309
312
|
background-color: var(--color-error);
|
|
@@ -405,6 +408,7 @@ export class CanvasNode extends RapidElement {
|
|
|
405
408
|
super();
|
|
406
409
|
// Track exits that are in "removing" state
|
|
407
410
|
this.exitRemovalTimeouts = new Map();
|
|
411
|
+
this.connectionTimeout = null;
|
|
408
412
|
// Set of exit UUIDs that are in the removing state
|
|
409
413
|
this.exitRemovingState = new Set();
|
|
410
414
|
// Track actions that are in "removing" state
|
|
@@ -460,19 +464,25 @@ export class CanvasNode extends RapidElement {
|
|
|
460
464
|
if (changes.has('node')) {
|
|
461
465
|
// Only proceed if plumber is available (for tests that don't set it up)
|
|
462
466
|
if (this.plumber) {
|
|
463
|
-
|
|
467
|
+
if (this.connectionTimeout) {
|
|
468
|
+
clearTimeout(this.connectionTimeout);
|
|
469
|
+
}
|
|
470
|
+
// Pass exit IDs explicitly to avoid DOM querying dependency
|
|
471
|
+
const exitIds = this.node.exits.map((e) => e.uuid);
|
|
472
|
+
this.plumber.removeNodeConnections(this.node.uuid, exitIds);
|
|
464
473
|
// make our initial connections
|
|
465
|
-
for
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
// so make our source endpoint
|
|
474
|
+
// We use setTimeout to allow for DOM updates to complete before querying for exits
|
|
475
|
+
this.connectionTimeout = window.setTimeout(() => {
|
|
476
|
+
for (const exit of this.node.exits) {
|
|
469
477
|
this.plumber.makeSource(exit.uuid);
|
|
478
|
+
if (exit.destination_uuid) {
|
|
479
|
+
this.plumber.connectIds(this.node.uuid, exit.uuid, exit.destination_uuid);
|
|
480
|
+
}
|
|
470
481
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
this.plumber.revalidate([this.node.uuid]);
|
|
482
|
+
// Note: revalidation is handled by plumber's processPendingConnections which calls repaintEverything
|
|
483
|
+
this.connectionTimeout = null;
|
|
484
|
+
this.plumber.revalidate([this.node.uuid]);
|
|
485
|
+
}, 0);
|
|
476
486
|
}
|
|
477
487
|
const ele = this.parentElement;
|
|
478
488
|
if (ele) {
|
|
@@ -482,6 +492,14 @@ export class CanvasNode extends RapidElement {
|
|
|
482
492
|
}
|
|
483
493
|
}
|
|
484
494
|
disconnectedCallback() {
|
|
495
|
+
// Force cleanup of connections for this node
|
|
496
|
+
if (this.plumber && this.node) {
|
|
497
|
+
if (this.connectionTimeout) {
|
|
498
|
+
clearTimeout(this.connectionTimeout);
|
|
499
|
+
this.connectionTimeout = null;
|
|
500
|
+
}
|
|
501
|
+
this.plumber.forgetNode(this.node.uuid);
|
|
502
|
+
}
|
|
485
503
|
// Remove the event listener when the component is removed
|
|
486
504
|
super.disconnectedCallback();
|
|
487
505
|
// Remove external drag event listeners
|
|
@@ -1047,23 +1065,19 @@ export class CanvasNode extends RapidElement {
|
|
|
1047
1065
|
return html `<div class="cn-title" style="background:${color}">
|
|
1048
1066
|
${((_c = this.ui) === null || _c === void 0 ? void 0 : _c.type) === 'execute_actions'
|
|
1049
1067
|
? html `<temba-icon
|
|
1050
|
-
class="drag-handle ${this.
|
|
1051
|
-
? 'translating-hidden'
|
|
1052
|
-
: ''}"
|
|
1068
|
+
class="drag-handle ${this.isReadOnly() ? 'read-only-hidden' : ''}"
|
|
1053
1069
|
name="sort"
|
|
1054
1070
|
></temba-icon>`
|
|
1055
1071
|
: ((_e = (_d = this.node) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.length) > 1
|
|
1056
1072
|
? html `<temba-icon
|
|
1057
|
-
class="drag-handle ${this.
|
|
1058
|
-
? 'translating-hidden'
|
|
1059
|
-
: ''}"
|
|
1073
|
+
class="drag-handle ${this.isReadOnly() ? 'read-only-hidden' : ''}"
|
|
1060
1074
|
name="sort"
|
|
1061
1075
|
></temba-icon>`
|
|
1062
1076
|
: html `<div class="title-spacer"></div>`}
|
|
1063
1077
|
|
|
1064
1078
|
<div class="name">${isRemoving ? 'Remove?' : config.name}</div>
|
|
1065
1079
|
<div
|
|
1066
|
-
class="remove-button ${this.
|
|
1080
|
+
class="remove-button ${this.isReadOnly() ? 'read-only-hidden' : ''}"
|
|
1067
1081
|
@click=${(e) => this.handleActionRemoveClick(e, action, index)}
|
|
1068
1082
|
title="Remove action"
|
|
1069
1083
|
>
|
|
@@ -1091,7 +1105,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1091
1105
|
: html `${config.name}`}
|
|
1092
1106
|
</div>
|
|
1093
1107
|
<div
|
|
1094
|
-
class="remove-button ${this.
|
|
1108
|
+
class="remove-button ${this.isReadOnly() ? 'read-only-hidden' : ''}"
|
|
1095
1109
|
@click=${(e) => this.handleNodeRemoveClick(e)}
|
|
1096
1110
|
title="Remove node"
|
|
1097
1111
|
>
|
|
@@ -1292,12 +1306,16 @@ export class CanvasNode extends RapidElement {
|
|
|
1292
1306
|
class=${getClasses({
|
|
1293
1307
|
exit: true,
|
|
1294
1308
|
connected: !!exit.destination_uuid,
|
|
1295
|
-
removing: this.exitRemovingState.has(exit.uuid)
|
|
1309
|
+
removing: this.exitRemovingState.has(exit.uuid),
|
|
1310
|
+
'read-only': this.isReadOnly()
|
|
1296
1311
|
})}
|
|
1297
1312
|
@click=${(e) => this.handleExitClick(e, exit)}
|
|
1298
1313
|
></div>
|
|
1299
1314
|
</div>`;
|
|
1300
1315
|
}
|
|
1316
|
+
isReadOnly() {
|
|
1317
|
+
return this.viewingRevision || this.isTranslating;
|
|
1318
|
+
}
|
|
1301
1319
|
render() {
|
|
1302
1320
|
var _b;
|
|
1303
1321
|
if (!this.node || !this.ui) {
|
|
@@ -1370,7 +1388,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1370
1388
|
: html `<div class="action-exits">
|
|
1371
1389
|
${repeat(this.node.exits, (exit) => exit.uuid, (exit) => this.renderExit(exit))}
|
|
1372
1390
|
</div>`}
|
|
1373
|
-
${this.ui.type === 'execute_actions' && !this.
|
|
1391
|
+
${this.ui.type === 'execute_actions' && !this.isReadOnly()
|
|
1374
1392
|
? html `<div
|
|
1375
1393
|
class="add-action-button"
|
|
1376
1394
|
@click=${(e) => this.handleAddActionClick(e)}
|
|
@@ -1398,6 +1416,9 @@ __decorate([
|
|
|
1398
1416
|
__decorate([
|
|
1399
1417
|
fromStore(zustand, (state) => state.languageCode)
|
|
1400
1418
|
], CanvasNode.prototype, "languageCode", void 0);
|
|
1419
|
+
__decorate([
|
|
1420
|
+
fromStore(zustand, (state) => state.viewingRevision)
|
|
1421
|
+
], CanvasNode.prototype, "viewingRevision", void 0);
|
|
1401
1422
|
__decorate([
|
|
1402
1423
|
fromStore(zustand, (state) => state.flowDefinition)
|
|
1403
1424
|
], CanvasNode.prototype, "flowDefinition", void 0);
|