@nyaruka/temba-components 0.121.1 → 0.121.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/dist/temba-components.js +737 -489
  3. package/dist/temba-components.js.map +1 -1
  4. package/out-tsc/src/flow/Editor.js +180 -0
  5. package/out-tsc/src/flow/Editor.js.map +1 -0
  6. package/out-tsc/src/flow/EditorNode.js +199 -0
  7. package/out-tsc/src/flow/EditorNode.js.map +1 -0
  8. package/out-tsc/src/flow/Plumber.js +119 -0
  9. package/out-tsc/src/flow/Plumber.js.map +1 -0
  10. package/out-tsc/src/flow/config.js +76 -0
  11. package/out-tsc/src/flow/config.js.map +1 -0
  12. package/out-tsc/src/flow/render.js +41 -0
  13. package/out-tsc/src/flow/render.js.map +1 -0
  14. package/out-tsc/src/store/AppState.js +63 -13
  15. package/out-tsc/src/store/AppState.js.map +1 -1
  16. package/out-tsc/src/{flow → store}/FlowStoreElement.js +1 -1
  17. package/out-tsc/src/store/FlowStoreElement.js.map +1 -0
  18. package/out-tsc/src/store/Store.js +5 -4
  19. package/out-tsc/src/store/Store.js.map +1 -1
  20. package/out-tsc/temba-modules.js +5 -1
  21. package/out-tsc/temba-modules.js.map +1 -1
  22. package/out-tsc/test/temba-select.test.js +5 -1
  23. package/out-tsc/test/temba-select.test.js.map +1 -1
  24. package/package.json +2 -1
  25. package/src/flow/Editor.ts +194 -0
  26. package/src/flow/EditorNode.ts +220 -0
  27. package/src/flow/Plumber.ts +135 -0
  28. package/src/flow/config.ts +91 -0
  29. package/src/flow/render.ts +56 -0
  30. package/src/store/AppState.ts +189 -109
  31. package/src/{flow → store}/FlowStoreElement.ts +1 -1
  32. package/src/store/Store.ts +6 -4
  33. package/src/store/flow-definition.d.ts +41 -6
  34. package/static/css/temba-components.css +2 -0
  35. package/temba-modules.ts +5 -1
  36. package/test/temba-select.test.ts +5 -1
  37. package/out-tsc/src/flow/FlowStoreElement.js.map +0 -1
@@ -0,0 +1,180 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit-html';
3
+ import { css, unsafeCSS } from 'lit';
4
+ import { property } from 'lit/decorators.js';
5
+ import { getStore } from '../store/Store';
6
+ import { fromStore, zustand } from '../store/AppState';
7
+ import { RapidElement } from '../RapidElement';
8
+ import { Plumber } from './Plumber';
9
+ import { EditorNode } from './EditorNode';
10
+ export class Editor extends RapidElement {
11
+ // Unfortunately, jsplumb requires that we be in light DOM
12
+ createRenderRoot() {
13
+ return this;
14
+ }
15
+ static get styles() {
16
+ return css `
17
+ #editor {
18
+ overflow: scroll;
19
+ flex: 1;
20
+ }
21
+
22
+ #grid {
23
+ position: relative;
24
+ background-color: #f9f9f9;
25
+ background-position: 13px 13px;
26
+ background-image: linear-gradient(
27
+ 0deg,
28
+ transparent 24%,
29
+ rgba(61, 177, 255, 0.15) 25%,
30
+ rgba(61, 177, 255, 0.15) 26%,
31
+ transparent 27%,
32
+ transparent 74%,
33
+ rgba(61, 177, 255, 0.15) 75%,
34
+ rgba(61, 177, 255, 0.15) 76%,
35
+ transparent 77%,
36
+ transparent
37
+ ),
38
+ linear-gradient(
39
+ 90deg,
40
+ transparent 24%,
41
+ rgba(61, 177, 255, 0.15) 25%,
42
+ rgba(61, 177, 255, 0.15) 26%,
43
+ transparent 27%,
44
+ transparent 74%,
45
+ rgba(61, 177, 255, 0.15) 75%,
46
+ rgba(61, 177, 255, 0.15) 76%,
47
+ transparent 77%,
48
+ transparent
49
+ );
50
+ background-size: 40px 40px;
51
+ box-shadow: inset -5px 0 10px rgba(0, 0, 0, 0.05);
52
+ border-top: 1px solid #e0e0e0;
53
+ display: inline-block;
54
+ }
55
+
56
+ #canvas {
57
+ position: relative;
58
+ padding: 20px;
59
+ margin: 20px;
60
+ }
61
+
62
+ body .jtk-endpoint {
63
+ width: initial;
64
+ height: initial;
65
+ }
66
+
67
+ .jtk-endpoint {
68
+ z-index: 1;
69
+ }
70
+
71
+ .plumb-source {
72
+ z-index: 300;
73
+ border: 0px solid var(--color-connectors);
74
+ }
75
+
76
+ .plumb-source.connected {
77
+ box-shadow: 0 3px 3px 0px rgba(0, 0, 0, 0.1);
78
+ border-radius: 50%;
79
+ }
80
+
81
+ .plumb-source circle {
82
+ fill: tomato;
83
+ }
84
+
85
+ .plumb-source.connected circle {
86
+ fill: #fff;
87
+ }
88
+
89
+ .plumb-source svg {
90
+ fill: var(--color-connectors) !important;
91
+ stroke: var(--color-connectors);
92
+ }
93
+
94
+ .plumb-target {
95
+ margin-top: -6px;
96
+ z-index: 200;
97
+ opacity: 0;
98
+ cursor: pointer;
99
+ }
100
+
101
+ body .plumb-connector path {
102
+ stroke: var(--color-connectors) !important;
103
+ stroke-width: 3px;
104
+ }
105
+
106
+ body .plumb-connector .plumb-arrow {
107
+ fill: var(--color-connectors);
108
+ stroke: var(--color-connectors);
109
+ stroke-width: 0px;
110
+ margin-top: 6px;
111
+ }
112
+
113
+ body svg.jtk-connector.jtk-hover path {
114
+ stroke: var(--color-success) !important;
115
+ stroke-width: 3px;
116
+ }
117
+
118
+ body .plumb-connector.jtk-hover .plumb-arrow {
119
+ fill: var(--color-success) !important;
120
+ stroke-width: 0px;
121
+ }
122
+ `;
123
+ }
124
+ constructor() {
125
+ super();
126
+ }
127
+ firstUpdated(changes) {
128
+ super.firstUpdated(changes);
129
+ this.plumber = new Plumber(this.querySelector('#canvas'));
130
+ if (changes.has('flow')) {
131
+ getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
132
+ }
133
+ }
134
+ updated(changes) {
135
+ super.updated(changes);
136
+ if (changes.has('canvasSize')) {
137
+ console.log('Setting canvas size', this.canvasSize);
138
+ }
139
+ }
140
+ render() {
141
+ // we have to embed our own style since we are in light DOM
142
+ const style = html `<style>
143
+ ${unsafeCSS(Editor.styles.cssText)}
144
+ ${unsafeCSS(EditorNode.styles.cssText)}
145
+ </style>`;
146
+ return html `${style}
147
+ <div id="editor">
148
+ <div
149
+ id="grid"
150
+ style="width:${this.canvasSize.width}px; height:${this.canvasSize
151
+ .height}px"
152
+ >
153
+ <div id="canvas">
154
+ ${this.definition
155
+ ? this.definition.nodes.map((node) => {
156
+ return html `<temba-flow-node
157
+ .plumber=${this.plumber}
158
+ .node=${node}
159
+ .ui=${this.definition._ui.nodes[node.uuid]}
160
+ ></temba-flow-node>`;
161
+ })
162
+ : html `<temba-loading></temba-loading>`}
163
+ </div>
164
+ </div>
165
+ </div>`;
166
+ }
167
+ }
168
+ __decorate([
169
+ property({ type: String })
170
+ ], Editor.prototype, "flow", void 0);
171
+ __decorate([
172
+ property({ type: String })
173
+ ], Editor.prototype, "version", void 0);
174
+ __decorate([
175
+ fromStore(zustand, (state) => state.flowDefinition)
176
+ ], Editor.prototype, "definition", void 0);
177
+ __decorate([
178
+ fromStore(zustand, (state) => state.canvasSize)
179
+ ], Editor.prototype, "canvasSize", void 0);
180
+ //# sourceMappingURL=Editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Editor.js","sourceRoot":"","sources":["../../../src/flow/Editor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAkB,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,GAAG,EAAoB,SAAS,EAAE,MAAM,KAAK,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAY,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,MAAO,SAAQ,YAAY;IACtC,0DAA0D;IAC1D,gBAAgB;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAiBD,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0GT,CAAC;IACJ,CAAC;IAED;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAES,YAAY,CACpB,OAA0D;QAE1D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;QAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,mBAAmB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAES,OAAO,CACf,OAA0D;QAE1D,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAEM,MAAM;QACX,2DAA2D;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAA;QACd,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;QAChC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;aAC/B,CAAC;QAEV,OAAO,IAAI,CAAA,GAAG,KAAK;;;;yBAIE,IAAI,CAAC,UAAU,CAAC,KAAK,cAAc,IAAI,CAAC,UAAU;aAC9D,MAAM;;;cAGL,IAAI,CAAC,UAAU;YACf,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACjC,OAAO,IAAI,CAAA;+BACE,IAAI,CAAC,OAAO;4BACf,IAAI;0BACN,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;sCACxB,CAAC;YACvB,CAAC,CAAC;YACJ,CAAC,CAAC,IAAI,CAAA,iCAAiC;;;aAGxC,CAAC;IACZ,CAAC;CACF;AA5KQ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oCACP;AAGb;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uCACJ;AAGf;IADP,SAAS,CAAC,OAAO,EAAE,CAAC,KAAe,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC;0CAC1B;AAG5B;IADP,SAAS,CAAC,OAAO,EAAE,CAAC,KAAe,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC;0CACH","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { css, PropertyValueMap, unsafeCSS } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { FlowDefinition } from '../store/flow-definition';\nimport { getStore } from '../store/Store';\nimport { AppState, fromStore, zustand } from '../store/AppState';\nimport { RapidElement } from '../RapidElement';\n\nimport { Plumber } from './Plumber';\nimport { EditorNode } from './EditorNode';\n\nexport class Editor extends RapidElement {\n // Unfortunately, jsplumb requires that we be in light DOM\n createRenderRoot() {\n return this;\n }\n\n // This is the master plumber\n private plumber: Plumber;\n\n @property({ type: String })\n public flow: string;\n\n @property({ type: String })\n public version: string;\n\n @fromStore(zustand, (state: AppState) => state.flowDefinition)\n private definition!: FlowDefinition;\n\n @fromStore(zustand, (state: AppState) => state.canvasSize)\n private canvasSize!: { width: number; height: number };\n\n static get styles() {\n return css`\n #editor {\n overflow: scroll;\n flex: 1;\n }\n\n #grid {\n position: relative;\n background-color: #f9f9f9;\n background-position: 13px 13px;\n background-image: linear-gradient(\n 0deg,\n transparent 24%,\n rgba(61, 177, 255, 0.15) 25%,\n rgba(61, 177, 255, 0.15) 26%,\n transparent 27%,\n transparent 74%,\n rgba(61, 177, 255, 0.15) 75%,\n rgba(61, 177, 255, 0.15) 76%,\n transparent 77%,\n transparent\n ),\n linear-gradient(\n 90deg,\n transparent 24%,\n rgba(61, 177, 255, 0.15) 25%,\n rgba(61, 177, 255, 0.15) 26%,\n transparent 27%,\n transparent 74%,\n rgba(61, 177, 255, 0.15) 75%,\n rgba(61, 177, 255, 0.15) 76%,\n transparent 77%,\n transparent\n );\n background-size: 40px 40px;\n box-shadow: inset -5px 0 10px rgba(0, 0, 0, 0.05);\n border-top: 1px solid #e0e0e0;\n display: inline-block;\n }\n\n #canvas {\n position: relative;\n padding: 20px;\n margin: 20px;\n }\n\n body .jtk-endpoint {\n width: initial;\n height: initial;\n }\n\n .jtk-endpoint {\n z-index: 1;\n }\n\n .plumb-source {\n z-index: 300;\n border: 0px solid var(--color-connectors);\n }\n\n .plumb-source.connected {\n box-shadow: 0 3px 3px 0px rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n }\n\n .plumb-source circle {\n fill: tomato;\n }\n\n .plumb-source.connected circle {\n fill: #fff;\n }\n\n .plumb-source svg {\n fill: var(--color-connectors) !important;\n stroke: var(--color-connectors);\n }\n\n .plumb-target {\n margin-top: -6px;\n z-index: 200;\n opacity: 0;\n cursor: pointer;\n }\n\n body .plumb-connector path {\n stroke: var(--color-connectors) !important;\n stroke-width: 3px;\n }\n\n body .plumb-connector .plumb-arrow {\n fill: var(--color-connectors);\n stroke: var(--color-connectors);\n stroke-width: 0px;\n margin-top: 6px;\n }\n\n body svg.jtk-connector.jtk-hover path {\n stroke: var(--color-success) !important;\n stroke-width: 3px;\n }\n\n body .plumb-connector.jtk-hover .plumb-arrow {\n fill: var(--color-success) !important;\n stroke-width: 0px;\n }\n `;\n }\n\n constructor() {\n super();\n }\n\n protected firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n this.plumber = new Plumber(this.querySelector('#canvas'));\n if (changes.has('flow')) {\n getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);\n }\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('canvasSize')) {\n console.log('Setting canvas size', this.canvasSize);\n }\n }\n\n public render(): TemplateResult {\n // we have to embed our own style since we are in light DOM\n const style = html`<style>\n ${unsafeCSS(Editor.styles.cssText)}\n ${unsafeCSS(EditorNode.styles.cssText)}\n </style>`;\n\n return html`${style}\n <div id=\"editor\">\n <div\n id=\"grid\"\n style=\"width:${this.canvasSize.width}px; height:${this.canvasSize\n .height}px\"\n >\n <div id=\"canvas\">\n ${this.definition\n ? this.definition.nodes.map((node) => {\n return html`<temba-flow-node\n .plumber=${this.plumber}\n .node=${node}\n .ui=${this.definition._ui.nodes[node.uuid]}\n ></temba-flow-node>`;\n })\n : html`<temba-loading></temba-loading>`}\n </div>\n </div>\n </div>`;\n }\n}\n"]}
@@ -0,0 +1,199 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html } from 'lit';
3
+ import { EDITOR_CONFIG } from './config';
4
+ import { state } from 'lit/decorators.js';
5
+ import { RapidElement } from '../RapidElement';
6
+ import { getClasses } from '../utils';
7
+ import { getStore } from '../store/Store';
8
+ export class EditorNode extends RapidElement {
9
+ createRenderRoot() {
10
+ return this;
11
+ }
12
+ static get styles() {
13
+ return css `
14
+ .node {
15
+ position: absolute;
16
+ background-color: #fff;
17
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
18
+ min-width: 200px;
19
+ border-radius: calc(var(--curvature) * 1.5);
20
+ overflow: hidden;
21
+ }
22
+
23
+ .action {
24
+ max-width: 200px;
25
+ }
26
+
27
+ .action .body {
28
+ padding: 1em;
29
+ }
30
+
31
+ .action .title,
32
+ .router .title {
33
+ color: #fff;
34
+ padding: 5px 1px;
35
+ text-align: center;
36
+ font-size: 1em;
37
+ font-weight: normal;
38
+ }
39
+
40
+ .quick-replies {
41
+ margin-top: 0.5em;
42
+ }
43
+
44
+ .quick-reply {
45
+ background-color: #f0f0f0;
46
+ border: 1px solid #e0e0e0;
47
+ border-radius: calc(var(--curvature) * 1.5);
48
+ padding: 0.2em 1em;
49
+ display: inline-block;
50
+ font-size: 0.8em;
51
+ margin: 0.2em;
52
+ }
53
+
54
+ .categories {
55
+ display: flex;
56
+ flex-direction: row;
57
+
58
+ }
59
+
60
+ .category {
61
+ margin:-1px -0.5px;
62
+ border: 1px solid #f3f3f3;
63
+ padding: 0.75em;
64
+ flex-grow:1;
65
+ text-align: center;
66
+ }
67
+
68
+ .action-exits {
69
+ padding-bottom: 0.75em;
70
+ margin-top: -0.75em;
71
+ }
72
+
73
+ .category .title {
74
+ font-weight: normal;
75
+ font-size: 1em;
76
+ }
77
+
78
+ .router .body {
79
+ padding: 0.75em;
80
+ }
81
+
82
+ .result-name {
83
+ font-weight: bold;
84
+ display: inline-block;
85
+ }
86
+
87
+ .exit {
88
+ padding-top: 10px;
89
+ margin-bottom: -10px;
90
+ }
91
+ }`;
92
+ }
93
+ updated(changes) {
94
+ super.updated(changes);
95
+ if (changes.has('node')) {
96
+ this.plumber.makeTarget(this.node.uuid);
97
+ // our node was changed, see if we have new destinations
98
+ for (const exit of this.node.exits) {
99
+ if (!exit.destination_uuid) {
100
+ this.plumber.makeSource(exit.uuid);
101
+ }
102
+ else {
103
+ this.plumber.connectIds(exit.uuid, exit.destination_uuid);
104
+ }
105
+ }
106
+ const ele = this.querySelector('.node');
107
+ const rect = ele.getBoundingClientRect();
108
+ getStore()
109
+ .getState()
110
+ .expandCanvas(this.ui.position.left + rect.width, this.ui.position.top + rect.height);
111
+ }
112
+ }
113
+ renderTitle(config) {
114
+ return html `<div class="title" style="background:${config.color}">
115
+ ${config.name}
116
+ </div>`;
117
+ }
118
+ renderAction(node, action) {
119
+ const config = EDITOR_CONFIG[action.type];
120
+ if (config) {
121
+ return html `<div class="action ${action.type}">
122
+ ${this.renderTitle(config)}
123
+ <div class="body">
124
+ ${config.render
125
+ ? config.render(node, action)
126
+ : html `<pre>${action.type}</pre>`}
127
+ </div>
128
+ </div>`;
129
+ }
130
+ return html `<div>${action.type}</div>`;
131
+ }
132
+ renderRouter(router, ui) {
133
+ const config = EDITOR_CONFIG[ui.type];
134
+ if (config) {
135
+ return html `<div class="router">
136
+ ${this.renderTitle(config)}
137
+ ${router.result_name
138
+ ? html `<div class="body">
139
+ Save as
140
+ <div class="result-name">${router.result_name}</div>
141
+ </div>`
142
+ : null}
143
+ </div>`;
144
+ }
145
+ }
146
+ renderCategories(node) {
147
+ if (!node.router || !node.router.categories) {
148
+ return null;
149
+ }
150
+ const categories = node.router.categories.map((category) => {
151
+ const exit = node.exits.find((exit) => exit.uuid == category.exit_uuid);
152
+ return html `<div class="category">
153
+ <div class="title">${category.name}</div>
154
+ ${this.renderExit(exit)}
155
+ </div>`;
156
+ });
157
+ return html `<div class="categories">${categories}</div>`;
158
+ }
159
+ renderExit(exit) {
160
+ return html `<div
161
+ id="${exit.uuid}"
162
+ class=${getClasses({
163
+ exit: true,
164
+ connected: !!exit.destination_uuid
165
+ })}
166
+ ></div>`;
167
+ }
168
+ render() {
169
+ return html `
170
+ <div
171
+ id="${this.node.uuid}"
172
+ class="node"
173
+ style="left:${this.ui.position.left}px;top:${this.ui.position.top}px"
174
+ >
175
+ ${this.node.actions.map((actionSpec) => {
176
+ return this.renderAction(this.node, actionSpec);
177
+ })}
178
+ ${this.node.router
179
+ ? html ` ${this.renderRouter(this.node.router, this.ui)}
180
+ ${this.renderCategories(this.node)}`
181
+ : html `<div class="action-exits">
182
+ ${this.node.exits.map((exit) => {
183
+ return this.renderExit(exit);
184
+ })}
185
+ </div>`}
186
+ </div>
187
+ `;
188
+ }
189
+ }
190
+ __decorate([
191
+ state()
192
+ ], EditorNode.prototype, "plumber", void 0);
193
+ __decorate([
194
+ state()
195
+ ], EditorNode.prototype, "node", void 0);
196
+ __decorate([
197
+ state()
198
+ ], EditorNode.prototype, "ui", void 0);
199
+ //# sourceMappingURL=EditorNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorNode.js","sourceRoot":"","sources":["../../../src/flow/EditorNode.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { EDITOR_CONFIG, UIConfig } from './config';\nimport { Action, Exit, Node, NodeUI, Router } from '../store/flow-definition';\nimport { state } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { getClasses } from '../utils';\nimport { Plumber } from './Plumber';\nimport { getStore } from '../store/Store';\n\nexport class EditorNode extends RapidElement {\n createRenderRoot() {\n return this;\n }\n\n @state()\n private plumber: Plumber;\n\n @state()\n private node: Node;\n\n @state()\n private ui: NodeUI;\n\n static get styles() {\n return css`\n .node {\n position: absolute;\n background-color: #fff;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);\n min-width: 200px;\n border-radius: calc(var(--curvature) * 1.5);\n overflow: hidden;\n }\n\n .action {\n max-width: 200px;\n }\n\n .action .body {\n padding: 1em;\n }\n\n .action .title,\n .router .title {\n color: #fff;\n padding: 5px 1px;\n text-align: center;\n font-size: 1em;\n font-weight: normal;\n }\n\n .quick-replies {\n margin-top: 0.5em;\n }\n\n .quick-reply {\n background-color: #f0f0f0;\n border: 1px solid #e0e0e0;\n border-radius: calc(var(--curvature) * 1.5);\n padding: 0.2em 1em;\n display: inline-block;\n font-size: 0.8em;\n margin: 0.2em;\n }\n\n .categories {\n display: flex;\n flex-direction: row;\n\n }\n\n .category {\n margin:-1px -0.5px;\n border: 1px solid #f3f3f3;\n padding: 0.75em;\n flex-grow:1;\n text-align: center;\n }\n\n .action-exits {\n padding-bottom: 0.75em;\n margin-top: -0.75em;\n }\n\n .category .title {\n font-weight: normal;\n font-size: 1em;\n }\n\n .router .body {\n padding: 0.75em;\n }\n\n .result-name {\n font-weight: bold;\n display: inline-block;\n }\n \n .exit {\n padding-top: 10px;\n margin-bottom: -10px;\n }\n }`;\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('node')) {\n this.plumber.makeTarget(this.node.uuid);\n\n // our node was changed, see if we have new destinations\n for (const exit of this.node.exits) {\n if (!exit.destination_uuid) {\n this.plumber.makeSource(exit.uuid);\n } else {\n this.plumber.connectIds(exit.uuid, exit.destination_uuid);\n }\n }\n\n const ele = this.querySelector('.node');\n const rect = ele.getBoundingClientRect();\n\n getStore()\n .getState()\n .expandCanvas(\n this.ui.position.left + rect.width,\n this.ui.position.top + rect.height\n );\n }\n }\n\n private renderTitle(config: UIConfig) {\n return html`<div class=\"title\" style=\"background:${config.color}\">\n ${config.name}\n </div>`;\n }\n\n private renderAction(node: Node, action: Action) {\n const config = EDITOR_CONFIG[action.type];\n\n if (config) {\n return html`<div class=\"action ${action.type}\">\n ${this.renderTitle(config)}\n <div class=\"body\">\n ${config.render\n ? config.render(node, action)\n : html`<pre>${action.type}</pre>`}\n </div>\n </div>`;\n }\n return html`<div>${action.type}</div>`;\n }\n\n private renderRouter(router: Router, ui: NodeUI) {\n const config = EDITOR_CONFIG[ui.type];\n if (config) {\n return html`<div class=\"router\">\n ${this.renderTitle(config)}\n ${router.result_name\n ? html`<div class=\"body\">\n Save as\n <div class=\"result-name\">${router.result_name}</div>\n </div>`\n : null}\n </div>`;\n }\n }\n\n private renderCategories(node: Node) {\n if (!node.router || !node.router.categories) {\n return null;\n }\n const categories = node.router.categories.map((category) => {\n const exit = node.exits.find(\n (exit: Exit) => exit.uuid == category.exit_uuid\n );\n\n return html`<div class=\"category\">\n <div class=\"title\">${category.name}</div>\n ${this.renderExit(exit)}\n </div>`;\n });\n\n return html`<div class=\"categories\">${categories}</div>`;\n }\n\n private renderExit(exit: Exit): TemplateResult {\n return html`<div\n id=\"${exit.uuid}\"\n class=${getClasses({\n exit: true,\n connected: !!exit.destination_uuid\n })}\n ></div>`;\n }\n\n public render() {\n return html`\n <div\n id=\"${this.node.uuid}\"\n class=\"node\"\n style=\"left:${this.ui.position.left}px;top:${this.ui.position.top}px\"\n >\n ${this.node.actions.map((actionSpec) => {\n return this.renderAction(this.node, actionSpec);\n })}\n ${this.node.router\n ? html` ${this.renderRouter(this.node.router, this.ui)}\n ${this.renderCategories(this.node)}`\n : html`<div class=\"action-exits\">\n ${this.node.exits.map((exit) => {\n return this.renderExit(exit);\n })}\n </div>`}\n </div>\n `;\n }\n}\n"]}
@@ -0,0 +1,119 @@
1
+ import { DotEndpoint, FlowchartConnector, newInstance, ready, RectangleEndpoint } from '@jsplumb/browser-ui';
2
+ export const SOURCE_DEFAULTS = {
3
+ endpoint: {
4
+ type: DotEndpoint.type,
5
+ options: {
6
+ radius: 6,
7
+ connectedClass: 'plumb-connected',
8
+ cssClass: 'plumb-source',
9
+ hoverClass: 'plumb-source-hover'
10
+ }
11
+ },
12
+ anchors: ['Bottom', 'Continuous'],
13
+ maxConnections: 1,
14
+ dragAllowedWhenFull: false,
15
+ deleteEndpointsOnEmpty: true,
16
+ isSource: true
17
+ };
18
+ export const TARGET_DEFAULTS = {
19
+ endpoint: {
20
+ type: RectangleEndpoint.type,
21
+ options: {
22
+ width: 23,
23
+ height: 23,
24
+ cssClass: 'plumb-target',
25
+ hoverClass: 'plumb-target-hover'
26
+ }
27
+ },
28
+ anchor: {
29
+ type: 'Continuous',
30
+ options: {
31
+ faces: ['top', 'left', 'right'],
32
+ cssClass: 'continuos plumb-target-anchor'
33
+ }
34
+ },
35
+ dragAllowedWhenFull: false,
36
+ deleteEndpointsOnEmpty: true,
37
+ isTarget: true
38
+ };
39
+ export class Plumber {
40
+ constructor(canvas) {
41
+ this.jsPlumb = null;
42
+ this.pendingConnections = [];
43
+ this.connectionWait = null;
44
+ ready(() => {
45
+ this.jsPlumb = newInstance({
46
+ container: canvas
47
+ });
48
+ });
49
+ }
50
+ makeTarget(uuid) {
51
+ const element = document.getElementById(uuid);
52
+ this.jsPlumb.addEndpoint(element, TARGET_DEFAULTS);
53
+ }
54
+ makeSource(uuid) {
55
+ const element = document.getElementById(uuid);
56
+ this.jsPlumb.addEndpoint(element, SOURCE_DEFAULTS);
57
+ }
58
+ // we'll process our pending connections, but we want to debounce this
59
+ processPendingConnections() {
60
+ // if we have a pending connection wait, clear it
61
+ if (this.connectionWait) {
62
+ clearTimeout(this.connectionWait);
63
+ this.connectionWait = null;
64
+ }
65
+ // debounce the connection processing
66
+ this.connectionWait = setTimeout(() => {
67
+ this.jsPlumb.batch(() => {
68
+ this.pendingConnections.forEach((connection) => {
69
+ const { fromId, toId } = connection;
70
+ const fromElement = document.getElementById(fromId);
71
+ const toElement = document.getElementById(toId);
72
+ const source = this.jsPlumb.addEndpoint(fromElement, {
73
+ ...SOURCE_DEFAULTS,
74
+ endpoint: {
75
+ ...SOURCE_DEFAULTS.endpoint,
76
+ options: {
77
+ ...SOURCE_DEFAULTS.endpoint.options,
78
+ cssClass: 'plumb-source connected'
79
+ }
80
+ }
81
+ });
82
+ const target = this.jsPlumb.addEndpoint(toElement, TARGET_DEFAULTS);
83
+ this.jsPlumb.connect({
84
+ source,
85
+ target,
86
+ connector: {
87
+ type: FlowchartConnector.type,
88
+ options: {
89
+ stub: 12,
90
+ midpoint: 0.75,
91
+ alwaysRespectStubs: false,
92
+ gap: [0, 5],
93
+ cornerRadius: 3,
94
+ cssClass: 'plumb-connector'
95
+ }
96
+ },
97
+ overlays: [
98
+ {
99
+ type: 'PlainArrow',
100
+ options: {
101
+ width: 13,
102
+ length: 13,
103
+ location: 0.999,
104
+ cssClass: 'plumb-arrow'
105
+ }
106
+ }
107
+ ]
108
+ });
109
+ });
110
+ this.pendingConnections = [];
111
+ });
112
+ }, 50);
113
+ }
114
+ connectIds(fromId, toId) {
115
+ this.pendingConnections.push({ fromId, toId });
116
+ this.processPendingConnections();
117
+ }
118
+ }
119
+ //# sourceMappingURL=Plumber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Plumber.js","sourceRoot":"","sources":["../../../src/flow/Plumber.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DotEndpoint,\n FlowchartConnector,\n newInstance,\n ready,\n RectangleEndpoint\n} from '@jsplumb/browser-ui';\n\nexport const SOURCE_DEFAULTS = {\n endpoint: {\n type: DotEndpoint.type,\n options: {\n radius: 6,\n connectedClass: 'plumb-connected',\n cssClass: 'plumb-source',\n hoverClass: 'plumb-source-hover'\n }\n },\n anchors: ['Bottom', 'Continuous'],\n maxConnections: 1,\n dragAllowedWhenFull: false,\n deleteEndpointsOnEmpty: true,\n isSource: true\n};\n\nexport const TARGET_DEFAULTS = {\n endpoint: {\n type: RectangleEndpoint.type,\n options: {\n width: 23,\n height: 23,\n cssClass: 'plumb-target',\n hoverClass: 'plumb-target-hover'\n }\n },\n anchor: {\n type: 'Continuous',\n options: {\n faces: ['top', 'left', 'right'],\n cssClass: 'continuos plumb-target-anchor'\n }\n },\n dragAllowedWhenFull: false,\n deleteEndpointsOnEmpty: true,\n isTarget: true\n};\n\nexport class Plumber {\n private jsPlumb = null;\n private pendingConnections = [];\n\n constructor(canvas: HTMLElement) {\n ready(() => {\n this.jsPlumb = newInstance({\n container: canvas\n });\n });\n }\n\n public makeTarget(uuid: string) {\n const element = document.getElementById(uuid);\n this.jsPlumb.addEndpoint(element, TARGET_DEFAULTS);\n }\n\n public makeSource(uuid: string) {\n const element = document.getElementById(uuid);\n this.jsPlumb.addEndpoint(element, SOURCE_DEFAULTS);\n }\n\n private connectionWait = null;\n\n // we'll process our pending connections, but we want to debounce this\n public processPendingConnections() {\n // if we have a pending connection wait, clear it\n if (this.connectionWait) {\n clearTimeout(this.connectionWait);\n this.connectionWait = null;\n }\n\n // debounce the connection processing\n this.connectionWait = setTimeout(() => {\n this.jsPlumb.batch(() => {\n this.pendingConnections.forEach((connection) => {\n const { fromId, toId } = connection;\n const fromElement = document.getElementById(fromId);\n const toElement = document.getElementById(toId);\n\n const source = this.jsPlumb.addEndpoint(fromElement, {\n ...SOURCE_DEFAULTS,\n endpoint: {\n ...SOURCE_DEFAULTS.endpoint,\n options: {\n ...SOURCE_DEFAULTS.endpoint.options,\n cssClass: 'plumb-source connected'\n }\n }\n });\n const target = this.jsPlumb.addEndpoint(toElement, TARGET_DEFAULTS);\n this.jsPlumb.connect({\n source,\n target,\n connector: {\n type: FlowchartConnector.type,\n options: {\n stub: 12,\n midpoint: 0.75,\n alwaysRespectStubs: false,\n gap: [0, 5],\n cornerRadius: 3,\n cssClass: 'plumb-connector'\n }\n },\n overlays: [\n {\n type: 'PlainArrow',\n options: {\n width: 13,\n length: 13,\n location: 0.999,\n cssClass: 'plumb-arrow'\n }\n }\n ]\n });\n });\n this.pendingConnections = [];\n });\n }, 50);\n }\n\n public connectIds(fromId: string, toId: string) {\n this.pendingConnections.push({ fromId, toId });\n this.processPendingConnections();\n }\n}\n"]}
@@ -0,0 +1,76 @@
1
+ import { renderAddToGroups, renderCallWebhook, renderSendMsg, renderSetContactName, renderSetRunResult } from './render';
2
+ export const EDITOR_CONFIG = {
3
+ add_input_labels: {
4
+ name: 'Add Labels',
5
+ color: '#01c1af'
6
+ },
7
+ add_contact_urn: {
8
+ name: 'Add Contact URN',
9
+ color: '#01c1af'
10
+ },
11
+ set_contact_field: {
12
+ name: 'Update Contact Field',
13
+ color: '#01c1af'
14
+ },
15
+ send_broadcast: {
16
+ name: 'Send Broadcast',
17
+ color: '#8e5ea7;'
18
+ },
19
+ set_run_result: {
20
+ name: 'Save Flow Result',
21
+ color: '#1a777c',
22
+ render: renderSetRunResult
23
+ },
24
+ send_msg: {
25
+ name: 'Send Message',
26
+ color: '#3498db',
27
+ render: renderSendMsg
28
+ },
29
+ send_email: {
30
+ name: 'Send Email',
31
+ color: '#8e5ea7'
32
+ },
33
+ start_session: { name: 'Start Somebody Else', color: '#df419f' },
34
+ call_webhook: {
35
+ name: 'Call Webhook',
36
+ color: '#e68628',
37
+ render: renderCallWebhook
38
+ },
39
+ call_llm: {
40
+ name: 'Call AI',
41
+ color: '#e68628'
42
+ },
43
+ transfer_airtime: {
44
+ name: 'Send Airtime',
45
+ color: '#e68628'
46
+ },
47
+ wait_for_response: { name: 'Wait for Response', color: '#4d7dad' },
48
+ split_by_expression: { name: 'Split by Expression', color: '#aaaaaa' },
49
+ split_by_contact_field: {
50
+ name: 'Split by <Contact Field Name>',
51
+ color: '#aaaaaa'
52
+ },
53
+ set_contact_name: {
54
+ name: 'Update Contact',
55
+ color: '#01c1af',
56
+ render: renderSetContactName
57
+ },
58
+ add_contact_groups: {
59
+ name: 'Add to Group',
60
+ color: '#309c42',
61
+ render: renderAddToGroups
62
+ },
63
+ remove_contact_groups: {
64
+ name: 'Remove from Group',
65
+ color: '#666'
66
+ },
67
+ request_optin: {
68
+ name: 'Request Opt-in',
69
+ color: '#3498db'
70
+ },
71
+ split_by_run_result: {
72
+ name: 'Split by Flow Result',
73
+ color: '#aaaaaa'
74
+ }
75
+ };
76
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/flow/config.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,UAAU,CAAC;AAQlB,MAAM,CAAC,MAAM,aAAa,GAEtB;IACF,gBAAgB,EAAE;QAChB,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,SAAS;KACjB;IACD,eAAe,EAAE;QACf,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,SAAS;KACjB;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,sBAAsB;QAC5B,KAAK,EAAE,SAAS;KACjB;IACD,cAAc,EAAE;QACd,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,UAAU;KAClB;IACD,cAAc,EAAE;QACd,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,kBAAkB;KAC3B;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,aAAa;KACtB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,SAAS;KACjB;IACD,aAAa,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE;IAChE,YAAY,EAAE;QACZ,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,iBAAiB;KAC1B;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;KACjB;IACD,gBAAgB,EAAE;QAChB,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,SAAS;KACjB;IACD,iBAAiB,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE;IAClE,mBAAmB,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE;IACtE,sBAAsB,EAAE;QACtB,IAAI,EAAE,+BAA+B;QACrC,KAAK,EAAE,SAAS;KACjB;IACD,gBAAgB,EAAE;QAChB,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,oBAAoB;KAC7B;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,iBAAiB;KAC1B;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,MAAM;KACd;IACD,aAAa,EAAE;QACb,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,SAAS;KACjB;IACD,mBAAmB,EAAE;QACnB,IAAI,EAAE,sBAAsB;QAC5B,KAAK,EAAE,SAAS;KACjB;CACF,CAAC","sourcesContent":["import { TemplateResult } from 'lit-html';\nimport {\n renderAddToGroups,\n renderCallWebhook,\n renderSendMsg,\n renderSetContactName,\n renderSetRunResult\n} from './render';\n\nexport interface UIConfig {\n name: string;\n color: string;\n render?: (node: any, action: any) => TemplateResult;\n}\n\nexport const EDITOR_CONFIG: {\n [key: string]: UIConfig;\n} = {\n add_input_labels: {\n name: 'Add Labels',\n color: '#01c1af'\n },\n add_contact_urn: {\n name: 'Add Contact URN',\n color: '#01c1af'\n },\n set_contact_field: {\n name: 'Update Contact Field',\n color: '#01c1af'\n },\n send_broadcast: {\n name: 'Send Broadcast',\n color: '#8e5ea7;'\n },\n set_run_result: {\n name: 'Save Flow Result',\n color: '#1a777c',\n render: renderSetRunResult\n },\n send_msg: {\n name: 'Send Message',\n color: '#3498db',\n render: renderSendMsg\n },\n send_email: {\n name: 'Send Email',\n color: '#8e5ea7'\n },\n start_session: { name: 'Start Somebody Else', color: '#df419f' },\n call_webhook: {\n name: 'Call Webhook',\n color: '#e68628',\n render: renderCallWebhook\n },\n call_llm: {\n name: 'Call AI',\n color: '#e68628'\n },\n transfer_airtime: {\n name: 'Send Airtime',\n color: '#e68628'\n },\n wait_for_response: { name: 'Wait for Response', color: '#4d7dad' },\n split_by_expression: { name: 'Split by Expression', color: '#aaaaaa' },\n split_by_contact_field: {\n name: 'Split by <Contact Field Name>',\n color: '#aaaaaa'\n },\n set_contact_name: {\n name: 'Update Contact',\n color: '#01c1af',\n render: renderSetContactName\n },\n add_contact_groups: {\n name: 'Add to Group',\n color: '#309c42',\n render: renderAddToGroups\n },\n remove_contact_groups: {\n name: 'Remove from Group',\n color: '#666'\n },\n request_optin: {\n name: 'Request Opt-in',\n color: '#3498db'\n },\n split_by_run_result: {\n name: 'Split by Flow Result',\n color: '#aaaaaa'\n }\n};\n"]}
@@ -0,0 +1,41 @@
1
+ import { html } from 'lit-html';
2
+ import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
3
+ const renderNamedObjects = (assets, icon) => {
4
+ return assets.map((asset) => {
5
+ return html `<div style="display:flex;items-align:center">
6
+ ${icon
7
+ ? html `<temba-icon
8
+ name=${icon}
9
+ style="margin-right:0.5em"
10
+ ></temba-icon>`
11
+ : null}
12
+ <div>${asset.name}</div>
13
+ </div>`;
14
+ });
15
+ };
16
+ export const renderSendMsg = (node, action) => {
17
+ const text = action.text.replace(/\n/g, '<br>');
18
+ return html `
19
+ ${unsafeHTML(text)}
20
+ ${action.quick_replies.length > 0
21
+ ? html `<div class="quick-replies">
22
+ ${action.quick_replies.map((reply) => {
23
+ return html `<div class="quick-reply">${reply}</div>`;
24
+ })}
25
+ </div>`
26
+ : null}
27
+ `;
28
+ };
29
+ export const renderSetContactName = (node, action) => {
30
+ return html `<div>Set contact name to <b>${action.name}</b></div>`;
31
+ };
32
+ export const renderSetRunResult = (node, action) => {
33
+ return html `<div>Save ${action.value} as <b>${action.name}</b></div>`;
34
+ };
35
+ export const renderCallWebhook = (node, action) => {
36
+ return html `<div style="word-break: break-all">${action.url}</div>`;
37
+ };
38
+ export const renderAddToGroups = (node, action) => {
39
+ return html `<div>${renderNamedObjects(action.groups, 'group')}</div>`;
40
+ };
41
+ //# sourceMappingURL=render.js.map