@nyaruka/temba-components 0.129.5 → 0.129.7

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 (85) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/demo/components/flow/example.html +8 -1
  3. package/demo/components/flow/index.html +206 -0
  4. package/demo/data/flows/food-order.json +141 -0
  5. package/demo/data/flows/sample-flow.json +14 -14
  6. package/demo/index.html +1 -1
  7. package/dist/temba-components.js +16 -6
  8. package/dist/temba-components.js.map +1 -1
  9. package/out-tsc/src/events.js.map +1 -1
  10. package/out-tsc/src/flow/CanvasNode.js +10 -2
  11. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  12. package/out-tsc/src/flow/StickyNote.js +1 -1
  13. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  14. package/out-tsc/src/flow/actions/send_email.js +1 -2
  15. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  16. package/out-tsc/src/flow/actions/send_msg.js +9 -2
  17. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  18. package/out-tsc/src/live/ContactChat.js +3 -3
  19. package/out-tsc/src/live/ContactChat.js.map +1 -1
  20. package/package.json +1 -1
  21. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  22. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  23. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  24. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  25. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  26. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  27. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  28. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  29. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  30. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  31. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  32. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  33. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  34. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  35. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  36. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  37. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  38. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  39. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  40. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  41. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  42. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  43. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  44. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  45. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  46. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  47. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  48. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  49. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  50. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  51. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  52. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  53. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  54. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  55. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  56. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  57. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  58. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  59. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  60. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  61. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  62. package/screenshots/truth/editor/send_msg.png +0 -0
  63. package/screenshots/truth/editor/set_contact_name.png +0 -0
  64. package/screenshots/truth/editor/set_run_result.png +0 -0
  65. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  66. package/screenshots/truth/sticky-note/blue.png +0 -0
  67. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  68. package/screenshots/truth/sticky-note/default.png +0 -0
  69. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  70. package/screenshots/truth/sticky-note/gray.png +0 -0
  71. package/screenshots/truth/sticky-note/green-color.png +0 -0
  72. package/screenshots/truth/sticky-note/green.png +0 -0
  73. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  74. package/screenshots/truth/sticky-note/pink.png +0 -0
  75. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  76. package/screenshots/truth/sticky-note/yellow.png +0 -0
  77. package/src/events.ts +1 -2
  78. package/src/flow/CanvasNode.ts +10 -2
  79. package/src/flow/StickyNote.ts +1 -1
  80. package/src/flow/actions/send_email.ts +1 -2
  81. package/src/flow/actions/send_msg.ts +9 -2
  82. package/src/live/ContactChat.ts +3 -3
  83. package/src/store/flow-definition.d.ts +25 -4
  84. package/test-assets/contacts/history.json +1 -2
  85. package/web-dev-server.config.mjs +20 -1
package/CHANGELOG.md CHANGED
@@ -4,9 +4,34 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- #### [v0.129.5](https://github.com/nyaruka/temba-components/compare/v0.129.3...v0.129.5)
7
+ #### [v0.129.7](https://github.com/nyaruka/temba-components/compare/v0.129.6...v0.129.7)
8
+
9
+ - Fix rendering of airtime transfer events [`#656`](https://github.com/nyaruka/temba-components/pull/656)
10
+ - Update some flow def, show wa templates, fix exit clicks [`#652`](https://github.com/nyaruka/temba-components/pull/652)
11
+ - Flow example list page [`#651`](https://github.com/nyaruka/temba-components/pull/651)
12
+ - Support multiple flow examples [`932de08`](https://github.com/nyaruka/temba-components/commit/932de08987089145781dd9756ef9a8752f630ccb)
13
+ - Update screenshots [`7ee7687`](https://github.com/nyaruka/temba-components/commit/7ee76872923341ba310ccfe99cea1a939d72d9f3)
14
+ - Use json for flow list [`208f26e`](https://github.com/nyaruka/temba-components/commit/208f26ead8060ebeedac68f4d50a9ade2f7fc4e6)
15
+
16
+ #### [v0.129.6](https://github.com/nyaruka/temba-components/compare/v0.129.5...v0.129.6)
17
+
18
+ > 12 August 2025
19
+
20
+ - Fix message event to use ID for chatevent [`#650`](https://github.com/nyaruka/temba-components/pull/650)
21
+
22
+ #### [v0.129.5](https://github.com/nyaruka/temba-components/compare/v0.129.4...v0.129.5)
23
+
24
+ > 12 August 2025
8
25
 
9
26
  - Don't trigger ref change on internal values change for Select [`#648`](https://github.com/nyaruka/temba-components/pull/648)
27
+ - Fixes for select change events [`cbb301f`](https://github.com/nyaruka/temba-components/commit/cbb301f372e5b7a17193365c2fc9392f4b0c7bf9)
28
+ - Remove unneccessary change [`7ab2e16`](https://github.com/nyaruka/temba-components/commit/7ab2e16686f805592c96f686ef67cbf31882fe3f)
29
+ - Update sample flow formatting [`c5b7554`](https://github.com/nyaruka/temba-components/commit/c5b75540e26b0ea0d775793af4259563af501f82)
30
+
31
+ #### [v0.129.4](https://github.com/nyaruka/temba-components/compare/v0.129.3...v0.129.4)
32
+
33
+ > 11 August 2025
34
+
10
35
  - Cleanup unused chat event types and remove some unused properties on other types [`#647`](https://github.com/nyaruka/temba-components/pull/647)
11
36
  - Nestable form layouts [`#644`](https://github.com/nyaruka/temba-components/pull/644)
12
37
  - Add KeyValueEditor and field config abstraction [`#643`](https://github.com/nyaruka/temba-components/pull/643)
@@ -37,10 +37,17 @@
37
37
  </head>
38
38
  <body>
39
39
  <temba-store></temba-store>
40
- <temba-flow-editor flow="sample-flow"></temba-flow-editor>
40
+ <temba-flow-editor id="flow-editor"></temba-flow-editor>
41
41
 
42
42
  <script type="module">
43
43
  import '/out-tsc/temba-modules.js';
44
+
45
+ // Get flow parameter from URL, default to 'sample-flow'
46
+ const urlParams = new URLSearchParams(window.location.search);
47
+ const flowName = urlParams.get('flow') || 'sample-flow';
48
+
49
+ // Set the flow attribute on the editor
50
+ document.getElementById('flow-editor').setAttribute('flow', flowName);
44
51
  </script>
45
52
  </body>
46
53
  </html>
@@ -0,0 +1,206 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-GB">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Flow Editor Examples</title>
6
+ <link
7
+ href="/static/css/temba-components.css"
8
+ rel="stylesheet"
9
+ type="text/css"
10
+ />
11
+ <link
12
+ href="https://fonts.googleapis.com/css?family=Roboto+Mono:300|Roboto:300,400,500"
13
+ rel="stylesheet"
14
+ />
15
+ <link href="../../styles.css" rel="stylesheet" type="text/css" />
16
+ <style>
17
+ .flow-list {
18
+ max-width: 800px;
19
+ margin: 0 auto;
20
+ padding: 40px 20px;
21
+ }
22
+
23
+ .flow-card {
24
+ background: white;
25
+ border: 1px solid #e1e5e9;
26
+ border-radius: 8px;
27
+ padding: 24px;
28
+ margin-bottom: 16px;
29
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
30
+ transition: box-shadow 0.2s ease;
31
+ display: flex;
32
+ justify-content: space-between;
33
+ align-items: center;
34
+ }
35
+
36
+ .flow-card:hover {
37
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
38
+ }
39
+
40
+ .flow-title {
41
+ font-size: 1.5em;
42
+ font-weight: 500;
43
+ color: #2c3e50;
44
+ margin: 0;
45
+ }
46
+
47
+ .flow-link {
48
+ display: inline-block;
49
+ background: #3498db;
50
+ color: white;
51
+ padding: 12px 24px;
52
+ text-decoration: none;
53
+ border-radius: 4px;
54
+ font-weight: 500;
55
+ transition: background-color 0.2s ease;
56
+ }
57
+
58
+ .flow-link:hover {
59
+ background: #2980b9;
60
+ color: white;
61
+ }
62
+
63
+ .back-link {
64
+ display: inline-block;
65
+ margin-bottom: 24px;
66
+ color: #3498db;
67
+ text-decoration: none;
68
+ }
69
+
70
+ .back-link:hover {
71
+ text-decoration: underline;
72
+ }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="flow-list">
77
+ <a href="../../index.html" class="back-link">← Back to Component Demos</a>
78
+
79
+ <h1>Flow Editor Examples</h1>
80
+ <p>
81
+ Choose a flow to open in the Flow Editor. Each flow demonstrates
82
+ different features and capabilities.
83
+ </p>
84
+
85
+ <div id="flow-cards">
86
+ <div class="flow-card">
87
+ <div class="flow-title">Loading flows...</div>
88
+ </div>
89
+ </div>
90
+ </div>
91
+
92
+ <script type="module">
93
+ // Function to load and display flows dynamically
94
+ async function loadFlows() {
95
+ const flowCardsContainer = document.getElementById('flow-cards');
96
+
97
+ try {
98
+ // Get list of flow files from the flows directory API
99
+ const response = await fetch('/api/flows-list');
100
+ const files = await response.json();
101
+
102
+ if (!Array.isArray(files) || files.length === 0) {
103
+ // Fallback: try known flows if directory listing doesn't work
104
+ await loadKnownFlows(flowCardsContainer);
105
+ return;
106
+ }
107
+
108
+ const flows = [];
109
+
110
+ // Load each flow file to get its definition
111
+ for (const fileName of files) {
112
+ const flowId = fileName.replace('.json', '');
113
+
114
+ try {
115
+ const flowResponse = await fetch(`/demo/data/flows/${fileName}`);
116
+ const flowData = await flowResponse.json();
117
+ const flowName = flowData.definition?.name || flowId;
118
+
119
+ flows.push({
120
+ id: flowId,
121
+ name: flowName
122
+ });
123
+ } catch (error) {
124
+ console.warn(`Failed to load flow ${fileName}:`, error);
125
+ // Add with fallback name
126
+ flows.push({
127
+ id: flowId,
128
+ name: flowId
129
+ .replace('-', ' ')
130
+ .replace(/\b\w/g, (l) => l.toUpperCase())
131
+ });
132
+ }
133
+ }
134
+
135
+ displayFlows(flows, flowCardsContainer);
136
+ } catch (error) {
137
+ console.warn(
138
+ 'Failed to load flows from directory, using fallback:',
139
+ error
140
+ );
141
+ // await loadKnownFlows(flowCardsContainer);
142
+ }
143
+ }
144
+
145
+ // Fallback function for known flows
146
+ async function loadKnownFlows(container) {
147
+ const knownFlows = ['sample-flow', 'food-order'];
148
+ const flows = [];
149
+
150
+ for (const flowId of knownFlows) {
151
+ try {
152
+ const response = await fetch(`/demo/data/flows/${flowId}.json`);
153
+ const flowData = await response.json();
154
+ const flowName = flowData.definition?.name || flowId;
155
+
156
+ flows.push({
157
+ id: flowId,
158
+ name: flowName
159
+ });
160
+ } catch (error) {
161
+ console.warn(`Failed to load flow ${flowId}:`, error);
162
+ }
163
+ }
164
+
165
+ displayFlows(flows, container);
166
+ }
167
+
168
+ // Function to display flows in the UI
169
+ function displayFlows(flows, container) {
170
+ if (flows.length === 0) {
171
+ container.innerHTML = `
172
+ <div class="flow-card">
173
+ <div class="flow-title">No flows found</div>
174
+ </div>
175
+ `;
176
+ return;
177
+ }
178
+
179
+ container.innerHTML = flows
180
+ .map(
181
+ (flow) => `
182
+ <div class="flow-card">
183
+ <div class="flow-title">${escapeHtml(flow.name)}</div>
184
+ <a href="example.html?flow=${encodeURIComponent(
185
+ flow.id
186
+ )}" class="flow-link">
187
+ Open Flow
188
+ </a>
189
+ </div>
190
+ `
191
+ )
192
+ .join('');
193
+ }
194
+
195
+ // Helper function to escape HTML
196
+ function escapeHtml(text) {
197
+ const div = document.createElement('div');
198
+ div.textContent = text;
199
+ return div.innerHTML;
200
+ }
201
+
202
+ // Load flows when the page loads
203
+ loadFlows();
204
+ </script>
205
+ </body>
206
+ </html>
@@ -0,0 +1,141 @@
1
+ {
2
+ "definition": {
3
+ "_ui": {
4
+ "nodes": {
5
+ "b01610c8-d6dc-4bdb-9439-5713cdcf9afa": {
6
+ "position": {
7
+ "left": 80,
8
+ "top": 80
9
+ },
10
+ "type": "execute_actions"
11
+ },
12
+ "3b28a90f-27be-4753-b0c0-3e98b83f0627": {
13
+ "type": "wait_for_response",
14
+ "position": {
15
+ "left": 80,
16
+ "top": 260
17
+ },
18
+ "config": {
19
+ "cases": {}
20
+ }
21
+ }
22
+ },
23
+ "stickies": {
24
+ "b1cb8cfa-8432-444c-bd48-3fd2cb3a014f": {
25
+ "position": {
26
+ "left": 340,
27
+ "top": 120
28
+ },
29
+ "title": "Long awaited note",
30
+ "body": "This is the body of a note that I have been waiting to write for a very long time. Now I am able to add it to my flow and that makes me very happy.",
31
+ "color": "blue"
32
+ }
33
+ }
34
+ },
35
+ "expire_after_minutes": 10080,
36
+ "language": "eng",
37
+ "localization": {},
38
+ "name": "Food Order",
39
+ "nodes": [
40
+ {
41
+ "uuid": "b01610c8-d6dc-4bdb-9439-5713cdcf9afa",
42
+ "actions": [
43
+ {
44
+ "attachments": [
45
+ "image/jpeg:http://minio:9000/temba-default/orgs/1/media/495c/495c33e3-237e-4c36-b854-6ca609839e3a/intro-1745448388.jpg",
46
+ "image:@fields.profile_pic"
47
+ ],
48
+ "text": "Chicken or fish?",
49
+ "type": "send_msg",
50
+ "quick_replies": [
51
+ "Chicken",
52
+ "Fish"
53
+ ],
54
+ "uuid": "90957b4e-05a4-4d00-8163-47046f81246d",
55
+ "template": {
56
+ "uuid": "b5e47571-4ee7-4e9e-b48f-1c4efd4d6429",
57
+ "name": "Dinner Menu"
58
+ },
59
+ "template_variables": [
60
+ "Food",
61
+ "@contact.name",
62
+ "Chicken",
63
+ "Fish",
64
+ "Rowan"
65
+ ]
66
+ }
67
+ ],
68
+ "exits": [
69
+ {
70
+ "uuid": "87e6cd04-4dd7-44e7-b517-3f3fa63e837e",
71
+ "destination_uuid": "3b28a90f-27be-4753-b0c0-3e98b83f0627"
72
+ }
73
+ ]
74
+ },
75
+ {
76
+ "uuid": "3b28a90f-27be-4753-b0c0-3e98b83f0627",
77
+ "actions": [],
78
+ "router": {
79
+ "type": "switch",
80
+ "default_category_uuid": "706df9a8-9f55-446f-9212-2493da1b42c2",
81
+ "cases": [
82
+ {
83
+ "arguments": [
84
+ "chicken 🐔"
85
+ ],
86
+ "type": "has_any_word",
87
+ "uuid": "a0046472-2a86-4c1f-b02d-a63a98abb5e3",
88
+ "category_uuid": "6f4689dd-6a8b-454c-a1db-192de1c283ee"
89
+ },
90
+ {
91
+ "arguments": [
92
+ "fish 🐟"
93
+ ],
94
+ "type": "has_any_word",
95
+ "uuid": "2f8fbf02-80cd-4b26-b7d7-709e8681d2ce",
96
+ "category_uuid": "390bbb17-49fd-4253-ac7f-6a27ef240b56"
97
+ }
98
+ ],
99
+ "categories": [
100
+ {
101
+ "uuid": "6f4689dd-6a8b-454c-a1db-192de1c283ee",
102
+ "name": "🐔",
103
+ "exit_uuid": "9e84e680-a710-4894-a838-dd22a8dcc341"
104
+ },
105
+ {
106
+ "uuid": "390bbb17-49fd-4253-ac7f-6a27ef240b56",
107
+ "name": "🐟",
108
+ "exit_uuid": "12043e9e-7aa0-41fd-8f04-e0d42a0c2099"
109
+ },
110
+ {
111
+ "uuid": "706df9a8-9f55-446f-9212-2493da1b42c2",
112
+ "name": "Other",
113
+ "exit_uuid": "79b6a4e6-1a00-44cc-9fd4-2d9ba2a394e0"
114
+ }
115
+ ],
116
+ "operand": "@input.text",
117
+ "wait": {
118
+ "type": "msg"
119
+ },
120
+ "result_name": "Order"
121
+ },
122
+ "exits": [
123
+ {
124
+ "uuid": "9e84e680-a710-4894-a838-dd22a8dcc341"
125
+ },
126
+ {
127
+ "uuid": "12043e9e-7aa0-41fd-8f04-e0d42a0c2099"
128
+ },
129
+ {
130
+ "uuid": "79b6a4e6-1a00-44cc-9fd4-2d9ba2a394e0",
131
+ "destination_uuid": null
132
+ }
133
+ ]
134
+ }
135
+ ],
136
+ "spec_version": "14.3.0",
137
+ "type": "messaging",
138
+ "uuid": "8f1fa2e3-740a-4f06-b67b-d521643eb52b",
139
+ "revision": 50
140
+ }
141
+ }
@@ -181,15 +181,6 @@
181
181
  {
182
182
  "uuid": "4efc49e0-ebfe-454d-a1a0-900a911dd5ef",
183
183
  "actions": [
184
- {
185
- "uuid": "9963160a-a007-4c7b-8c9e-7325e1b69ed8",
186
- "type": "send_msg",
187
- "text": "Excellent choices.",
188
- "quick_replies": [
189
- "blooooop",
190
- "bleep"
191
- ]
192
- },
193
184
  {
194
185
  "uuid": "ffe1c2d3-4e5f-6a7b-8c9d-e0f1a2b3c4d5",
195
186
  "type": "remove_contact_groups",
@@ -230,6 +221,15 @@
230
221
  ],
231
222
  "all_groups": false
232
223
  },
224
+ {
225
+ "uuid": "9963160a-a007-4c7b-8c9e-7325e1b69ed8",
226
+ "type": "send_msg",
227
+ "text": "Excellent choices.",
228
+ "quick_replies": [
229
+ "blooooop",
230
+ "bleep"
231
+ ]
232
+ },
233
233
  {
234
234
  "uuid": "d1ca86da-f321-4e09-8bb2-981de03f5a90",
235
235
  "type": "add_contact_groups",
@@ -907,14 +907,14 @@
907
907
  "3dfe9cf2-72d1-496f-8d20-d5743af0f9c8": {
908
908
  "type": "split_by_llm",
909
909
  "position": {
910
- "left": 580,
911
- "top": 1040
910
+ "left": 520,
911
+ "top": 1020
912
912
  },
913
913
  "config": {}
914
914
  },
915
915
  "425c4757-bead-440f-92aa-a1cc3fcd7d35": {
916
916
  "position": {
917
- "left": 620,
917
+ "left": 760,
918
918
  "top": 840
919
919
  },
920
920
  "type": "execute_actions"
@@ -922,8 +922,8 @@
922
922
  "21ff86c2-5276-4448-afb6-54d1f832ba0c": {
923
923
  "type": "split_by_ticket",
924
924
  "position": {
925
- "left": 920,
926
- "top": 900
925
+ "left": 820,
926
+ "top": 980
927
927
  },
928
928
  "config": {}
929
929
  }
package/demo/index.html CHANGED
@@ -175,7 +175,7 @@
175
175
  A work in progress editor for RapidPro flows to replace existing
176
176
  react editor.
177
177
  </p>
178
- <a href="components/flow/example.html">Example</a>
178
+ <a href="components/flow/index.html">Examples</a>
179
179
  </div>
180
180
 
181
181
  <div class="component-card">
@@ -2725,7 +2725,7 @@ let Ar=rr,Mr=!1;const Tr=["es","fr","pt"],Pr="data:image/png;base64,iVBORw0KGgoA
2725
2725
  </div>
2726
2726
  <slot class="header" name="header"></slot>
2727
2727
  <slot class="footer" name="footer"></slot>
2728
- </div>`}}var Gc;t([xe({type:Array})],Wc.prototype,"messageGroups",void 0),t([xe({type:Boolean})],Wc.prototype,"fetching",void 0),t([xe({type:Boolean,attribute:!1})],Wc.prototype,"hideTopScroll",void 0),t([xe({type:Boolean,attribute:!1})],Wc.prototype,"hideBottomScroll",void 0),t([xe({type:String,attribute:"avatar"})],Wc.prototype,"defaultAvatar",void 0),t([xe({type:Boolean})],Wc.prototype,"agent",void 0),function(t){t.send="send-03",t.attachment="paperclip",t.attachment_audio="volume-min",t.attachment_document="file-06",t.attachment_image="image-01",t.attachment_location="marker-pin-01",t.attachment_video="video-recorder"}(Gc||(Gc={}));var Zc;!function(t){t.MESSAGE_CREATED="msg_created",t.MESSAGE_RECEIVED="msg_received",t.BROADCAST_CREATED="broadcast_created",t.IVR_CREATED="ivr_created",t.FLOW_ENTERED="flow_entered",t.FLOW_EXITED="flow_exited",t.CONTACT_FIELD_CHANGED="contact_field_changed",t.CONTACT_GROUPS_CHANGED="contact_groups_changed",t.CONTACT_NAME_CHANGED="contact_name_changed",t.CONTACT_URNS_CHANGED="contact_urns_changed",t.CHANNEL_EVENT="channel_event",t.CONTACT_LANGUAGE_CHANGED="contact_language_changed",t.AIRTIME_TRANSFERRED="airtime_transferred",t.CALL_STARTED="call_started",t.NOTE_CREATED="note_created",t.TICKET_ASSIGNED="ticket_assigned",t.TICKET_NOTE_ADDED="ticket_note_added",t.TICKET_CLOSED="ticket_closed",t.TICKET_OPENED="ticket_opened",t.TICKET_REOPENED="ticket_reopened",t.TICKET_TOPIC_CHANGED="ticket_topic_changed",t.OPTIN_REQUESTED="optin_requested"}(Zc||(Zc={}));const Yc=(t,e,i)=>{if(1===i.length)return`${t} **${i[0].name}**`;{const t=i.map((t=>`**${t.name}**`));if(2===t.length)return`${e} ${t.join(" and ")}`;{const i=t.pop();return`${e} ${t.join(", ")}, and ${i}`}}},Xc=t=>{var e,i;return"mt_miss"===t.event.type?"Missed outgoing call":"mo_miss"===t.event.type?"Missed incoming call":"new_conversation"===t.event.type?"Started conversation":"welcome_message"===t.channel_event_type?"Welcome Message Sent":"referral"===t.event.type?"Referred":"follow"===t.event.type?"Followed":"stop_contact"===t.event.type?"Stopped":"mt_call"===t.event.type?"Outgoing Phone Call":"mo_call"==t.event.type?"Incoming Phone call":"optin"==t.event.type?`Opted in to **${null===(e=t.event.optin)||void 0===e?void 0:e.name}**`:"optout"==t.event.type?`Opted out of **${null===(i=t.event.optin)||void 0===i?void 0:i.name}**`:void 0},Kc=t=>{let e="Interrupted";return"I"!==t.status&&(e=t.type===Zc.FLOW_ENTERED?"Started":"Completed"),`${e} [**${t.flow.name}**](/flow/editor/${t.flow.uuid}/)`},Qc=t=>t.value?`Updated **${t.field.name}** to **${t.value.text}**`:`Cleared **${t.field.name}**`,Jc=t=>`Updated **Contact Name** to **${t.name}**`,th=t=>`Updated **URNs** to ${le(t.urns,(t=>`**${t.split(":")[1].split("?")[0]}**`))}`,eh=(t,e)=>t.created_by?`**${(t=>{if(t)return t.first_name&&t.last_name?`${t.first_name} ${t.last_name}`:t.first_name?t.first_name:t.email})(t.created_by)}** ${e} a **[ticket](/ticket/all/closed/${t.ticket.uuid}/)**`:`A **[ticket](/ticket/all/closed/${t.ticket.uuid}/)** was **${e}**`,ih=t=>t.assignee?t.assignee.id===t.created_by.id?`**${ch(t.created_by)}** took this ticket`:`${ch(t.created_by)} assigned this ticket to **${ch(t.assignee)}**`:`**${ch(t.created_by)}** unassigned this ticket`,nh=t=>{const e=t;return e.groups_added?Yc("Added to group","Added to groups",e.groups_added):e.groups_removed?Yc("Removed from group","Removed from groups",e.groups_removed):void 0},oh=t=>0===parseFloat(t.actual_amount)?"Airtime transfer failed":`Transferred **${t.actual_amount}** ${t.currency} of airtime`,sh=t=>`Language updated to **${t.language}**`,rh=t=>`Requested opt-in for ${t.optin.name}`;class ah extends Fc{static get styles(){return a`
2728
+ </div>`}}var Gc;t([xe({type:Array})],Wc.prototype,"messageGroups",void 0),t([xe({type:Boolean})],Wc.prototype,"fetching",void 0),t([xe({type:Boolean,attribute:!1})],Wc.prototype,"hideTopScroll",void 0),t([xe({type:Boolean,attribute:!1})],Wc.prototype,"hideBottomScroll",void 0),t([xe({type:String,attribute:"avatar"})],Wc.prototype,"defaultAvatar",void 0),t([xe({type:Boolean})],Wc.prototype,"agent",void 0),function(t){t.send="send-03",t.attachment="paperclip",t.attachment_audio="volume-min",t.attachment_document="file-06",t.attachment_image="image-01",t.attachment_location="marker-pin-01",t.attachment_video="video-recorder"}(Gc||(Gc={}));var Zc;!function(t){t.MESSAGE_CREATED="msg_created",t.MESSAGE_RECEIVED="msg_received",t.BROADCAST_CREATED="broadcast_created",t.IVR_CREATED="ivr_created",t.FLOW_ENTERED="flow_entered",t.FLOW_EXITED="flow_exited",t.CONTACT_FIELD_CHANGED="contact_field_changed",t.CONTACT_GROUPS_CHANGED="contact_groups_changed",t.CONTACT_NAME_CHANGED="contact_name_changed",t.CONTACT_URNS_CHANGED="contact_urns_changed",t.CHANNEL_EVENT="channel_event",t.CONTACT_LANGUAGE_CHANGED="contact_language_changed",t.AIRTIME_TRANSFERRED="airtime_transferred",t.CALL_STARTED="call_started",t.NOTE_CREATED="note_created",t.TICKET_ASSIGNED="ticket_assigned",t.TICKET_NOTE_ADDED="ticket_note_added",t.TICKET_CLOSED="ticket_closed",t.TICKET_OPENED="ticket_opened",t.TICKET_REOPENED="ticket_reopened",t.TICKET_TOPIC_CHANGED="ticket_topic_changed",t.OPTIN_REQUESTED="optin_requested"}(Zc||(Zc={}));const Yc=(t,e,i)=>{if(1===i.length)return`${t} **${i[0].name}**`;{const t=i.map((t=>`**${t.name}**`));if(2===t.length)return`${e} ${t.join(" and ")}`;{const i=t.pop();return`${e} ${t.join(", ")}, and ${i}`}}},Xc=t=>{var e,i;return"mt_miss"===t.event.type?"Missed outgoing call":"mo_miss"===t.event.type?"Missed incoming call":"new_conversation"===t.event.type?"Started conversation":"welcome_message"===t.channel_event_type?"Welcome Message Sent":"referral"===t.event.type?"Referred":"follow"===t.event.type?"Followed":"stop_contact"===t.event.type?"Stopped":"mt_call"===t.event.type?"Outgoing Phone Call":"mo_call"==t.event.type?"Incoming Phone call":"optin"==t.event.type?`Opted in to **${null===(e=t.event.optin)||void 0===e?void 0:e.name}**`:"optout"==t.event.type?`Opted out of **${null===(i=t.event.optin)||void 0===i?void 0:i.name}**`:void 0},Kc=t=>{let e="Interrupted";return"I"!==t.status&&(e=t.type===Zc.FLOW_ENTERED?"Started":"Completed"),`${e} [**${t.flow.name}**](/flow/editor/${t.flow.uuid}/)`},Qc=t=>t.value?`Updated **${t.field.name}** to **${t.value.text}**`:`Cleared **${t.field.name}**`,Jc=t=>`Updated **Contact Name** to **${t.name}**`,th=t=>`Updated **URNs** to ${le(t.urns,(t=>`**${t.split(":")[1].split("?")[0]}**`))}`,eh=(t,e)=>t.created_by?`**${(t=>{if(t)return t.first_name&&t.last_name?`${t.first_name} ${t.last_name}`:t.first_name?t.first_name:t.email})(t.created_by)}** ${e} a **[ticket](/ticket/all/closed/${t.ticket.uuid}/)**`:`A **[ticket](/ticket/all/closed/${t.ticket.uuid}/)** was **${e}**`,ih=t=>t.assignee?t.assignee.id===t.created_by.id?`**${ch(t.created_by)}** took this ticket`:`${ch(t.created_by)} assigned this ticket to **${ch(t.assignee)}**`:`**${ch(t.created_by)}** unassigned this ticket`,nh=t=>{const e=t;return e.groups_added?Yc("Added to group","Added to groups",e.groups_added):e.groups_removed?Yc("Removed from group","Removed from groups",e.groups_removed):void 0},oh=t=>0===parseFloat(t.amount)?"Airtime transfer failed":`Transferred **${t.amount}** ${t.currency} of airtime`,sh=t=>`Language updated to **${t.language}**`,rh=t=>`Requested opt-in for ${t.optin.name}`;class ah extends Fc{static get styles(){return a`
2729
2729
  :host {
2730
2730
  flex-grow: 1;
2731
2731
  display: flex;
@@ -2924,7 +2924,7 @@ let Ar=rr,Mr=!1;const Tr=["es","fr","pt"],Pr="data:image/png;base64,iVBORw0KGgoA
2924
2924
  temba-button {
2925
2925
  --button-border: 1px solid #ddd;
2926
2926
  }
2927
- `}constructor(){super(),this.contactsEndpoint="/api/v2/contacts.json",this.currentNote="",this.showDetails=!0,this.currentTicket=null,this.currentContact=null,this.agent="",this.blockFetching=!1,this.showInterrupt=!1,this.avatar=Pr,this.ticket=null,this.lastEventTime=null,this.newestEventTime=null,this.refreshId=null,this.polling=!1}firstUpdated(t){super.firstUpdated(t)}connectedCallback(){super.connectedCallback(),this.chat=this.shadowRoot.querySelector("temba-chat")}disconnectedCallback(){super.disconnectedCallback(),this.refreshId&&clearInterval(this.refreshId)}updated(t){super.updated(t),(t.has("data")||t.has("currentContact"))&&(this.refreshId&&(clearTimeout(this.refreshId),this.refreshId=null),this.currentContact=this.data),t.has("currentContact")&&(this.chat=this.shadowRoot.querySelector("temba-chat"),this.reset(),this.fetchPreviousMessages())}reset(){this.chat&&this.chat.reset(),this.blockFetching=!1,this.ticket=null,this.lastEventTime=null,this.newestEventTime=null,this.refreshId=null,this.polling=!1,this.errorMessage=null;const t=this.shadowRoot.querySelector("temba-compose");t&&t.reset()}handleInterrupt(){this.fireCustomEvent(je.Interrupt,{contact:this.currentContact})}handleRetry(){this.shadowRoot.querySelector("temba-compose").triggerSend()}handleSend(t){this.errorMessage=null;const e=t.currentTarget,i=t.detail.langValues.und,n={contact:this.currentContact.uuid},o=i.text;o&&o.length>0&&(n.text=o);const s=i.attachments;if(s&&s.length>0){const t=s.map((t=>t.uuid));n.attachments=t}this.currentTicket&&(n.ticket=this.currentTicket.uuid);const r="Send failed, please try again.";ne("/api/v2/messages.json",n).then((t=>{t.status<400?(this.checkForNewMessages(),e.reset(),this.fireCustomEvent(je.MessageSent,{msg:n})):this.errorMessage=r})).catch((()=>{this.errorMessage=r}))}getEndpoint(){return this.contact?`/contact/history/${this.contact}/?_format=json`:null}scheduleRefresh(){let t=(new Date).getTime()-this.newestEventTime/1e3-5e3;this.refreshId&&(clearTimeout(this.refreshId),this.refreshId=null),t=Math.min(t,15e3),t=Math.max(t,2e3),this.refreshId=setTimeout((()=>{this.checkForNewMessages()}),t)}getEventMessage(t){let e=null;switch(t.type){case Zc.TICKET_OPENED:e={type:Vc.Inline,text:eh(t,"opened")};break;case Zc.TICKET_ASSIGNED:e={type:Vc.Inline,text:ih(t)};break;case Zc.TICKET_REOPENED:e={type:Vc.Inline,text:eh(t,"reopened")};break;case Zc.TICKET_CLOSED:e={type:Vc.Inline,text:eh(t,"closed")};break;case Zc.TICKET_TOPIC_CHANGED:e={type:Vc.Inline,text:`Topic changed to **${t.topic.name}**`};break;case Zc.FLOW_ENTERED:case Zc.FLOW_EXITED:e={type:Vc.Inline,text:Kc(t)};break;case Zc.CONTACT_FIELD_CHANGED:e={type:Vc.Inline,text:Qc(t)};break;case Zc.CONTACT_NAME_CHANGED:e={type:Vc.Inline,text:Jc(t)};break;case Zc.CONTACT_URNS_CHANGED:e={type:Vc.Inline,text:th(t)};break;case Zc.CONTACT_GROUPS_CHANGED:e={type:Vc.Inline,text:nh(t)};break;case Zc.AIRTIME_TRANSFERRED:e={type:Vc.Inline,text:oh(t)};break;case Zc.CALL_STARTED:e={type:Vc.Inline,text:"Call Started"};break;case Zc.CHANNEL_EVENT:e={type:Vc.Inline,text:Xc(t)};break;case Zc.CONTACT_LANGUAGE_CHANGED:e={type:Vc.Inline,text:sh(t)};break;case Zc.OPTIN_REQUESTED:e={type:Vc.Inline,text:rh(t)}}return e&&t.created_on?e.date=new Date(t.created_on):console.error("Unknown event type",t),e}getUserForEvent(t){let e=null;return"msg_received"===t.type?e={name:this.currentContact.name}:t.created_by&&(e={email:t.created_by.email,name:`${t.created_by.first_name} ${t.created_by.last_name}`.trim(),avatar:t.created_by.avatar}),e}createMessages(t){if(t.events){let e=[];return t.events.forEach((t=>{const i=1e3*new Date(t.created_on).getTime();if(i>this.newestEventTime&&(this.newestEventTime=i),"ticket_note_added"===t.type){const i=t;e.push({type:Vc.Note,id:t.created_on+t.type,user:this.getUserForEvent(i),date:new Date(i.created_on),text:i.note})}else if("ticket_opened"===t.type){const i=t;e.push({type:Vc.Note,id:t.created_on+t.type+"_note",user:this.getUserForEvent(i),date:new Date(i.created_on),text:i.note}),e.push(this.getEventMessage(t))}else if("msg_created"===t.type||"msg_received"===t.type||"broadcast_created"===t.type){const i=t;e.push({uuid:t.uuid,type:"msg_received"===i.type?"msg_in":"msg_out",user:this.getUserForEvent(i),date:new Date(i.created_on),attachments:i.msg.attachments,text:i.msg.text,sendError:"E"===i.status||"F"===i.status,popup:H`<div
2927
+ `}constructor(){super(),this.contactsEndpoint="/api/v2/contacts.json",this.currentNote="",this.showDetails=!0,this.currentTicket=null,this.currentContact=null,this.agent="",this.blockFetching=!1,this.showInterrupt=!1,this.avatar=Pr,this.ticket=null,this.lastEventTime=null,this.newestEventTime=null,this.refreshId=null,this.polling=!1}firstUpdated(t){super.firstUpdated(t)}connectedCallback(){super.connectedCallback(),this.chat=this.shadowRoot.querySelector("temba-chat")}disconnectedCallback(){super.disconnectedCallback(),this.refreshId&&clearInterval(this.refreshId)}updated(t){super.updated(t),(t.has("data")||t.has("currentContact"))&&(this.refreshId&&(clearTimeout(this.refreshId),this.refreshId=null),this.currentContact=this.data),t.has("currentContact")&&(this.chat=this.shadowRoot.querySelector("temba-chat"),this.reset(),this.fetchPreviousMessages())}reset(){this.chat&&this.chat.reset(),this.blockFetching=!1,this.ticket=null,this.lastEventTime=null,this.newestEventTime=null,this.refreshId=null,this.polling=!1,this.errorMessage=null;const t=this.shadowRoot.querySelector("temba-compose");t&&t.reset()}handleInterrupt(){this.fireCustomEvent(je.Interrupt,{contact:this.currentContact})}handleRetry(){this.shadowRoot.querySelector("temba-compose").triggerSend()}handleSend(t){this.errorMessage=null;const e=t.currentTarget,i=t.detail.langValues.und,n={contact:this.currentContact.uuid},o=i.text;o&&o.length>0&&(n.text=o);const s=i.attachments;if(s&&s.length>0){const t=s.map((t=>t.uuid));n.attachments=t}this.currentTicket&&(n.ticket=this.currentTicket.uuid);const r="Send failed, please try again.";ne("/api/v2/messages.json",n).then((t=>{t.status<400?(this.checkForNewMessages(),e.reset(),this.fireCustomEvent(je.MessageSent,{msg:n})):this.errorMessage=r})).catch((()=>{this.errorMessage=r}))}getEndpoint(){return this.contact?`/contact/history/${this.contact}/?_format=json`:null}scheduleRefresh(){let t=(new Date).getTime()-this.newestEventTime/1e3-5e3;this.refreshId&&(clearTimeout(this.refreshId),this.refreshId=null),t=Math.min(t,15e3),t=Math.max(t,2e3),this.refreshId=setTimeout((()=>{this.checkForNewMessages()}),t)}getEventMessage(t){let e=null;switch(t.type){case Zc.TICKET_OPENED:e={type:Vc.Inline,text:eh(t,"opened")};break;case Zc.TICKET_ASSIGNED:e={type:Vc.Inline,text:ih(t)};break;case Zc.TICKET_REOPENED:e={type:Vc.Inline,text:eh(t,"reopened")};break;case Zc.TICKET_CLOSED:e={type:Vc.Inline,text:eh(t,"closed")};break;case Zc.TICKET_TOPIC_CHANGED:e={type:Vc.Inline,text:`Topic changed to **${t.topic.name}**`};break;case Zc.FLOW_ENTERED:case Zc.FLOW_EXITED:e={type:Vc.Inline,text:Kc(t)};break;case Zc.CONTACT_FIELD_CHANGED:e={type:Vc.Inline,text:Qc(t)};break;case Zc.CONTACT_NAME_CHANGED:e={type:Vc.Inline,text:Jc(t)};break;case Zc.CONTACT_URNS_CHANGED:e={type:Vc.Inline,text:th(t)};break;case Zc.CONTACT_GROUPS_CHANGED:e={type:Vc.Inline,text:nh(t)};break;case Zc.AIRTIME_TRANSFERRED:e={type:Vc.Inline,text:oh(t)};break;case Zc.CALL_STARTED:e={type:Vc.Inline,text:"Call Started"};break;case Zc.CHANNEL_EVENT:e={type:Vc.Inline,text:Xc(t)};break;case Zc.CONTACT_LANGUAGE_CHANGED:e={type:Vc.Inline,text:sh(t)};break;case Zc.OPTIN_REQUESTED:e={type:Vc.Inline,text:rh(t)}}return e&&t.created_on?e.date=new Date(t.created_on):console.error("Unknown event type",t),e}getUserForEvent(t){let e=null;return"msg_received"===t.type?e={name:this.currentContact.name}:t.created_by&&(e={email:t.created_by.email,name:`${t.created_by.first_name} ${t.created_by.last_name}`.trim(),avatar:t.created_by.avatar}),e}createMessages(t){if(t.events){let e=[];return t.events.forEach((t=>{const i=1e3*new Date(t.created_on).getTime();if(i>this.newestEventTime&&(this.newestEventTime=i),"ticket_note_added"===t.type){const i=t;e.push({type:Vc.Note,id:t.created_on+t.type,user:this.getUserForEvent(i),date:new Date(i.created_on),text:i.note})}else if("ticket_opened"===t.type){const i=t;e.push({type:Vc.Note,id:t.created_on+t.type+"_note",user:this.getUserForEvent(i),date:new Date(i.created_on),text:i.note}),e.push(this.getEventMessage(t))}else if("msg_created"===t.type||"msg_received"===t.type||"broadcast_created"===t.type){const i=t;e.push({id:t.uuid,type:"msg_received"===i.type?"msg_in":"msg_out",user:this.getUserForEvent(i),date:new Date(i.created_on),attachments:i.msg.attachments,text:i.msg.text,sendError:"E"===i.status||"F"===i.status,popup:H`<div
2928
2928
  style="display: flex; flex-direction: row; align-items:center; justify-content: space-between;font-size:0.9em;line-height:1em;min-width:10em"
2929
2929
  >
2930
2930
  <div style="justify-content:left;text-align:left">
@@ -8169,8 +8169,14 @@ const{I:ud}=at,pd=()=>document.createComment(""),md=(t,e,i)=>{const n=t._$AA.par
8169
8169
  ${Ba(n)}
8170
8170
  ${(null===(i=e.quick_replies)||void 0===i?void 0:i.length)>0?H`<div class="quick-replies">
8171
8171
  ${e.quick_replies.map((t=>H`<div class="quick-reply">${t}</div>`))}
8172
+ ${e.template?H`<div
8173
+ style="border: 1px solid var(--color-widget-border);padding: 0.5em;margin-top: 1em;border-radius: var(--curvature); display:flex;background: rgba(0,0,0,.03);"
8174
+ >
8175
+ <temba-icon name="channel_wac"></temba-icon>
8176
+ <div style="margin-left:0.5em">${e.template.name}</div>
8177
+ </div>`:null}
8172
8178
  </div>`:null}
8173
- `},form:{text:{type:"textarea",label:"Message Text",helpText:"Enter the message to send. You can use expressions like @contact.name",required:!0,evaluated:!0,rows:5,minHeight:75},quick_replies:{type:"select",label:"Quick Replies",helpText:"Add quick reply options for this message",options:[],multi:!0,tags:!0,searchable:!0,placeholder:"Add quick replies...",maxItems:10,evaluated:!0}},validate:t=>{const e={};return t.text&&""!==t.text.trim()||(e.text="Message text is required"),{valid:0===Object.keys(e).length,errors:e}}},bb={name:"Send Email",color:lb,render:(t,e)=>H`<div>
8179
+ `},form:{text:{type:"textarea",label:"Message Text",helpText:"Enter the message to send. You can use expressions like @contact.name",required:!0,evaluated:!0,minHeight:175},quick_replies:{type:"select",label:"Quick Replies",helpText:"Add quick reply options for this message",options:[],multi:!0,tags:!0,searchable:!0,placeholder:"Add quick replies...",maxItems:10,evaluated:!0}},validate:t=>{const e={};return t.text&&""!==t.text.trim()||(e.text="Message text is required"),{valid:0===Object.keys(e).length,errors:e}}},bb={name:"Send Email",color:lb,render:(t,e)=>H`<div>
8174
8180
  <div>${gb(e.addresses,Ee.email)}</div>
8175
8181
  <div style="margin-top: 0.5em">
8176
8182
  <div
@@ -8179,7 +8185,7 @@ const{I:ud}=at,pd=()=>document.createComment(""),md=(t,e,i)=>{const n=t._$AA.par
8179
8185
  ${e.subject}
8180
8186
  </div>
8181
8187
  </div>
8182
- </div>`,form:{addresses:{type:"select",label:"Recipients",options:[],multi:!0,searchable:!0,placeholder:"Search for contacts...",emails:!0},subject:{type:"text",label:"Subject",required:!0,placeholder:"Enter email subject",maxLength:255},body:{type:"textarea",required:!0,evaluated:!0,rows:4,minHeight:75}},validate:t=>{const e={};return t.addresses&&0!==t.addresses.length||(e.addresses="At least one recipient email address is required"),{valid:0===Object.keys(e).length,errors:e}}},xb={name:"Call Webhook",color:hb,render:(t,e)=>H`<div
8188
+ </div>`,form:{addresses:{type:"select",label:"Recipients",options:[],multi:!0,searchable:!0,placeholder:"Search for contacts...",emails:!0},subject:{type:"text",label:"Subject",required:!0,placeholder:"Enter email subject",maxLength:255},body:{type:"textarea",required:!0,evaluated:!0,minHeight:175}},validate:t=>{const e={};return t.addresses&&0!==t.addresses.length||(e.addresses="At least one recipient email address is required"),{valid:0===Object.keys(e).length,errors:e}}},xb={name:"Call Webhook",color:hb,render:(t,e)=>H`<div
8183
8189
  style="word-wrap: break-word; overflow-wrap: break-word; hyphens: auto;"
8184
8190
  >
8185
8191
  ${e.url}
@@ -8320,6 +8326,10 @@ const{I:ud}=at,pd=()=>document.createComment(""),md=(t,e,i)=>{const n=t._$AA.par
8320
8326
  overflow: hidden;
8321
8327
  }
8322
8328
 
8329
+ .node.execute-actions temba-sortable-list .action:last-child .body {
8330
+ padding-bottom: 1.5em;
8331
+ }
8332
+
8323
8333
  .action .drag-handle {
8324
8334
  opacity: 0;
8325
8335
  transition: all 200ms ease-in-out;
@@ -8493,7 +8503,7 @@ const{I:ud}=at,pd=()=>document.createComment(""),md=(t,e,i)=>{const n=t._$AA.par
8493
8503
  border-top-left-radius: var(--curvature);
8494
8504
  border-top-right-radius: var(--curvature);
8495
8505
  }
8496
- }`}constructor(){super(),this.exitRemovalTimeouts=new Map,this.exitRemovingState=new Set,this.actionRemovalTimeouts=new Map,this.actionRemovingState=new Set,this.actionClickStartPos=null,this.pendingActionClick=null,this.nodeClickStartPos=null,this.pendingNodeClick=null,this.handleActionOrderChanged=this.handleActionOrderChanged.bind(this)}updated(t){var e;if(super.updated(t),t.has("node")){if(this.plumber){this.plumber.removeNodeConnections(this.node.uuid);for(const t of this.node.exits)t.destination_uuid?this.plumber.connectIds(this.node.uuid,t.uuid,t.destination_uuid):this.plumber.makeSource(t.uuid);this.plumber.revalidate([this.node.uuid])}const t=this.parentElement;if(t){const i=t.getBoundingClientRect();null===(e=Pa())||void 0===e||e.getState().expandCanvas(this.ui.position.left+i.width,this.ui.position.top+i.height)}}}disconnectedCallback(){super.disconnectedCallback(),this.exitRemovalTimeouts.forEach((t=>{clearTimeout(t)})),this.exitRemovalTimeouts.clear(),this.actionRemovalTimeouts.forEach((t=>{clearTimeout(t)})),this.actionRemovalTimeouts.clear(),this.exitRemovingState.clear(),this.actionRemovingState.clear()}handleExitClick(t,e){t.preventDefault(),t.stopPropagation();const i=e.uuid;if(!e.destination_uuid)return;if(this.exitRemovingState.has(i))return void this.disconnectExit(e);this.exitRemovingState.add(i),this.requestUpdate(),this.plumber.setConnectionRemovingState(i,!0),this.exitRemovalTimeouts.has(i)&&clearTimeout(this.exitRemovalTimeouts.get(i));const n=window.setTimeout((()=>{this.exitRemovingState.delete(i),this.exitRemovalTimeouts.delete(i),this.plumber.setConnectionRemovingState(i,!1),this.requestUpdate()}),1500);this.exitRemovalTimeouts.set(i,n)}disconnectExit(t){var e;const i=t.uuid;this.exitRemovingState.delete(i),this.plumber.setConnectionRemovingState(i,!1),this.exitRemovalTimeouts.has(i)&&(clearTimeout(this.exitRemovalTimeouts.get(i)),this.exitRemovalTimeouts.delete(i)),this.plumber.removeExitConnection(i);const n={...t,destination_uuid:null},o=this.node.exits.map((t=>t.uuid===i?n:t)),s={...this.node,exits:o};null===(e=Pa())||void 0===e||e.getState().updateNode(this.node.uuid,s),this.requestUpdate()}handleActionRemoveClick(t,e,i){t.preventDefault(),t.stopPropagation();const n=e.uuid;if(this.actionRemovingState.has(n))return void this.removeAction(e,i);this.actionRemovingState.add(n),this.requestUpdate(),this.actionRemovalTimeouts.has(n)&&clearTimeout(this.actionRemovalTimeouts.get(n));const o=window.setTimeout((()=>{this.actionRemovingState.delete(n),this.actionRemovalTimeouts.delete(n),this.requestUpdate()}),1e3);this.actionRemovalTimeouts.set(n,o)}removeAction(t,e){var i;const n=t.uuid;this.actionRemovingState.delete(n),this.actionRemovalTimeouts.has(n)&&(clearTimeout(this.actionRemovalTimeouts.get(n)),this.actionRemovalTimeouts.delete(n));const o=this.node.actions.filter((t=>t.uuid!==n));if(0===o.length)this.fireCustomEvent(je.NodeDeleted,{uuid:this.node.uuid});else{const t={...this.node,actions:o};null===(i=Pa())||void 0===i||i.getState().updateNode(this.node.uuid,t),this.requestUpdate()}}handleNodeRemoveClick(t){t.preventDefault(),t.stopPropagation();const e=this.node.uuid;if(this.actionRemovingState.has(e))return void this.removeNode();this.actionRemovingState.add(e),this.requestUpdate(),this.actionRemovalTimeouts.has(e)&&clearTimeout(this.actionRemovalTimeouts.get(e));const i=window.setTimeout((()=>{this.actionRemovingState.delete(e),this.actionRemovalTimeouts.delete(e),this.requestUpdate()}),1e3);this.actionRemovalTimeouts.set(e,i)}removeNode(){const t=this.node.uuid;this.actionRemovingState.delete(t),this.actionRemovalTimeouts.has(t)&&(clearTimeout(this.actionRemovalTimeouts.get(t)),this.actionRemovalTimeouts.delete(t)),this.fireCustomEvent(je.NodeDeleted,{uuid:this.node.uuid})}handleActionOrderChanged(t){var e;const[i,n]=t.detail.swap,o=[...this.node.actions],s=o.splice(i,1)[0];o.splice(n,0,s),this.node={...this.node,actions:o},null===(e=Pa())||void 0===e||e.getState().updateNode(this.node.uuid,{...this.node,actions:o})}handleActionMouseDown(t,e){t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid)||(this.actionClickStartPos={x:t.clientX,y:t.clientY},this.pendingActionClick={action:e,event:t})}handleActionMouseUp(t,e){if(!this.pendingActionClick||this.pendingActionClick.action.uuid!==e.uuid)return this.actionClickStartPos=null,void(this.pendingActionClick=null);if(t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid))return this.actionClickStartPos=null,void(this.pendingActionClick=null);if(this.actionClickStartPos){const i=t.clientX-this.actionClickStartPos.x,n=t.clientY-this.actionClickStartPos.y,o=Math.sqrt(i*i+n*n),s=this.closest("temba-flow-editor"),r=null==s?void 0:s.dragging;!(o<=5)||s&&r||this.fireCustomEvent(je.ActionEditRequested,{action:e,nodeUuid:this.node.uuid})}this.actionClickStartPos=null,this.pendingActionClick=null}handleActionClick(t,e){t.preventDefault(),t.stopPropagation();t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid)||this.fireCustomEvent(je.ActionEditRequested,{action:e,nodeUuid:this.node.uuid})}handleNodeEditClick(t){t.preventDefault(),t.stopPropagation();t.target.closest(".remove-button")||this.actionRemovingState.has(this.node.uuid)||this.node.router&&(this.node.actions&&1===this.node.actions.length?this.fireCustomEvent(je.ActionEditRequested,{action:this.node.actions[0],nodeUuid:this.node.uuid}):this.fireCustomEvent(je.NodeEditRequested,{node:this.node,nodeUI:this.ui}))}handleNodeMouseDown(t){t.target.closest(".remove-button")||this.actionRemovingState.has(this.node.uuid)||(this.nodeClickStartPos={x:t.clientX,y:t.clientY},this.pendingNodeClick={event:t})}handleNodeMouseUp(t){if(!this.pendingNodeClick)return this.nodeClickStartPos=null,void(this.pendingNodeClick=null);if(t.target.closest(".remove-button")||this.actionRemovingState.has(this.node.uuid))return this.nodeClickStartPos=null,void(this.pendingNodeClick=null);if(this.nodeClickStartPos){const e=t.clientX-this.nodeClickStartPos.x,i=t.clientY-this.nodeClickStartPos.y,n=Math.sqrt(e*e+i*i),o=this.closest("temba-flow-editor"),s=null==o?void 0:o.dragging;!(n<=5)||o&&s||this.node.router&&(this.node.actions&&1===this.node.actions.length?this.fireCustomEvent(je.ActionEditRequested,{action:this.node.actions[0],nodeUuid:this.node.uuid}):this.fireCustomEvent(je.NodeEditRequested,{node:this.node,nodeUI:this.ui}))}this.nodeClickStartPos=null,this.pendingNodeClick=null}renderTitle(t,e=!1){var i,n;return H`<div class="title" style="background:${t.color}">
8506
+ }`}constructor(){super(),this.exitRemovalTimeouts=new Map,this.exitRemovingState=new Set,this.actionRemovalTimeouts=new Map,this.actionRemovingState=new Set,this.actionClickStartPos=null,this.pendingActionClick=null,this.nodeClickStartPos=null,this.pendingNodeClick=null,this.handleActionOrderChanged=this.handleActionOrderChanged.bind(this)}updated(t){var e;if(super.updated(t),t.has("node")){if(this.plumber){this.plumber.removeNodeConnections(this.node.uuid);for(const t of this.node.exits)t.destination_uuid?this.plumber.connectIds(this.node.uuid,t.uuid,t.destination_uuid):this.plumber.makeSource(t.uuid);this.plumber.revalidate([this.node.uuid])}const t=this.parentElement;if(t){const i=t.getBoundingClientRect();null===(e=Pa())||void 0===e||e.getState().expandCanvas(this.ui.position.left+i.width,this.ui.position.top+i.height)}}}disconnectedCallback(){super.disconnectedCallback(),this.exitRemovalTimeouts.forEach((t=>{clearTimeout(t)})),this.exitRemovalTimeouts.clear(),this.actionRemovalTimeouts.forEach((t=>{clearTimeout(t)})),this.actionRemovalTimeouts.clear(),this.exitRemovingState.clear(),this.actionRemovingState.clear()}handleExitClick(t,e){t.preventDefault(),t.stopPropagation();const i=e.uuid;if(!e.destination_uuid)return;if(this.exitRemovingState.has(i))return void this.disconnectExit(e);this.exitRemovingState.add(i),this.requestUpdate(),this.plumber.setConnectionRemovingState(i,!0),this.exitRemovalTimeouts.has(i)&&clearTimeout(this.exitRemovalTimeouts.get(i));const n=window.setTimeout((()=>{this.exitRemovingState.delete(i),this.exitRemovalTimeouts.delete(i),this.plumber.setConnectionRemovingState(i,!1),this.requestUpdate()}),1500);this.exitRemovalTimeouts.set(i,n)}disconnectExit(t){var e;const i=t.uuid;this.exitRemovingState.delete(i),this.plumber.setConnectionRemovingState(i,!1),this.exitRemovalTimeouts.has(i)&&(clearTimeout(this.exitRemovalTimeouts.get(i)),this.exitRemovalTimeouts.delete(i)),this.plumber.removeExitConnection(i);const n={...t,destination_uuid:null},o=this.node.exits.map((t=>t.uuid===i?n:t)),s={...this.node,exits:o};null===(e=Pa())||void 0===e||e.getState().updateNode(this.node.uuid,s),this.requestUpdate()}handleActionRemoveClick(t,e,i){t.preventDefault(),t.stopPropagation();const n=e.uuid;if(this.actionRemovingState.has(n))return void this.removeAction(e,i);this.actionRemovingState.add(n),this.requestUpdate(),this.actionRemovalTimeouts.has(n)&&clearTimeout(this.actionRemovalTimeouts.get(n));const o=window.setTimeout((()=>{this.actionRemovingState.delete(n),this.actionRemovalTimeouts.delete(n),this.requestUpdate()}),1e3);this.actionRemovalTimeouts.set(n,o)}removeAction(t,e){var i;const n=t.uuid;this.actionRemovingState.delete(n),this.actionRemovalTimeouts.has(n)&&(clearTimeout(this.actionRemovalTimeouts.get(n)),this.actionRemovalTimeouts.delete(n));const o=this.node.actions.filter((t=>t.uuid!==n));if(0===o.length)this.fireCustomEvent(je.NodeDeleted,{uuid:this.node.uuid});else{const t={...this.node,actions:o};null===(i=Pa())||void 0===i||i.getState().updateNode(this.node.uuid,t),this.requestUpdate()}}handleNodeRemoveClick(t){t.preventDefault(),t.stopPropagation();const e=this.node.uuid;if(this.actionRemovingState.has(e))return void this.removeNode();this.actionRemovingState.add(e),this.requestUpdate(),this.actionRemovalTimeouts.has(e)&&clearTimeout(this.actionRemovalTimeouts.get(e));const i=window.setTimeout((()=>{this.actionRemovingState.delete(e),this.actionRemovalTimeouts.delete(e),this.requestUpdate()}),1e3);this.actionRemovalTimeouts.set(e,i)}removeNode(){const t=this.node.uuid;this.actionRemovingState.delete(t),this.actionRemovalTimeouts.has(t)&&(clearTimeout(this.actionRemovalTimeouts.get(t)),this.actionRemovalTimeouts.delete(t)),this.fireCustomEvent(je.NodeDeleted,{uuid:this.node.uuid})}handleActionOrderChanged(t){var e;const[i,n]=t.detail.swap,o=[...this.node.actions],s=o.splice(i,1)[0];o.splice(n,0,s),this.node={...this.node,actions:o},null===(e=Pa())||void 0===e||e.getState().updateNode(this.node.uuid,{...this.node,actions:o})}handleActionMouseDown(t,e){t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid)||(this.actionClickStartPos={x:t.clientX,y:t.clientY},this.pendingActionClick={action:e,event:t})}handleActionMouseUp(t,e){if(!this.pendingActionClick||this.pendingActionClick.action.uuid!==e.uuid)return this.actionClickStartPos=null,void(this.pendingActionClick=null);if(t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid))return this.actionClickStartPos=null,void(this.pendingActionClick=null);if(this.actionClickStartPos){const i=t.clientX-this.actionClickStartPos.x,n=t.clientY-this.actionClickStartPos.y,o=Math.sqrt(i*i+n*n),s=this.closest("temba-flow-editor"),r=null==s?void 0:s.dragging;!(o<=5)||s&&r||this.fireCustomEvent(je.ActionEditRequested,{action:e,nodeUuid:this.node.uuid})}this.actionClickStartPos=null,this.pendingActionClick=null}handleActionClick(t,e){t.preventDefault(),t.stopPropagation();t.target.closest(".remove-button")||this.actionRemovingState.has(e.uuid)||this.fireCustomEvent(je.ActionEditRequested,{action:e,nodeUuid:this.node.uuid})}handleNodeEditClick(t){t.preventDefault(),t.stopPropagation();t.target.closest(".remove-button")||this.actionRemovingState.has(this.node.uuid)||this.node.router&&(this.node.actions&&1===this.node.actions.length?this.fireCustomEvent(je.ActionEditRequested,{action:this.node.actions[0],nodeUuid:this.node.uuid}):this.fireCustomEvent(je.NodeEditRequested,{node:this.node,nodeUI:this.ui}))}handleNodeMouseDown(t){const e=t.target;e.closest(".remove-button")||e.closest(".exit")||e.closest(".exit-wrapper")||this.actionRemovingState.has(this.node.uuid)||(this.nodeClickStartPos={x:t.clientX,y:t.clientY},this.pendingNodeClick={event:t})}handleNodeMouseUp(t){if(!this.pendingNodeClick)return this.nodeClickStartPos=null,void(this.pendingNodeClick=null);const e=t.target;if(e.closest(".remove-button")||e.closest(".exit")||e.closest(".exit-wrapper")||this.actionRemovingState.has(this.node.uuid))return this.nodeClickStartPos=null,void(this.pendingNodeClick=null);if(this.nodeClickStartPos){const e=t.clientX-this.nodeClickStartPos.x,i=t.clientY-this.nodeClickStartPos.y,n=Math.sqrt(e*e+i*i),o=this.closest("temba-flow-editor"),s=null==o?void 0:o.dragging;!(n<=5)||o&&s||this.node.router&&(this.node.actions&&1===this.node.actions.length?this.fireCustomEvent(je.ActionEditRequested,{action:this.node.actions[0],nodeUuid:this.node.uuid}):this.fireCustomEvent(je.NodeEditRequested,{node:this.node,nodeUI:this.ui}))}this.nodeClickStartPos=null,this.pendingNodeClick=null}renderTitle(t,e=!1){var i,n;return H`<div class="title" style="background:${t.color}">
8497
8507
  ${(null===(n=null===(i=this.node)||void 0===i?void 0:i.actions)||void 0===n?void 0:n.length)>1?H`<temba-icon class="drag-handle" name="sort"></temba-icon>`:null}
8498
8508
 
8499
8509
  <div class="name">${e?"Remove?":t.name}</div>
@@ -8796,7 +8806,7 @@ const{I:ud}=at,pd=()=>document.createComment(""),md=(t,e,i)=>{const n=t._$AA.par
8796
8806
  }
8797
8807
 
8798
8808
  .sticky-note {
8799
- width: 200px;
8809
+ width: 182px;
8800
8810
  background-color: var(--sticky-color);
8801
8811
  border: 1px solid var(--sticky-border-color);
8802
8812
  border-radius: var(--curvature);