@nyaruka/temba-components 0.122.0 → 0.123.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.
Files changed (224) hide show
  1. package/.github/copilot-instructions.md +163 -0
  2. package/.github/workflows/build.yml +3 -3
  3. package/.github/workflows/cla.yml +6 -6
  4. package/.github/workflows/copilot-setup-steps.yml +86 -0
  5. package/CHANGELOG.md +33 -0
  6. package/demo/index.html +42 -0
  7. package/dist/locales/es.js +1 -0
  8. package/dist/locales/es.js.map +1 -1
  9. package/dist/locales/fr.js +1 -0
  10. package/dist/locales/fr.js.map +1 -1
  11. package/dist/locales/pt.js +1 -0
  12. package/dist/locales/pt.js.map +1 -1
  13. package/dist/temba-components.js +59 -72
  14. package/dist/temba-components.js.map +1 -1
  15. package/out-tsc/src/chart/TembaChart.js +81 -14
  16. package/out-tsc/src/chart/TembaChart.js.map +1 -1
  17. package/out-tsc/src/list/RunList.js +13 -8
  18. package/out-tsc/src/list/RunList.js.map +1 -1
  19. package/out-tsc/src/locales/es.js +1 -0
  20. package/out-tsc/src/locales/es.js.map +1 -1
  21. package/out-tsc/src/locales/fr.js +1 -0
  22. package/out-tsc/src/locales/fr.js.map +1 -1
  23. package/out-tsc/src/locales/pt.js +1 -0
  24. package/out-tsc/src/locales/pt.js.map +1 -1
  25. package/out-tsc/src/options/Options.js +36 -13
  26. package/out-tsc/src/options/Options.js.map +1 -1
  27. package/out-tsc/src/select/Select.js +28 -5
  28. package/out-tsc/src/select/Select.js.map +1 -1
  29. package/out-tsc/src/store/AppState.js +3 -3
  30. package/out-tsc/src/store/AppState.js.map +1 -1
  31. package/out-tsc/src/utils/index.js +6 -1
  32. package/out-tsc/src/utils/index.js.map +1 -1
  33. package/out-tsc/src/vectoricon/VectorIcon.js +2 -1
  34. package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
  35. package/out-tsc/temba-modules.js +0 -2
  36. package/out-tsc/temba-modules.js.map +1 -1
  37. package/out-tsc/test/temba-appstate-language.test.js +176 -0
  38. package/out-tsc/test/temba-appstate-language.test.js.map +1 -0
  39. package/out-tsc/test/temba-chart.test.js +125 -0
  40. package/out-tsc/test/temba-chart.test.js.map +1 -1
  41. package/out-tsc/test/temba-dropdown.test.js +317 -0
  42. package/out-tsc/test/temba-dropdown.test.js.map +1 -0
  43. package/out-tsc/test/temba-run-list.test.js +588 -0
  44. package/out-tsc/test/temba-run-list.test.js.map +1 -0
  45. package/out-tsc/test/temba-select.test.js +16 -0
  46. package/out-tsc/test/temba-select.test.js.map +1 -1
  47. package/out-tsc/test/temba-toast.test.js +299 -0
  48. package/out-tsc/test/temba-toast.test.js.map +1 -0
  49. package/out-tsc/test/temba-utils-index.test.js +1178 -0
  50. package/out-tsc/test/temba-utils-index.test.js.map +1 -0
  51. package/out-tsc/test/temba-webchat.test.js +816 -0
  52. package/out-tsc/test/temba-webchat.test.js.map +1 -0
  53. package/out-tsc/test/utils.test.js +3 -1
  54. package/out-tsc/test/utils.test.js.map +1 -1
  55. package/package.json +6 -8
  56. package/screenshots/truth/alert/error.png +0 -0
  57. package/screenshots/truth/alert/info.png +0 -0
  58. package/screenshots/truth/alert/warning.png +0 -0
  59. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  60. package/screenshots/truth/checkbox/checked.png +0 -0
  61. package/screenshots/truth/checkbox/default.png +0 -0
  62. package/screenshots/truth/colorpicker/default.png +0 -0
  63. package/screenshots/truth/colorpicker/focused.png +0 -0
  64. package/screenshots/truth/colorpicker/initialized.png +0 -0
  65. package/screenshots/truth/colorpicker/selected.png +0 -0
  66. package/screenshots/truth/compose/attachments-tab.png +0 -0
  67. package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
  68. package/screenshots/truth/compose/attachments-with-files.png +0 -0
  69. package/screenshots/truth/compose/intial-text.png +0 -0
  70. package/screenshots/truth/compose/no-counter.png +0 -0
  71. package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
  72. package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
  73. package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
  74. package/screenshots/truth/contacts/badges.png +0 -0
  75. package/screenshots/truth/contacts/chat-failure.png +0 -0
  76. package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
  77. package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
  78. package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
  79. package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
  80. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  81. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  82. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  83. package/screenshots/truth/content-menu/button-no-items.png +0 -0
  84. package/screenshots/truth/content-menu/items-and-buttons.png +0 -0
  85. package/screenshots/truth/counter/summary.png +0 -0
  86. package/screenshots/truth/counter/text.png +0 -0
  87. package/screenshots/truth/counter/unicode-variables.png +0 -0
  88. package/screenshots/truth/counter/unicode.png +0 -0
  89. package/screenshots/truth/counter/variable.png +0 -0
  90. package/screenshots/truth/date/date-inline.png +0 -0
  91. package/screenshots/truth/date/date.png +0 -0
  92. package/screenshots/truth/date/datetime.png +0 -0
  93. package/screenshots/truth/date/duration.png +0 -0
  94. package/screenshots/truth/date/timedate.png +0 -0
  95. package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
  96. package/screenshots/truth/datepicker/date.png +0 -0
  97. package/screenshots/truth/datepicker/initial-timezone.png +0 -0
  98. package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
  99. package/screenshots/truth/dialog/focused.png +0 -0
  100. package/screenshots/truth/dropdown/after-blur.png +0 -0
  101. package/screenshots/truth/dropdown/bottom-edge-collision.png +0 -0
  102. package/screenshots/truth/dropdown/custom-arrow-size.png +0 -0
  103. package/screenshots/truth/dropdown/default.png +0 -0
  104. package/screenshots/truth/dropdown/narrow-toggle.png +0 -0
  105. package/screenshots/truth/dropdown/no-mask.png +0 -0
  106. package/screenshots/truth/dropdown/opened.png +0 -0
  107. package/screenshots/truth/dropdown/positioned.png +0 -0
  108. package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
  109. package/screenshots/truth/dropdown/with-mask.png +0 -0
  110. package/screenshots/truth/label/custom.png +0 -0
  111. package/screenshots/truth/label/danger.png +0 -0
  112. package/screenshots/truth/label/dark.png +0 -0
  113. package/screenshots/truth/label/default-icon.png +0 -0
  114. package/screenshots/truth/label/no-icon.png +0 -0
  115. package/screenshots/truth/label/primary.png +0 -0
  116. package/screenshots/truth/label/secondary.png +0 -0
  117. package/screenshots/truth/label/shadow.png +0 -0
  118. package/screenshots/truth/label/tertiary.png +0 -0
  119. package/screenshots/truth/lightbox/img-zoomed.png +0 -0
  120. package/screenshots/truth/list/fields-dragging.png +0 -0
  121. package/screenshots/truth/list/fields-filtered.png +0 -0
  122. package/screenshots/truth/list/fields-hovered.png +0 -0
  123. package/screenshots/truth/list/fields.png +0 -0
  124. package/screenshots/truth/list/items-selected.png +0 -0
  125. package/screenshots/truth/list/items-updated.png +0 -0
  126. package/screenshots/truth/list/items.png +0 -0
  127. package/screenshots/truth/list/sortable-dragging.png +0 -0
  128. package/screenshots/truth/list/sortable-dropped.png +0 -0
  129. package/screenshots/truth/list/sortable.png +0 -0
  130. package/screenshots/truth/menu/menu-focused-with items.png +0 -0
  131. package/screenshots/truth/menu/menu-refresh-1.png +0 -0
  132. package/screenshots/truth/menu/menu-refresh-2.png +0 -0
  133. package/screenshots/truth/menu/menu-root.png +0 -0
  134. package/screenshots/truth/menu/menu-submenu.png +0 -0
  135. package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
  136. package/screenshots/truth/menu/menu-tasks.png +0 -0
  137. package/screenshots/truth/modax/form.png +0 -0
  138. package/screenshots/truth/modax/simple.png +0 -0
  139. package/screenshots/truth/omnibox/selected.png +0 -0
  140. package/screenshots/truth/options/block.png +0 -0
  141. package/screenshots/truth/run-list/basic.png +0 -0
  142. package/screenshots/truth/select/disabled-multi-selection.png +0 -0
  143. package/screenshots/truth/select/disabled-selection.png +0 -0
  144. package/screenshots/truth/select/disabled.png +0 -0
  145. package/screenshots/truth/select/embedded.png +0 -0
  146. package/screenshots/truth/select/empty-options.png +0 -0
  147. package/screenshots/truth/select/expression-selected.png +0 -0
  148. package/screenshots/truth/select/expressions.png +0 -0
  149. package/screenshots/truth/select/functions.png +0 -0
  150. package/screenshots/truth/select/local-options.png +0 -0
  151. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  152. package/screenshots/truth/select/multiple-initial-values.png +0 -0
  153. package/screenshots/truth/select/remote-options.png +0 -0
  154. package/screenshots/truth/select/search-enabled.png +0 -0
  155. package/screenshots/truth/select/search-multi-no-matches.png +0 -0
  156. package/screenshots/truth/select/search-selected-focus.png +0 -0
  157. package/screenshots/truth/select/search-selected.png +0 -0
  158. package/screenshots/truth/select/search-with-selected.png +0 -0
  159. package/screenshots/truth/select/searching.png +0 -0
  160. package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
  161. package/screenshots/truth/select/selected-multi.png +0 -0
  162. package/screenshots/truth/select/selected-single.png +0 -0
  163. package/screenshots/truth/select/selection-clearable.png +0 -0
  164. package/screenshots/truth/select/static-initial-value.png +0 -0
  165. package/screenshots/truth/select/static-initial-via-selected.png +0 -0
  166. package/screenshots/truth/select/truncated-selection.png +0 -0
  167. package/screenshots/truth/select/with-placeholder.png +0 -0
  168. package/screenshots/truth/select/without-placeholder.png +0 -0
  169. package/screenshots/truth/slider/custom-min-custom-max-valid-value.png +0 -0
  170. package/screenshots/truth/slider/custom-min-default-max-no-value.png +0 -0
  171. package/screenshots/truth/slider/default-min-custom-max-no-value.png +0 -0
  172. package/screenshots/truth/slider/default-min-default-max-invalid-value.png +0 -0
  173. package/screenshots/truth/slider/default-min-default-max-valid-value.png +0 -0
  174. package/screenshots/truth/slider/update-slider-on-value-change.png +0 -0
  175. package/screenshots/truth/templates/default.png +0 -0
  176. package/screenshots/truth/templates/unapproved.png +0 -0
  177. package/screenshots/truth/textinput/input-disabled.png +0 -0
  178. package/screenshots/truth/textinput/input-focused.png +0 -0
  179. package/screenshots/truth/textinput/input-form.png +0 -0
  180. package/screenshots/truth/textinput/input-inserted.png +0 -0
  181. package/screenshots/truth/textinput/input-placeholder.png +0 -0
  182. package/screenshots/truth/textinput/input-updated.png +0 -0
  183. package/screenshots/truth/textinput/input.png +0 -0
  184. package/screenshots/truth/textinput/textarea-focused.png +0 -0
  185. package/screenshots/truth/textinput/textarea.png +0 -0
  186. package/screenshots/truth/tip/bottom.png +0 -0
  187. package/screenshots/truth/tip/left.png +0 -0
  188. package/screenshots/truth/tip/right.png +0 -0
  189. package/screenshots/truth/tip/top.png +0 -0
  190. package/screenshots/truth/webchat/closed-widget.png +0 -0
  191. package/screenshots/truth/webchat/connected-state.png +0 -0
  192. package/screenshots/truth/webchat/connecting-state.png +0 -0
  193. package/screenshots/truth/webchat/disconnected-state.png +0 -0
  194. package/screenshots/truth/webchat/opened-widget.png +0 -0
  195. package/src/chart/TembaChart.ts +86 -15
  196. package/src/list/RunList.ts +11 -8
  197. package/src/locales/es.ts +1 -0
  198. package/src/locales/fr.ts +1 -0
  199. package/src/locales/pt.ts +1 -0
  200. package/src/options/Options.ts +38 -13
  201. package/src/select/Select.ts +32 -5
  202. package/src/store/AppState.ts +3 -3
  203. package/src/utils/index.ts +17 -5
  204. package/src/vectoricon/VectorIcon.ts +2 -1
  205. package/temba-modules.ts +0 -2
  206. package/test/temba-appstate-language.test.ts +218 -0
  207. package/test/temba-chart.test.ts +161 -1
  208. package/test/temba-dropdown.test.ts +444 -0
  209. package/test/temba-run-list.test.ts +774 -0
  210. package/test/temba-select.test.ts +27 -0
  211. package/test/temba-toast.test.ts +386 -0
  212. package/test/temba-utils-index.test.ts +1547 -0
  213. package/test/temba-webchat.test.ts +1095 -0
  214. package/test/utils.test.ts +4 -2
  215. package/test-assets/list/flow-results.json +17 -0
  216. package/test-assets/list/runs.json +126 -0
  217. package/test-assets/style.css +23 -0
  218. package/web-test-runner.config.mjs +33 -7
  219. package/xliff/es.xlf +3 -0
  220. package/xliff/fr.xlf +3 -0
  221. package/xliff/pt.xlf +3 -0
  222. package/out-tsc/src/outboxmonitor/OutboxMonitor.js +0 -136
  223. package/out-tsc/src/outboxmonitor/OutboxMonitor.js.map +0 -1
  224. package/src/outboxmonitor/OutboxMonitor.ts +0 -148
@@ -188,7 +188,9 @@ export const assertScreenshot = async (
188
188
  await waitUntil(waitFor.predicate);
189
189
  }
190
190
 
191
- const threshold = 0.1;
191
+ // detect if we're running in copilot's environment and use adaptive threshold
192
+ const isCopilotEnvironment = (window as any).isCopilotEnvironment;
193
+ const threshold = isCopilotEnvironment ? 1.0 : 0.1;
192
194
  const exclude: Clip[] = [];
193
195
 
194
196
  try {
@@ -238,7 +240,7 @@ export const getClip = (ele: HTMLElement) => {
238
240
  return newClip;
239
241
  };
240
242
 
241
- export const mouseClickElement = async (ele: HTMLElement) => {
243
+ export const mouseClickElement = async (ele: HTMLElement | Element) => {
242
244
  const bounds = ele.getBoundingClientRect();
243
245
  await mouseClick(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
244
246
  };
@@ -0,0 +1,17 @@
1
+ [
2
+ {
3
+ "key": "name",
4
+ "name": "Name",
5
+ "categories": ["Text"]
6
+ },
7
+ {
8
+ "key": "age",
9
+ "name": "Age",
10
+ "categories": ["Number"]
11
+ },
12
+ {
13
+ "key": "gender",
14
+ "name": "Gender",
15
+ "categories": ["Male", "Female", "Other"]
16
+ }
17
+ ]
@@ -0,0 +1,126 @@
1
+ {
2
+ "next": null,
3
+ "previous": null,
4
+ "results": [
5
+ {
6
+ "id": 1,
7
+ "uuid": "run-uuid-1",
8
+ "contact": {
9
+ "uuid": "contact-uuid-1",
10
+ "name": "John Doe",
11
+ "urn": "tel:+1234567890",
12
+ "anon_display": "1234567890"
13
+ },
14
+ "flow": {
15
+ "uuid": "flow-uuid-1",
16
+ "name": "Registration Flow"
17
+ },
18
+ "exit_type": "completed",
19
+ "exited_on": "2023-12-01T10:30:00.000Z",
20
+ "created_on": "2023-12-01T10:00:00.000Z",
21
+ "modified_on": "2023-12-01T10:30:00.000Z",
22
+ "responded": true,
23
+ "values": {
24
+ "name": {
25
+ "name": "Name",
26
+ "key": "name",
27
+ "value": "John Doe",
28
+ "category": "Text"
29
+ },
30
+ "age": {
31
+ "name": "Age",
32
+ "key": "age",
33
+ "value": "25",
34
+ "category": "Number"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "id": 2,
40
+ "uuid": "run-uuid-2",
41
+ "contact": {
42
+ "uuid": "contact-uuid-2",
43
+ "name": "Jane Smith",
44
+ "urn": "tel:+1987654321",
45
+ "anon_display": "1987654321"
46
+ },
47
+ "flow": {
48
+ "uuid": "flow-uuid-1",
49
+ "name": "Registration Flow"
50
+ },
51
+ "exit_type": "interrupted",
52
+ "exited_on": "2023-12-01T11:15:00.000Z",
53
+ "created_on": "2023-12-01T11:00:00.000Z",
54
+ "modified_on": "2023-12-01T11:15:00.000Z",
55
+ "responded": false,
56
+ "values": {}
57
+ },
58
+ {
59
+ "id": 3,
60
+ "uuid": "run-uuid-3",
61
+ "contact": {
62
+ "uuid": "contact-uuid-3",
63
+ "name": null,
64
+ "urn": "tel:+1122334455",
65
+ "anon_display": "1122334455"
66
+ },
67
+ "flow": {
68
+ "uuid": "flow-uuid-1",
69
+ "name": "Registration Flow"
70
+ },
71
+ "exit_type": "expired",
72
+ "exited_on": "2023-12-01T12:00:00.000Z",
73
+ "created_on": "2023-12-01T11:30:00.000Z",
74
+ "modified_on": "2023-12-01T12:00:00.000Z",
75
+ "responded": true,
76
+ "values": {
77
+ "name": {
78
+ "name": "Name",
79
+ "key": "name",
80
+ "value": "Anonymous User",
81
+ "category": "Text"
82
+ }
83
+ }
84
+ },
85
+ {
86
+ "id": 4,
87
+ "uuid": "run-uuid-4",
88
+ "contact": {
89
+ "uuid": "contact-uuid-4",
90
+ "name": "Active User",
91
+ "urn": "tel:+1555666777",
92
+ "anon_display": "1555666777"
93
+ },
94
+ "flow": {
95
+ "uuid": "flow-uuid-1",
96
+ "name": "Registration Flow"
97
+ },
98
+ "exit_type": null,
99
+ "exited_on": null,
100
+ "created_on": "2023-12-01T12:30:00.000Z",
101
+ "modified_on": "2023-12-01T12:45:00.000Z",
102
+ "responded": true,
103
+ "values": {}
104
+ },
105
+ {
106
+ "id": 5,
107
+ "uuid": "run-uuid-5",
108
+ "contact": {
109
+ "uuid": "contact-uuid-5",
110
+ "name": "Pending User",
111
+ "urn": "tel:+1888999000",
112
+ "anon_display": "1888999000"
113
+ },
114
+ "flow": {
115
+ "uuid": "flow-uuid-1",
116
+ "name": "Registration Flow"
117
+ },
118
+ "exit_type": null,
119
+ "exited_on": null,
120
+ "created_on": "2023-12-01T13:00:00.000Z",
121
+ "modified_on": "2023-12-01T13:00:00.000Z",
122
+ "responded": false,
123
+ "values": {}
124
+ }
125
+ ]
126
+ }
@@ -25,6 +25,29 @@ temba-dialog {
25
25
  caret-color: transparent;
26
26
  }
27
27
 
28
+ /* Disable CSS animations for deterministic screenshots */
29
+ *,
30
+ *::before,
31
+ *::after {
32
+ animation-duration: 0s !important;
33
+ animation-delay: 0s !important;
34
+ transition-duration: 0s !important;
35
+ transition-delay: 0s !important;
36
+ animation-iteration-count: 1 !important;
37
+ }
38
+
39
+ /* Override CSS custom properties for animation control in tests */
40
+ :root {
41
+ --test-animation-duration: 0s !important;
42
+ --test-animation-play-state: paused !important;
43
+ }
44
+
45
+ /* Force disable spin animations by overriding keyframes - this pierces shadow DOM */
46
+ @keyframes spin {
47
+ from { transform: rotate(0deg); }
48
+ to { transform: rotate(0deg); }
49
+ }
50
+
28
51
  html {
29
52
  --transition-speed: 0ms !important;
30
53
  --input-caret: transparent !important;
@@ -186,7 +186,7 @@ const wireScreenshots = async (page, context, wait, replaceScreenshots) => {
186
186
  await page.screenshot({ path: testFile, clip });
187
187
 
188
188
  try {
189
- const result = await checkScreenshot(filename);
189
+ const result = await checkScreenshot(filename, excluded, threshold);
190
190
  // const end = Date.now();
191
191
  // console.log(`Screenshot took ${end - start}ms`);
192
192
  resolve(result);
@@ -351,6 +351,28 @@ export default {
351
351
  '--force-device-scale-factor=1',
352
352
  '--no-sandbox',
353
353
  '--disable-gpu',
354
+ '--disable-font-subpixel-positioning',
355
+ '--disable-lcd-text',
356
+ '--force-prefers-reduced-motion',
357
+ '--disable-background-timer-throttling',
358
+ '--disable-backgrounding-occluded-windows',
359
+ '--disable-renderer-backgrounding',
360
+ // additional flags for consistent rendering across environments
361
+ '--disable-gpu-sandbox',
362
+ '--disable-software-rasterizer',
363
+ '--disable-background-networking',
364
+ '--disable-default-apps',
365
+ '--disable-extensions',
366
+ '--disable-sync',
367
+ '--disable-translate',
368
+ '--hide-crash-restore-bubble',
369
+ '--metrics-recording-only',
370
+ '--no-first-run',
371
+ '--safebrowsing-disable-auto-update',
372
+ '--use-mock-keychain',
373
+ '--disable-ipc-flooding-protection',
374
+ '--disable-component-update',
375
+ '--disable-domain-reliability',
354
376
  ],
355
377
  headless: true,
356
378
  },
@@ -363,13 +385,17 @@ export default {
363
385
  await page.setUserAgent(
364
386
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
365
387
  );
388
+
389
+ // detect if we're running in copilot's environment
390
+ const isCopilotEnvironment = process.env.COPILOT_API_URL || process.env.COPILOT_AGENT_CALLBACK_URL;
391
+
392
+ // inject script into every document that loads
393
+ await page.evaluateOnNewDocument((watched, copilotEnv) => {
394
+ window.watched = watched;
395
+ window.isCopilotEnvironment = copilotEnv;
396
+ }, config.watch, !!isCopilotEnvironment);
397
+
366
398
  await page.once('load', async () => {
367
- await page.addScriptTag({
368
- content: `
369
- window.watched = ${config.watch};
370
- `,
371
- });
372
-
373
399
  await wireScreenshots(page, context, wait, replaceScreenshots);
374
400
  });
375
401
 
package/xliff/es.xlf CHANGED
@@ -15,6 +15,9 @@
15
15
  <trans-unit id="s4788ee206c4570c7">
16
16
  <source>Have not started this flow in the last 90 days</source>
17
17
  </trans-unit>
18
+ <trans-unit id="s73b4d70c02f4b4e0">
19
+ <source>No options</source>
20
+ </trans-unit>
18
21
  </body>
19
22
  </file>
20
23
  </xliff>
package/xliff/fr.xlf CHANGED
@@ -14,6 +14,9 @@
14
14
  <trans-unit id="s4788ee206c4570c7">
15
15
  <source>Have not started this flow in the last 90 days</source>
16
16
  </trans-unit>
17
+ <trans-unit id="s73b4d70c02f4b4e0">
18
+ <source>No options</source>
19
+ </trans-unit>
17
20
  </body>
18
21
  </file>
19
22
  </xliff>
package/xliff/pt.xlf CHANGED
@@ -14,6 +14,9 @@
14
14
  <trans-unit id="s4788ee206c4570c7">
15
15
  <source>Have not started this flow in the last 90 days</source>
16
16
  </trans-unit>
17
+ <trans-unit id="s73b4d70c02f4b4e0">
18
+ <source>No options</source>
19
+ </trans-unit>
17
20
  </body>
18
21
  </file>
19
22
  </xliff>
@@ -1,136 +0,0 @@
1
- import { __decorate } from "tslib";
2
- import { css, html } from 'lit';
3
- import { property } from 'lit/decorators.js';
4
- import { ResizeElement } from '../ResizeElement';
5
- import { fetchResults } from '../utils';
6
- const MIN_BACKLOG = 500000;
7
- export class OutboxMonitor extends ResizeElement {
8
- constructor() {
9
- super(...arguments);
10
- this.backlogSize = 0;
11
- this.endpoint = '/msg/menu/';
12
- this.folders = {};
13
- this.fetches = 0;
14
- this.msgsPerSecond = 0;
15
- }
16
- static get styles() {
17
- return css `
18
- .monitor {
19
- margin: 1rem;
20
- margin-bottom: -0.5rem;
21
- }
22
-
23
- .header {
24
- font-weight: bold;
25
- }
26
-
27
- .estimate {
28
- font-size: 0.9em;
29
- }
30
- `;
31
- }
32
- fetchFolders() {
33
- fetchResults(this.endpoint).then((items) => {
34
- items
35
- .filter((item) => item.id === 'outbox' || item.id === 'sent' || item.id === 'failed')
36
- .forEach((item) => {
37
- if (this.folders[item.id]) {
38
- this.folders[item.id].current = item.count;
39
- }
40
- else {
41
- this.folders[item.id] = {
42
- start: item.count,
43
- current: item.count
44
- };
45
- }
46
- });
47
- if (this.firstFetch) {
48
- this.lastFetch = new Date();
49
- }
50
- else {
51
- this.firstFetch = new Date();
52
- }
53
- this.fetches++;
54
- this.scheduleRefresh(Math.min(this.fetches * 5000, 60000));
55
- const outbox = this.folders['outbox'];
56
- this.backlogSize = outbox.current;
57
- if (outbox.current > 1) {
58
- this.estimateCompletion();
59
- }
60
- });
61
- }
62
- estimateCompletion() {
63
- if (this.lastFetch) {
64
- const time = (this.lastFetch.getTime() - this.firstFetch.getTime()) / 1000;
65
- const sent = this.folders['sent'];
66
- const failed = this.folders['failed'];
67
- const totalCompleted = sent.current + failed.current;
68
- const startCount = sent.start + failed.start;
69
- const sentInWindow = totalCompleted - startCount;
70
- this.msgsPerSecond = sentInWindow / time;
71
- const remaining = this.folders['outbox'].current;
72
- const secondsRemaining = remaining / this.msgsPerSecond;
73
- this.estimatedCompletionDate = new Date(new Date().getTime() + secondsRemaining * 1000);
74
- }
75
- }
76
- scheduleRefresh(time) {
77
- setTimeout(() => {
78
- this.fetchFolders();
79
- }, time);
80
- }
81
- firstUpdated(changes) {
82
- if (changes.has('endpoint') && this.endpoint) {
83
- this.fetchFolders();
84
- }
85
- }
86
- hasBacklog() {
87
- return this.backlogSize > MIN_BACKLOG;
88
- }
89
- render() {
90
- const roundedRate = Math.round(this.msgsPerSecond);
91
- if (this.hasBacklog() && this.estimatedCompletionDate && !this.isMobile()) {
92
- return html `<div class="monitor">
93
- <temba-alert
94
- ><div class="header">Outbox Notice</div>
95
- <div class="estimate">
96
- If your outbox becomes too full, you won't be able to send new flows
97
- or broadcasts. Your channels are currently sending at
98
- ${roundedRate.toLocaleString()}
99
- message${roundedRate == 1 ? '' : 's'} per second. At that rate, your
100
- outbox will clear
101
- <temba-date
102
- value="${this.estimatedCompletionDate.toISOString()}"
103
- display="duration"
104
- ></temba-date
105
- >.
106
- </div></temba-alert
107
- >
108
- </div>`;
109
- }
110
- else {
111
- return null;
112
- }
113
- }
114
- }
115
- __decorate([
116
- property({ type: Number })
117
- ], OutboxMonitor.prototype, "backlogSize", void 0);
118
- __decorate([
119
- property({ type: String })
120
- ], OutboxMonitor.prototype, "endpoint", void 0);
121
- __decorate([
122
- property({ type: Object })
123
- ], OutboxMonitor.prototype, "firstFetch", void 0);
124
- __decorate([
125
- property({ type: Object })
126
- ], OutboxMonitor.prototype, "lastFetch", void 0);
127
- __decorate([
128
- property({ type: Number })
129
- ], OutboxMonitor.prototype, "fetches", void 0);
130
- __decorate([
131
- property({ type: Number })
132
- ], OutboxMonitor.prototype, "msgsPerSecond", void 0);
133
- __decorate([
134
- property({ type: Object })
135
- ], OutboxMonitor.prototype, "estimatedCompletionDate", void 0);
136
- //# sourceMappingURL=OutboxMonitor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"OutboxMonitor.js","sourceRoot":"","sources":["../../../src/outboxmonitor/OutboxMonitor.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { ResizeElement } from '../ResizeElement';\nimport { fetchResults } from '../utils';\n\nconst MIN_BACKLOG = 500000;\nexport class OutboxMonitor extends ResizeElement {\n @property({ type: Number })\n backlogSize = 0;\n\n @property({ type: String })\n endpoint = '/msg/menu/';\n\n folders: { [id: string]: { start: number; current: number } } = {};\n\n @property({ type: Object })\n firstFetch: Date;\n\n @property({ type: Object })\n lastFetch: Date;\n\n @property({ type: Number })\n fetches = 0;\n\n @property({ type: Number })\n msgsPerSecond = 0;\n\n @property({ type: Object })\n estimatedCompletionDate: Date;\n\n public static get styles() {\n return css`\n .monitor {\n margin: 1rem;\n margin-bottom: -0.5rem;\n }\n\n .header {\n font-weight: bold;\n }\n\n .estimate {\n font-size: 0.9em;\n }\n `;\n }\n\n private fetchFolders() {\n fetchResults(this.endpoint).then((items) => {\n items\n .filter(\n (item) =>\n item.id === 'outbox' || item.id === 'sent' || item.id === 'failed'\n )\n .forEach((item) => {\n if (this.folders[item.id]) {\n this.folders[item.id].current = item.count;\n } else {\n this.folders[item.id] = {\n start: item.count,\n current: item.count\n };\n }\n });\n\n if (this.firstFetch) {\n this.lastFetch = new Date();\n } else {\n this.firstFetch = new Date();\n }\n this.fetches++;\n\n this.scheduleRefresh(Math.min(this.fetches * 5000, 60000));\n\n const outbox = this.folders['outbox'];\n\n this.backlogSize = outbox.current;\n if (outbox.current > 1) {\n this.estimateCompletion();\n }\n });\n }\n\n private estimateCompletion() {\n if (this.lastFetch) {\n const time =\n (this.lastFetch.getTime() - this.firstFetch.getTime()) / 1000;\n const sent = this.folders['sent'];\n const failed = this.folders['failed'];\n\n const totalCompleted = sent.current + failed.current;\n const startCount = sent.start + failed.start;\n\n const sentInWindow = totalCompleted - startCount;\n this.msgsPerSecond = sentInWindow / time;\n\n const remaining = this.folders['outbox'].current;\n const secondsRemaining = remaining / this.msgsPerSecond;\n\n this.estimatedCompletionDate = new Date(\n new Date().getTime() + secondsRemaining * 1000\n );\n }\n }\n\n private scheduleRefresh(time: number) {\n setTimeout(() => {\n this.fetchFolders();\n }, time);\n }\n\n protected firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n if (changes.has('endpoint') && this.endpoint) {\n this.fetchFolders();\n }\n }\n\n public hasBacklog() {\n return this.backlogSize > MIN_BACKLOG;\n }\n\n public render() {\n const roundedRate = Math.round(this.msgsPerSecond);\n if (this.hasBacklog() && this.estimatedCompletionDate && !this.isMobile()) {\n return html`<div class=\"monitor\">\n <temba-alert\n ><div class=\"header\">Outbox Notice</div>\n <div class=\"estimate\">\n If your outbox becomes too full, you won't be able to send new flows\n or broadcasts. Your channels are currently sending at\n ${roundedRate.toLocaleString()}\n message${roundedRate == 1 ? '' : 's'} per second. At that rate, your\n outbox will clear\n <temba-date\n value=\"${this.estimatedCompletionDate.toISOString()}\"\n display=\"duration\"\n ></temba-date\n >.\n </div></temba-alert\n >\n </div>`;\n } else {\n return null;\n }\n }\n}\n"]}
@@ -1,148 +0,0 @@
1
- import { css, html, PropertyValueMap } from 'lit';
2
- import { property } from 'lit/decorators.js';
3
- import { ResizeElement } from '../ResizeElement';
4
- import { fetchResults } from '../utils';
5
-
6
- const MIN_BACKLOG = 500000;
7
- export class OutboxMonitor extends ResizeElement {
8
- @property({ type: Number })
9
- backlogSize = 0;
10
-
11
- @property({ type: String })
12
- endpoint = '/msg/menu/';
13
-
14
- folders: { [id: string]: { start: number; current: number } } = {};
15
-
16
- @property({ type: Object })
17
- firstFetch: Date;
18
-
19
- @property({ type: Object })
20
- lastFetch: Date;
21
-
22
- @property({ type: Number })
23
- fetches = 0;
24
-
25
- @property({ type: Number })
26
- msgsPerSecond = 0;
27
-
28
- @property({ type: Object })
29
- estimatedCompletionDate: Date;
30
-
31
- public static get styles() {
32
- return css`
33
- .monitor {
34
- margin: 1rem;
35
- margin-bottom: -0.5rem;
36
- }
37
-
38
- .header {
39
- font-weight: bold;
40
- }
41
-
42
- .estimate {
43
- font-size: 0.9em;
44
- }
45
- `;
46
- }
47
-
48
- private fetchFolders() {
49
- fetchResults(this.endpoint).then((items) => {
50
- items
51
- .filter(
52
- (item) =>
53
- item.id === 'outbox' || item.id === 'sent' || item.id === 'failed'
54
- )
55
- .forEach((item) => {
56
- if (this.folders[item.id]) {
57
- this.folders[item.id].current = item.count;
58
- } else {
59
- this.folders[item.id] = {
60
- start: item.count,
61
- current: item.count
62
- };
63
- }
64
- });
65
-
66
- if (this.firstFetch) {
67
- this.lastFetch = new Date();
68
- } else {
69
- this.firstFetch = new Date();
70
- }
71
- this.fetches++;
72
-
73
- this.scheduleRefresh(Math.min(this.fetches * 5000, 60000));
74
-
75
- const outbox = this.folders['outbox'];
76
-
77
- this.backlogSize = outbox.current;
78
- if (outbox.current > 1) {
79
- this.estimateCompletion();
80
- }
81
- });
82
- }
83
-
84
- private estimateCompletion() {
85
- if (this.lastFetch) {
86
- const time =
87
- (this.lastFetch.getTime() - this.firstFetch.getTime()) / 1000;
88
- const sent = this.folders['sent'];
89
- const failed = this.folders['failed'];
90
-
91
- const totalCompleted = sent.current + failed.current;
92
- const startCount = sent.start + failed.start;
93
-
94
- const sentInWindow = totalCompleted - startCount;
95
- this.msgsPerSecond = sentInWindow / time;
96
-
97
- const remaining = this.folders['outbox'].current;
98
- const secondsRemaining = remaining / this.msgsPerSecond;
99
-
100
- this.estimatedCompletionDate = new Date(
101
- new Date().getTime() + secondsRemaining * 1000
102
- );
103
- }
104
- }
105
-
106
- private scheduleRefresh(time: number) {
107
- setTimeout(() => {
108
- this.fetchFolders();
109
- }, time);
110
- }
111
-
112
- protected firstUpdated(
113
- changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
114
- ): void {
115
- if (changes.has('endpoint') && this.endpoint) {
116
- this.fetchFolders();
117
- }
118
- }
119
-
120
- public hasBacklog() {
121
- return this.backlogSize > MIN_BACKLOG;
122
- }
123
-
124
- public render() {
125
- const roundedRate = Math.round(this.msgsPerSecond);
126
- if (this.hasBacklog() && this.estimatedCompletionDate && !this.isMobile()) {
127
- return html`<div class="monitor">
128
- <temba-alert
129
- ><div class="header">Outbox Notice</div>
130
- <div class="estimate">
131
- If your outbox becomes too full, you won't be able to send new flows
132
- or broadcasts. Your channels are currently sending at
133
- ${roundedRate.toLocaleString()}
134
- message${roundedRate == 1 ? '' : 's'} per second. At that rate, your
135
- outbox will clear
136
- <temba-date
137
- value="${this.estimatedCompletionDate.toISOString()}"
138
- display="duration"
139
- ></temba-date
140
- >.
141
- </div></temba-alert
142
- >
143
- </div>`;
144
- } else {
145
- return null;
146
- }
147
- }
148
- }