@nyaruka/temba-components 0.141.0 → 0.142.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 (206) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/static/svg/index.svg +1 -1
  3. package/dist/temba-components.js +859 -656
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/Icons.js +3 -1
  6. package/out-tsc/src/Icons.js.map +1 -1
  7. package/out-tsc/src/display/Button.js +2 -2
  8. package/out-tsc/src/display/Button.js.map +1 -1
  9. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  10. package/out-tsc/src/flow/CanvasMenu.js +24 -1
  11. package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
  12. package/out-tsc/src/flow/CanvasNode.js +7 -2
  13. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  14. package/out-tsc/src/flow/Editor.js +665 -67
  15. package/out-tsc/src/flow/Editor.js.map +1 -1
  16. package/out-tsc/src/flow/NodeEditor.js +8 -5
  17. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  18. package/out-tsc/src/flow/Plumber.js +40 -28
  19. package/out-tsc/src/flow/Plumber.js.map +1 -1
  20. package/out-tsc/src/flow/actions/send_msg.js +2 -1
  21. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  22. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
  23. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  24. package/out-tsc/src/flow/reflow.js +393 -0
  25. package/out-tsc/src/flow/reflow.js.map +1 -0
  26. package/out-tsc/src/flow/types.js.map +1 -1
  27. package/out-tsc/src/flow/utils.js +18 -3
  28. package/out-tsc/src/flow/utils.js.map +1 -1
  29. package/out-tsc/src/form/Compose.js +5 -0
  30. package/out-tsc/src/form/Compose.js.map +1 -1
  31. package/out-tsc/src/form/FieldRenderer.js +1 -3
  32. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  33. package/out-tsc/src/layout/Dialog.js +2 -0
  34. package/out-tsc/src/layout/Dialog.js.map +1 -1
  35. package/out-tsc/src/list/SortableList.js +39 -19
  36. package/out-tsc/src/list/SortableList.js.map +1 -1
  37. package/out-tsc/src/live/ContactChat.js +10 -1
  38. package/out-tsc/src/live/ContactChat.js.map +1 -1
  39. package/out-tsc/src/version.js +9 -0
  40. package/out-tsc/src/version.js.map +1 -0
  41. package/out-tsc/test/temba-canvas-menu.test.js +44 -0
  42. package/out-tsc/test/temba-canvas-menu.test.js.map +1 -1
  43. package/out-tsc/test/temba-contact-chat.test.js +12 -0
  44. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  45. package/out-tsc/test/temba-flow-collision.test.js +25 -0
  46. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  47. package/out-tsc/test/temba-flow-editor-zoom.test.js +491 -0
  48. package/out-tsc/test/temba-flow-editor-zoom.test.js.map +1 -0
  49. package/out-tsc/test/temba-flow-editor.test.js +164 -1
  50. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  51. package/out-tsc/test/temba-flow-node-drag.test.js +123 -0
  52. package/out-tsc/test/temba-flow-node-drag.test.js.map +1 -1
  53. package/out-tsc/test/temba-flow-plumber.test.js +31 -0
  54. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  55. package/out-tsc/test/temba-flow-reflow.test.js +472 -0
  56. package/out-tsc/test/temba-flow-reflow.test.js.map +1 -0
  57. package/out-tsc/test/temba-sortable-list.test.js +93 -0
  58. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  59. package/package.json +1 -1
  60. package/rollup.components.mjs +7 -1
  61. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  62. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  63. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  64. package/screenshots/truth/actions/add_contact_urn/editor/expression-facebook.png +0 -0
  65. package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
  66. package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
  67. package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
  68. package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
  69. package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
  70. package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
  71. package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
  72. package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
  73. package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
  74. package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
  75. package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
  76. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  77. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  78. package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
  79. package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
  80. package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
  81. package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
  82. package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
  83. package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
  84. package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
  85. package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
  86. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  87. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  88. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  89. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  90. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  91. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  92. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  93. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  94. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  95. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  96. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  97. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  98. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  99. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  100. package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
  101. package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
  102. package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
  103. package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
  104. package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
  105. package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
  106. package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
  107. package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
  108. package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
  109. package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
  110. package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
  111. package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
  112. package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
  113. package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
  114. package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
  115. package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
  116. package/screenshots/truth/actions/start_session/editor/many-recipients.png +0 -0
  117. package/screenshots/truth/list/fields-dragging.png +0 -0
  118. package/screenshots/truth/list/sortable-dragging.png +0 -0
  119. package/screenshots/truth/modax/simple.png +0 -0
  120. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  121. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  122. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  123. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  124. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  125. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  126. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  127. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  128. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  129. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  130. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  131. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  132. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  133. package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
  134. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  135. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  136. package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
  137. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  138. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  139. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  140. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  141. package/src/Icons.ts +3 -1
  142. package/src/display/Button.ts +2 -2
  143. package/src/display/FloatingTab.ts +1 -1
  144. package/src/flow/CanvasMenu.ts +28 -3
  145. package/src/flow/CanvasNode.ts +7 -2
  146. package/src/flow/Editor.ts +769 -76
  147. package/src/flow/NodeEditor.ts +8 -4
  148. package/src/flow/Plumber.ts +65 -35
  149. package/src/flow/actions/send_msg.ts +2 -1
  150. package/src/flow/nodes/wait_for_response.ts +1 -1
  151. package/src/flow/reflow.ts +534 -0
  152. package/src/flow/types.ts +1 -0
  153. package/src/flow/utils.ts +19 -3
  154. package/src/form/Compose.ts +5 -0
  155. package/src/form/FieldRenderer.ts +1 -3
  156. package/src/layout/Dialog.ts +2 -0
  157. package/src/list/SortableList.ts +40 -19
  158. package/src/live/ContactChat.ts +10 -1
  159. package/src/store/flow-definition.d.ts +1 -0
  160. package/src/version.ts +10 -0
  161. package/static/svg/index.svg +1 -1
  162. package/static/svg/work/traced/expand-06.svg +1 -0
  163. package/static/svg/work/used/expand-06.svg +3 -0
  164. package/test/temba-canvas-menu.test.ts +55 -0
  165. package/test/temba-contact-chat.test.ts +17 -0
  166. package/test/temba-flow-collision.test.ts +31 -0
  167. package/test/temba-flow-editor-zoom.test.ts +583 -0
  168. package/test/temba-flow-editor.test.ts +211 -1
  169. package/test/temba-flow-node-drag.test.ts +171 -0
  170. package/test/temba-flow-plumber.test.ts +38 -0
  171. package/test/temba-flow-reflow.test.ts +703 -0
  172. package/test/temba-sortable-list.test.ts +120 -0
  173. package/web-dev-server.config.mjs +5 -1
  174. package/web-test-runner.config.mjs +4 -1
  175. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  176. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  177. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  178. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  179. package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
  180. package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
  181. package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
  182. package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
  183. package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
  184. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  185. package/screenshots/truth/compose/attachments-with-failures.png +0 -0
  186. package/screenshots/truth/compose/attachments-with-files-and-failures.png +0 -0
  187. package/screenshots/truth/contacts/tickets-assignment.png +0 -0
  188. package/screenshots/truth/contacts/tickets.png +0 -0
  189. package/screenshots/truth/flow/editor-basic.png +0 -0
  190. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  191. package/screenshots/truth/formfield/no-errors.png +0 -0
  192. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  193. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  194. package/screenshots/truth/omnibox/selected.png +0 -0
  195. package/screenshots/truth/select/enabled-multi-selection.png +0 -0
  196. package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
  197. package/screenshots/truth/select/endpoint-initial-value.png +0 -0
  198. package/screenshots/truth/select/initial-value.png +0 -0
  199. package/screenshots/truth/select/multi-reorder-final.png +0 -0
  200. package/screenshots/truth/select/multi-reorder-initial.png +0 -0
  201. package/screenshots/truth/select/selected-multi-test.png +0 -0
  202. package/screenshots/truth/select/value-initial.png +0 -0
  203. package/screenshots/truth/wait-for-response/rules-editor.png +0 -0
  204. package/screenshots/truth/wait-for-response/timeout-editor-unchecked.png +0 -0
  205. package/screenshots/truth/wait-for-response/timeout-editor.png +0 -0
  206. package/screenshots/truth/webchat/connecting-state.png +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ContactChat.js","sourceRoot":"","sources":["../../../src/live/ContactChat.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport {\n Contact,\n CustomEventType,\n NamedUser,\n Ticket,\n User\n} from '../interfaces';\nimport {\n fetchResults,\n generateUUIDv7,\n getUrl,\n postJSON,\n postUrl,\n WebResponse\n} from '../utils';\nimport { ContactStoreElement } from './ContactStoreElement';\nimport { Compose, ComposeValue } from '../form/Compose';\nimport { ContactHistoryPage } from '../events';\nimport { Chat, MessageType, ContactEvent } from '../display/Chat';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\nimport { UserSelect } from '../form/select/UserSelect';\nimport { Select } from '../form/select/Select';\nimport {\n renderEvent,\n renderTicketAction,\n renderTicketAssigneeChanged\n} from '../events/eventRenderers';\n\n/*\nexport const SCROLL_THRESHOLD = 100;\nexport const SIMULATED_WEB_SLOWNESS = 0;\nexport const MAX_CHAT_REFRESH = 10000;\nexport const MIN_CHAT_REFRESH = 500;\nexport const BODY_SNIPPET_LENGTH = 250;\n*/\n\n// re-export for backwards compatibility\nexport { renderTicketAction, renderTicketAssigneeChanged };\n\nexport class ContactChat extends ContactStoreElement {\n public static get styles() {\n return css`\n :host {\n flex-grow: 1;\n display: flex;\n flex-direction: row;\n min-height: 0;\n --compose-shadow: none;\n --compose-border: none;\n --compose-padding: 3px;\n --compose-curvature: none;\n border-top: 1px inset rgba(0, 0, 0, 0.05);\n\n\n }\n\n .chat-wrapper {\n display: flex;\n flex-grow: 1;\n flex-direction: column;\n min-height: 0;\n background: #f9f9f9;\n }\n\n temba-contact-history {\n border-bottom: 1px solid #f6f6f6;\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n\n .compose {\n background: #fff;\n display: flex;\n flex-direction: column;\n --textarea-min-height: 8em;\n --textarea-height: 0.5em;\n --widget-box-shadow-focused: none;\n --compose-curvature: 0px;\n overflow: hidden;\n }\n\n .closed-footer {\n padding: 1em;\n background: #f2f2f2;\n border-top: 3px solid #e1e1e1;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n a {\n color: var(--color-link-primary);\n }\n\n a:hover {\n text-decoration: underline;\n color: var(--color-link-primary-hover);\n }\n\n temba-button {\n margin: 0.1em 0.25em;\n }\n\n temba-completion {\n --widget-box-shadow: none;\n --color-widget-border: transparent;\n --widget-box-shadow-focused: none;\n --color-focus: transparent;\n --color-widget-bg-focused: transparent;\n }\n\n .border {\n }\n\n temba-compose {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n --temba-tabs-options-padding: 0.5em 0.5em 0 0.5em;\n --temba-tabs-border-left: none;\n --temba-tabs-border-right: none;\n --temba-tabs-border-bottom: none;\n }\n\n .error-gutter {\n display: flex;\n padding: 0.5em 1em;\n background: #f9f9f9;\n item-align: center;\n }\n\n .error-message {\n color: var(--color-error);\n padding-right: 1em;\n flex-grow: 1;\n align-self: center;\n }\n\n temba-chat {\n border-bottom: 1px solid #ddd;\n background: linear-gradient(0deg, #fff, #fff);\n --chat-border-in: 1px solid #eee;\n --color-chat-out: var(--color-message)\n );\n }\n\n .action-bar {\n }\n\n .in-flow {\n border-radius: 0.8em;\n align-items: center;\n background: #666;\n padding: 0.5em 1em;\n margin: 1em;\n margin-right: 2em;\n display: inline-flex;\n opacity: 0.9;\n }\n\n .in-flow:hover {\n opacity: 1;\n }\n\n .in-flow .flow-name {\n display: flex;\n color: #fff;\n }\n\n .in-flow a {\n font-weight: bold;\n color: #fff;\n }\n\n .in-flow .interrupt-button {\n margin-left: 1em;\n }\n\n .in-flow .interrupt {\n text-align: center;\n align-self: stretch;\n display: flex;\n align-items: center;\n cursor: pointer;\n justify-content: center;\n padding: 0.5em 1em;\n font-weight: bold;\n }\n\n .in-flow .interrupt:hover {\n background: rgba(var(--error-rgb), 0.92);\n }\n\n .in-flow temba-icon,\n .in-ticket temba-icon {\n margin-right: 0.5em;\n }\n\n .in-ticket-wrapper {\n }\n\n .in-ticket {\n box-shadow: none;\n padding: 0.5em 0.5em;\n text-align: center;\n align-items: center;\n border-bottom: 1px solid #ddd;\n display: flex;\n box-shadow: none;\n margin: 0em;\n background: rgba(0, 0, 0, 0.03);\n }\n\n temba-user {\n border: 1px solid #ddd;\n padding: 0.2em 0.5em;\n border-radius: var(--curvature);\n min-width: 10em;\n background: #fff;\n }\n\n temba-user:hover {\n border: 1px solid #ddd;\n background: #f9f9f9;\n }\n\n .assign-button {\n --button-mask: #ebebeb;\n color: #333;\n margin: 0.25em;\n }\n\n temba-user-select {\n width: 250px;\n }\n\n temba-button {\n --button-border: 1px solid #ddd;\n }\n `;\n }\n\n @property({ type: String, attribute: 'ticket' })\n ticketUUID: string;\n\n @property({ type: String })\n contactsEndpoint = '/api/v2/contacts.json';\n\n @property({ type: String })\n currentNote = '';\n\n @property({ type: Boolean })\n showDetails = true;\n\n @property({ type: Object })\n currentTicket: Ticket = null;\n\n @property({ type: Object })\n currentContact: Contact = null;\n\n @property({ type: String })\n agent = '';\n\n @property({ type: Boolean })\n blockFetching = false;\n\n @property({ type: Boolean })\n showInterrupt = false;\n\n @property({ type: Boolean })\n disableAssign = false;\n\n @property({ type: Boolean })\n disableReply = false;\n\n @property({ type: String })\n avatar = DEFAULT_AVATAR;\n\n @property({ type: String })\n set showMessageLogsAfter(value: string) {\n const oldValue = this._showMessageLogsAfter;\n this._showMessageLogsAfter = value ? new Date(value) : null;\n this.requestUpdate('showMessageLogsAfter', oldValue);\n }\n\n get showMessageLogsAfter(): Date {\n return this._showMessageLogsAfter;\n }\n\n private _showMessageLogsAfter: Date = null;\n\n @property({ type: String })\n errorMessage: string;\n\n // http promise to monitor for completeness\n public httpComplete: Promise<void>;\n private chat: Chat;\n\n ticket = null;\n beforeUUID: string = null; // for scrolling back through history\n afterUUID: string = null; // for polling new messages\n refreshId = null;\n polling = false;\n pollingInterval = 2000; // start at 2 seconds\n lastFetchTime: number = null;\n\n constructor() {\n super();\n }\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n }\n\n public connectedCallback() {\n super.connectedCallback();\n this.chat = this.shadowRoot.querySelector('temba-chat');\n }\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this.refreshId) {\n clearInterval(this.refreshId);\n }\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n // if we don't have an endpoint infer one\n if (\n changedProperties.has('data') ||\n changedProperties.has('currentContact')\n ) {\n // unschedule any previous refreshes\n if (this.refreshId) {\n clearTimeout(this.refreshId);\n this.refreshId = null;\n }\n\n this.currentContact = this.data;\n }\n\n if (changedProperties.has('currentContact') && this.currentContact) {\n this.chat = this.shadowRoot.querySelector('temba-chat');\n if (\n this.currentContact.uuid !==\n changedProperties.get('currentContact')?.uuid\n ) {\n this.reset();\n } else {\n setTimeout(() => this.checkForNewMessages(), 500);\n }\n this.fetchPreviousMessages();\n }\n }\n\n private reset() {\n if (this.chat) {\n this.chat.reset();\n }\n this.blockFetching = false;\n this.ticket = null;\n this.beforeUUID = null;\n this.afterUUID = null;\n this.refreshId = null;\n this.polling = false;\n this.pollingInterval = 2000;\n this.lastFetchTime = null;\n this.errorMessage = null;\n\n const compose = this.shadowRoot.querySelector('temba-compose') as Compose;\n if (compose) {\n compose.reset();\n }\n }\n\n private handleInterrupt() {\n this.fireCustomEvent(CustomEventType.Interrupt, {\n contact: this.currentContact\n });\n }\n\n private handleRetry() {\n const compose = this.shadowRoot.querySelector('temba-compose') as Compose;\n compose.triggerSend();\n }\n\n private handleSend(evt: CustomEvent) {\n this.errorMessage = null;\n const composeEle = evt.currentTarget as Compose;\n const compose = evt.detail.langValues['und'] as ComposeValue;\n\n const payload = {\n contact: this.currentContact.uuid\n };\n\n const text = compose.text;\n if (text && text.length > 0) {\n payload['text'] = text;\n }\n const attachments = compose.attachments;\n if (attachments && attachments.length > 0) {\n const attachment_uuids = attachments.map((attachment) => attachment.uuid);\n payload['attachments'] = attachment_uuids;\n }\n\n if (this.currentTicket) {\n payload['ticket'] = this.currentTicket.uuid;\n }\n\n const genericError = 'Send failed, please try again.';\n postJSON(`/contact/chat/${this.currentContact.uuid}/`, payload)\n .then((response) => {\n if (response.status < 400) {\n const event = response.json.event;\n event.created_on = new Date(event.created_on);\n this.chat.addMessages([event], null, true);\n // reset polling interval to 2 seconds after sending a message\n this.pollingInterval = 2000;\n this.checkForNewMessages();\n composeEle.reset();\n this.fireCustomEvent(CustomEventType.MessageSent, {\n msg: payload,\n response\n });\n } else {\n this.errorMessage = genericError;\n }\n })\n .catch(() => {\n this.errorMessage = genericError;\n });\n }\n\n private getEndpoint() {\n if (this.contact) {\n return `/contact/chat/${this.contact}/`;\n }\n return null;\n }\n\n private scheduleRefresh(hasNewEvents = false) {\n if (this.refreshId) {\n clearTimeout(this.refreshId);\n this.refreshId = null;\n }\n\n // reset to 2 seconds if we received new events\n if (hasNewEvents) {\n this.pollingInterval = 2000;\n } else {\n // increase interval by 1 second up to max of 15 seconds\n this.pollingInterval = Math.min(this.pollingInterval + 1000, 15000);\n }\n\n this.refreshId = setTimeout(() => {\n this.checkForNewMessages();\n }, this.pollingInterval);\n }\n\n public prerender(event: ContactEvent) {\n // use the unified renderEvent function with isSimulation = false\n const rendered = renderEvent(event, false);\n\n if (rendered) {\n event._rendered = {\n html: rendered,\n type: MessageType.Inline\n };\n }\n }\n\n private createMessages(page: ContactHistoryPage): ContactEvent[] {\n if (page.events) {\n const messages: ContactEvent[] = [];\n page.events.forEach((event) => {\n // track the UUID of the newest event for polling\n if (\n !this.afterUUID ||\n event.uuid.toLowerCase() > this.afterUUID.toLowerCase()\n ) {\n this.afterUUID = event.uuid;\n }\n\n // convert to dates\n event.created_on = new Date(event.created_on);\n\n if (\n event.type === 'msg_created' ||\n event.type === 'msg_received' ||\n event.type === 'ivr_created'\n ) {\n messages.push(event);\n } else {\n this.prerender(event);\n if (event._rendered) {\n messages.push(event);\n }\n }\n });\n\n // remove any messages we don't recognize\n return messages.filter((msg) => !!msg);\n }\n return [];\n }\n\n private checkForNewMessages() {\n // we are already working on it\n if (this.polling) {\n return;\n }\n\n const chat = this.chat;\n if (this.currentContact && this.afterUUID) {\n this.polling = true;\n this.lastFetchTime = Date.now();\n const endpoint = this.getEndpoint();\n if (!endpoint) {\n return;\n }\n\n const fetchContact = this.currentContact.uuid;\n\n fetchContactHistory(\n endpoint,\n this.currentTicket?.uuid,\n null,\n this.afterUUID\n ).then((page: ContactHistoryPage) => {\n const messages = this.createMessages(page);\n messages.reverse();\n if (fetchContact === this.currentContact.uuid) {\n const hasNewEvents = messages.length > 0;\n chat.addMessages(messages, null, true);\n this.polling = false;\n this.scheduleRefresh(hasNewEvents);\n } else {\n this.polling = false;\n }\n });\n }\n }\n\n private fetchPreviousMessages() {\n const chat = this.chat;\n const contactChat = this;\n if (!chat || chat.fetching || contactChat.blockFetching) {\n return;\n }\n\n chat.fetching = true;\n if (this.currentContact) {\n const endpoint = this.getEndpoint();\n if (!endpoint) {\n return;\n }\n\n // initialize anchor UUID if not set (first fetch)\n if (!this.beforeUUID && !this.afterUUID) {\n // generate a UUID v7 for current time as the anchor\n const anchorUUID = generateUUIDv7();\n this.beforeUUID = anchorUUID;\n this.afterUUID = anchorUUID;\n }\n\n fetchContactHistory(\n endpoint,\n this.currentTicket?.uuid,\n this.beforeUUID,\n null\n ).then((page: ContactHistoryPage) => {\n const messages = this.createMessages(page);\n messages.reverse();\n\n if (messages.length === 0) {\n contactChat.blockFetching = true;\n } else if (page.next) {\n // update beforeUUID for next fetch of older messages\n this.beforeUUID = page.next;\n } else {\n // no more history, mark end and show oldest event date\n contactChat.blockFetching = true;\n if (page.events && page.events.length > 0) {\n const oldestEvent = page.events[page.events.length - 1];\n chat.setEndOfHistory(new Date(oldestEvent.created_on));\n }\n }\n\n chat.addMessages(messages);\n this.scheduleRefresh();\n });\n }\n }\n\n private fetchComplete() {\n if (this.chat) {\n this.chat.fetching = false;\n }\n }\n\n private getTembaCompose(): TemplateResult {\n if (this.currentTicket) {\n if (this.currentContact && this.currentContact.status !== 'active') {\n //no chatbox for archived, blocked, or stopped contacts\n return null;\n } else {\n if (!this.currentTicket.closed_on) {\n // hide compose if agent can't reply to unassigned tickets\n if (\n this.disableReply &&\n (!this.currentTicket.assignee ||\n this.currentTicket.assignee.email !== this.agent)\n ) {\n return null;\n }\n //chatbox for active contacts with an open ticket\n return this.getCompose();\n } else {\n return null;\n }\n }\n }\n\n if (this.currentContact && this.currentContact.status !== 'active') {\n //no chatbox for archived, blocked, or stopped contacts\n return null;\n } else {\n //chatbox for active contacts\n return this.getCompose();\n }\n }\n\n private getCompose(): TemplateResult {\n return html`<div class=\"border\"></div>\n <div class=\"compose\">\n <temba-compose\n attachments\n counter\n autogrow\n shortcuts\n ?embeddedTabs=${!this.currentTicket}\n @temba-submitted=${this.handleSend.bind(this)}\n >\n </temba-compose>\n ${this.errorMessage\n ? html` <div class=\"error-gutter\">\n <div class=\"error-message\">${this.errorMessage}</div>\n <temba-button\n name=\"Retry\"\n @click=${this.handleRetry}\n ></temba-button>\n </div>`\n : null}\n </div>`;\n }\n\n private handleAssignmentChanged(evt: CustomEvent) {\n const users = evt.currentTarget as UserSelect;\n const assignee = users.values[0];\n\n this.assignTicket(assignee ? assignee.email : null);\n users.blur();\n }\n\n private handleTopicChanged(evt: CustomEvent) {\n const select = evt.target as Select<any>;\n const topic = select.values[0];\n\n if (this.currentTicket.topic.uuid !== topic.uuid) {\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [this.currentTicket.uuid],\n action: 'change_topic',\n topic: topic.uuid\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n }\n\n public assignTicket(email: string) {\n if (this.disableAssign) {\n return;\n }\n\n // if its already assigned to use, it's a noop\n if (\n (this.currentTicket.assignee &&\n this.currentTicket.assignee.email === email) ||\n (this.currentTicket.assignee === null && email === null)\n ) {\n return;\n }\n\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [this.currentTicket.uuid],\n action: 'assign',\n assignee: email\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n return true;\n }\n\n public refreshTicket() {\n if (this.currentTicket) {\n fetchResults(`/api/v2/tickets.json?uuid=${this.currentTicket.uuid}`).then(\n (values) => {\n if (values.length > 0) {\n this.fireCustomEvent(CustomEventType.TicketUpdated, {\n ticket: values[0],\n previous: this.currentTicket\n });\n this.currentTicket = values[0];\n }\n }\n );\n }\n }\n\n private handleReopen() {\n const uuid = this.currentTicket.uuid;\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [uuid],\n action: 'reopen'\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n\n private handleClose() {\n const uuid = this.currentTicket.uuid;\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [uuid],\n action: 'close'\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n\n public render(): TemplateResult {\n const inFlow = this.currentContact && this.currentContact.flow;\n\n const inTicket = this.currentTicket;\n const ticketClosed = this.currentTicket && this.currentTicket.closed_on;\n\n return html`<div class=\"chat-wrapper\">\n ${this.currentContact\n ? html`<temba-chat\n @temba-scroll-threshold=${this.fetchPreviousMessages}\n @temba-fetch-complete=${this.fetchComplete}\n avatar=${this.avatar}\n agent\n avatars\n ?hasFooter=${inFlow}\n .showMessageLogsAfter=${this.showMessageLogsAfter}\n >\n ${inFlow\n ? html`\n <div slot=\"footer\" style=\"text-align:center;\">\n <div class=\"in-flow\">\n <div class=\"flow-name\">\n <temba-icon name=\"flow\" size=\"1.2\"></temba-icon>\n <div>\n Currently in\n <a\n href=\"/flow/editor/${this.currentContact.flow\n .uuid}/\"\n >${this.currentContact.flow.name}</a\n >\n </div>\n </div>\n ${this.showInterrupt\n ? html`<temba-button\n class=\"interrupt-button\"\n destructive\n small\n @click=${this.handleInterrupt}\n name=\"Interrupt\"\n >\n </temba-button>`\n : null}\n </div>\n </div>\n `\n : null}\n <div slot=\"footer\"></div>\n </temba-chat>\n ${inTicket\n ? html`<div class=\"in-ticket-wrapper\">\n <div class=\"in-ticket\">\n <temba-user-select\n placeholder=\"Assign to..\"\n searchable\n searchOnFocus\n clearable\n .values=${this.currentTicket.assignee\n ? [this.currentTicket.assignee]\n : []}\n @change=${this.handleAssignmentChanged}\n ?disabled=${ticketClosed || this.disableAssign}\n ></temba-user-select>\n\n <temba-select\n style=\"margin:0 0.5em; flex-grow:1\"\n endpoint=\"/api/v2/topics.json\"\n searchable\n valuekey=\"uuid\"\n .values=${[this.currentTicket.topic]}\n @change=${this.handleTopicChanged}\n ?disabled=${ticketClosed}\n ></temba-select>\n\n ${this.currentTicket.closed_on\n ? html`\n <temba-button\n name=\"Reopen\"\n @click=${this.handleReopen}\n ></temba-button>\n `\n : html`\n <temba-button\n name=\"Close\"\n destructive\n @click=${this.handleClose}\n ></temba-button>\n `}\n </div>\n </div> `\n : null}\n ${this.getTembaCompose()}`\n : null}\n </div>`;\n }\n}\nexport const closeTicket = (uuid: string): Promise<WebResponse> => {\n const formData = new FormData();\n formData.append('status', 'C');\n return postUrl(`/ticket/update/${uuid}/?_format=json`, formData);\n};\nexport const fetchContact = (endpoint: string): Promise<Contact> => {\n return new Promise<Contact>((resolve, reject) => {\n fetchResults(endpoint).then((contacts: Contact[]) => {\n if (contacts && contacts.length === 1) {\n resolve(contacts[0]);\n } else {\n reject('No contact found');\n }\n });\n });\n};\nexport const fetchContactHistory = (\n endpoint: string,\n ticket: string = undefined,\n before: string = undefined,\n after: string = undefined\n): Promise<ContactHistoryPage> => {\n return new Promise<ContactHistoryPage>((resolve) => {\n const controller = new AbortController();\n pendingRequests.push(controller);\n\n let url = endpoint;\n const params = [];\n\n if (before) {\n params.push(`before=${before}`);\n }\n\n if (after) {\n params.push(`after=${after}`);\n }\n\n if (ticket) {\n params.push(`ticket=${ticket}`);\n }\n\n if (params.length > 0) {\n url += (url.includes('?') ? '&' : '?') + params.join('&');\n }\n\n getUrl(url, controller)\n .then((response: WebResponse) => {\n // on success, remove our abort controller\n pendingRequests = pendingRequests.filter(\n (controller: AbortController) => {\n return response.controller === controller;\n }\n );\n\n resolve(response.json as ContactHistoryPage);\n })\n .catch(() => {\n // canceled\n });\n });\n};\nexport const getDisplayName = (user: User) => {\n if (!user) {\n return 'Somebody';\n }\n\n if ((user as NamedUser).name) {\n return (user as NamedUser).name;\n }\n\n if (user.first_name && user.last_name) {\n return `${user.first_name} ${user.last_name}`;\n }\n\n if (user.first_name) {\n return user.first_name;\n }\n\n return user.email;\n};\nexport let pendingRequests: AbortController[] = [];\n"]}
1
+ {"version":3,"file":"ContactChat.js","sourceRoot":"","sources":["../../../src/live/ContactChat.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-this-alias */\nimport { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport {\n Contact,\n CustomEventType,\n NamedUser,\n Ticket,\n User\n} from '../interfaces';\nimport {\n fetchResults,\n generateUUIDv7,\n getUrl,\n postJSON,\n postUrl,\n WebResponse\n} from '../utils';\nimport { ContactStoreElement } from './ContactStoreElement';\nimport { Compose, ComposeValue } from '../form/Compose';\nimport { ContactHistoryPage } from '../events';\nimport { Chat, MessageType, ContactEvent } from '../display/Chat';\nimport { DEFAULT_AVATAR } from '../webchat/assets';\nimport { UserSelect } from '../form/select/UserSelect';\nimport { Select } from '../form/select/Select';\nimport {\n renderEvent,\n renderTicketAction,\n renderTicketAssigneeChanged\n} from '../events/eventRenderers';\n\n/*\nexport const SCROLL_THRESHOLD = 100;\nexport const SIMULATED_WEB_SLOWNESS = 0;\nexport const MAX_CHAT_REFRESH = 10000;\nexport const MIN_CHAT_REFRESH = 500;\nexport const BODY_SNIPPET_LENGTH = 250;\n*/\n\n// re-export for backwards compatibility\nexport { renderTicketAction, renderTicketAssigneeChanged };\n\nexport class ContactChat extends ContactStoreElement {\n public static get styles() {\n return css`\n :host {\n flex-grow: 1;\n display: flex;\n flex-direction: row;\n min-height: 0;\n --compose-shadow: none;\n --compose-border: none;\n --compose-padding: 3px;\n --compose-curvature: none;\n border-top: 1px inset rgba(0, 0, 0, 0.05);\n\n\n }\n\n .chat-wrapper {\n display: flex;\n flex-grow: 1;\n flex-direction: column;\n min-height: 0;\n background: #f9f9f9;\n }\n\n temba-contact-history {\n border-bottom: 1px solid #f6f6f6;\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n\n .compose {\n background: #fff;\n display: flex;\n flex-direction: column;\n --textarea-min-height: 8em;\n --textarea-height: 0.5em;\n --widget-box-shadow-focused: none;\n --compose-curvature: 0px;\n overflow: hidden;\n }\n\n .closed-footer {\n padding: 1em;\n background: #f2f2f2;\n border-top: 3px solid #e1e1e1;\n display: flex;\n flex-direction: column;\n align-items: center;\n }\n\n a {\n color: var(--color-link-primary);\n }\n\n a:hover {\n text-decoration: underline;\n color: var(--color-link-primary-hover);\n }\n\n temba-button {\n margin: 0.1em 0.25em;\n }\n\n temba-completion {\n --widget-box-shadow: none;\n --color-widget-border: transparent;\n --widget-box-shadow-focused: none;\n --color-focus: transparent;\n --color-widget-bg-focused: transparent;\n }\n\n .border {\n }\n\n temba-compose {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n --temba-tabs-options-padding: 0.5em 0.5em 0 0.5em;\n --temba-tabs-border-left: none;\n --temba-tabs-border-right: none;\n --temba-tabs-border-bottom: none;\n }\n\n .error-gutter {\n display: flex;\n padding: 0.5em 1em;\n background: #f9f9f9;\n item-align: center;\n }\n\n .error-message {\n color: var(--color-error);\n padding-right: 1em;\n flex-grow: 1;\n align-self: center;\n }\n\n temba-chat {\n border-bottom: 1px solid #ddd;\n background: linear-gradient(0deg, #fff, #fff);\n --chat-border-in: 1px solid #eee;\n --color-chat-out: var(--color-message)\n );\n }\n\n .action-bar {\n }\n\n .in-flow {\n border-radius: 0.8em;\n align-items: center;\n background: #666;\n padding: 0.5em 1em;\n margin: 1em;\n margin-right: 2em;\n display: inline-flex;\n opacity: 0.9;\n }\n\n .flow-footer {\n text-align: center;\n pointer-events: none;\n }\n\n .flow-footer .in-flow {\n pointer-events: auto;\n }\n\n .in-flow:hover {\n opacity: 1;\n }\n\n .in-flow .flow-name {\n display: flex;\n color: #fff;\n }\n\n .in-flow a {\n font-weight: bold;\n color: #fff;\n }\n\n .in-flow .interrupt-button {\n margin-left: 1em;\n }\n\n .in-flow .interrupt {\n text-align: center;\n align-self: stretch;\n display: flex;\n align-items: center;\n cursor: pointer;\n justify-content: center;\n padding: 0.5em 1em;\n font-weight: bold;\n }\n\n .in-flow .interrupt:hover {\n background: rgba(var(--error-rgb), 0.92);\n }\n\n .in-flow temba-icon,\n .in-ticket temba-icon {\n margin-right: 0.5em;\n }\n\n .in-ticket-wrapper {\n }\n\n .in-ticket {\n box-shadow: none;\n padding: 0.5em 0.5em;\n text-align: center;\n align-items: center;\n border-bottom: 1px solid #ddd;\n display: flex;\n box-shadow: none;\n margin: 0em;\n background: rgba(0, 0, 0, 0.03);\n }\n\n temba-user {\n border: 1px solid #ddd;\n padding: 0.2em 0.5em;\n border-radius: var(--curvature);\n min-width: 10em;\n background: #fff;\n }\n\n temba-user:hover {\n border: 1px solid #ddd;\n background: #f9f9f9;\n }\n\n .assign-button {\n --button-mask: #ebebeb;\n color: #333;\n margin: 0.25em;\n }\n\n temba-user-select {\n width: 250px;\n }\n\n temba-button {\n --button-border: 1px solid #ddd;\n }\n `;\n }\n\n @property({ type: String, attribute: 'ticket' })\n ticketUUID: string;\n\n @property({ type: String })\n contactsEndpoint = '/api/v2/contacts.json';\n\n @property({ type: String })\n currentNote = '';\n\n @property({ type: Boolean })\n showDetails = true;\n\n @property({ type: Object })\n currentTicket: Ticket = null;\n\n @property({ type: Object })\n currentContact: Contact = null;\n\n @property({ type: String })\n agent = '';\n\n @property({ type: Boolean })\n blockFetching = false;\n\n @property({ type: Boolean })\n showInterrupt = false;\n\n @property({ type: Boolean })\n disableAssign = false;\n\n @property({ type: Boolean })\n disableReply = false;\n\n @property({ type: String })\n avatar = DEFAULT_AVATAR;\n\n @property({ type: String })\n set showMessageLogsAfter(value: string) {\n const oldValue = this._showMessageLogsAfter;\n this._showMessageLogsAfter = value ? new Date(value) : null;\n this.requestUpdate('showMessageLogsAfter', oldValue);\n }\n\n get showMessageLogsAfter(): Date {\n return this._showMessageLogsAfter;\n }\n\n private _showMessageLogsAfter: Date = null;\n\n @property({ type: String })\n errorMessage: string;\n\n // http promise to monitor for completeness\n public httpComplete: Promise<void>;\n private chat: Chat;\n\n ticket = null;\n beforeUUID: string = null; // for scrolling back through history\n afterUUID: string = null; // for polling new messages\n refreshId = null;\n polling = false;\n pollingInterval = 2000; // start at 2 seconds\n lastFetchTime: number = null;\n\n constructor() {\n super();\n }\n\n public firstUpdated(\n changed: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changed);\n }\n\n public connectedCallback() {\n super.connectedCallback();\n this.chat = this.shadowRoot.querySelector('temba-chat');\n }\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n if (this.refreshId) {\n clearInterval(this.refreshId);\n }\n }\n\n public updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n\n // if we don't have an endpoint infer one\n if (\n changedProperties.has('data') ||\n changedProperties.has('currentContact')\n ) {\n // unschedule any previous refreshes\n if (this.refreshId) {\n clearTimeout(this.refreshId);\n this.refreshId = null;\n }\n\n this.currentContact = this.data;\n }\n\n if (changedProperties.has('currentContact') && this.currentContact) {\n this.chat = this.shadowRoot.querySelector('temba-chat');\n if (\n this.currentContact.uuid !==\n changedProperties.get('currentContact')?.uuid\n ) {\n this.reset();\n } else {\n setTimeout(() => this.checkForNewMessages(), 500);\n }\n this.fetchPreviousMessages();\n }\n }\n\n private reset() {\n if (this.chat) {\n this.chat.reset();\n }\n this.blockFetching = false;\n this.ticket = null;\n this.beforeUUID = null;\n this.afterUUID = null;\n this.refreshId = null;\n this.polling = false;\n this.pollingInterval = 2000;\n this.lastFetchTime = null;\n this.errorMessage = null;\n\n const compose = this.shadowRoot.querySelector('temba-compose') as Compose;\n if (compose) {\n compose.reset();\n }\n }\n\n private handleInterrupt() {\n this.fireCustomEvent(CustomEventType.Interrupt, {\n contact: this.currentContact\n });\n }\n\n private handleRetry() {\n const compose = this.shadowRoot.querySelector('temba-compose') as Compose;\n compose.triggerSend();\n }\n\n private handleSend(evt: CustomEvent) {\n this.errorMessage = null;\n const composeEle = evt.currentTarget as Compose;\n const compose = evt.detail.langValues['und'] as ComposeValue;\n\n const payload = {\n contact: this.currentContact.uuid\n };\n\n const text = compose.text;\n if (text && text.length > 0) {\n payload['text'] = text;\n }\n const attachments = compose.attachments;\n if (attachments && attachments.length > 0) {\n const attachment_uuids = attachments.map((attachment) => attachment.uuid);\n payload['attachments'] = attachment_uuids;\n }\n\n if (this.currentTicket) {\n payload['ticket'] = this.currentTicket.uuid;\n }\n\n const genericError = 'Send failed, please try again.';\n postJSON(`/contact/chat/${this.currentContact.uuid}/`, payload)\n .then((response) => {\n if (response.status < 400) {\n const event = response.json.event;\n event.created_on = new Date(event.created_on);\n this.chat.addMessages([event], null, true);\n // reset polling interval to 2 seconds after sending a message\n this.pollingInterval = 2000;\n this.checkForNewMessages();\n composeEle.reset();\n this.fireCustomEvent(CustomEventType.MessageSent, {\n msg: payload,\n response\n });\n } else {\n this.errorMessage = genericError;\n }\n })\n .catch(() => {\n this.errorMessage = genericError;\n });\n }\n\n private getEndpoint() {\n if (this.contact) {\n return `/contact/chat/${this.contact}/`;\n }\n return null;\n }\n\n private scheduleRefresh(hasNewEvents = false) {\n if (this.refreshId) {\n clearTimeout(this.refreshId);\n this.refreshId = null;\n }\n\n // reset to 2 seconds if we received new events\n if (hasNewEvents) {\n this.pollingInterval = 2000;\n } else {\n // increase interval by 1 second up to max of 15 seconds\n this.pollingInterval = Math.min(this.pollingInterval + 1000, 15000);\n }\n\n this.refreshId = setTimeout(() => {\n this.checkForNewMessages();\n }, this.pollingInterval);\n }\n\n public prerender(event: ContactEvent) {\n // use the unified renderEvent function with isSimulation = false\n const rendered = renderEvent(event, false);\n\n if (rendered) {\n event._rendered = {\n html: rendered,\n type: MessageType.Inline\n };\n }\n }\n\n private createMessages(page: ContactHistoryPage): ContactEvent[] {\n if (page.events) {\n const messages: ContactEvent[] = [];\n page.events.forEach((event) => {\n // track the UUID of the newest event for polling\n if (\n !this.afterUUID ||\n event.uuid.toLowerCase() > this.afterUUID.toLowerCase()\n ) {\n this.afterUUID = event.uuid;\n }\n\n // convert to dates\n event.created_on = new Date(event.created_on);\n\n if (\n event.type === 'msg_created' ||\n event.type === 'msg_received' ||\n event.type === 'ivr_created'\n ) {\n messages.push(event);\n } else {\n this.prerender(event);\n if (event._rendered) {\n messages.push(event);\n }\n }\n });\n\n // remove any messages we don't recognize\n return messages.filter((msg) => !!msg);\n }\n return [];\n }\n\n private checkForNewMessages() {\n // we are already working on it\n if (this.polling) {\n return;\n }\n\n const chat = this.chat;\n if (this.currentContact && this.afterUUID) {\n this.polling = true;\n this.lastFetchTime = Date.now();\n const endpoint = this.getEndpoint();\n if (!endpoint) {\n return;\n }\n\n const fetchContact = this.currentContact.uuid;\n\n fetchContactHistory(\n endpoint,\n this.currentTicket?.uuid,\n null,\n this.afterUUID\n ).then((page: ContactHistoryPage) => {\n const messages = this.createMessages(page);\n messages.reverse();\n if (fetchContact === this.currentContact.uuid) {\n const hasNewEvents = messages.length > 0;\n chat.addMessages(messages, null, true);\n this.polling = false;\n this.scheduleRefresh(hasNewEvents);\n } else {\n this.polling = false;\n }\n });\n }\n }\n\n private fetchPreviousMessages() {\n const chat = this.chat;\n const contactChat = this;\n if (!chat || chat.fetching || contactChat.blockFetching) {\n return;\n }\n\n chat.fetching = true;\n if (this.currentContact) {\n const endpoint = this.getEndpoint();\n if (!endpoint) {\n return;\n }\n\n // initialize anchor UUID if not set (first fetch)\n if (!this.beforeUUID && !this.afterUUID) {\n // generate a UUID v7 for current time as the anchor\n const anchorUUID = generateUUIDv7();\n this.beforeUUID = anchorUUID;\n this.afterUUID = anchorUUID;\n }\n\n fetchContactHistory(\n endpoint,\n this.currentTicket?.uuid,\n this.beforeUUID,\n null\n ).then((page: ContactHistoryPage) => {\n const messages = this.createMessages(page);\n messages.reverse();\n\n if (messages.length === 0) {\n contactChat.blockFetching = true;\n } else if (page.next) {\n // update beforeUUID for next fetch of older messages\n this.beforeUUID = page.next;\n } else {\n // no more history, mark end and show oldest event date\n contactChat.blockFetching = true;\n if (page.events && page.events.length > 0) {\n const oldestEvent = page.events[page.events.length - 1];\n chat.setEndOfHistory(new Date(oldestEvent.created_on));\n }\n }\n\n chat.addMessages(messages);\n this.scheduleRefresh();\n });\n }\n }\n\n private fetchComplete() {\n if (this.chat) {\n this.chat.fetching = false;\n }\n }\n\n private getTembaCompose(): TemplateResult {\n if (this.currentTicket) {\n if (this.currentContact && this.currentContact.status !== 'active') {\n //no chatbox for archived, blocked, or stopped contacts\n return null;\n } else {\n if (!this.currentTicket.closed_on) {\n // hide compose if agent can't reply to unassigned tickets\n if (\n this.disableReply &&\n (!this.currentTicket.assignee ||\n this.currentTicket.assignee.email !== this.agent)\n ) {\n return null;\n }\n //chatbox for active contacts with an open ticket\n return this.getCompose();\n } else {\n return null;\n }\n }\n }\n\n if (this.currentContact && this.currentContact.status !== 'active') {\n //no chatbox for archived, blocked, or stopped contacts\n return null;\n } else {\n //chatbox for active contacts\n return this.getCompose();\n }\n }\n\n private getCompose(): TemplateResult {\n return html`<div class=\"border\"></div>\n <div class=\"compose\">\n <temba-compose\n attachments\n counter\n autogrow\n shortcuts\n ?embeddedTabs=${!this.currentTicket}\n @temba-submitted=${this.handleSend.bind(this)}\n >\n </temba-compose>\n ${this.errorMessage\n ? html` <div class=\"error-gutter\">\n <div class=\"error-message\">${this.errorMessage}</div>\n <temba-button\n name=\"Retry\"\n @click=${this.handleRetry}\n ></temba-button>\n </div>`\n : null}\n </div>`;\n }\n\n private handleAssignmentChanged(evt: CustomEvent) {\n const users = evt.currentTarget as UserSelect;\n const assignee = users.values[0];\n\n this.assignTicket(assignee ? assignee.email : null);\n users.blur();\n }\n\n private handleTopicChanged(evt: CustomEvent) {\n const select = evt.target as Select<any>;\n const topic = select.values[0];\n\n if (this.currentTicket.topic.uuid !== topic.uuid) {\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [this.currentTicket.uuid],\n action: 'change_topic',\n topic: topic.uuid\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n }\n\n public assignTicket(email: string) {\n if (this.disableAssign) {\n return;\n }\n\n // if its already assigned to use, it's a noop\n if (\n (this.currentTicket.assignee &&\n this.currentTicket.assignee.email === email) ||\n (this.currentTicket.assignee === null && email === null)\n ) {\n return;\n }\n\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [this.currentTicket.uuid],\n action: 'assign',\n assignee: email\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n return true;\n }\n\n public refreshTicket() {\n if (this.currentTicket) {\n fetchResults(`/api/v2/tickets.json?uuid=${this.currentTicket.uuid}`).then(\n (values) => {\n if (values.length > 0) {\n this.fireCustomEvent(CustomEventType.TicketUpdated, {\n ticket: values[0],\n previous: this.currentTicket\n });\n this.currentTicket = values[0];\n }\n }\n );\n }\n }\n\n private handleReopen() {\n const uuid = this.currentTicket.uuid;\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [uuid],\n action: 'reopen'\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n\n private handleClose() {\n const uuid = this.currentTicket.uuid;\n postJSON(`/api/v2/ticket_actions.json`, {\n tickets: [uuid],\n action: 'close'\n })\n .then(() => {\n this.refreshTicket();\n })\n .catch((response: any) => {\n console.error(response);\n });\n }\n\n public render(): TemplateResult {\n const inFlow = this.currentContact && this.currentContact.flow;\n\n const inTicket = this.currentTicket;\n const ticketClosed = this.currentTicket && this.currentTicket.closed_on;\n\n return html`<div class=\"chat-wrapper\">\n ${this.currentContact\n ? html`<temba-chat\n @temba-scroll-threshold=${this.fetchPreviousMessages}\n @temba-fetch-complete=${this.fetchComplete}\n avatar=${this.avatar}\n agent\n avatars\n ?hasFooter=${inFlow}\n .showMessageLogsAfter=${this.showMessageLogsAfter}\n >\n ${inFlow\n ? html`\n <div slot=\"footer\" class=\"flow-footer\">\n <div class=\"in-flow\">\n <div class=\"flow-name\">\n <temba-icon name=\"flow\" size=\"1.2\"></temba-icon>\n <div>\n Currently in\n <a\n href=\"/flow/editor/${this.currentContact.flow\n .uuid}/\"\n >${this.currentContact.flow.name}</a\n >\n </div>\n </div>\n ${this.showInterrupt\n ? html`<temba-button\n class=\"interrupt-button\"\n destructive\n small\n @click=${this.handleInterrupt}\n name=\"Interrupt\"\n >\n </temba-button>`\n : null}\n </div>\n </div>\n `\n : null}\n <div slot=\"footer\"></div>\n </temba-chat>\n ${inTicket\n ? html`<div class=\"in-ticket-wrapper\">\n <div class=\"in-ticket\">\n <temba-user-select\n placeholder=\"Assign to..\"\n searchable\n searchOnFocus\n clearable\n .values=${this.currentTicket.assignee\n ? [this.currentTicket.assignee]\n : []}\n @change=${this.handleAssignmentChanged}\n ?disabled=${ticketClosed || this.disableAssign}\n ></temba-user-select>\n\n <temba-select\n style=\"margin:0 0.5em; flex-grow:1\"\n endpoint=\"/api/v2/topics.json\"\n searchable\n valuekey=\"uuid\"\n .values=${[this.currentTicket.topic]}\n @change=${this.handleTopicChanged}\n ?disabled=${ticketClosed}\n ></temba-select>\n\n ${this.currentTicket.closed_on\n ? html`\n <temba-button\n name=\"Reopen\"\n @click=${this.handleReopen}\n ></temba-button>\n `\n : html`\n <temba-button\n name=\"Close\"\n destructive\n @click=${this.handleClose}\n ></temba-button>\n `}\n </div>\n </div> `\n : null}\n ${this.getTembaCompose()}`\n : null}\n </div>`;\n }\n}\nexport const closeTicket = (uuid: string): Promise<WebResponse> => {\n const formData = new FormData();\n formData.append('status', 'C');\n return postUrl(`/ticket/update/${uuid}/?_format=json`, formData);\n};\nexport const fetchContact = (endpoint: string): Promise<Contact> => {\n return new Promise<Contact>((resolve, reject) => {\n fetchResults(endpoint).then((contacts: Contact[]) => {\n if (contacts && contacts.length === 1) {\n resolve(contacts[0]);\n } else {\n reject('No contact found');\n }\n });\n });\n};\nexport const fetchContactHistory = (\n endpoint: string,\n ticket: string = undefined,\n before: string = undefined,\n after: string = undefined\n): Promise<ContactHistoryPage> => {\n return new Promise<ContactHistoryPage>((resolve) => {\n const controller = new AbortController();\n pendingRequests.push(controller);\n\n let url = endpoint;\n const params = [];\n\n if (before) {\n params.push(`before=${before}`);\n }\n\n if (after) {\n params.push(`after=${after}`);\n }\n\n if (ticket) {\n params.push(`ticket=${ticket}`);\n }\n\n if (params.length > 0) {\n url += (url.includes('?') ? '&' : '?') + params.join('&');\n }\n\n getUrl(url, controller)\n .then((response: WebResponse) => {\n // on success, remove our abort controller\n pendingRequests = pendingRequests.filter(\n (controller: AbortController) => {\n return response.controller === controller;\n }\n );\n\n resolve(response.json as ContactHistoryPage);\n })\n .catch(() => {\n // canceled\n });\n });\n};\nexport const getDisplayName = (user: User) => {\n if (!user) {\n return 'Somebody';\n }\n\n if ((user as NamedUser).name) {\n return (user as NamedUser).name;\n }\n\n if (user.first_name && user.last_name) {\n return `${user.first_name} ${user.last_name}`;\n }\n\n if (user.first_name) {\n return user.first_name;\n }\n\n return user.email;\n};\nexport let pendingRequests: AbortController[] = [];\n"]}
@@ -0,0 +1,9 @@
1
+ let _version = 'dev';
2
+ try {
3
+ _version = __TEMBA_COMPONENTS_VERSION__;
4
+ }
5
+ catch (_a) {
6
+ // not replaced by build tooling; keep default
7
+ }
8
+ export const TEMBA_COMPONENTS_VERSION = _version;
9
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAEA,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB,IAAI,CAAC;IACH,QAAQ,GAAG,4BAA4B,CAAC;AAC1C,CAAC;AAAC,WAAM,CAAC;IACP,8CAA8C;AAChD,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAQ,CAAC","sourcesContent":["declare const __TEMBA_COMPONENTS_VERSION__: string;\n\nlet _version = 'dev';\ntry {\n _version = __TEMBA_COMPONENTS_VERSION__;\n} catch {\n // not replaced by build tooling; keep default\n}\n\nexport const TEMBA_COMPONENTS_VERSION = _version;\n"]}
@@ -81,6 +81,50 @@ describe('temba-canvas-menu', () => {
81
81
  });
82
82
  expect(menu.open).to.be.false;
83
83
  });
84
+ it('shows reflow option when showReflow is true', async () => {
85
+ var _a;
86
+ const menu = await createCanvasMenu();
87
+ menu.show(100, 100, { x: 50, y: 50 }, true, true);
88
+ await menu.updateComplete;
89
+ const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
90
+ expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(4);
91
+ const titles = Array.from(menuItems || []).map((item) => { var _a; return (_a = item.querySelector('.menu-item-title')) === null || _a === void 0 ? void 0 : _a.textContent; });
92
+ expect(titles).to.deep.equal([
93
+ 'Add Action',
94
+ 'Add Split',
95
+ 'Add Sticky Note',
96
+ 'Reflow'
97
+ ]);
98
+ });
99
+ it('fires reflow selection event when reflow is clicked', async () => {
100
+ var _a;
101
+ const menu = await createCanvasMenu();
102
+ menu.show(100, 100, { x: 50, y: 50 }, true, true);
103
+ await menu.updateComplete;
104
+ let selectionDetail = null;
105
+ menu.addEventListener('temba-selection', (event) => {
106
+ selectionDetail = event.detail;
107
+ });
108
+ const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
109
+ const reflowItem = menuItems === null || menuItems === void 0 ? void 0 : menuItems[3];
110
+ reflowItem.click();
111
+ await menu.updateComplete;
112
+ expect(selectionDetail).to.deep.equal({
113
+ action: 'reflow',
114
+ position: { x: 50, y: 50 }
115
+ });
116
+ expect(menu.open).to.be.false;
117
+ });
118
+ it('hides reflow option by default', async () => {
119
+ var _a;
120
+ const menu = await createCanvasMenu();
121
+ menu.show(100, 100, { x: 50, y: 50 });
122
+ await menu.updateComplete;
123
+ const menuItems = (_a = menu.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.menu-item');
124
+ expect(menuItems === null || menuItems === void 0 ? void 0 : menuItems.length).to.equal(3);
125
+ const titles = Array.from(menuItems || []).map((item) => { var _a; return (_a = item.querySelector('.menu-item-title')) === null || _a === void 0 ? void 0 : _a.textContent; });
126
+ expect(titles).to.not.include('Reflow');
127
+ });
84
128
  it('adjusts position to stay within viewport bounds', async () => {
85
129
  var _a, _b;
86
130
  const menu = await createCanvasMenu();
@@ -1 +1 @@
1
- {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has three menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the third item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[2] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const actionItem = menuItems?.[0] as HTMLElement;\n actionItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}
1
+ {"version":3,"file":"temba-canvas-menu.test.js","sourceRoot":"","sources":["../../test/temba-canvas-menu.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { CanvasMenu } from '../src/flow/CanvasMenu';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-canvas-menu', () => {\n const createCanvasMenu = async () => {\n const component = (await getComponent(\n 'temba-canvas-menu',\n {},\n '',\n 250,\n 250\n )) as CanvasMenu;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const menu = await createCanvasMenu();\n assert.instanceOf(menu, CanvasMenu);\n expect(menu.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const menu = await createCanvasMenu();\n expect(menu.open).to.be.false;\n\n // verify no menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.be.null;\n });\n\n it('shows menu when opened', async () => {\n const menu = await createCanvasMenu();\n\n // open the menu\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n expect(menu.x).to.equal(100);\n expect(menu.y).to.equal(100);\n\n // verify menu is rendered\n const menuElement = menu.shadowRoot?.querySelector('.menu');\n expect(menuElement).to.not.be.null;\n\n await assertScreenshot('canvas-menu/open', getClip(menu));\n });\n\n it('has three menu items', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n // check menu item titles\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note'\n ]);\n });\n\n it('closes when close() is called', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n expect(menu.open).to.be.true;\n\n menu.close();\n await menu.updateComplete;\n\n expect(menu.open).to.be.false;\n });\n\n it('fires selection event when menu item is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on sticky note option (now the third item)\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const stickyItem = menuItems?.[2] as HTMLElement;\n stickyItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.deep.equal({\n action: 'sticky',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('shows reflow option when showReflow is true', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(4);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.deep.equal([\n 'Add Action',\n 'Add Split',\n 'Add Sticky Note',\n 'Reflow'\n ]);\n });\n\n it('fires reflow selection event when reflow is clicked', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 }, true, true);\n await menu.updateComplete;\n\n let selectionDetail = null;\n menu.addEventListener('temba-selection', (event: any) => {\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const reflowItem = menuItems?.[3] as HTMLElement;\n reflowItem.click();\n await menu.updateComplete;\n\n expect(selectionDetail).to.deep.equal({\n action: 'reflow',\n position: { x: 50, y: 50 }\n });\n expect(menu.open).to.be.false;\n });\n\n it('hides reflow option by default', async () => {\n const menu = await createCanvasMenu();\n menu.show(100, 100, { x: 50, y: 50 });\n await menu.updateComplete;\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n expect(menuItems?.length).to.equal(3);\n\n const titles = Array.from(menuItems || []).map(\n (item) => item.querySelector('.menu-item-title')?.textContent\n );\n expect(titles).to.not.include('Reflow');\n });\n\n it('adjusts position to stay within viewport bounds', async () => {\n const menu = await createCanvasMenu();\n\n // open menu at position that would go off screen\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const margin = 10; // matches the margin in CanvasMenu\n\n // position that would go off the right and bottom edges\n menu.show(viewportWidth - 50, viewportHeight - 50, {\n x: 100,\n y: 100\n });\n await menu.updateComplete;\n\n // wait for position adjustment\n await new Promise((resolve) => setTimeout(resolve, 100));\n await menu.updateComplete;\n\n const menuElement = menu.shadowRoot?.querySelector('.menu') as HTMLElement;\n expect(menuElement).to.not.be.null;\n\n const menuRect = menuElement.getBoundingClientRect();\n\n // verify menu stays within viewport with margin\n expect(menuRect.right).to.be.at.most(viewportWidth - margin);\n expect(menuRect.bottom).to.be.at.most(viewportHeight - margin);\n\n // verify click position is preserved (not adjusted)\n let selectionFired = false;\n let selectionDetail = null;\n\n menu.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n const menuItems = menu.shadowRoot?.querySelectorAll('.menu-item');\n const actionItem = menuItems?.[0] as HTMLElement;\n actionItem.click();\n await menu.updateComplete;\n\n expect(selectionFired).to.be.true;\n // click position should remain unchanged\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n });\n});\n"]}
@@ -70,6 +70,18 @@ describe('temba-contact-chat', () => {
70
70
  });
71
71
  await assertScreenshot('contacts/chat-for-stopped-contact', getClip(chat));
72
72
  });
73
+ it('keeps flow footer from blocking scrollbar drag interactions', async () => {
74
+ await loadStore();
75
+ const chat = await getContactChat({
76
+ contact: 'contact-dave-active'
77
+ });
78
+ const flowFooter = chat.shadowRoot.querySelector('.flow-footer');
79
+ const inFlow = flowFooter.querySelector('.in-flow');
80
+ expect(flowFooter).to.exist;
81
+ expect(inFlow).to.exist;
82
+ expect(getComputedStyle(flowFooter).pointerEvents).to.equal('none');
83
+ expect(getComputedStyle(inFlow).pointerEvents).to.equal('auto');
84
+ });
73
85
  it('sends text without attachments', async () => {
74
86
  // we are a StoreElement, so load a store first
75
87
  await loadStore();
@@ -1 +1 @@
1
- {"version":3,"file":"temba-contact-chat.test.js","sourceRoot":"","sources":["../../test/temba-contact-chat.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { SinonStub, useFakeTimers } from 'sinon';\nimport { Compose } from '../src/form/Compose';\nimport { ContactChat } from '../src/live/ContactChat';\nimport { Attachment, CustomEventType } from '../src/interfaces';\nimport {\n assertScreenshot,\n clearMockPosts,\n getClip,\n getComponent,\n getValidAttachments,\n getValidText,\n loadStore,\n mockAPI,\n mockGET,\n mockNow,\n mockPOST,\n updateComponent\n} from '../test/utils.test';\n\nimport { expect, oneEvent } from '@open-wc/testing';\n\nlet clock: any;\n\nconst TAG = 'temba-contact-chat';\nconst getContactChat = async (attrs: any = {}) => {\n attrs['endpoint'] = '/test-assets/contacts/';\n // add some sizes and styles to force our chat history to scroll\n const chat = (await getComponent(\n TAG,\n attrs,\n '',\n 500,\n 500,\n 'display:flex;flex-direction:column;flex-grow:1;min-height:0;'\n )) as ContactChat;\n\n // TODO: this should be waiting for an event instead\n await waitFor(100);\n await clock.tick(0);\n return chat;\n};\n\nconst getResponseSuccessFiles = (attachments: Attachment[]) => {\n const response_attachments = attachments.map((attachment) => {\n return { content_type: attachment.content_type, url: attachment.url };\n });\n return response_attachments;\n};\n\ndescribe('temba-contact-chat', () => {\n let mockedNow: SinonStub;\n // map requests for contact history to our static files\n // we'll just us the same historylist for everybody for now\n beforeEach(() => {\n mockedNow = mockNow('2021-03-31T00:31:00.000-00:00');\n clearMockPosts();\n mockGET(\n /\\/contact\\/chat\\/contact-.*/,\n '/test-assets/contacts/history.json'\n );\n\n mockGET(\n /\\/api\\/v2\\/users\\.json\\?email=admin1%40nyaruka\\.com/,\n '/test-assets/api/users/admin1.json'\n );\n\n mockAPI();\n clock = useFakeTimers();\n });\n\n afterEach(function () {\n clock.restore();\n mockedNow.restore();\n });\n\n // temporarily disabled as it's too flaky in CI\n xit('show history and show chatbox if contact is active', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active',\n showMessageLogsAfter: '2025-01-01T00:00:00.000Z'\n });\n\n await assertScreenshot('contacts/chat-for-active-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is archived', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-barack-archived',\n showMessageLogsAfter: '2025-01-01T00:00:00.000Z'\n });\n\n await assertScreenshot('contacts/chat-for-archived-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is blocked', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-michelle-blocked'\n });\n\n await assertScreenshot('contacts/chat-for-blocked-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is stopped', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-tim-stopped'\n });\n\n await assertScreenshot('contacts/chat-for-stopped-contact', getClip(chat));\n });\n\n it('sends text without attachments', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const text = getValidText();\n await updateComponent(compose, text);\n\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text: text,\n attachments: []\n }\n }\n };\n mockPOST(/contact\\/chat\\/contact-dave-active\\//, response_body);\n\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', text, true, true);\n expect(await listener).to.exist;\n\n await assertScreenshot('contacts/chat-sends-text-only', getClip(chat));\n });\n\n it('sends attachments without text', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const attachments = getValidAttachments();\n await updateComponent(compose, null, attachments);\n const response_attachments = getResponseSuccessFiles(attachments);\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text: '',\n attachments: response_attachments\n }\n }\n };\n const response_headers = {};\n const response_status = '200';\n mockPOST(\n /contact\\/chat\\/contact-dave-active\\//,\n response_body,\n response_headers,\n response_status\n );\n\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot(\n 'contacts/chat-sends-attachments-only',\n getClip(chat)\n );\n });\n\n it('sends text with attachments', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const text = getValidText();\n const attachments = getValidAttachments();\n await updateComponent(compose, text, attachments);\n const response_attachments = getResponseSuccessFiles(attachments);\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text,\n attachments: response_attachments\n }\n }\n };\n mockPOST(/contact\\/chat\\/contact-dave-active\\//, response_body);\n\n // press enter\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot(\n 'contacts/chat-sends-text-and-attachments',\n getClip(chat)\n );\n });\n\n it('shows failure message with retry', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n await updateComponent(compose, getValidText(), getValidAttachments());\n\n const response_body = {};\n const response_headers = {};\n const response_status = '500';\n mockPOST(\n /api\\/v2\\/messages\\.json/,\n response_body,\n response_headers,\n response_status\n );\n\n // press\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot('contacts/chat-failure', getClip(chat));\n });\n});\n"]}
1
+ {"version":3,"file":"temba-contact-chat.test.js","sourceRoot":"","sources":["../../test/temba-contact-chat.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { SinonStub, useFakeTimers } from 'sinon';\nimport { Compose } from '../src/form/Compose';\nimport { ContactChat } from '../src/live/ContactChat';\nimport { Attachment, CustomEventType } from '../src/interfaces';\nimport {\n assertScreenshot,\n clearMockPosts,\n getClip,\n getComponent,\n getValidAttachments,\n getValidText,\n loadStore,\n mockAPI,\n mockGET,\n mockNow,\n mockPOST,\n updateComponent\n} from '../test/utils.test';\n\nimport { expect, oneEvent } from '@open-wc/testing';\n\nlet clock: any;\n\nconst TAG = 'temba-contact-chat';\nconst getContactChat = async (attrs: any = {}) => {\n attrs['endpoint'] = '/test-assets/contacts/';\n // add some sizes and styles to force our chat history to scroll\n const chat = (await getComponent(\n TAG,\n attrs,\n '',\n 500,\n 500,\n 'display:flex;flex-direction:column;flex-grow:1;min-height:0;'\n )) as ContactChat;\n\n // TODO: this should be waiting for an event instead\n await waitFor(100);\n await clock.tick(0);\n return chat;\n};\n\nconst getResponseSuccessFiles = (attachments: Attachment[]) => {\n const response_attachments = attachments.map((attachment) => {\n return { content_type: attachment.content_type, url: attachment.url };\n });\n return response_attachments;\n};\n\ndescribe('temba-contact-chat', () => {\n let mockedNow: SinonStub;\n // map requests for contact history to our static files\n // we'll just us the same historylist for everybody for now\n beforeEach(() => {\n mockedNow = mockNow('2021-03-31T00:31:00.000-00:00');\n clearMockPosts();\n mockGET(\n /\\/contact\\/chat\\/contact-.*/,\n '/test-assets/contacts/history.json'\n );\n\n mockGET(\n /\\/api\\/v2\\/users\\.json\\?email=admin1%40nyaruka\\.com/,\n '/test-assets/api/users/admin1.json'\n );\n\n mockAPI();\n clock = useFakeTimers();\n });\n\n afterEach(function () {\n clock.restore();\n mockedNow.restore();\n });\n\n // temporarily disabled as it's too flaky in CI\n xit('show history and show chatbox if contact is active', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active',\n showMessageLogsAfter: '2025-01-01T00:00:00.000Z'\n });\n\n await assertScreenshot('contacts/chat-for-active-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is archived', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-barack-archived',\n showMessageLogsAfter: '2025-01-01T00:00:00.000Z'\n });\n\n await assertScreenshot('contacts/chat-for-archived-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is blocked', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-michelle-blocked'\n });\n\n await assertScreenshot('contacts/chat-for-blocked-contact', getClip(chat));\n });\n\n it('show history and hide chatbox if contact is stopped', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-tim-stopped'\n });\n\n await assertScreenshot('contacts/chat-for-stopped-contact', getClip(chat));\n });\n\n it('keeps flow footer from blocking scrollbar drag interactions', async () => {\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n\n const flowFooter = chat.shadowRoot.querySelector(\n '.flow-footer'\n ) as HTMLElement;\n const inFlow = flowFooter.querySelector('.in-flow') as HTMLElement;\n\n expect(flowFooter).to.exist;\n expect(inFlow).to.exist;\n expect(getComputedStyle(flowFooter).pointerEvents).to.equal('none');\n expect(getComputedStyle(inFlow).pointerEvents).to.equal('auto');\n });\n\n it('sends text without attachments', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const text = getValidText();\n await updateComponent(compose, text);\n\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text: text,\n attachments: []\n }\n }\n };\n mockPOST(/contact\\/chat\\/contact-dave-active\\//, response_body);\n\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', text, true, true);\n expect(await listener).to.exist;\n\n await assertScreenshot('contacts/chat-sends-text-only', getClip(chat));\n });\n\n it('sends attachments without text', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const attachments = getValidAttachments();\n await updateComponent(compose, null, attachments);\n const response_attachments = getResponseSuccessFiles(attachments);\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text: '',\n attachments: response_attachments\n }\n }\n };\n const response_headers = {};\n const response_status = '200';\n mockPOST(\n /contact\\/chat\\/contact-dave-active\\//,\n response_body,\n response_headers,\n response_status\n );\n\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot(\n 'contacts/chat-sends-attachments-only',\n getClip(chat)\n );\n });\n\n it('sends text with attachments', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n const text = getValidText();\n const attachments = getValidAttachments();\n await updateComponent(compose, text, attachments);\n const response_attachments = getResponseSuccessFiles(attachments);\n const response_body = {\n event: {\n uuid: 'msg-uuid',\n contact: { uuid: 'contact-dave-active', name: 'Dave Matthews' },\n msg: {\n text,\n attachments: response_attachments\n }\n }\n };\n mockPOST(/contact\\/chat\\/contact-dave-active\\//, response_body);\n\n // press enter\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot(\n 'contacts/chat-sends-text-and-attachments',\n getClip(chat)\n );\n });\n\n it('shows failure message with retry', async () => {\n // we are a StoreElement, so load a store first\n await loadStore();\n const chat: ContactChat = await getContactChat({\n contact: 'contact-dave-active'\n });\n const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;\n await updateComponent(compose, getValidText(), getValidAttachments());\n\n const response_body = {};\n const response_headers = {};\n const response_status = '500';\n mockPOST(\n /api\\/v2\\/messages\\.json/,\n response_body,\n response_headers,\n response_status\n );\n\n // press\n const listener = oneEvent(compose, CustomEventType.Submitted, false);\n await typeInto('temba-contact-chat:temba-compose', '', false, true);\n expect(await listener).to.exist;\n\n await assertScreenshot('contacts/chat-failure', getClip(chat));\n });\n});\n"]}
@@ -26,6 +26,31 @@ describe('Collision Detection Utilities', () => {
26
26
  expect(bounds.height).to.equal(150);
27
27
  document.body.removeChild(mockElement);
28
28
  });
29
+ it('uses layout-space dimensions unaffected by ancestor CSS transform', () => {
30
+ // Simulate zoom: ancestor has transform: scale(0.5)
31
+ const container = document.createElement('div');
32
+ container.style.transform = 'scale(0.5)';
33
+ container.style.transformOrigin = '0 0';
34
+ document.body.appendChild(container);
35
+ const mockElement = document.createElement('div');
36
+ mockElement.id = 'zoom-test-node';
37
+ mockElement.style.width = '200px';
38
+ mockElement.style.height = '150px';
39
+ container.appendChild(mockElement);
40
+ const position = { left: 100, top: 200 };
41
+ const bounds = getNodeBounds('zoom-test-node', position, mockElement);
42
+ // getNodeBounds uses offsetWidth/offsetHeight which are layout-space
43
+ expect(bounds).to.not.be.null;
44
+ expect(bounds.width).to.equal(200);
45
+ expect(bounds.height).to.equal(150);
46
+ expect(bounds.right).to.equal(300); // left + layout width
47
+ expect(bounds.bottom).to.equal(350); // top + layout height
48
+ // Verify that getBoundingClientRect WOULD return scaled values
49
+ const rect = mockElement.getBoundingClientRect();
50
+ expect(rect.width).to.equal(100); // 200 * 0.5 scale
51
+ expect(rect.height).to.equal(75); // 150 * 0.5 scale
52
+ container.remove();
53
+ });
29
54
  });
30
55
  describe('nodesOverlap', () => {
31
56
  it('detects overlapping nodes horizontally and vertically', () => {