@nyaruka/temba-components 0.35.3 → 0.37.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 (232) hide show
  1. package/.eslintrc.js +0 -2
  2. package/.github/workflows/build.yml +1 -0
  3. package/.github/workflows/publish.yml +2 -3
  4. package/.github/workflows/stale.yml +26 -0
  5. package/CHANGELOG.md +31 -0
  6. package/demo/index.html +1 -3
  7. package/dist/46adbabc.js +5792 -0
  8. package/dist/index.js +541 -487
  9. package/dist/sw.js +1 -1
  10. package/dist/sw.js.map +1 -1
  11. package/dist/templates/components-body.html +1 -1
  12. package/dist/templates/components-head.html +1 -1
  13. package/dist/workbox-919adfb7.js +2 -0
  14. package/dist/workbox-919adfb7.js.map +1 -0
  15. package/out-tsc/src/FormElement.js +1 -1
  16. package/out-tsc/src/FormElement.js.map +1 -1
  17. package/out-tsc/src/RefreshElement.js +1 -1
  18. package/out-tsc/src/RefreshElement.js.map +1 -1
  19. package/out-tsc/src/alert/Alert.js +1 -1
  20. package/out-tsc/src/alert/Alert.js.map +1 -1
  21. package/out-tsc/src/aliaseditor/AliasEditor.js +6 -6
  22. package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
  23. package/out-tsc/src/anchor/Anchor.js +1 -1
  24. package/out-tsc/src/anchor/Anchor.js.map +1 -1
  25. package/out-tsc/src/button/Button.js +1 -1
  26. package/out-tsc/src/button/Button.js.map +1 -1
  27. package/out-tsc/src/charcount/CharCount.js +1 -1
  28. package/out-tsc/src/charcount/CharCount.js.map +1 -1
  29. package/out-tsc/src/checkbox/Checkbox.js +1 -1
  30. package/out-tsc/src/checkbox/Checkbox.js.map +1 -1
  31. package/out-tsc/src/completion/Completion.js +3 -3
  32. package/out-tsc/src/completion/Completion.js.map +1 -1
  33. package/out-tsc/src/completion/helpers.js +2 -2
  34. package/out-tsc/src/completion/helpers.js.map +1 -1
  35. package/out-tsc/src/contacts/ContactChat.js +184 -156
  36. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  37. package/out-tsc/src/contacts/ContactDetails.js +1 -1
  38. package/out-tsc/src/contacts/ContactDetails.js.map +1 -1
  39. package/out-tsc/src/contacts/ContactFieldEditor.js +1 -1
  40. package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
  41. package/out-tsc/src/contacts/ContactFields.js +1 -1
  42. package/out-tsc/src/contacts/ContactFields.js.map +1 -1
  43. package/out-tsc/src/contacts/ContactHistory.js +1 -1
  44. package/out-tsc/src/contacts/ContactHistory.js.map +1 -1
  45. package/out-tsc/src/contacts/ContactName.js +1 -1
  46. package/out-tsc/src/contacts/ContactName.js.map +1 -1
  47. package/out-tsc/src/contacts/ContactNameFetch.js +1 -1
  48. package/out-tsc/src/contacts/ContactNameFetch.js.map +1 -1
  49. package/out-tsc/src/contacts/ContactPending.js +13 -13
  50. package/out-tsc/src/contacts/ContactPending.js.map +1 -1
  51. package/out-tsc/src/contacts/ContactStoreElement.js +1 -1
  52. package/out-tsc/src/contacts/ContactStoreElement.js.map +1 -1
  53. package/out-tsc/src/contacts/ContactTickets.js +1 -1
  54. package/out-tsc/src/contacts/ContactTickets.js.map +1 -1
  55. package/out-tsc/src/contacts/ContactUrn.js +1 -1
  56. package/out-tsc/src/contacts/ContactUrn.js.map +1 -1
  57. package/out-tsc/src/contactsearch/ContactSearch.js +1 -1
  58. package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
  59. package/out-tsc/src/date/TembaDate.js +1 -1
  60. package/out-tsc/src/date/TembaDate.js.map +1 -1
  61. package/out-tsc/src/datepicker/DatePicker.js +8 -8
  62. package/out-tsc/src/datepicker/DatePicker.js.map +1 -1
  63. package/out-tsc/src/dialog/Dialog.js +11 -11
  64. package/out-tsc/src/dialog/Dialog.js.map +1 -1
  65. package/out-tsc/src/dialog/Modax.js +16 -17
  66. package/out-tsc/src/dialog/Modax.js.map +1 -1
  67. package/out-tsc/src/dropdown/Dropdown.js +1 -1
  68. package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
  69. package/out-tsc/src/fields/FieldManager.js +1 -1
  70. package/out-tsc/src/fields/FieldManager.js.map +1 -1
  71. package/out-tsc/src/flow/FlowStoreElement.js +1 -1
  72. package/out-tsc/src/flow/FlowStoreElement.js.map +1 -1
  73. package/out-tsc/src/formfield/FormField.js +1 -1
  74. package/out-tsc/src/formfield/FormField.js.map +1 -1
  75. package/out-tsc/src/label/Label.js +2 -2
  76. package/out-tsc/src/label/Label.js.map +1 -1
  77. package/out-tsc/src/leafletmap/LeafletMap.js +12 -12
  78. package/out-tsc/src/leafletmap/LeafletMap.js.map +1 -1
  79. package/out-tsc/src/list/ContentMenu.js +176 -0
  80. package/out-tsc/src/list/ContentMenu.js.map +1 -0
  81. package/out-tsc/src/list/RunList.js +13 -12
  82. package/out-tsc/src/list/RunList.js.map +1 -1
  83. package/out-tsc/src/list/SortableList.js +14 -14
  84. package/out-tsc/src/list/SortableList.js.map +1 -1
  85. package/out-tsc/src/list/TembaList.js +14 -16
  86. package/out-tsc/src/list/TembaList.js.map +1 -1
  87. package/out-tsc/src/list/TembaMenu.js +108 -108
  88. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  89. package/out-tsc/src/list/TicketList.js +8 -8
  90. package/out-tsc/src/list/TicketList.js.map +1 -1
  91. package/out-tsc/src/loading/Loading.js +2 -2
  92. package/out-tsc/src/loading/Loading.js.map +1 -1
  93. package/out-tsc/src/omnibox/Omnibox.js +2 -2
  94. package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
  95. package/out-tsc/src/options/Options.js +2 -2
  96. package/out-tsc/src/options/Options.js.map +1 -1
  97. package/out-tsc/src/remote/Remote.js +1 -1
  98. package/out-tsc/src/remote/Remote.js.map +1 -1
  99. package/out-tsc/src/select/Select.js +2 -2
  100. package/out-tsc/src/select/Select.js.map +1 -1
  101. package/out-tsc/src/shadowless/Shadowless.js +1 -1
  102. package/out-tsc/src/shadowless/Shadowless.js.map +1 -1
  103. package/out-tsc/src/slider/TembaSlider.js +2 -2
  104. package/out-tsc/src/slider/TembaSlider.js.map +1 -1
  105. package/out-tsc/src/store/Store.js +8 -5
  106. package/out-tsc/src/store/Store.js.map +1 -1
  107. package/out-tsc/src/store/StoreElement.js +1 -1
  108. package/out-tsc/src/store/StoreElement.js.map +1 -1
  109. package/out-tsc/src/tabpane/Tab.js +1 -1
  110. package/out-tsc/src/tabpane/Tab.js.map +1 -1
  111. package/out-tsc/src/tabpane/TabPane.js +1 -1
  112. package/out-tsc/src/tabpane/TabPane.js.map +1 -1
  113. package/out-tsc/src/textinput/TextInput.js +15 -15
  114. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  115. package/out-tsc/src/tip/Tip.js +2 -2
  116. package/out-tsc/src/tip/Tip.js.map +1 -1
  117. package/out-tsc/src/utils/index.js +1 -6
  118. package/out-tsc/src/utils/index.js.map +1 -1
  119. package/out-tsc/src/vectoricon/VectorIcon.js +9 -9
  120. package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
  121. package/out-tsc/temba-modules.js +3 -0
  122. package/out-tsc/temba-modules.js.map +1 -1
  123. package/out-tsc/test/MouseHelper.js +1 -1
  124. package/out-tsc/test/MouseHelper.js.map +1 -1
  125. package/out-tsc/test/temba-contact-chat.test.js +93 -50
  126. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  127. package/out-tsc/test/temba-contact-history.test.js +1 -1
  128. package/out-tsc/test/temba-contact-history.test.js.map +1 -1
  129. package/out-tsc/test/temba-content-menu.test.js +71 -0
  130. package/out-tsc/test/temba-content-menu.test.js.map +1 -0
  131. package/out-tsc/test/temba-modax.test.js +18 -19
  132. package/out-tsc/test/temba-modax.test.js.map +1 -1
  133. package/out-tsc/test/temba-select.test.js +1 -0
  134. package/out-tsc/test/temba-select.test.js.map +1 -1
  135. package/out-tsc/test/temba-tip.test.js +4 -6
  136. package/out-tsc/test/temba-tip.test.js.map +1 -1
  137. package/out-tsc/test/utils.test.js +5 -17
  138. package/out-tsc/test/utils.test.js.map +1 -1
  139. package/package.json +16 -28
  140. package/rollup.config.js +13 -7
  141. package/screenshots/truth/contacts/{contact-active-show-chat-history.png → contact-active-show-chatbox.png} +0 -0
  142. package/screenshots/truth/contacts/contact-active-ticket-closed-show-reopen-button.png +0 -0
  143. package/screenshots/truth/contacts/contact-active-ticket-open-show-chatbox.png +0 -0
  144. package/screenshots/truth/contacts/{contact-archived-hide-chat-msg.png → contact-archived-hide-chatbox.png} +0 -0
  145. package/screenshots/truth/contacts/contact-archived-ticket-closed-hide-chatbox.png +0 -0
  146. package/screenshots/truth/contacts/{contact-archived-show-chat-history.png → contact-blocked-hide-chatbox.png} +0 -0
  147. package/screenshots/truth/contacts/{contact-blocked-hide-chat-msg.png → contact-stopped-hide-chatbox.png} +0 -0
  148. package/screenshots/truth/content-menu/button-no-items.png +0 -0
  149. package/screenshots/truth/content-menu/item-no-buttons.png +0 -0
  150. package/screenshots/truth/content-menu/items-and-buttons.png +0 -0
  151. package/src/FormElement.ts +1 -1
  152. package/src/RefreshElement.ts +1 -1
  153. package/src/alert/Alert.ts +1 -1
  154. package/src/aliaseditor/AliasEditor.ts +2 -2
  155. package/src/anchor/Anchor.ts +1 -1
  156. package/src/button/Button.ts +1 -1
  157. package/src/charcount/CharCount.ts +1 -1
  158. package/src/checkbox/Checkbox.ts +1 -1
  159. package/src/completion/Completion.ts +3 -3
  160. package/src/completion/helpers.ts +8 -2
  161. package/src/contacts/ContactChat.ts +185 -157
  162. package/src/contacts/ContactDetails.ts +1 -1
  163. package/src/contacts/ContactFieldEditor.ts +1 -1
  164. package/src/contacts/ContactFields.ts +1 -1
  165. package/src/contacts/ContactHistory.ts +1 -1
  166. package/src/contacts/ContactName.ts +1 -1
  167. package/src/contacts/ContactNameFetch.ts +1 -1
  168. package/src/contacts/ContactPending.ts +1 -1
  169. package/src/contacts/ContactStoreElement.ts +1 -1
  170. package/src/contacts/ContactTickets.ts +1 -1
  171. package/src/contacts/ContactUrn.ts +1 -1
  172. package/src/contactsearch/ContactSearch.ts +1 -1
  173. package/src/date/TembaDate.ts +1 -1
  174. package/src/datepicker/DatePicker.ts +1 -1
  175. package/src/dialog/Dialog.ts +2 -2
  176. package/src/dialog/Modax.ts +17 -24
  177. package/src/dropdown/Dropdown.ts +1 -1
  178. package/src/fields/FieldManager.ts +1 -1
  179. package/src/flow/FlowStoreElement.ts +1 -1
  180. package/src/formfield/FormField.ts +1 -1
  181. package/src/label/Label.ts +2 -2
  182. package/src/leafletmap/LeafletMap.ts +1 -1
  183. package/src/list/ContentMenu.ts +192 -0
  184. package/src/list/RunList.ts +4 -3
  185. package/src/list/SortableList.ts +1 -1
  186. package/src/list/TembaList.ts +2 -4
  187. package/src/list/TembaMenu.ts +1 -1
  188. package/src/list/TicketList.ts +1 -1
  189. package/src/loading/Loading.ts +2 -2
  190. package/src/omnibox/Omnibox.ts +2 -2
  191. package/src/options/Options.ts +2 -2
  192. package/src/remote/Remote.ts +1 -1
  193. package/src/select/Select.ts +2 -2
  194. package/src/shadowless/Shadowless.ts +1 -1
  195. package/src/slider/TembaSlider.ts +2 -2
  196. package/src/store/Store.ts +11 -7
  197. package/src/store/StoreElement.ts +1 -1
  198. package/src/tabpane/Tab.ts +1 -1
  199. package/src/tabpane/TabPane.ts +1 -1
  200. package/src/textinput/TextInput.ts +3 -3
  201. package/src/tip/Tip.ts +6 -6
  202. package/src/untyped.d.ts +0 -2
  203. package/src/utils/index.ts +1 -5
  204. package/src/vectoricon/VectorIcon.ts +1 -1
  205. package/temba-modules.ts +3 -0
  206. package/test/MouseHelper.ts +1 -1
  207. package/test/temba-contact-chat.test.ts +148 -62
  208. package/test/temba-contact-history.test.ts +1 -1
  209. package/test/temba-content-menu.test.ts +100 -0
  210. package/test/temba-modax.test.ts +25 -21
  211. package/test/temba-select.test.ts +2 -0
  212. package/test/temba-tip.test.ts +10 -5
  213. package/test/utils.test.ts +6 -19
  214. package/test-assets/contacts/{contact-barak-archived → contact-barack-archived} +1 -1
  215. package/test-assets/contacts/contact-carter-active +52 -0
  216. package/test-assets/contacts/contact-michelle-blocked +1 -1
  217. package/test-assets/contacts/contact-tim-stopped +1 -1
  218. package/test-assets/list/content-menu-archived-contacts.json +12 -0
  219. package/test-assets/list/content-menu-contact-read.json +49 -0
  220. package/test-assets/list/content-menu-new-campaign.json +15 -0
  221. package/test-assets/tickets/empty.json +6 -0
  222. package/test-assets/tickets/ticket-barack-closed.json +22 -0
  223. package/test-assets/tickets/ticket-carter-closed.json +22 -0
  224. package/test-assets/tickets/ticket-carter-open.json +22 -0
  225. package/web-test-runner.config.mjs +21 -18
  226. package/dist/445f048b.js +0 -5738
  227. package/dist/workbox-80efdfd1.js +0 -2
  228. package/dist/workbox-80efdfd1.js.map +0 -1
  229. package/screenshots/truth/contacts/contact-active-show-chat-msg.png +0 -0
  230. package/screenshots/truth/contacts/contact-blocked-show-chat-history.png +0 -0
  231. package/screenshots/truth/contacts/contact-stopped-hide-chat-msg.png +0 -0
  232. package/screenshots/truth/contacts/contact-stopped-show-chat-history.png +0 -0
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { Contact, CustomEventType, Ticket } from '../interfaces';
4
4
  import { COOKIE_KEYS, getCookieBoolean, postJSON, setCookie } from '../utils';
5
5
  import { TextInput } from '../textinput/TextInput';
@@ -194,6 +194,9 @@ export class ContactChat extends ContactStoreElement {
194
194
  @property({ type: String })
195
195
  agent = '';
196
196
 
197
+ // http promise to monitor for completeness
198
+ public httpComplete: Promise<void>;
199
+
197
200
  constructor() {
198
201
  super();
199
202
  this.showDetails = getCookieBoolean(COOKIE_KEYS.TICKET_SHOW_DETAILS);
@@ -272,7 +275,7 @@ export class ContactChat extends ContactStoreElement {
272
275
  this.currentChat = chat.value;
273
276
  }
274
277
 
275
- private handleReopen() {
278
+ private handleTicketReopen() {
276
279
  const uuid = this.currentTicket.uuid;
277
280
  postJSON(`/api/v2/ticket_actions.json`, {
278
281
  tickets: [uuid],
@@ -321,163 +324,188 @@ export class ContactChat extends ContactStoreElement {
321
324
  }
322
325
 
323
326
  public render(): TemplateResult {
324
- return html`
325
- <div
326
- style="flex-grow: 1; margin-right: 0em; display:flex; flex-direction:row; min-height: 0;"
327
- class="left-pane ${this.showDetails ? 'open' : ''}"
328
- >
329
- <div class="chat-wrapper">
330
- ${this.currentContact
331
- ? html`<temba-contact-history
332
- .uuid=${this.currentContact.uuid}
333
- .contact=${this.currentContact}
334
- .ticket=${
335
- this.currentTicket ? this.currentTicket.uuid : null
336
- }
337
- .endDate=${
338
- this.currentTicket ? this.currentTicket.closed_on : null
339
- }
340
- .agent=${this.agent}
341
- ></temba-contact-history>
342
-
343
- ${
344
- this.currentTicket && this.currentTicket.closed_on
345
- ? html`<div class="closed-footer">
346
- <temba-button
347
- id="reopen-button"
348
- name="Reopen"
349
- @click=${this.handleReopen}
350
- ></temba-button>
351
- </div>`
352
- : html` <div
353
- class="chatbox ${this.toolbar ? 'full' : ''}"
354
- style="${this.currentContact.status !== 'active'
355
- ? 'display:none'
356
- : ''}"
357
- >
358
- <temba-completion
359
- @change=${this.handleChatChange}
360
- .value=${this.currentChat}
361
- @keydown=${(e: KeyboardEvent) => {
362
- if (e.key === 'Enter' && !e.shiftKey) {
363
- const chat = e.target as Completion;
364
- if (!chat.hasVisibleOptions()) {
365
- this.handleSend();
366
- e.preventDefault();
367
- e.stopPropagation();
368
- }
369
- }
370
- }}
371
- textarea
372
- >
373
- </temba-completion>
374
- <temba-button
375
- id="send-button"
376
- name="Send"
377
- @click=${this.handleSend}
378
- ?disabled=${this.currentChat.trim().length === 0}
379
- ></temba-button>
380
- </div>`
381
- }
382
- </div>`
383
- : null}
327
+ const contactHistory = this.currentContact
328
+ ? this.getTembaContactHistory()
329
+ : null;
330
+ const chatbox = this.currentContact ? this.getTembaChatbox() : null;
331
+
332
+ const contactHistoryAndChatbox = html`<div
333
+ style="flex-grow: 1; margin-right: 0em; display:flex; flex-direction:row; min-height: 0;"
334
+ class="left-pane ${this.showDetails ? 'open' : ''}"
335
+ >
336
+ <div class="chat-wrapper">${contactHistory} ${chatbox}</div>
337
+ </div>`;
338
+
339
+ if (this.toolbar) {
340
+ const contactDetails = this.currentContact
341
+ ? this.getTembaContactDetails()
342
+ : null;
343
+ const toggleContactDetails = this.currentContact
344
+ ? this.getToggleDetailsTembaTip()
345
+ : null;
346
+ const addNoteAndAssignTicketTembaTips =
347
+ this.currentContact && this.currentTicket
348
+ ? this.getAddNoteAndAssignTicketTembaTips()
349
+ : null;
350
+ const addNoteAndAssignTicketTembaModaxes = this.currentTicket
351
+ ? this.getAddNoteAndAssignTicketTembaModaxes()
352
+ : null;
353
+
354
+ const contactDetailsAndActions = html`${contactDetails}
355
+ <div class="toolbar ${this.showDetails ? '' : 'closed'}">
356
+ ${toggleContactDetails} ${addNoteAndAssignTicketTembaTips}
384
357
  </div>
385
- </div>
386
-
387
- ${this.toolbar
388
- ? html`${
389
- this.currentContact
390
- ? html`<temba-contact-details
391
- style="z-index: 10"
392
- class="${this.showDetails ? '' : 'hidden'}"
393
- showGroups="true"
394
- .visible=${this.showDetails}
395
- .ticket=${this.currentTicket}
396
- .contact=${this.currentContact}
397
- ></temba-contact-details>`
398
- : null
399
- }
358
+ ${addNoteAndAssignTicketTembaModaxes}`;
400
359
 
401
- <div class="toolbar ${this.showDetails ? '' : 'closed'}">
402
- ${
403
- this.currentContact
404
- ? html`
405
- <temba-tip
406
- style="margin-top:5px"
407
- text="${this.showDetails ? 'Hide Details' : 'Show Details'}"
408
- position="left"
409
- hideOnChange
410
- >
411
- <temba-icon
412
- id="details-button"
413
- name="${this.showDetails
414
- ? Icon.menu_collapse
415
- : 'layout-left'}"
416
- @click="${this.handleDetailSlider}"
417
- clickable
418
- animatechange="spin"
419
- ></temba-icon>
420
- </temba-tip>
421
-
422
- ${this.currentTicket
423
- ? html`<temba-tip
424
- style="margin-top:5px"
425
- text="Assign"
426
- position="left"
427
- >
428
- <temba-icon
429
- id="assign-button"
430
- name="${Icon.users}"
431
- @click="${() => {
432
- const modax = this.shadowRoot.getElementById(
433
- 'assign-dialog'
434
- ) as Modax;
435
- modax.open = true;
436
- }}"
437
- clickable
438
- ></temba-icon>
439
- </temba-tip>
440
- <temba-tip
441
- style="margin-top:5px"
442
- text="Add Note"
443
- position="left"
444
- >
445
- <temba-icon
446
- id="add-note-button"
447
- name="${Icon.add_note}"
448
- @click="${() => {
449
- const note = this.shadowRoot.getElementById(
450
- 'note-dialog'
451
- ) as Modax;
452
- note.open = true;
453
- }}"
454
- clickable
455
- ></temba-icon>
456
- </temba-tip>`
457
- : null}
458
- `
459
- : null
360
+ return html`${contactHistoryAndChatbox} ${contactDetailsAndActions}`;
361
+ }
362
+
363
+ return html`${contactHistoryAndChatbox}`;
364
+ }
365
+
366
+ private getTembaContactHistory(): TemplateResult {
367
+ return html` <temba-contact-history
368
+ .uuid=${this.currentContact.uuid}
369
+ .contact=${this.currentContact}
370
+ .ticket=${this.currentTicket ? this.currentTicket.uuid : null}
371
+ .endDate=${this.currentTicket ? this.currentTicket.closed_on : null}
372
+ .agent=${this.agent}
373
+ >
374
+ </temba-contact-history>`;
375
+ }
376
+
377
+ private getTembaChatbox(): TemplateResult {
378
+ if (this.currentTicket) {
379
+ if (this.currentContact && this.currentContact.status !== 'active') {
380
+ //no chatbox for archived, blocked, or stopped contacts
381
+ return null;
382
+ } else {
383
+ if (this.currentTicket.closed_on) {
384
+ //reopen button for active contacts with a closed ticket
385
+ return html` <div class="closed-footer">
386
+ <temba-button
387
+ id="reopen-button"
388
+ name="Reopen"
389
+ @click=${this.handleTicketReopen}
390
+ ></temba-button>
391
+ </div>`;
392
+ } else {
393
+ //chatbox for active contacts with an open ticket
394
+ return this.getChatbox();
395
+ }
396
+ }
397
+ }
398
+
399
+ if (this.currentContact && this.currentContact.status !== 'active') {
400
+ //no chatbox for archived, blocked, or stopped contacts
401
+ return null;
402
+ } else {
403
+ //chatbox for active contacts
404
+ return this.getChatbox();
405
+ }
406
+ }
407
+
408
+ private getChatbox(): TemplateResult {
409
+ return html` <div class="chatbox ${this.toolbar ? 'full' : ''}">
410
+ <temba-completion
411
+ @change=${this.handleChatChange}
412
+ .value=${this.currentChat}
413
+ @keydown=${(e: KeyboardEvent) => {
414
+ if (e.key === 'Enter' && !e.shiftKey) {
415
+ const chat = e.target as Completion;
416
+ if (!chat.hasVisibleOptions()) {
417
+ this.handleSend();
418
+ e.preventDefault();
419
+ e.stopPropagation();
420
+ }
460
421
  }
461
- </div>
462
- </div>
463
-
464
- ${
465
- this.currentTicket
466
- ? html`<temba-modax
467
- header="Add Note"
468
- id="note-dialog"
469
- @temba-submitted=${this.refresh}
470
- endpoint="/ticket/note/${this.currentTicket.uuid}/"
471
- ></temba-modax>
472
- <temba-modax
473
- header="Assign Ticket"
474
- id="assign-dialog"
475
- @temba-submitted=${this.handleTicketAssigned}
476
- endpoint="/ticket/assign/${this.currentTicket.uuid}/"
477
- /></temba-modax>`
478
- : null
479
- }`
480
- : null}
481
- `;
422
+ }}
423
+ textarea
424
+ >
425
+ </temba-completion>
426
+ <temba-button
427
+ id="send-button"
428
+ name="Send"
429
+ @click=${this.handleSend}
430
+ ?disabled=${this.currentChat.trim().length === 0}
431
+ ></temba-button>
432
+ </div>`;
433
+ }
434
+
435
+ private getTembaContactDetails(): TemplateResult {
436
+ return html` <temba-contact-details
437
+ style="z-index: 10"
438
+ class="${this.showDetails ? '' : 'hidden'}"
439
+ showGroups="true"
440
+ .visible=${this.showDetails}
441
+ .ticket=${this.currentTicket}
442
+ .contact=${this.currentContact}
443
+ >
444
+ </temba-contact-details>`;
445
+ }
446
+
447
+ private getToggleDetailsTembaTip(): TemplateResult {
448
+ return html` <temba-tip
449
+ style="margin-top:5px"
450
+ text="${this.showDetails ? 'Hide Details' : 'Show Details'}"
451
+ position="left"
452
+ hideOnChange
453
+ >
454
+ <temba-icon
455
+ id="details-button"
456
+ name="${this.showDetails ? Icon.menu_collapse : 'layout-left'}"
457
+ @click="${this.handleDetailSlider}"
458
+ clickable
459
+ animatechange="spin"
460
+ ></temba-icon>
461
+ </temba-tip>`;
462
+ }
463
+
464
+ private getAddNoteAndAssignTicketTembaTips(): TemplateResult {
465
+ return html` <temba-tip
466
+ style="margin-top:5px"
467
+ text="Assign"
468
+ position="left"
469
+ >
470
+ <temba-icon
471
+ id="assign-button"
472
+ name="${Icon.users}"
473
+ @click="${() => {
474
+ const modax = this.shadowRoot.getElementById(
475
+ 'assign-dialog'
476
+ ) as Modax;
477
+ modax.open = true;
478
+ }}"
479
+ clickable
480
+ ></temba-icon>
481
+ </temba-tip>
482
+ <temba-tip style="margin-top:5px" text="Add Note" position="left">
483
+ <temba-icon
484
+ id="add-note-button"
485
+ name="${Icon.add_note}"
486
+ @click="${() => {
487
+ const note = this.shadowRoot.getElementById('note-dialog') as Modax;
488
+ note.open = true;
489
+ }}"
490
+ clickable
491
+ ></temba-icon>
492
+ </temba-tip>`;
493
+ }
494
+
495
+ private getAddNoteAndAssignTicketTembaModaxes(): TemplateResult {
496
+ return html` <temba-modax
497
+ header="Add Note"
498
+ id="note-dialog"
499
+ @temba-submitted=${this.refresh}
500
+ endpoint="/ticket/note/${this.currentTicket.uuid}/"
501
+ >
502
+ </temba-modax>
503
+ <temba-modax
504
+ header="Assign Ticket"
505
+ id="assign-dialog"
506
+ @temba-submitted=${this.handleTicketAssigned}
507
+ endpoint="/ticket/assign/${this.currentTicket.uuid}/"
508
+ >
509
+ </temba-modax>`;
482
510
  }
483
511
  }
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { Contact, Group, Ticket } from '../interfaces';
4
4
  import { RapidElement } from '../RapidElement';
5
5
  import { isDate, timeSince, truncate } from '../utils';
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { FormElement } from '../FormElement';
4
4
  import { CustomEventType } from '../interfaces';
5
5
  import { RapidElement } from '../RapidElement';
@@ -1,5 +1,5 @@
1
1
  import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { postJSON } from '../utils';
4
4
  import { ContactFieldEditor } from './ContactFieldEditor';
5
5
  import { ContactStoreElement } from './ContactStoreElement';
@@ -1,5 +1,5 @@
1
1
  import { css } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { html, TemplateResult } from 'lit-html';
4
4
  import { Contact, CustomEventType, Ticket } from '../interfaces';
5
5
  import { RapidElement } from '../RapidElement';
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
 
5
5
  export class ContactName extends RapidElement {
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { ContactStoreElement } from './ContactStoreElement';
4
4
 
5
5
  export class ContactNameFetch extends ContactStoreElement {
@@ -1,5 +1,5 @@
1
1
  import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import {
4
4
  CustomEventType,
5
5
  ScheduledEvent,
@@ -1,5 +1,5 @@
1
1
  import { PropertyValueMap } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { Contact, Group } from '../interfaces';
4
4
  import { StoreElement } from '../store/StoreElement';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { Ticket, TicketStatus } from '../interfaces';
4
4
  import { StoreElement } from '../store/StoreElement';
5
5
  import { Icon } from '../vectoricon';
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
 
5
5
  export class ContactUrn extends RapidElement {
@@ -1,5 +1,5 @@
1
1
  import { TemplateResult, html, css } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { getClasses, postJSON, WebResponse } from '../utils';
4
4
  import { TextInput } from '../textinput/TextInput';
5
5
  import '../alert/Alert';
@@ -1,5 +1,5 @@
1
1
  import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
  import { Store } from '../store/Store';
5
5
  import { DateTime } from 'luxon';
@@ -1,5 +1,5 @@
1
1
  import { TemplateResult, html, css, PropertyValueMap } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { FormElement } from '../FormElement';
4
4
  import { getClasses } from '../utils';
5
5
  import { DateTime } from 'luxon';
@@ -1,9 +1,9 @@
1
- import { property } from 'lit/decorators';
1
+ import { property } from 'lit/decorators.js';
2
2
  import { TemplateResult, html, css } from 'lit';
3
3
  import { Button } from '../button/Button';
4
4
  import { RapidElement } from '../RapidElement';
5
5
  import { CustomEventType } from '../interfaces';
6
- import { styleMap } from 'lit-html/directives/style-map';
6
+ import { styleMap } from 'lit-html/directives/style-map.js';
7
7
  import { getClasses } from '../utils';
8
8
 
9
9
  export class Dialog extends RapidElement {
@@ -1,6 +1,6 @@
1
1
  import { TemplateResult, html, css } from 'lit';
2
- import { property } from 'lit/decorators';
3
- import { unsafeHTML } from 'lit-html/directives/unsafe-html';
2
+ import { property } from 'lit/decorators.js';
3
+ import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
4
4
 
5
5
  import { RapidElement } from '../RapidElement';
6
6
  import { getUrl, serialize, postUrl, WebResponse } from '../utils';
@@ -10,9 +10,6 @@ import { Dialog } from './Dialog';
10
10
  export class Modax extends RapidElement {
11
11
  static get styles() {
12
12
  return css`
13
- :host {
14
- }
15
-
16
13
  fieldset {
17
14
  border: none;
18
15
  margin: 0;
@@ -117,9 +114,6 @@ export class Modax extends RapidElement {
117
114
  suspendSubmit = false;
118
115
  // private cancelToken: CancelTokenSource;
119
116
 
120
- // http promise to monitor for completeness
121
- public httpComplete: Promise<void | WebResponse>;
122
-
123
117
  private handleSlotClicked(): void {
124
118
  this.open = true;
125
119
  }
@@ -152,22 +146,22 @@ export class Modax extends RapidElement {
152
146
  return html`<temba-loading units="6" size="8"></temba-loading>`;
153
147
  }
154
148
 
155
- private updatePrimaryButton(): void {
149
+ public updatePrimaryButton(): void {
156
150
  if (!this.noSubmit) {
157
- window.setTimeout(() => {
151
+ this.updateComplete.then(()=>{
158
152
  const submitButton = this.shadowRoot.querySelector(
159
153
  "input[type='submit']"
160
154
  ) as any;
161
155
 
162
156
  if (submitButton) {
163
157
  this.primaryName = submitButton.value;
158
+ this.cancelName = 'Cancel';
164
159
  } else {
165
160
  this.primaryName = null;
166
161
  this.cancelName = 'Ok';
167
162
  }
168
-
169
163
  this.submitting = false;
170
- }, 0);
164
+ });
171
165
  }
172
166
  }
173
167
 
@@ -196,7 +190,7 @@ export class Modax extends RapidElement {
196
190
  const script = this.ownerDocument.createElement('script');
197
191
  const code = scripts[i].innerText;
198
192
 
199
- if (scripts[i].src) {
193
+ if (scripts[i].src && scripts[i].src.indexOf("web-dev-server") === -1) {
200
194
  script.src = scripts[i].src;
201
195
  script.type = 'text/javascript';
202
196
  script.async = true;
@@ -219,12 +213,11 @@ export class Modax extends RapidElement {
219
213
  this.body = unsafeHTML(div.innerHTML);
220
214
  }
221
215
 
222
- window.setTimeout(() => {
216
+ this.updateComplete.then(()=>{
223
217
  for (const script of toAdd) {
224
218
  scriptBlock.appendChild(script);
225
219
  }
226
- }, 0);
227
-
220
+ });
228
221
  return !scriptOnly;
229
222
  }
230
223
 
@@ -239,16 +232,16 @@ export class Modax extends RapidElement {
239
232
  // this.cancelToken = CancelToken.source();
240
233
  this.fetching = true;
241
234
  this.body = this.getLoading();
242
- this.httpComplete = getUrl(this.endpoint, null, this.getHeaders()).then(
235
+ getUrl(this.endpoint, null, this.getHeaders()).then(
243
236
  (response: WebResponse) => {
244
- this.setBody(response.body);
245
- this.updatePrimaryButton();
237
+ this.setBody(response.body);
246
238
  this.fetching = false;
247
- window.setTimeout(() => {
239
+ this.updateComplete.then(()=>{
240
+ this.updatePrimaryButton();
248
241
  this.fireCustomEvent(CustomEventType.Loaded, {
249
242
  body: this.getBody(),
250
243
  });
251
- }, 0);
244
+ });
252
245
  }
253
246
  );
254
247
  }
@@ -258,7 +251,7 @@ export class Modax extends RapidElement {
258
251
  const form = this.shadowRoot.querySelector('form');
259
252
  const postData = form ? serialize(form) : {};
260
253
 
261
- this.httpComplete = postUrl(
254
+ postUrl(
262
255
  this.endpoint,
263
256
  postData,
264
257
  this.getHeaders(),
@@ -277,10 +270,10 @@ export class Modax extends RapidElement {
277
270
 
278
271
  if (redirect) {
279
272
  if (redirect === 'hide') {
280
- window.setTimeout(() => {
273
+ this.updateComplete.then(()=>{
281
274
  this.open = false;
282
275
  this.fireCustomEvent(CustomEventType.Submitted);
283
- }, 0);
276
+ });
284
277
  } else {
285
278
  this.fireCustomEvent(CustomEventType.Redirected, {
286
279
  url: redirect,
@@ -1,5 +1,5 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
 
5
5
  export class Dropdown extends RapidElement {
@@ -1,5 +1,5 @@
1
1
  import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { ContactField, CustomEventType } from '../interfaces';
4
4
 
5
5
  import { SortableList } from '../list/SortableList';
@@ -1,5 +1,5 @@
1
1
  import { html, PropertyValueMap, TemplateResult } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { FlowDetails } from '../interfaces';
4
4
  import { StoreElement } from '../store/StoreElement';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { TemplateResult, html, css, LitElement } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
 
4
4
  /**
5
5
  * A small wrapper to display labels and help text in a smartmin style.
@@ -1,7 +1,7 @@
1
1
  import { LitElement, TemplateResult, html, css } from 'lit';
2
- import { property } from 'lit/decorators';
2
+ import { property } from 'lit/decorators.js';
3
3
  import { getClasses } from '../utils';
4
- import { styleMap } from 'lit-html/directives/style-map';
4
+ import { styleMap } from 'lit-html/directives/style-map.js';
5
5
 
6
6
  export default class Label extends LitElement {
7
7
  static get styles() {