@memberjunction/ng-conversations 6.1.4 → 6.2.0-edge.1

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 (424) hide show
  1. package/README.md +36 -3
  2. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts +19 -3
  3. package/dist/lib/components/active-tasks/active-tasks-panel.component.d.ts.map +1 -1
  4. package/dist/lib/components/active-tasks/active-tasks-panel.component.js +39 -7
  5. package/dist/lib/components/active-tasks/active-tasks-panel.component.js.map +1 -1
  6. package/dist/lib/components/agent/active-agent-indicator.component.d.ts +74 -6
  7. package/dist/lib/components/agent/active-agent-indicator.component.d.ts.map +1 -1
  8. package/dist/lib/components/agent/active-agent-indicator.component.js +111 -21
  9. package/dist/lib/components/agent/active-agent-indicator.component.js.map +1 -1
  10. package/dist/lib/components/agent/agent-process-panel.component.d.ts +31 -5
  11. package/dist/lib/components/agent/agent-process-panel.component.d.ts.map +1 -1
  12. package/dist/lib/components/agent/agent-process-panel.component.js +71 -15
  13. package/dist/lib/components/agent/agent-process-panel.component.js.map +1 -1
  14. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts +65 -9
  15. package/dist/lib/components/artifact/artifact-share-modal.component.d.ts.map +1 -1
  16. package/dist/lib/components/artifact/artifact-share-modal.component.js +169 -57
  17. package/dist/lib/components/artifact/artifact-share-modal.component.js.map +1 -1
  18. package/dist/lib/components/attachment/image-viewer.component.d.ts +77 -11
  19. package/dist/lib/components/attachment/image-viewer.component.d.ts.map +1 -1
  20. package/dist/lib/components/attachment/image-viewer.component.js +181 -47
  21. package/dist/lib/components/attachment/image-viewer.component.js.map +1 -1
  22. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts +129 -19
  23. package/dist/lib/components/collection/artifact-collection-picker-modal.component.d.ts.map +1 -1
  24. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js +350 -116
  25. package/dist/lib/components/collection/artifact-collection-picker-modal.component.js.map +1 -1
  26. package/dist/lib/components/collection/artifact-create-modal.component.d.ts +60 -8
  27. package/dist/lib/components/collection/artifact-create-modal.component.d.ts.map +1 -1
  28. package/dist/lib/components/collection/artifact-create-modal.component.js +130 -46
  29. package/dist/lib/components/collection/artifact-create-modal.component.js.map +1 -1
  30. package/dist/lib/components/collection/collection-artifact-card.component.d.ts +63 -3
  31. package/dist/lib/components/collection/collection-artifact-card.component.d.ts.map +1 -1
  32. package/dist/lib/components/collection/collection-artifact-card.component.js +113 -19
  33. package/dist/lib/components/collection/collection-artifact-card.component.js.map +1 -1
  34. package/dist/lib/components/collection/collection-form-modal.component.d.ts +54 -8
  35. package/dist/lib/components/collection/collection-form-modal.component.d.ts.map +1 -1
  36. package/dist/lib/components/collection/collection-form-modal.component.js +130 -46
  37. package/dist/lib/components/collection/collection-form-modal.component.js.map +1 -1
  38. package/dist/lib/components/collection/collection-share-modal.component.d.ts +70 -10
  39. package/dist/lib/components/collection/collection-share-modal.component.d.ts.map +1 -1
  40. package/dist/lib/components/collection/collection-share-modal.component.js +175 -53
  41. package/dist/lib/components/collection/collection-share-modal.component.js.map +1 -1
  42. package/dist/lib/components/collection/collection-tree.component.d.ts +89 -9
  43. package/dist/lib/components/collection/collection-tree.component.d.ts.map +1 -1
  44. package/dist/lib/components/collection/collection-tree.component.js +220 -70
  45. package/dist/lib/components/collection/collection-tree.component.js.map +1 -1
  46. package/dist/lib/components/collection/collection-view.component.d.ts +89 -11
  47. package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
  48. package/dist/lib/components/collection/collection-view.component.js +154 -40
  49. package/dist/lib/components/collection/collection-view.component.js.map +1 -1
  50. package/dist/lib/components/collection/collections-full-view.component.d.ts +390 -38
  51. package/dist/lib/components/collection/collections-full-view.component.d.ts.map +1 -1
  52. package/dist/lib/components/collection/collections-full-view.component.js +951 -367
  53. package/dist/lib/components/collection/collections-full-view.component.js.map +1 -1
  54. package/dist/lib/components/composer/ai-composer.component.d.ts +213 -18
  55. package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
  56. package/dist/lib/components/composer/ai-composer.component.js +388 -44
  57. package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
  58. package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts +12 -1
  59. package/dist/lib/components/conversation/conversation-agent-picker.component.d.ts.map +1 -1
  60. package/dist/lib/components/conversation/conversation-agent-picker.component.js +26 -4
  61. package/dist/lib/components/conversation/conversation-agent-picker.component.js.map +1 -1
  62. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +1090 -123
  63. package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
  64. package/dist/lib/components/conversation/conversation-chat-area.component.js +2407 -731
  65. package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
  66. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts +139 -19
  67. package/dist/lib/components/conversation/conversation-empty-state.component.d.ts.map +1 -1
  68. package/dist/lib/components/conversation/conversation-empty-state.component.js +296 -59
  69. package/dist/lib/components/conversation/conversation-empty-state.component.js.map +1 -1
  70. package/dist/lib/components/conversation/conversation-list.component.d.ts +579 -78
  71. package/dist/lib/components/conversation/conversation-list.component.d.ts.map +1 -1
  72. package/dist/lib/components/conversation/conversation-list.component.js +2322 -823
  73. package/dist/lib/components/conversation/conversation-list.component.js.map +1 -1
  74. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts +40 -4
  75. package/dist/lib/components/conversation/pinned-messages-panel.component.d.ts.map +1 -1
  76. package/dist/lib/components/conversation/pinned-messages-panel.component.js +72 -14
  77. package/dist/lib/components/conversation/pinned-messages-panel.component.js.map +1 -1
  78. package/dist/lib/components/dialogs/input-dialog.component.d.ts +57 -11
  79. package/dist/lib/components/dialogs/input-dialog.component.d.ts.map +1 -1
  80. package/dist/lib/components/dialogs/input-dialog.component.js +128 -16
  81. package/dist/lib/components/dialogs/input-dialog.component.js.map +1 -1
  82. package/dist/lib/components/dialogs/rating-dialog.component.d.ts +68 -10
  83. package/dist/lib/components/dialogs/rating-dialog.component.d.ts.map +1 -1
  84. package/dist/lib/components/dialogs/rating-dialog.component.js +151 -27
  85. package/dist/lib/components/dialogs/rating-dialog.component.js.map +1 -1
  86. package/dist/lib/components/export/export-modal.component.d.ts +84 -10
  87. package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
  88. package/dist/lib/components/export/export-modal.component.js +173 -49
  89. package/dist/lib/components/export/export-modal.component.js.map +1 -1
  90. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts +29 -3
  91. package/dist/lib/components/global-tasks/global-tasks-panel.component.d.ts.map +1 -1
  92. package/dist/lib/components/global-tasks/global-tasks-panel.component.js +58 -12
  93. package/dist/lib/components/global-tasks/global-tasks-panel.component.js.map +1 -1
  94. package/dist/lib/components/library/library-full-view.component.d.ts +57 -8
  95. package/dist/lib/components/library/library-full-view.component.d.ts.map +1 -1
  96. package/dist/lib/components/library/library-full-view.component.js +119 -35
  97. package/dist/lib/components/library/library-full-view.component.js.map +1 -1
  98. package/dist/lib/components/members/members-modal.component.d.ts +76 -10
  99. package/dist/lib/components/members/members-modal.component.d.ts.map +1 -1
  100. package/dist/lib/components/members/members-modal.component.js +164 -50
  101. package/dist/lib/components/members/members-modal.component.js.map +1 -1
  102. package/dist/lib/components/message/actionable-commands.component.d.ts +37 -5
  103. package/dist/lib/components/message/actionable-commands.component.d.ts.map +1 -1
  104. package/dist/lib/components/message/actionable-commands.component.js +82 -16
  105. package/dist/lib/components/message/actionable-commands.component.js.map +1 -1
  106. package/dist/lib/components/message/conversation-message-rating.component.d.ts +46 -10
  107. package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
  108. package/dist/lib/components/message/conversation-message-rating.component.js +120 -36
  109. package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
  110. package/dist/lib/components/message/message-input.component.d.ts +549 -74
  111. package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
  112. package/dist/lib/components/message/message-input.component.js +1250 -421
  113. package/dist/lib/components/message/message-input.component.js.map +1 -1
  114. package/dist/lib/components/message/message-item.component.d.ts +411 -29
  115. package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
  116. package/dist/lib/components/message/message-item.component.js +896 -222
  117. package/dist/lib/components/message/message-item.component.js.map +1 -1
  118. package/dist/lib/components/message/message-list.component.d.ts +288 -29
  119. package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
  120. package/dist/lib/components/message/message-list.component.js +561 -123
  121. package/dist/lib/components/message/message-list.component.js.map +1 -1
  122. package/dist/lib/components/navigation/conversation-navigation.component.d.ts +64 -5
  123. package/dist/lib/components/navigation/conversation-navigation.component.d.ts.map +1 -1
  124. package/dist/lib/components/navigation/conversation-navigation.component.js +101 -11
  125. package/dist/lib/components/navigation/conversation-navigation.component.js.map +1 -1
  126. package/dist/lib/components/notification/activity-indicator.component.d.ts +6 -2
  127. package/dist/lib/components/notification/activity-indicator.component.d.ts.map +1 -1
  128. package/dist/lib/components/notification/activity-indicator.component.js +13 -3
  129. package/dist/lib/components/notification/activity-indicator.component.js.map +1 -1
  130. package/dist/lib/components/notification/notification-badge.component.d.ts +15 -3
  131. package/dist/lib/components/notification/notification-badge.component.d.ts.map +1 -1
  132. package/dist/lib/components/notification/notification-badge.component.js +36 -8
  133. package/dist/lib/components/notification/notification-badge.component.js.map +1 -1
  134. package/dist/lib/components/overlay/chat-overlay.component.d.ts +1 -1
  135. package/dist/lib/components/overlay/chat-overlay.component.js +4 -4
  136. package/dist/lib/components/overlay/chat-overlay.component.js.map +1 -1
  137. package/dist/lib/components/project/project-form-modal.component.d.ts +93 -11
  138. package/dist/lib/components/project/project-form-modal.component.d.ts.map +1 -1
  139. package/dist/lib/components/project/project-form-modal.component.js +348 -87
  140. package/dist/lib/components/project/project-form-modal.component.js.map +1 -1
  141. package/dist/lib/components/project/project-selector.component.d.ts +78 -8
  142. package/dist/lib/components/project/project-selector.component.d.ts.map +1 -1
  143. package/dist/lib/components/project/project-selector.component.js +177 -46
  144. package/dist/lib/components/project/project-selector.component.js.map +1 -1
  145. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts +1 -1
  146. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.d.ts.map +1 -1
  147. package/dist/lib/components/realtime/channels/channel-onboarding-panel.component.js.map +1 -1
  148. package/dist/lib/components/realtime/channels/client-context-channel.d.ts +1 -1
  149. package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
  150. package/dist/lib/components/realtime/channels/client-context-channel.js +1 -1
  151. package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
  152. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +1 -1
  153. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
  154. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +3 -0
  155. package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
  156. package/dist/lib/components/realtime/media/media-channel.d.ts +2 -1
  157. package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
  158. package/dist/lib/components/realtime/media/media-channel.js +1 -1
  159. package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
  160. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts +2 -2
  161. package/dist/lib/components/realtime/realtime-activity-rail.component.d.ts.map +1 -1
  162. package/dist/lib/components/realtime/realtime-activity-rail.component.js +2 -2
  163. package/dist/lib/components/realtime/realtime-activity-rail.component.js.map +1 -1
  164. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +1 -1
  165. package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
  166. package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
  167. package/dist/lib/components/realtime/realtime-composer.component.d.ts +3 -1
  168. package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
  169. package/dist/lib/components/realtime/realtime-composer.component.js +26 -8
  170. package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
  171. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts +2 -2
  172. package/dist/lib/components/realtime/realtime-delegation-card.component.d.ts.map +1 -1
  173. package/dist/lib/components/realtime/realtime-delegation-card.component.js +2 -2
  174. package/dist/lib/components/realtime/realtime-delegation-card.component.js.map +1 -1
  175. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +4 -4
  176. package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
  177. package/dist/lib/components/realtime/realtime-session-overlay.component.js +19 -19
  178. package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
  179. package/dist/lib/components/realtime/realtime-session-state.d.ts +2 -3
  180. package/dist/lib/components/realtime/realtime-session-state.d.ts.map +1 -1
  181. package/dist/lib/components/realtime/realtime-session-state.js +3 -2
  182. package/dist/lib/components/realtime/realtime-session-state.js.map +1 -1
  183. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts +17 -1
  184. package/dist/lib/components/realtime/realtime-session-thread.component.d.ts.map +1 -1
  185. package/dist/lib/components/realtime/realtime-session-thread.component.js +122 -45
  186. package/dist/lib/components/realtime/realtime-session-thread.component.js.map +1 -1
  187. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts +47 -31
  188. package/dist/lib/components/realtime/realtime-session-timeline-card.component.d.ts.map +1 -1
  189. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js +138 -124
  190. package/dist/lib/components/realtime/realtime-session-timeline-card.component.js.map +1 -1
  191. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +4 -4
  192. package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
  193. package/dist/lib/components/realtime/realtime-surface-tabs.component.js +4 -4
  194. package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
  195. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +2 -2
  196. package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
  197. package/dist/lib/components/realtime/realtime-surface-tabs.model.js +3 -3
  198. package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
  199. package/dist/lib/components/realtime/realtime-ui-config.d.ts +13 -11
  200. package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
  201. package/dist/lib/components/realtime/realtime-ui-config.js +29 -25
  202. package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
  203. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +1 -1
  204. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
  205. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +1 -1
  206. package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
  207. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +4 -2
  208. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
  209. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +7 -3
  210. package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
  211. package/dist/lib/components/search/search-panel.component.d.ts +133 -22
  212. package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
  213. package/dist/lib/components/search/search-panel.component.js +312 -83
  214. package/dist/lib/components/search/search-panel.component.js.map +1 -1
  215. package/dist/lib/components/share/share-modal.component.d.ts +69 -9
  216. package/dist/lib/components/share/share-modal.component.d.ts.map +1 -1
  217. package/dist/lib/components/share/share-modal.component.js +139 -31
  218. package/dist/lib/components/share/share-modal.component.js.map +1 -1
  219. package/dist/lib/components/shared/user-picker.component.d.ts +48 -8
  220. package/dist/lib/components/shared/user-picker.component.d.ts.map +1 -1
  221. package/dist/lib/components/shared/user-picker.component.js +110 -30
  222. package/dist/lib/components/shared/user-picker.component.js.map +1 -1
  223. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts +114 -11
  224. package/dist/lib/components/sidebar/conversation-sidebar.component.d.ts.map +1 -1
  225. package/dist/lib/components/sidebar/conversation-sidebar.component.js +199 -21
  226. package/dist/lib/components/sidebar/conversation-sidebar.component.js.map +1 -1
  227. package/dist/lib/components/sidebar/routines-section.component.d.ts +20 -1
  228. package/dist/lib/components/sidebar/routines-section.component.d.ts.map +1 -1
  229. package/dist/lib/components/sidebar/routines-section.component.js +25 -5
  230. package/dist/lib/components/sidebar/routines-section.component.js.map +1 -1
  231. package/dist/lib/components/slots/slot-interfaces.d.ts +19 -0
  232. package/dist/lib/components/slots/slot-interfaces.d.ts.map +1 -1
  233. package/dist/lib/components/slots/slot-interfaces.js.map +1 -1
  234. package/dist/lib/components/task/tasks-full-view.component.d.ts +95 -13
  235. package/dist/lib/components/task/tasks-full-view.component.d.ts.map +1 -1
  236. package/dist/lib/components/task/tasks-full-view.component.js +223 -75
  237. package/dist/lib/components/task/tasks-full-view.component.js.map +1 -1
  238. package/dist/lib/components/tasks/task-widget.component.d.ts +46 -6
  239. package/dist/lib/components/tasks/task-widget.component.d.ts.map +1 -1
  240. package/dist/lib/components/tasks/task-widget.component.js +100 -16
  241. package/dist/lib/components/tasks/task-widget.component.js.map +1 -1
  242. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts +64 -7
  243. package/dist/lib/components/tasks/tasks-dropdown.component.d.ts.map +1 -1
  244. package/dist/lib/components/tasks/tasks-dropdown.component.js +127 -27
  245. package/dist/lib/components/tasks/tasks-dropdown.component.js.map +1 -1
  246. package/dist/lib/components/thread/thread-panel.component.d.ts +66 -8
  247. package/dist/lib/components/thread/thread-panel.component.d.ts.map +1 -1
  248. package/dist/lib/components/thread/thread-panel.component.js +146 -36
  249. package/dist/lib/components/thread/thread-panel.component.js.map +1 -1
  250. package/dist/lib/components/toast/toast.component.d.ts +11 -1
  251. package/dist/lib/components/toast/toast.component.d.ts.map +1 -1
  252. package/dist/lib/components/toast/toast.component.js +25 -5
  253. package/dist/lib/components/toast/toast.component.js.map +1 -1
  254. package/dist/lib/components/workspace/conversation-workspace.component.d.ts +385 -42
  255. package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
  256. package/dist/lib/components/workspace/conversation-workspace.component.js +887 -291
  257. package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
  258. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts +8 -0
  259. package/dist/lib/composer-plugins/base-conversation-mention.provider.d.ts.map +1 -1
  260. package/dist/lib/composer-plugins/base-conversation-mention.provider.js +8 -1
  261. package/dist/lib/composer-plugins/base-conversation-mention.provider.js.map +1 -1
  262. package/dist/lib/conversations.module.d.ts.map +1 -1
  263. package/dist/lib/conversations.module.js.map +1 -1
  264. package/dist/lib/directives/chat-slot.directive.d.ts +5 -1
  265. package/dist/lib/directives/chat-slot.directive.d.ts.map +1 -1
  266. package/dist/lib/directives/chat-slot.directive.js.map +1 -1
  267. package/dist/lib/directives/search-shortcut.directive.d.ts +9 -1
  268. package/dist/lib/directives/search-shortcut.directive.d.ts.map +1 -1
  269. package/dist/lib/directives/search-shortcut.directive.js +14 -4
  270. package/dist/lib/directives/search-shortcut.directive.js.map +1 -1
  271. package/dist/lib/events/chat-events.d.ts +34 -7
  272. package/dist/lib/events/chat-events.d.ts.map +1 -1
  273. package/dist/lib/events/chat-events.js +37 -7
  274. package/dist/lib/events/chat-events.js.map +1 -1
  275. package/dist/lib/models/agent-turn.model.d.ts +103 -0
  276. package/dist/lib/models/agent-turn.model.d.ts.map +1 -0
  277. package/dist/lib/models/agent-turn.model.js +12 -0
  278. package/dist/lib/models/agent-turn.model.js.map +1 -0
  279. package/dist/lib/models/collection-view.model.js.map +1 -1
  280. package/dist/lib/models/conversation-state.model.d.ts +8 -0
  281. package/dist/lib/models/conversation-state.model.d.ts.map +1 -1
  282. package/dist/lib/models/conversation-state.model.js.map +1 -1
  283. package/dist/lib/models/lazy-artifact-info.d.ts +44 -12
  284. package/dist/lib/models/lazy-artifact-info.d.ts.map +1 -1
  285. package/dist/lib/models/lazy-artifact-info.js +98 -34
  286. package/dist/lib/models/lazy-artifact-info.js.map +1 -1
  287. package/dist/lib/services/active-tasks.service.d.ts +30 -4
  288. package/dist/lib/services/active-tasks.service.d.ts.map +1 -1
  289. package/dist/lib/services/active-tasks.service.js +71 -19
  290. package/dist/lib/services/active-tasks.service.js.map +1 -1
  291. package/dist/lib/services/agent-state.service.d.ts +17 -1
  292. package/dist/lib/services/agent-state.service.d.ts.map +1 -1
  293. package/dist/lib/services/agent-state.service.js +48 -16
  294. package/dist/lib/services/agent-state.service.js.map +1 -1
  295. package/dist/lib/services/artifact-permission.service.d.ts +39 -0
  296. package/dist/lib/services/artifact-permission.service.d.ts.map +1 -1
  297. package/dist/lib/services/artifact-permission.service.js +152 -17
  298. package/dist/lib/services/artifact-permission.service.js.map +1 -1
  299. package/dist/lib/services/artifact-state.service.d.ts +58 -5
  300. package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
  301. package/dist/lib/services/artifact-state.service.js +135 -35
  302. package/dist/lib/services/artifact-state.service.js.map +1 -1
  303. package/dist/lib/services/browser-realtime-media-host.d.ts +24 -0
  304. package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -0
  305. package/dist/lib/services/browser-realtime-media-host.js +95 -0
  306. package/dist/lib/services/browser-realtime-media-host.js.map +1 -0
  307. package/dist/lib/services/collection-permission.service.d.ts +28 -0
  308. package/dist/lib/services/collection-permission.service.d.ts.map +1 -1
  309. package/dist/lib/services/collection-permission.service.js +88 -32
  310. package/dist/lib/services/collection-permission.service.js.map +1 -1
  311. package/dist/lib/services/collection-state.service.d.ts +11 -1
  312. package/dist/lib/services/collection-state.service.d.ts.map +1 -1
  313. package/dist/lib/services/collection-state.service.js +25 -5
  314. package/dist/lib/services/collection-state.service.js.map +1 -1
  315. package/dist/lib/services/conversation-agent.service.d.ts +26 -4
  316. package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
  317. package/dist/lib/services/conversation-agent.service.js +57 -18
  318. package/dist/lib/services/conversation-agent.service.js.map +1 -1
  319. package/dist/lib/services/conversation-attachment.service.d.ts +41 -2
  320. package/dist/lib/services/conversation-attachment.service.d.ts.map +1 -1
  321. package/dist/lib/services/conversation-attachment.service.js +80 -13
  322. package/dist/lib/services/conversation-attachment.service.js.map +1 -1
  323. package/dist/lib/services/conversation-streaming.service.d.ts +22 -0
  324. package/dist/lib/services/conversation-streaming.service.d.ts.map +1 -1
  325. package/dist/lib/services/conversation-streaming.service.js +50 -10
  326. package/dist/lib/services/conversation-streaming.service.js.map +1 -1
  327. package/dist/lib/services/data-cache.service.d.ts +31 -0
  328. package/dist/lib/services/data-cache.service.d.ts.map +1 -1
  329. package/dist/lib/services/data-cache.service.js +71 -15
  330. package/dist/lib/services/data-cache.service.js.map +1 -1
  331. package/dist/lib/services/dialog.service.d.ts +13 -0
  332. package/dist/lib/services/dialog.service.d.ts.map +1 -1
  333. package/dist/lib/services/dialog.service.js +25 -5
  334. package/dist/lib/services/dialog.service.js.map +1 -1
  335. package/dist/lib/services/export.service.d.ts +2 -0
  336. package/dist/lib/services/export.service.d.ts.map +1 -1
  337. package/dist/lib/services/export.service.js +5 -1
  338. package/dist/lib/services/export.service.js.map +1 -1
  339. package/dist/lib/services/graphql-attachment-blob-store.d.ts +44 -0
  340. package/dist/lib/services/graphql-attachment-blob-store.d.ts.map +1 -0
  341. package/dist/lib/services/graphql-attachment-blob-store.js +113 -0
  342. package/dist/lib/services/graphql-attachment-blob-store.js.map +1 -0
  343. package/dist/lib/services/mention-autocomplete.service.d.ts +17 -141
  344. package/dist/lib/services/mention-autocomplete.service.d.ts.map +1 -1
  345. package/dist/lib/services/mention-autocomplete.service.js +15 -460
  346. package/dist/lib/services/mention-autocomplete.service.js.map +1 -1
  347. package/dist/lib/services/mention-parser.service.d.ts +10 -0
  348. package/dist/lib/services/mention-parser.service.d.ts.map +1 -1
  349. package/dist/lib/services/mention-parser.service.js +25 -5
  350. package/dist/lib/services/mention-parser.service.js.map +1 -1
  351. package/dist/lib/services/notification.service.d.ts +54 -6
  352. package/dist/lib/services/notification.service.d.ts.map +1 -1
  353. package/dist/lib/services/notification.service.js +123 -27
  354. package/dist/lib/services/notification.service.js.map +1 -1
  355. package/dist/lib/services/realtime-audio-recorder.d.ts +4 -4
  356. package/dist/lib/services/realtime-audio-recorder.js +12 -12
  357. package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
  358. package/dist/lib/services/realtime-pcm-wav.d.ts +4 -0
  359. package/dist/lib/services/realtime-pcm-wav.d.ts.map +1 -1
  360. package/dist/lib/services/realtime-pcm-wav.js +10 -2
  361. package/dist/lib/services/realtime-pcm-wav.js.map +1 -1
  362. package/dist/lib/services/realtime-session-review.service.d.ts +1 -1
  363. package/dist/lib/services/realtime-session-review.service.d.ts.map +1 -1
  364. package/dist/lib/services/realtime-session-review.service.js +1 -1
  365. package/dist/lib/services/realtime-session-review.service.js.map +1 -1
  366. package/dist/lib/services/realtime-session.service.d.ts +16 -1150
  367. package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
  368. package/dist/lib/services/realtime-session.service.js +28 -2430
  369. package/dist/lib/services/realtime-session.service.js.map +1 -1
  370. package/dist/lib/services/search.service.d.ts +42 -9
  371. package/dist/lib/services/search.service.d.ts.map +1 -1
  372. package/dist/lib/services/search.service.js +103 -23
  373. package/dist/lib/services/search.service.js.map +1 -1
  374. package/dist/lib/services/toast.service.d.ts +19 -1
  375. package/dist/lib/services/toast.service.d.ts.map +1 -1
  376. package/dist/lib/services/toast.service.js +45 -9
  377. package/dist/lib/services/toast.service.js.map +1 -1
  378. package/dist/lib/services/ui-command-handler.service.d.ts +16 -2
  379. package/dist/lib/services/ui-command-handler.service.d.ts.map +1 -1
  380. package/dist/lib/services/ui-command-handler.service.js +36 -8
  381. package/dist/lib/services/ui-command-handler.service.js.map +1 -1
  382. package/dist/lib/utils/agent-artifact-summary.d.ts +2 -2
  383. package/dist/lib/utils/agent-artifact-summary.js +3 -3
  384. package/dist/lib/utils/agent-artifact-summary.js.map +1 -1
  385. package/dist/lib/utils/agent-turn-routing.d.ts +69 -0
  386. package/dist/lib/utils/agent-turn-routing.d.ts.map +1 -0
  387. package/dist/lib/utils/agent-turn-routing.js +96 -0
  388. package/dist/lib/utils/agent-turn-routing.js.map +1 -0
  389. package/dist/lib/utils/artifact-panel-action.d.ts +15 -4
  390. package/dist/lib/utils/artifact-panel-action.d.ts.map +1 -1
  391. package/dist/lib/utils/artifact-panel-action.js +10 -2
  392. package/dist/lib/utils/artifact-panel-action.js.map +1 -1
  393. package/dist/lib/utils/distinct-artifacts.d.ts +2 -0
  394. package/dist/lib/utils/distinct-artifacts.d.ts.map +1 -1
  395. package/dist/lib/utils/distinct-artifacts.js +5 -1
  396. package/dist/lib/utils/distinct-artifacts.js.map +1 -1
  397. package/dist/lib/utils/plan-mode-preference.d.ts +2 -2
  398. package/dist/lib/utils/plan-mode-preference.js +6 -6
  399. package/dist/lib/utils/plan-mode-preference.js.map +1 -1
  400. package/dist/lib/utils/realtime-session-timeline.d.ts +8 -79
  401. package/dist/lib/utils/realtime-session-timeline.d.ts.map +1 -1
  402. package/dist/lib/utils/realtime-session-timeline.js +8 -89
  403. package/dist/lib/utils/realtime-session-timeline.js.map +1 -1
  404. package/dist/public-api.d.ts +5 -2
  405. package/dist/public-api.d.ts.map +1 -1
  406. package/dist/public-api.js +9 -2
  407. package/dist/public-api.js.map +1 -1
  408. package/package.json +33 -32
  409. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts +0 -384
  410. package/dist/lib/components/realtime/channels/base-realtime-channel-client.d.ts.map +0 -1
  411. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js +0 -231
  412. package/dist/lib/components/realtime/channels/base-realtime-channel-client.js.map +0 -1
  413. package/dist/lib/services/delegation-result-parser.d.ts +0 -50
  414. package/dist/lib/services/delegation-result-parser.d.ts.map +0 -1
  415. package/dist/lib/services/delegation-result-parser.js +0 -60
  416. package/dist/lib/services/delegation-result-parser.js.map +0 -1
  417. package/dist/lib/services/narration-template.d.ts +0 -42
  418. package/dist/lib/services/narration-template.d.ts.map +0 -1
  419. package/dist/lib/services/narration-template.js +0 -73
  420. package/dist/lib/services/narration-template.js.map +0 -1
  421. package/dist/lib/services/skill-picker-narrowing.d.ts +0 -13
  422. package/dist/lib/services/skill-picker-narrowing.d.ts.map +0 -1
  423. package/dist/lib/services/skill-picker-narrowing.js +0 -13
  424. package/dist/lib/services/skill-picker-narrowing.js.map +0 -1
@@ -1,6 +1,7 @@
1
- import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, HostListener, ViewChild } from '@angular/core';
2
2
  import { ConversationEngine, UserInfoEngine } from '@memberjunction/core-entities';
3
3
  import { ProjectFormModalComponent } from '../project/project-form-modal.component';
4
+ import { MJResourcePermissionShareAdapter } from '@memberjunction/ng-resource-permissions';
4
5
  import { Subject } from 'rxjs';
5
6
  import { takeUntil } from 'rxjs/operators';
6
7
  import { UUIDsEqual, NormalizeUUID } from '@memberjunction/global';
@@ -11,578 +12,724 @@ import * as i3 from "../../services/active-tasks.service";
11
12
  import * as i4 from "@memberjunction/ng-ui-components";
12
13
  import * as i5 from "@angular/common";
13
14
  import * as i6 from "@angular/forms";
14
- import * as i7 from "../notification/notification-badge.component";
15
- const _c0 = a0 => ({ $implicit: a0 });
16
- const _c1 = (a0, a1) => ({ $implicit: a0, depth: a1 });
15
+ import * as i7 from "@memberjunction/ng-resource-permissions";
16
+ import * as i8 from "../notification/notification-badge.component";
17
+ const _c0 = ["searchInput"];
18
+ const _c1 = ["contextMenuEl"];
19
+ const _c2 = a0 => ({ $implicit: a0 });
20
+ const _c3 = (a0, a1) => ({ $implicit: a0, depth: a1 });
17
21
  const _forTrack0 = ($index, $item) => $item.ID;
18
22
  const _forTrack1 = ($index, $item) => $item.project.ID;
19
23
  function ConversationListComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
20
24
  const _r1 = i0.ɵɵgetCurrentView();
21
- i0.ɵɵelementStart(0, "input", 12);
22
- i0.ɵɵtwoWayListener("ngModelChange", function ConversationListComponent_Conditional_1_Conditional_2_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.searchQuery, $event) || (ctx_r1.searchQuery = $event); return i0.ɵɵresetView($event); });
25
+ i0.ɵɵelementStart(0, "div", 14)(1, "button", 16);
26
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_2_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ClearSelection()); });
27
+ i0.ɵɵelement(2, "i", 17);
28
+ i0.ɵɵelementEnd();
29
+ i0.ɵɵelementStart(3, "span", 18);
30
+ i0.ɵɵtext(4);
31
+ i0.ɵɵelementEnd();
32
+ i0.ɵɵelementStart(5, "button", 19);
33
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.BarSetPinned()); });
34
+ i0.ɵɵelement(6, "i", 20);
23
35
  i0.ɵɵelementEnd();
36
+ i0.ɵɵelementStart(7, "button", 21);
37
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_2_Template_button_click_7_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.BarOpenMoveMenu($event)); });
38
+ i0.ɵɵelement(8, "i", 22);
39
+ i0.ɵɵelementEnd();
40
+ i0.ɵɵelementStart(9, "button", 23);
41
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.BarShare()); });
42
+ i0.ɵɵelement(10, "i", 24);
43
+ i0.ɵɵelementEnd();
44
+ i0.ɵɵelementStart(11, "button", 25);
45
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.BarDelete()); });
46
+ i0.ɵɵelement(12, "i", 26);
47
+ i0.ɵɵelementEnd()();
24
48
  } if (rf & 2) {
25
49
  const ctx_r1 = i0.ɵɵnextContext(2);
26
- i0.ɵɵtwoWayProperty("ngModel", ctx_r1.searchQuery);
50
+ i0.ɵɵadvance(4);
51
+ i0.ɵɵtextInterpolate1("", ctx_r1.SelectedConversationIds.size, " selected");
52
+ i0.ɵɵadvance();
53
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.SelectedIds))("title", ctx_r1.CanChangeAny(ctx_r1.SelectedIds) ? ctx_r1.SelectionHasUnpinned() ? "Pin" : "Unpin" : ctx_r1.ChangeRefusedReason);
54
+ i0.ɵɵattribute("aria-label", ctx_r1.SelectionHasUnpinned() ? "Pin" : "Unpin");
55
+ i0.ɵɵadvance();
56
+ i0.ɵɵclassProp("fa-rotate-90", !ctx_r1.SelectionHasUnpinned());
57
+ i0.ɵɵadvance();
58
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.SelectedIds))("title", ctx_r1.CanChangeAny(ctx_r1.SelectedIds) ? "Move to folder" : ctx_r1.ChangeRefusedReason);
59
+ i0.ɵɵadvance(2);
60
+ i0.ɵɵproperty("disabled", !ctx_r1.CanShareAny(ctx_r1.SelectedIds))("title", ctx_r1.CanShareAny(ctx_r1.SelectedIds) ? "Share" : ctx_r1.ShareRefusedReason);
27
61
  } }
28
- function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Conditional_13_Template(rf, ctx) { if (rf & 1) {
29
- const _r5 = i0.ɵɵgetCurrentView();
30
- i0.ɵɵelementStart(0, "button", 18);
31
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Conditional_13_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.onUnpinSidebarClick($event)); });
32
- i0.ɵɵelement(1, "i", 22);
62
+ function ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
63
+ const _r4 = i0.ɵɵgetCurrentView();
64
+ i0.ɵɵelementStart(0, "button", 31);
65
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ClearSearch()); });
66
+ i0.ɵɵelement(1, "i", 17);
67
+ i0.ɵɵelementEnd();
68
+ } }
69
+ function ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
70
+ const _r3 = i0.ɵɵgetCurrentView();
71
+ i0.ɵɵelementStart(0, "div", 27)(1, "input", 29, 2);
72
+ i0.ɵɵtwoWayListener("ngModelChange", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Template_input_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.SearchQuery, $event) || (ctx_r1.SearchQuery = $event); return i0.ɵɵresetView($event); });
73
+ i0.ɵɵlistener("keydown", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Template_input_keydown_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnSearchKeydown($event)); });
74
+ i0.ɵɵelementEnd();
75
+ i0.ɵɵconditionalCreate(3, ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Conditional_3_Template, 2, 0, "button", 30);
76
+ i0.ɵɵelementEnd();
77
+ } if (rf & 2) {
78
+ const ctx_r1 = i0.ɵɵnextContext(3);
79
+ i0.ɵɵadvance();
80
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.SearchQuery);
81
+ i0.ɵɵadvance(2);
82
+ i0.ɵɵconditional(ctx_r1.IsSearching ? 3 : -1);
83
+ } }
84
+ function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Conditional_9_Template(rf, ctx) { if (rf & 1) {
85
+ const _r7 = i0.ɵɵgetCurrentView();
86
+ i0.ɵɵelementStart(0, "button", 37);
87
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Conditional_9_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.OnUnpinSidebarClick($event)); });
88
+ i0.ɵɵelement(1, "i", 40);
33
89
  i0.ɵɵelementStart(2, "span");
34
90
  i0.ɵɵtext(3, "Hide Sidebar");
35
91
  i0.ɵɵelementEnd()();
36
92
  } }
37
- function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Template(rf, ctx) { if (rf & 1) {
38
- const _r4 = i0.ɵɵgetCurrentView();
39
- i0.ɵɵelementStart(0, "div", 15)(1, "button", 16);
40
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRefreshConversationsClick($event)); });
41
- i0.ɵɵelement(2, "i", 17);
93
+ function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
94
+ const _r6 = i0.ɵɵgetCurrentView();
95
+ i0.ɵɵelementStart(0, "div", 34)(1, "button", 35);
96
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnRefreshConversationsClick($event)); });
97
+ i0.ɵɵelement(2, "i", 36);
42
98
  i0.ɵɵelementStart(3, "span");
43
99
  i0.ɵɵtext(4);
44
100
  i0.ɵɵelementEnd()();
45
- i0.ɵɵelementStart(5, "button", 18);
46
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Template_button_click_5_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onSelectConversationsClick($event)); });
47
- i0.ɵɵelement(6, "i", 19);
101
+ i0.ɵɵelementStart(5, "button", 37);
102
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Template_button_click_5_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnToggleGroupByClick($event)); });
103
+ i0.ɵɵelement(6, "i", 38);
48
104
  i0.ɵɵelementStart(7, "span");
49
- i0.ɵɵtext(8, "Select Conversations");
50
- i0.ɵɵelementEnd()();
51
- i0.ɵɵelementStart(9, "button", 18);
52
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Template_button_click_9_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onToggleGroupByClick($event)); });
53
- i0.ɵɵelement(10, "i", 20);
54
- i0.ɵɵelementStart(11, "span");
55
- i0.ɵɵtext(12);
105
+ i0.ɵɵtext(8);
56
106
  i0.ɵɵelementEnd()();
57
- i0.ɵɵconditionalCreate(13, ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Conditional_13_Template, 4, 0, "button", 21);
107
+ i0.ɵɵconditionalCreate(9, ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Conditional_9_Template, 4, 0, "button", 39);
58
108
  i0.ɵɵelementEnd();
59
109
  } if (rf & 2) {
60
- const ctx_r1 = i0.ɵɵnextContext(3);
110
+ const ctx_r1 = i0.ɵɵnextContext(4);
61
111
  i0.ɵɵadvance();
62
- i0.ɵɵproperty("disabled", ctx_r1.isRefreshing);
112
+ i0.ɵɵproperty("disabled", ctx_r1.IsRefreshing);
63
113
  i0.ɵɵadvance();
64
- i0.ɵɵclassProp("fa-spin", ctx_r1.isRefreshing);
114
+ i0.ɵɵclassProp("fa-spin", ctx_r1.IsRefreshing);
65
115
  i0.ɵɵadvance(2);
66
- i0.ɵɵtextInterpolate(ctx_r1.isRefreshing ? "Refreshing..." : "Refresh");
67
- i0.ɵɵadvance(6);
68
- i0.ɵɵclassProp("fa-folder-tree", ctx_r1.groupBy !== "project")("fa-list", ctx_r1.groupBy === "project");
116
+ i0.ɵɵtextInterpolate(ctx_r1.IsRefreshing ? "Refreshing..." : "Refresh");
69
117
  i0.ɵɵadvance(2);
70
- i0.ɵɵtextInterpolate(ctx_r1.groupBy === "project" ? "Show as flat list" : "Group by folder");
118
+ i0.ɵɵclassProp("fa-folder-tree", ctx_r1.GroupBy !== "project")("fa-list", ctx_r1.GroupBy === "project");
119
+ i0.ɵɵadvance(2);
120
+ i0.ɵɵtextInterpolate(ctx_r1.GroupBy === "project" ? "Show as flat list" : "Group by folder");
71
121
  i0.ɵɵadvance();
72
- i0.ɵɵconditional(!ctx_r1.isMobileView ? 13 : -1);
122
+ i0.ɵɵconditional(!ctx_r1.IsMobileView ? 9 : -1);
73
123
  } }
74
- function ConversationListComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
75
- const _r3 = i0.ɵɵgetCurrentView();
76
- i0.ɵɵelementStart(0, "div", 11)(1, "button", 13);
77
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleHeaderMenu($event)); });
78
- i0.ɵɵelement(2, "i", 14);
124
+ function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
125
+ const _r5 = i0.ɵɵgetCurrentView();
126
+ i0.ɵɵelementStart(0, "div", 28)(1, "button", 32);
127
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ToggleHeaderMenu($event)); });
128
+ i0.ɵɵelement(2, "i", 33);
79
129
  i0.ɵɵelementEnd();
80
- i0.ɵɵconditionalCreate(3, ConversationListComponent_Conditional_1_Conditional_3_Conditional_3_Template, 14, 10, "div", 15);
130
+ i0.ɵɵconditionalCreate(3, ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Conditional_3_Template, 10, 10, "div", 34);
81
131
  i0.ɵɵelementEnd();
132
+ } if (rf & 2) {
133
+ const ctx_r1 = i0.ɵɵnextContext(3);
134
+ i0.ɵɵadvance(3);
135
+ i0.ɵɵconditional(ctx_r1.IsHeaderMenuOpen ? 3 : -1);
136
+ } }
137
+ function ConversationListComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
138
+ i0.ɵɵconditionalCreate(0, ConversationListComponent_Conditional_1_Conditional_3_Conditional_0_Template, 4, 2, "div", 27);
139
+ i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_1_Conditional_3_Conditional_1_Template, 4, 1, "div", 28);
140
+ } if (rf & 2) {
141
+ const ctx_r1 = i0.ɵɵnextContext(2);
142
+ i0.ɵɵconditional(ctx_r1.showSearch ? 0 : -1);
143
+ i0.ɵɵadvance();
144
+ i0.ɵɵconditional(ctx_r1.ShowHeaderMenu ? 1 : -1);
145
+ } }
146
+ function ConversationListComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
147
+ const _r8 = i0.ɵɵgetCurrentView();
148
+ i0.ɵɵelementStart(0, "div", 15)(1, "button", 41);
149
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_4_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetSort("date")); });
150
+ i0.ɵɵelement(2, "i", 42);
151
+ i0.ɵɵelementStart(3, "span");
152
+ i0.ɵɵtext(4, "Date");
153
+ i0.ɵɵelementEnd()();
154
+ i0.ɵɵelementStart(5, "button", 41);
155
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_1_Conditional_4_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetSort("name")); });
156
+ i0.ɵɵelement(6, "i", 42);
157
+ i0.ɵɵelementStart(7, "span");
158
+ i0.ɵɵtext(8, "Name");
159
+ i0.ɵɵelementEnd()()();
82
160
  } if (rf & 2) {
83
161
  const ctx_r1 = i0.ɵɵnextContext(2);
162
+ i0.ɵɵadvance();
163
+ i0.ɵɵclassProp("active", ctx_r1.SortBy === "date");
164
+ i0.ɵɵproperty("title", ctx_r1.SortBy === "date" ? ctx_r1.SortDirection === "asc" ? "Oldest first" : "Newest first" : "Sort by date");
165
+ i0.ɵɵadvance();
166
+ i0.ɵɵproperty("ngClass", ctx_r1.SortIcon("date"));
84
167
  i0.ɵɵadvance(3);
85
- i0.ɵɵconditional(ctx_r1.isHeaderMenuOpen ? 3 : -1);
168
+ i0.ɵɵclassProp("active", ctx_r1.SortBy === "name");
169
+ i0.ɵɵproperty("title", ctx_r1.SortBy === "name" ? ctx_r1.SortDirection === "asc" ? "A to Z" : "Z to A" : "Sort by name");
170
+ i0.ɵɵadvance();
171
+ i0.ɵɵproperty("ngClass", ctx_r1.SortIcon("name"));
86
172
  } }
87
173
  function ConversationListComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
88
- i0.ɵɵelementStart(0, "div", 3)(1, "div", 9);
89
- i0.ɵɵconditionalCreate(2, ConversationListComponent_Conditional_1_Conditional_2_Template, 1, 1, "input", 10);
90
- i0.ɵɵconditionalCreate(3, ConversationListComponent_Conditional_1_Conditional_3_Template, 4, 1, "div", 11);
91
- i0.ɵɵelementEnd()();
174
+ i0.ɵɵelementStart(0, "div", 5)(1, "div", 13);
175
+ i0.ɵɵconditionalCreate(2, ConversationListComponent_Conditional_1_Conditional_2_Template, 13, 10, "div", 14)(3, ConversationListComponent_Conditional_1_Conditional_3_Template, 2, 2);
176
+ i0.ɵɵelementEnd();
177
+ i0.ɵɵconditionalCreate(4, ConversationListComponent_Conditional_1_Conditional_4_Template, 9, 8, "div", 15);
178
+ i0.ɵɵelementEnd();
92
179
  } if (rf & 2) {
93
180
  const ctx_r1 = i0.ɵɵnextContext();
94
181
  i0.ɵɵadvance(2);
95
- i0.ɵɵconditional(ctx_r1.showSearch ? 2 : -1);
96
- i0.ɵɵadvance();
97
- i0.ɵɵconditional(ctx_r1.showHeaderMenu && !ctx_r1.isSelectionMode ? 3 : -1);
182
+ i0.ɵɵconditional(ctx_r1.IsSelectionMode ? 2 : 3);
183
+ i0.ɵɵadvance(2);
184
+ i0.ɵɵconditional(ctx_r1.showSearch || ctx_r1.ShowHeaderMenu ? 4 : -1);
98
185
  } }
99
186
  function ConversationListComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
100
- const _r6 = i0.ɵɵgetCurrentView();
101
- i0.ɵɵelementStart(0, "button", 23);
102
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.createNewConversation()); });
103
- i0.ɵɵelement(1, "i", 24);
187
+ const _r9 = i0.ɵɵgetCurrentView();
188
+ i0.ɵɵelementStart(0, "button", 43);
189
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CreateNewConversation()); });
190
+ i0.ɵɵelement(1, "i", 44);
104
191
  i0.ɵɵelementStart(2, "span");
105
192
  i0.ɵɵtext(3, "New Conversation");
106
193
  i0.ɵɵelementEnd()();
107
194
  } }
108
195
  function ConversationListComponent_Conditional_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
109
- const _r7 = i0.ɵɵgetCurrentView();
110
- i0.ɵɵelementStart(0, "div", 28);
111
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_4_Conditional_1_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.togglePinned()); });
112
- i0.ɵɵelementStart(1, "div", 29);
113
- i0.ɵɵelement(2, "i", 30)(3, "i", 31);
196
+ const _r10 = i0.ɵɵgetCurrentView();
197
+ i0.ɵɵelementStart(0, "div", 48);
198
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_4_Conditional_1_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.TogglePinned()); });
199
+ i0.ɵɵelementStart(1, "div", 49);
200
+ i0.ɵɵelement(2, "i", 50)(3, "i", 51);
114
201
  i0.ɵɵelementStart(4, "span");
115
202
  i0.ɵɵtext(5, "Pinned");
116
203
  i0.ɵɵelementEnd()()();
117
204
  } if (rf & 2) {
118
205
  const ctx_r1 = i0.ɵɵnextContext(2);
119
- i0.ɵɵclassProp("expanded", ctx_r1.pinnedExpanded);
206
+ i0.ɵɵclassProp("expanded", ctx_r1.PinnedExpanded);
120
207
  } }
121
208
  function ConversationListComponent_Conditional_4_For_4_Template(rf, ctx) { if (rf & 1) {
122
- i0.ɵɵelementContainer(0, 27);
209
+ i0.ɵɵelementContainer(0, 47);
123
210
  } if (rf & 2) {
124
- const conversation_r8 = ctx.$implicit;
211
+ const conversation_r11 = ctx.$implicit;
125
212
  i0.ɵɵnextContext(2);
126
- const conversationItem_r9 = i0.ɵɵreference(11);
127
- i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r9)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, conversation_r8));
213
+ const conversationItem_r12 = i0.ɵɵreference(11);
214
+ i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c2, conversation_r11));
128
215
  } }
129
216
  function ConversationListComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
130
- i0.ɵɵelementStart(0, "div", 6);
131
- i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_4_Conditional_1_Template, 6, 2, "div", 25);
132
- i0.ɵɵelementStart(2, "div", 26);
133
- i0.ɵɵrepeaterCreate(3, ConversationListComponent_Conditional_4_For_4_Template, 1, 4, "ng-container", 27, _forTrack0);
217
+ i0.ɵɵelementStart(0, "div", 8);
218
+ i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_4_Conditional_1_Template, 6, 2, "div", 45);
219
+ i0.ɵɵelementStart(2, "div", 46);
220
+ i0.ɵɵrepeaterCreate(3, ConversationListComponent_Conditional_4_For_4_Template, 1, 4, "ng-container", 47, _forTrack0);
134
221
  i0.ɵɵelementEnd()();
135
222
  } if (rf & 2) {
136
223
  const ctx_r1 = i0.ɵɵnextContext();
137
224
  i0.ɵɵadvance();
138
- i0.ɵɵconditional(ctx_r1.showSectionHeaders ? 1 : -1);
225
+ i0.ɵɵconditional(ctx_r1.ShowSectionHeaders ? 1 : -1);
139
226
  i0.ɵɵadvance();
140
- i0.ɵɵclassProp("expanded", !ctx_r1.showSectionHeaders || ctx_r1.pinnedExpanded);
227
+ i0.ɵɵclassProp("expanded", !ctx_r1.ShowSectionHeaders || ctx_r1.PinnedExpanded);
141
228
  i0.ɵɵadvance();
142
- i0.ɵɵrepeater(ctx_r1.pinnedConversations);
229
+ i0.ɵɵrepeater(ctx_r1.PinnedConversations);
143
230
  } }
144
231
  function ConversationListComponent_Conditional_5_For_10_Conditional_0_Template(rf, ctx) { if (rf & 1) {
145
- i0.ɵɵelementContainer(0, 27);
232
+ i0.ɵɵelementContainer(0, 47);
146
233
  } if (rf & 2) {
147
- const node_r11 = i0.ɵɵnextContext().$implicit;
234
+ const node_r14 = i0.ɵɵnextContext().$implicit;
148
235
  i0.ɵɵnextContext(2);
149
- const folderNode_r12 = i0.ɵɵreference(9);
150
- i0.ɵɵproperty("ngTemplateOutlet", folderNode_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, node_r11));
236
+ const folderNode_r15 = i0.ɵɵreference(9);
237
+ i0.ɵɵproperty("ngTemplateOutlet", folderNode_r15)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c2, node_r14));
151
238
  } }
152
239
  function ConversationListComponent_Conditional_5_For_10_Template(rf, ctx) { if (rf & 1) {
153
- i0.ɵɵconditionalCreate(0, ConversationListComponent_Conditional_5_For_10_Conditional_0_Template, 1, 4, "ng-container", 27);
240
+ i0.ɵɵconditionalCreate(0, ConversationListComponent_Conditional_5_For_10_Conditional_0_Template, 1, 4, "ng-container", 47);
154
241
  } if (rf & 2) {
155
- const node_r11 = ctx.$implicit;
242
+ const node_r14 = ctx.$implicit;
156
243
  const ctx_r1 = i0.ɵɵnextContext(2);
157
- i0.ɵɵconditional(!ctx_r1.isSearching || node_r11.hasContent ? 0 : -1);
244
+ i0.ɵɵconditional(!ctx_r1.IsSearching || node_r14.hasContent ? 0 : -1);
158
245
  } }
159
246
  function ConversationListComponent_Conditional_5_Conditional_11_Template(rf, ctx) { if (rf & 1) {
160
- i0.ɵɵelementStart(0, "div", 36);
247
+ i0.ɵɵelementStart(0, "div", 56);
161
248
  i0.ɵɵtext(1, "No folders yet \u2014 create one to organize conversations.");
162
249
  i0.ɵɵelementEnd();
163
250
  } }
164
251
  function ConversationListComponent_Conditional_5_For_20_Template(rf, ctx) { if (rf & 1) {
165
- i0.ɵɵelementContainer(0, 27);
252
+ i0.ɵɵelementContainer(0, 47);
166
253
  } if (rf & 2) {
167
- const conversation_r13 = ctx.$implicit;
254
+ const conversation_r16 = ctx.$implicit;
168
255
  i0.ɵɵnextContext(2);
169
- const conversationItem_r9 = i0.ɵɵreference(11);
170
- i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r9)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, conversation_r13));
256
+ const conversationItem_r12 = i0.ɵɵreference(11);
257
+ i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c2, conversation_r16));
171
258
  } }
172
259
  function ConversationListComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
173
- const _r10 = i0.ɵɵgetCurrentView();
174
- i0.ɵɵelementStart(0, "div", 32)(1, "div", 33);
175
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleFolders()); })("dragover", function ConversationListComponent_Conditional_5_Template_div_dragover_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFoldersRootDragOver($event)); })("dragleave", function ConversationListComponent_Conditional_5_Template_div_dragleave_1_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDragLeave("folders-root")); })("drop", function ConversationListComponent_Conditional_5_Template_div_drop_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFoldersRootDrop($event)); });
176
- i0.ɵɵelementStart(2, "div", 29);
177
- i0.ɵɵelement(3, "i", 30);
260
+ const _r13 = i0.ɵɵgetCurrentView();
261
+ i0.ɵɵelementStart(0, "div", 52)(1, "div", 53);
262
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleFolders()); })("dragover", function ConversationListComponent_Conditional_5_Template_div_dragover_1_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFoldersRootDragOver($event)); })("dragleave", function ConversationListComponent_Conditional_5_Template_div_dragleave_1_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave("folders-root")); })("drop", function ConversationListComponent_Conditional_5_Template_div_drop_1_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFoldersRootDrop($event)); });
263
+ i0.ɵɵelementStart(2, "div", 49);
264
+ i0.ɵɵelement(3, "i", 50);
178
265
  i0.ɵɵelementStart(4, "span");
179
266
  i0.ɵɵtext(5, "Folders");
180
267
  i0.ɵɵelementEnd()();
181
- i0.ɵɵelementStart(6, "button", 34);
182
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_button_click_6_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.createFolder(null, $event)); });
183
- i0.ɵɵelement(7, "i", 35);
268
+ i0.ɵɵelementStart(6, "button", 54);
269
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_button_click_6_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CreateFolder(null, $event)); });
270
+ i0.ɵɵelement(7, "i", 55);
184
271
  i0.ɵɵelementEnd()();
185
- i0.ɵɵelementStart(8, "div", 26);
272
+ i0.ɵɵelementStart(8, "div", 46);
186
273
  i0.ɵɵrepeaterCreate(9, ConversationListComponent_Conditional_5_For_10_Template, 1, 1, null, null, _forTrack1);
187
- i0.ɵɵconditionalCreate(11, ConversationListComponent_Conditional_5_Conditional_11_Template, 2, 0, "div", 36);
274
+ i0.ɵɵconditionalCreate(11, ConversationListComponent_Conditional_5_Conditional_11_Template, 2, 0, "div", 56);
188
275
  i0.ɵɵelementEnd()();
189
- i0.ɵɵelementStart(12, "div", 37);
190
- i0.ɵɵlistener("dragover", function ConversationListComponent_Conditional_5_Template_div_dragover_12_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onUngroupedDragOver($event)); })("dragleave", function ConversationListComponent_Conditional_5_Template_div_dragleave_12_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDragLeave("ungrouped")); })("drop", function ConversationListComponent_Conditional_5_Template_div_drop_12_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onUngroupedDrop($event)); });
191
- i0.ɵɵelementStart(13, "div", 28);
192
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_div_click_13_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleUngrouped()); });
193
- i0.ɵɵelementStart(14, "div", 29);
194
- i0.ɵɵelement(15, "i", 30);
276
+ i0.ɵɵelementStart(12, "div", 57);
277
+ i0.ɵɵlistener("dragover", function ConversationListComponent_Conditional_5_Template_div_dragover_12_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnUngroupedDragOver($event)); })("dragleave", function ConversationListComponent_Conditional_5_Template_div_dragleave_12_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave("ungrouped")); })("drop", function ConversationListComponent_Conditional_5_Template_div_drop_12_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnUngroupedDrop($event)); });
278
+ i0.ɵɵelementStart(13, "div", 48);
279
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_5_Template_div_click_13_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleUngrouped()); });
280
+ i0.ɵɵelementStart(14, "div", 49);
281
+ i0.ɵɵelement(15, "i", 50);
195
282
  i0.ɵɵelementStart(16, "span");
196
283
  i0.ɵɵtext(17);
197
284
  i0.ɵɵelementEnd()()();
198
- i0.ɵɵelementStart(18, "div", 26);
199
- i0.ɵɵrepeaterCreate(19, ConversationListComponent_Conditional_5_For_20_Template, 1, 4, "ng-container", 27, _forTrack0);
285
+ i0.ɵɵelementStart(18, "div", 46);
286
+ i0.ɵɵrepeaterCreate(19, ConversationListComponent_Conditional_5_For_20_Template, 1, 4, "ng-container", 47, _forTrack0);
200
287
  i0.ɵɵelementEnd()();
201
288
  } if (rf & 2) {
202
289
  const ctx_r1 = i0.ɵɵnextContext();
203
290
  i0.ɵɵadvance();
204
- i0.ɵɵclassProp("expanded", ctx_r1.foldersExpanded)("drag-over", ctx_r1.dragOverTargetId === "folders-root");
291
+ i0.ɵɵclassProp("expanded", ctx_r1.FoldersExpanded)("drag-over", ctx_r1.DragOverTargetId === "folders-root");
205
292
  i0.ɵɵadvance(7);
206
- i0.ɵɵclassProp("expanded", ctx_r1.foldersExpanded);
293
+ i0.ɵɵclassProp("expanded", ctx_r1.FoldersExpanded);
207
294
  i0.ɵɵadvance();
208
- i0.ɵɵrepeater(ctx_r1.folderTree);
295
+ i0.ɵɵrepeater(ctx_r1.FolderTree);
209
296
  i0.ɵɵadvance(2);
210
- i0.ɵɵconditional(ctx_r1.folderTree.length === 0 ? 11 : -1);
297
+ i0.ɵɵconditional(ctx_r1.FolderTree.length === 0 ? 11 : -1);
211
298
  i0.ɵɵadvance();
212
- i0.ɵɵclassProp("drag-over", ctx_r1.dragOverTargetId === "ungrouped");
299
+ i0.ɵɵclassProp("drag-over", ctx_r1.DragOverTargetId === "ungrouped");
213
300
  i0.ɵɵadvance();
214
- i0.ɵɵclassProp("expanded", ctx_r1.ungroupedExpanded);
301
+ i0.ɵɵclassProp("expanded", ctx_r1.UngroupedExpanded);
215
302
  i0.ɵɵadvance(4);
216
- i0.ɵɵtextInterpolate(ctx_r1.folderTree.length > 0 ? "Ungrouped" : "Messages");
303
+ i0.ɵɵtextInterpolate(ctx_r1.FolderTree.length > 0 ? "Ungrouped" : "Messages");
217
304
  i0.ɵɵadvance();
218
- i0.ɵɵclassProp("expanded", ctx_r1.ungroupedExpanded);
305
+ i0.ɵɵclassProp("expanded", ctx_r1.UngroupedExpanded);
219
306
  i0.ɵɵadvance();
220
- i0.ɵɵrepeater(ctx_r1.ungroupedConversations);
307
+ i0.ɵɵrepeater(ctx_r1.UngroupedConversations);
221
308
  } }
222
309
  function ConversationListComponent_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
223
- const _r14 = i0.ɵɵgetCurrentView();
224
- i0.ɵɵelementStart(0, "div", 28);
225
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_6_Conditional_1_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleDirectMessages()); });
226
- i0.ɵɵelementStart(1, "div", 29);
227
- i0.ɵɵelement(2, "i", 30);
310
+ const _r17 = i0.ɵɵgetCurrentView();
311
+ i0.ɵɵelementStart(0, "div", 48);
312
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_6_Conditional_1_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleDirectMessages()); });
313
+ i0.ɵɵelementStart(1, "div", 49);
314
+ i0.ɵɵelement(2, "i", 50);
228
315
  i0.ɵɵelementStart(3, "span");
229
316
  i0.ɵɵtext(4, "Messages");
230
317
  i0.ɵɵelementEnd()()();
231
318
  } if (rf & 2) {
232
319
  const ctx_r1 = i0.ɵɵnextContext(2);
233
- i0.ɵɵclassProp("expanded", ctx_r1.directMessagesExpanded);
320
+ i0.ɵɵclassProp("expanded", ctx_r1.DirectMessagesExpanded);
234
321
  } }
235
322
  function ConversationListComponent_Conditional_6_For_4_Template(rf, ctx) { if (rf & 1) {
236
- i0.ɵɵelementContainer(0, 27);
323
+ i0.ɵɵelementContainer(0, 47);
237
324
  } if (rf & 2) {
238
- const conversation_r15 = ctx.$implicit;
325
+ const conversation_r18 = ctx.$implicit;
239
326
  i0.ɵɵnextContext(2);
240
- const conversationItem_r9 = i0.ɵɵreference(11);
241
- i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r9)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, conversation_r15));
327
+ const conversationItem_r12 = i0.ɵɵreference(11);
328
+ i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c2, conversation_r18));
242
329
  } }
243
330
  function ConversationListComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
244
- i0.ɵɵelementStart(0, "div", 7);
245
- i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_6_Conditional_1_Template, 5, 2, "div", 25);
246
- i0.ɵɵelementStart(2, "div", 26);
247
- i0.ɵɵrepeaterCreate(3, ConversationListComponent_Conditional_6_For_4_Template, 1, 4, "ng-container", 27, _forTrack0);
331
+ i0.ɵɵelementStart(0, "div", 9);
332
+ i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_6_Conditional_1_Template, 5, 2, "div", 45);
333
+ i0.ɵɵelementStart(2, "div", 46);
334
+ i0.ɵɵrepeaterCreate(3, ConversationListComponent_Conditional_6_For_4_Template, 1, 4, "ng-container", 47, _forTrack0);
248
335
  i0.ɵɵelementEnd()();
249
336
  } if (rf & 2) {
250
337
  const ctx_r1 = i0.ɵɵnextContext();
251
338
  i0.ɵɵadvance();
252
- i0.ɵɵconditional(ctx_r1.showSectionHeaders ? 1 : -1);
339
+ i0.ɵɵconditional(ctx_r1.ShowSectionHeaders ? 1 : -1);
253
340
  i0.ɵɵadvance();
254
- i0.ɵɵclassProp("expanded", !ctx_r1.showSectionHeaders || ctx_r1.directMessagesExpanded);
341
+ i0.ɵɵclassProp("expanded", !ctx_r1.ShowSectionHeaders || ctx_r1.DirectMessagesExpanded);
255
342
  i0.ɵɵadvance();
256
- i0.ɵɵrepeater(ctx_r1.unpinnedConversations);
257
- } }
258
- function ConversationListComponent_Conditional_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
259
- const _r17 = i0.ɵɵgetCurrentView();
260
- i0.ɵɵelementStart(0, "button", 45);
261
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_7_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.selectAll()); });
262
- i0.ɵɵtext(1, "Select All");
263
- i0.ɵɵelementEnd();
264
- } }
265
- function ConversationListComponent_Conditional_7_Conditional_5_Template(rf, ctx) { if (rf & 1) {
266
- const _r18 = i0.ɵɵgetCurrentView();
267
- i0.ɵɵelementStart(0, "button", 45);
268
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_7_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.deselectAll()); });
269
- i0.ɵɵtext(1, "Deselect All");
270
- i0.ɵɵelementEnd();
343
+ i0.ɵɵrepeater(ctx_r1.UnpinnedConversations);
271
344
  } }
272
345
  function ConversationListComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
273
- const _r16 = i0.ɵɵgetCurrentView();
274
- i0.ɵɵelementStart(0, "div", 8)(1, "div", 38)(2, "span", 39);
346
+ const _r19 = i0.ɵɵgetCurrentView();
347
+ i0.ɵɵelementStart(0, "button", 58);
348
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.EscalateSearch()); });
349
+ i0.ɵɵelement(1, "i", 59);
350
+ i0.ɵɵelementStart(2, "span", 60);
275
351
  i0.ɵɵtext(3);
276
352
  i0.ɵɵelementEnd();
277
- i0.ɵɵconditionalCreate(4, ConversationListComponent_Conditional_7_Conditional_4_Template, 2, 0, "button", 40)(5, ConversationListComponent_Conditional_7_Conditional_5_Template, 2, 0, "button", 40);
278
- i0.ɵɵelementEnd();
279
- i0.ɵɵelementStart(6, "div", 41)(7, "button", 42);
280
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_7_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.bulkDeleteConversations()); });
281
- i0.ɵɵelement(8, "i", 43);
282
- i0.ɵɵtext(9);
353
+ i0.ɵɵelement(4, "i", 61);
283
354
  i0.ɵɵelementEnd();
284
- i0.ɵɵelementStart(10, "button", 44);
285
- i0.ɵɵlistener("click", function ConversationListComponent_Conditional_7_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleSelectionMode()); });
286
- i0.ɵɵtext(11, " Cancel ");
287
- i0.ɵɵelementEnd()()();
288
355
  } if (rf & 2) {
289
356
  const ctx_r1 = i0.ɵɵnextContext();
290
357
  i0.ɵɵadvance(3);
291
- i0.ɵɵtextInterpolate1("", ctx_r1.selectedConversationIds.size, " selected");
292
- i0.ɵɵadvance();
293
- i0.ɵɵconditional(ctx_r1.selectedConversationIds.size < ctx_r1.filteredConversations.length ? 4 : 5);
294
- i0.ɵɵadvance(3);
295
- i0.ɵɵproperty("disabled", ctx_r1.selectedConversationIds.size === 0);
296
- i0.ɵɵadvance(2);
297
- i0.ɵɵtextInterpolate1(" Delete (", ctx_r1.selectedConversationIds.size, ") ");
358
+ i0.ɵɵtextInterpolate1("Search all of Chat for \u201C", ctx_r1.SearchQuery, "\u201D");
298
359
  } }
299
- function ConversationListComponent_ng_template_8_Conditional_14_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
300
- i0.ɵɵelementContainer(0, 27);
360
+ function ConversationListComponent_ng_template_8_Conditional_5_Template(rf, ctx) { if (rf & 1) {
361
+ i0.ɵɵelementStart(0, "span", 65);
362
+ i0.ɵɵelement(1, "i", 69);
363
+ i0.ɵɵelementEnd();
364
+ } }
365
+ function ConversationListComponent_ng_template_8_Conditional_9_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
366
+ i0.ɵɵelementContainer(0, 47);
301
367
  } if (rf & 2) {
302
- const child_r21 = i0.ɵɵnextContext().$implicit;
368
+ const child_r22 = i0.ɵɵnextContext().$implicit;
303
369
  i0.ɵɵnextContext(3);
304
- const folderNode_r12 = i0.ɵɵreference(9);
305
- i0.ɵɵproperty("ngTemplateOutlet", folderNode_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, child_r21));
370
+ const folderNode_r15 = i0.ɵɵreference(9);
371
+ i0.ɵɵproperty("ngTemplateOutlet", folderNode_r15)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c2, child_r22));
306
372
  } }
307
- function ConversationListComponent_ng_template_8_Conditional_14_For_2_Template(rf, ctx) { if (rf & 1) {
308
- i0.ɵɵconditionalCreate(0, ConversationListComponent_ng_template_8_Conditional_14_For_2_Conditional_0_Template, 1, 4, "ng-container", 27);
373
+ function ConversationListComponent_ng_template_8_Conditional_9_For_2_Template(rf, ctx) { if (rf & 1) {
374
+ i0.ɵɵconditionalCreate(0, ConversationListComponent_ng_template_8_Conditional_9_For_2_Conditional_0_Template, 1, 4, "ng-container", 47);
309
375
  } if (rf & 2) {
310
- const child_r21 = ctx.$implicit;
376
+ const child_r22 = ctx.$implicit;
311
377
  const ctx_r1 = i0.ɵɵnextContext(3);
312
- i0.ɵɵconditional(!ctx_r1.isSearching || child_r21.hasContent ? 0 : -1);
378
+ i0.ɵɵconditional(!ctx_r1.IsSearching || child_r22.hasContent ? 0 : -1);
313
379
  } }
314
- function ConversationListComponent_ng_template_8_Conditional_14_For_4_Template(rf, ctx) { if (rf & 1) {
315
- i0.ɵɵelementContainer(0, 27);
380
+ function ConversationListComponent_ng_template_8_Conditional_9_For_4_Template(rf, ctx) { if (rf & 1) {
381
+ i0.ɵɵelementContainer(0, 47);
316
382
  } if (rf & 2) {
317
- const conversation_r22 = ctx.$implicit;
318
- const node_r20 = i0.ɵɵnextContext(2).$implicit;
383
+ const conversation_r23 = ctx.$implicit;
384
+ const node_r21 = i0.ɵɵnextContext(2).$implicit;
319
385
  i0.ɵɵnextContext();
320
- const conversationItem_r9 = i0.ɵɵreference(11);
321
- i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r9)("ngTemplateOutletContext", i0.ɵɵpureFunction2(2, _c1, conversation_r22, node_r20.depth + 1));
386
+ const conversationItem_r12 = i0.ɵɵreference(11);
387
+ i0.ɵɵproperty("ngTemplateOutlet", conversationItem_r12)("ngTemplateOutletContext", i0.ɵɵpureFunction2(2, _c3, conversation_r23, node_r21.depth + 1));
322
388
  } }
323
- function ConversationListComponent_ng_template_8_Conditional_14_Conditional_5_Template(rf, ctx) { if (rf & 1) {
324
- i0.ɵɵelementStart(0, "div", 36);
389
+ function ConversationListComponent_ng_template_8_Conditional_9_Conditional_5_Template(rf, ctx) { if (rf & 1) {
390
+ i0.ɵɵelementStart(0, "div", 56);
325
391
  i0.ɵɵtext(1, "Empty \u2014 drop a conversation here");
326
392
  i0.ɵɵelementEnd();
327
393
  } if (rf & 2) {
328
- const node_r20 = i0.ɵɵnextContext(2).$implicit;
329
- i0.ɵɵstyleProp("padding-left", 26 + node_r20.depth * 14, "px");
394
+ const node_r21 = i0.ɵɵnextContext(2).$implicit;
395
+ i0.ɵɵstyleProp("padding-left", 26 + node_r21.depth * 14, "px");
330
396
  } }
331
- function ConversationListComponent_ng_template_8_Conditional_14_Template(rf, ctx) { if (rf & 1) {
332
- i0.ɵɵelementStart(0, "div", 55);
333
- i0.ɵɵrepeaterCreate(1, ConversationListComponent_ng_template_8_Conditional_14_For_2_Template, 1, 1, null, null, _forTrack1);
334
- i0.ɵɵrepeaterCreate(3, ConversationListComponent_ng_template_8_Conditional_14_For_4_Template, 1, 5, "ng-container", 27, _forTrack0);
335
- i0.ɵɵconditionalCreate(5, ConversationListComponent_ng_template_8_Conditional_14_Conditional_5_Template, 2, 2, "div", 56);
397
+ function ConversationListComponent_ng_template_8_Conditional_9_Template(rf, ctx) { if (rf & 1) {
398
+ i0.ɵɵelementStart(0, "div", 68);
399
+ i0.ɵɵrepeaterCreate(1, ConversationListComponent_ng_template_8_Conditional_9_For_2_Template, 1, 1, null, null, _forTrack1);
400
+ i0.ɵɵrepeaterCreate(3, ConversationListComponent_ng_template_8_Conditional_9_For_4_Template, 1, 5, "ng-container", 47, _forTrack0);
401
+ i0.ɵɵconditionalCreate(5, ConversationListComponent_ng_template_8_Conditional_9_Conditional_5_Template, 2, 2, "div", 70);
336
402
  i0.ɵɵelementEnd();
337
403
  } if (rf & 2) {
338
- const node_r20 = i0.ɵɵnextContext().$implicit;
404
+ const node_r21 = i0.ɵɵnextContext().$implicit;
339
405
  const ctx_r1 = i0.ɵɵnextContext();
340
406
  i0.ɵɵadvance();
341
- i0.ɵɵrepeater(node_r20.children);
407
+ i0.ɵɵrepeater(node_r21.children);
342
408
  i0.ɵɵadvance(2);
343
- i0.ɵɵrepeater(node_r20.conversations);
409
+ i0.ɵɵrepeater(node_r21.conversations);
344
410
  i0.ɵɵadvance(2);
345
- i0.ɵɵconditional(node_r20.totalCount === 0 && !ctx_r1.isSearching ? 5 : -1);
411
+ i0.ɵɵconditional(node_r21.totalCount === 0 && !ctx_r1.IsSearching ? 5 : -1);
346
412
  } }
347
413
  function ConversationListComponent_ng_template_8_Template(rf, ctx) { if (rf & 1) {
348
- const _r19 = i0.ɵɵgetCurrentView();
349
- i0.ɵɵelementStart(0, "div", 46);
350
- i0.ɵɵlistener("dragstart", function ConversationListComponent_ng_template_8_Template_div_dragstart_0_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFolderDragStart(node_r20, $event)); })("dragend", function ConversationListComponent_ng_template_8_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFolderDragEnd()); })("click", function ConversationListComponent_ng_template_8_Template_div_click_0_listener() { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleFolder(node_r20.project.ID)); })("dragover", function ConversationListComponent_ng_template_8_Template_div_dragover_0_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFolderDragOver(node_r20.project.ID, $event)); })("dragleave", function ConversationListComponent_ng_template_8_Template_div_dragleave_0_listener() { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDragLeave(node_r20.project.ID)); })("drop", function ConversationListComponent_ng_template_8_Template_div_drop_0_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFolderDrop(node_r20.project, $event)); });
351
- i0.ɵɵelement(1, "i", 47)(2, "i");
352
- i0.ɵɵelementStart(3, "span", 48);
414
+ const _r20 = i0.ɵɵgetCurrentView();
415
+ i0.ɵɵelementStart(0, "div", 62);
416
+ i0.ɵɵlistener("dragstart", function ConversationListComponent_ng_template_8_Template_div_dragstart_0_listener($event) { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFolderDragStart(node_r21, $event)); })("dragend", function ConversationListComponent_ng_template_8_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFolderDragEnd()); })("click", function ConversationListComponent_ng_template_8_Template_div_click_0_listener() { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleFolder(node_r21.project.ID)); })("dragover", function ConversationListComponent_ng_template_8_Template_div_dragover_0_listener($event) { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFolderDragOver(node_r21.project.ID, $event)); })("dragleave", function ConversationListComponent_ng_template_8_Template_div_dragleave_0_listener() { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave(node_r21.project.ID)); })("drop", function ConversationListComponent_ng_template_8_Template_div_drop_0_listener($event) { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFolderDrop(node_r21.project, $event)); })("contextmenu", function ConversationListComponent_ng_template_8_Template_div_contextmenu_0_listener($event) { const node_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFolderContextMenu(node_r21.project, $event)); });
417
+ i0.ɵɵelement(1, "i", 63)(2, "i");
418
+ i0.ɵɵelementStart(3, "span", 64);
353
419
  i0.ɵɵtext(4);
354
420
  i0.ɵɵelementEnd();
355
- i0.ɵɵelementStart(5, "span", 49);
356
- i0.ɵɵtext(6);
357
- i0.ɵɵelementEnd();
358
- i0.ɵɵelementStart(7, "div", 50);
359
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_8_Template_div_click_7_listener($event) { return $event.stopPropagation(); });
360
- i0.ɵɵelementStart(8, "button", 51);
361
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_8_Template_button_click_8_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.createFolder(node_r20.project.ID, $event)); });
362
- i0.ɵɵelement(9, "i", 35);
363
- i0.ɵɵelementEnd();
364
- i0.ɵɵelementStart(10, "button", 52);
365
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_8_Template_button_click_10_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.editFolder(node_r20.project, $event)); });
366
- i0.ɵɵelement(11, "i", 53);
367
- i0.ɵɵelementEnd();
368
- i0.ɵɵelementStart(12, "button", 54);
369
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_8_Template_button_click_12_listener($event) { const node_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.deleteFolder(node_r20.project, $event)); });
370
- i0.ɵɵelement(13, "i", 43);
371
- i0.ɵɵelementEnd()()();
372
- i0.ɵɵconditionalCreate(14, ConversationListComponent_ng_template_8_Conditional_14_Template, 6, 1, "div", 55);
421
+ i0.ɵɵconditionalCreate(5, ConversationListComponent_ng_template_8_Conditional_5_Template, 2, 0, "span", 65);
422
+ i0.ɵɵelement(6, "span", 66);
423
+ i0.ɵɵelementStart(7, "span", 67);
424
+ i0.ɵɵtext(8);
425
+ i0.ɵɵelementEnd()();
426
+ i0.ɵɵconditionalCreate(9, ConversationListComponent_ng_template_8_Conditional_9_Template, 6, 1, "div", 68);
373
427
  } if (rf & 2) {
374
- const node_r20 = ctx.$implicit;
428
+ const node_r21 = ctx.$implicit;
375
429
  const ctx_r1 = i0.ɵɵnextContext();
376
- i0.ɵɵstyleProp("padding-left", 12 + node_r20.depth * 14, "px");
377
- i0.ɵɵclassProp("drag-over", ctx_r1.dragOverTargetId === node_r20.project.ID)("dragging", ctx_r1.draggedFolderId === node_r20.project.ID);
378
- i0.ɵɵproperty("draggable", true)("title", node_r20.project.Name);
430
+ i0.ɵɵstyleProp("padding-left", 12 + node_r21.depth * 14, "px");
431
+ i0.ɵɵclassProp("drag-over", ctx_r1.DragOverTargetId === node_r21.project.ID)("dragging", ctx_r1.DraggedFolderId === node_r21.project.ID);
432
+ i0.ɵɵproperty("draggable", true)("title", node_r21.project.Name);
379
433
  i0.ɵɵadvance();
380
- i0.ɵɵclassProp("expanded", ctx_r1.isFolderExpanded(node_r20.project.ID));
434
+ i0.ɵɵclassProp("expanded", ctx_r1.IsFolderExpanded(node_r21.project.ID));
381
435
  i0.ɵɵadvance();
382
- i0.ɵɵclassMap(i0.ɵɵinterpolate1("fas ", node_r20.project.Icon || "fa-folder", " folder-icon"));
383
- i0.ɵɵstyleProp("color", node_r20.project.Color || null);
436
+ i0.ɵɵclassMap(i0.ɵɵinterpolate1("fas ", node_r21.project.Icon || "fa-folder", " folder-icon"));
437
+ i0.ɵɵstyleProp("color", node_r21.project.Color || null);
384
438
  i0.ɵɵadvance(2);
385
- i0.ɵɵtextInterpolate(node_r20.project.Name);
386
- i0.ɵɵadvance(2);
387
- i0.ɵɵtextInterpolate(node_r20.totalCount);
388
- i0.ɵɵadvance(8);
389
- i0.ɵɵconditional(ctx_r1.isFolderExpanded(node_r20.project.ID) ? 14 : -1);
439
+ i0.ɵɵtextInterpolate(node_r21.project.Name);
440
+ i0.ɵɵadvance();
441
+ i0.ɵɵconditional(!node_r21.project.OwnerUserID ? 5 : -1);
442
+ i0.ɵɵadvance(3);
443
+ i0.ɵɵtextInterpolate(node_r21.totalCount);
444
+ i0.ɵɵadvance();
445
+ i0.ɵɵconditional(ctx_r1.IsFolderExpanded(node_r21.project.ID) ? 9 : -1);
390
446
  } }
391
- function ConversationListComponent_ng_template_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
392
- const _r25 = i0.ɵɵgetCurrentView();
393
- i0.ɵɵelementStart(0, "div", 58)(1, "input", 68);
394
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_1_Template_input_click_1_listener($event) { i0.ɵɵrestoreView(_r25); const conversation_r24 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); $event.stopPropagation(); return i0.ɵɵresetView(ctx_r1.toggleConversationSelection(conversation_r24.ID)); });
395
- i0.ɵɵelementEnd()();
447
+ function ConversationListComponent_ng_template_10_Conditional_4_Template(rf, ctx) { if (rf & 1) {
448
+ i0.ɵɵelementStart(0, "div", 75);
449
+ i0.ɵɵelement(1, "i", 85);
450
+ i0.ɵɵelementEnd();
451
+ } }
452
+ function ConversationListComponent_ng_template_10_Conditional_10_Template(rf, ctx) { if (rf & 1) {
453
+ i0.ɵɵelement(0, "i", 80);
396
454
  } if (rf & 2) {
397
- const conversation_r24 = i0.ɵɵnextContext().$implicit;
455
+ const conversation_r25 = i0.ɵɵnextContext().$implicit;
398
456
  const ctx_r1 = i0.ɵɵnextContext();
399
- i0.ɵɵadvance();
400
- i0.ɵɵproperty("checked", ctx_r1.selectedConversationIds.has(conversation_r24.ID));
457
+ i0.ɵɵproperty("title", ctx_r1.SharedWithMeTooltip(conversation_r25));
401
458
  } }
402
- function ConversationListComponent_ng_template_10_Conditional_3_Template(rf, ctx) { if (rf & 1) {
403
- i0.ɵɵelementStart(0, "div", 60);
404
- i0.ɵɵelement(1, "i", 69);
459
+ function ConversationListComponent_ng_template_10_Template(rf, ctx) { if (rf & 1) {
460
+ const _r24 = i0.ɵɵgetCurrentView();
461
+ i0.ɵɵelementStart(0, "div", 71);
462
+ i0.ɵɵlistener("dragstart", function ConversationListComponent_ng_template_10_Template_div_dragstart_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnConversationDragStart(conversation_r25, $event)); })("dragend", function ConversationListComponent_ng_template_10_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnConversationDragEnd()); })("dragover", function ConversationListComponent_ng_template_10_Template_div_dragover_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnConversationRowDragOver(conversation_r25, $event)); })("dragleave", function ConversationListComponent_ng_template_10_Template_div_dragleave_0_listener() { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave(ctx_r1.ConversationDropTargetId(conversation_r25))); })("drop", function ConversationListComponent_ng_template_10_Template_div_drop_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnConversationRowDrop(conversation_r25, $event)); })("pointerdown", function ConversationListComponent_ng_template_10_Template_div_pointerdown_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRowPointerDown(conversation_r25, $event)); })("pointermove", function ConversationListComponent_ng_template_10_Template_div_pointermove_0_listener($event) { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRowPointerMove($event)); })("pointerup", function ConversationListComponent_ng_template_10_Template_div_pointerup_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CancelLongPress()); })("pointercancel", function ConversationListComponent_ng_template_10_Template_div_pointercancel_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CancelLongPress()); })("click", function ConversationListComponent_ng_template_10_Template_div_click_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.HandleConversationClick(conversation_r25, $event)); })("contextmenu", function ConversationListComponent_ng_template_10_Template_div_contextmenu_0_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnConversationContextMenu(conversation_r25, $event)); });
463
+ i0.ɵɵelementStart(1, "button", 72);
464
+ i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Template_button_click_1_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnRowCheckboxClick(conversation_r25, $event)); });
465
+ i0.ɵɵelement(2, "i", 73);
405
466
  i0.ɵɵelementEnd();
406
- } }
407
- function ConversationListComponent_ng_template_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
408
- i0.ɵɵelement(0, "i", 65);
467
+ i0.ɵɵelementStart(3, "div", 74);
468
+ i0.ɵɵconditionalCreate(4, ConversationListComponent_ng_template_10_Conditional_4_Template, 2, 0, "div", 75);
469
+ i0.ɵɵelementStart(5, "div", 76);
470
+ i0.ɵɵelement(6, "mj-notification-badge", 77);
471
+ i0.ɵɵelementEnd()();
472
+ i0.ɵɵelementStart(7, "div", 78)(8, "div", 79);
473
+ i0.ɵɵtext(9);
474
+ i0.ɵɵconditionalCreate(10, ConversationListComponent_ng_template_10_Conditional_10_Template, 1, 1, "i", 80);
475
+ i0.ɵɵelementEnd();
476
+ i0.ɵɵelementStart(11, "div", 81);
477
+ i0.ɵɵtext(12);
478
+ i0.ɵɵelementEnd()();
479
+ i0.ɵɵelementStart(13, "div", 82)(14, "button", 83);
480
+ i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Template_button_click_14_listener($event) { const conversation_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OpenRowMenu(conversation_r25, $event)); });
481
+ i0.ɵɵelement(15, "i", 84);
482
+ i0.ɵɵelementEnd()()();
409
483
  } if (rf & 2) {
410
- const conversation_r24 = i0.ɵɵnextContext().$implicit;
484
+ const conversation_r25 = ctx.$implicit;
485
+ const depth_r26 = ctx.depth;
411
486
  const ctx_r1 = i0.ɵɵnextContext();
412
- i0.ɵɵproperty("title", ctx_r1.sharedWithMeTooltip(conversation_r24));
487
+ i0.ɵɵstyleProp("padding-left", depth_r26 ? 16 + depth_r26 * 14 : 16, "px");
488
+ i0.ɵɵclassProp("active", ctx_r1.IsConversationActive(conversation_r25))("selected", ctx_r1.IsConversationSelected(conversation_r25))("renamed", ctx_r1.IsConversationRenamed(conversation_r25))("dragging", ctx_r1.IsConversationDragging(conversation_r25));
489
+ i0.ɵɵproperty("draggable", ctx_r1.CanChange(conversation_r25));
490
+ i0.ɵɵadvance();
491
+ i0.ɵɵstyleProp("left", (depth_r26 || 0) * 14 + 4, "px");
492
+ i0.ɵɵclassProp("checked", ctx_r1.IsConversationSelected(conversation_r25));
493
+ i0.ɵɵattribute("aria-checked", ctx_r1.IsConversationSelected(conversation_r25))("aria-label", "Select " + (conversation_r25.Name || "conversation"));
494
+ i0.ɵɵadvance(3);
495
+ i0.ɵɵconditional(ctx_r1.HasActiveTasks(conversation_r25.ID) ? 4 : -1);
496
+ i0.ɵɵadvance(2);
497
+ i0.ɵɵproperty("conversationId", conversation_r25.ID);
498
+ i0.ɵɵadvance();
499
+ i0.ɵɵproperty("title", conversation_r25.Name + (conversation_r25.Description ? "\n" + conversation_r25.Description : ""));
500
+ i0.ɵɵadvance(2);
501
+ i0.ɵɵtextInterpolate1(" ", conversation_r25.Name, " ");
502
+ i0.ɵɵadvance();
503
+ i0.ɵɵconditional(ctx_r1.IsSharedWithMe(conversation_r25) ? 10 : -1);
504
+ i0.ɵɵadvance(2);
505
+ i0.ɵɵtextInterpolate(conversation_r25.Description);
413
506
  } }
414
- function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_For_11_Template(rf, ctx) { if (rf & 1) {
415
- const _r28 = i0.ɵɵgetCurrentView();
416
- i0.ɵɵelementStart(0, "button", 78);
417
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_For_11_Template_button_click_0_listener() { const f_r29 = i0.ɵɵrestoreView(_r28).$implicit; const conversation_r24 = i0.ɵɵnextContext(4).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.selectMoveTarget(conversation_r24, f_r29.project.ID)); });
507
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_0_For_11_Template(rf, ctx) { if (rf & 1) {
508
+ const _r29 = i0.ɵɵgetCurrentView();
509
+ i0.ɵɵelementStart(0, "button", 91);
510
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_0_For_11_Template_button_click_0_listener() { const f_r30 = i0.ɵɵrestoreView(_r29).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ContextMoveToFolder(f_r30.project.ID)); });
418
511
  i0.ɵɵelement(1, "i");
419
512
  i0.ɵɵelementStart(2, "span");
420
513
  i0.ɵɵtext(3);
421
514
  i0.ɵɵelementEnd()();
422
515
  } if (rf & 2) {
423
- const f_r29 = ctx.$implicit;
424
- const conversation_r24 = i0.ɵɵnextContext(4).$implicit;
425
- const ctx_r1 = i0.ɵɵnextContext();
426
- i0.ɵɵstyleProp("padding-left", 14 + f_r29.depth * 12, "px");
427
- i0.ɵɵclassProp("current", ctx_r1.IsInFolder(conversation_r24, f_r29.project.ID));
516
+ const f_r30 = ctx.$implicit;
517
+ const ctx_r1 = i0.ɵɵnextContext(4);
518
+ i0.ɵɵstyleProp("padding-left", 14 + f_r30.depth * 12, "px");
519
+ i0.ɵɵclassProp("current", ctx_r1.IsSingleTargetInFolder(f_r30.project.ID));
428
520
  i0.ɵɵadvance();
429
- i0.ɵɵclassMap(i0.ɵɵinterpolate1("fas ", f_r29.project.Icon || "fa-folder"));
430
- i0.ɵɵstyleProp("color", f_r29.project.Color || null);
521
+ i0.ɵɵclassMap(i0.ɵɵinterpolate1("fas ", f_r30.project.Icon || "fa-folder"));
522
+ i0.ɵɵstyleProp("color", f_r30.project.Color || null);
431
523
  i0.ɵɵadvance(2);
432
- i0.ɵɵtextInterpolate(f_r29.project.Name);
524
+ i0.ɵɵtextInterpolate(f_r30.project.Name);
433
525
  } }
434
- function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
435
- const _r27 = i0.ɵɵgetCurrentView();
436
- i0.ɵɵelementStart(0, "button", 74);
437
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.closeMoveSubmenu($event)); });
438
- i0.ɵɵelement(1, "i", 75);
526
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
527
+ const _r28 = i0.ɵɵgetCurrentView();
528
+ i0.ɵɵelementStart(0, "button", 87);
529
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_0_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.CloseMoveSubmenu($event)); });
530
+ i0.ɵɵelement(1, "i", 88);
439
531
  i0.ɵɵelementStart(2, "span");
440
532
  i0.ɵɵtext(3, "Move to folder");
441
533
  i0.ɵɵelementEnd()();
442
- i0.ɵɵelement(4, "div", 76);
443
- i0.ɵɵelementStart(5, "div", 77)(6, "button", 78);
444
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r27); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.selectMoveTarget(conversation_r24, null)); });
445
- i0.ɵɵelement(7, "i", 79);
534
+ i0.ɵɵelement(4, "div", 89);
535
+ i0.ɵɵelementStart(5, "div", 90)(6, "button", 91);
536
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ContextMoveToFolder(null)); });
537
+ i0.ɵɵelement(7, "i", 92);
446
538
  i0.ɵɵelementStart(8, "span");
447
539
  i0.ɵɵtext(9, "No folder");
448
540
  i0.ɵɵelementEnd()();
449
- i0.ɵɵrepeaterCreate(10, ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_For_11_Template, 4, 10, "button", 80, _forTrack1);
541
+ i0.ɵɵrepeaterCreate(10, ConversationListComponent_Conditional_13_Case_2_Conditional_0_For_11_Template, 4, 10, "button", 93, _forTrack1);
450
542
  i0.ɵɵelementEnd();
451
- i0.ɵɵelement(12, "div", 76);
452
- i0.ɵɵelementStart(13, "button", 78);
453
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_Template_button_click_13_listener($event) { i0.ɵɵrestoreView(_r27); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.createFolderForConversation(conversation_r24, $event)); });
454
- i0.ɵɵelement(14, "i", 35);
543
+ i0.ɵɵelement(12, "div", 89);
544
+ i0.ɵɵelementStart(13, "button", 91);
545
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_0_Template_button_click_13_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ContextMoveToNewFolder($event)); });
546
+ i0.ɵɵelement(14, "i", 55);
455
547
  i0.ɵɵelementStart(15, "span");
456
548
  i0.ɵɵtext(16, "New folder\u2026");
457
549
  i0.ɵɵelementEnd()();
458
550
  } if (rf & 2) {
459
- const conversation_r24 = i0.ɵɵnextContext(3).$implicit;
460
- const ctx_r1 = i0.ɵɵnextContext();
551
+ const ctx_r1 = i0.ɵɵnextContext(3);
461
552
  i0.ɵɵadvance(6);
462
- i0.ɵɵclassProp("current", !conversation_r24.ProjectID);
553
+ i0.ɵɵclassProp("current", ctx_r1.IsSingleTargetInFolder(null));
554
+ i0.ɵɵadvance(4);
555
+ i0.ɵɵrepeater(ctx_r1.FlatFolders);
556
+ } }
557
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
558
+ const _r32 = i0.ɵɵgetCurrentView();
559
+ i0.ɵɵelementStart(0, "div", 99);
560
+ i0.ɵɵtext(1);
561
+ i0.ɵɵelementEnd();
562
+ i0.ɵɵelementStart(2, "button", 95);
563
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_0_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ContextSetPinned(true)); });
564
+ i0.ɵɵelement(3, "i", 20);
565
+ i0.ɵɵelementStart(4, "span");
566
+ i0.ɵɵtext(5, "Pin");
567
+ i0.ɵɵelementEnd()();
568
+ i0.ɵɵelementStart(6, "button", 95);
569
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r32); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ContextSetPinned(false)); });
570
+ i0.ɵɵelement(7, "i", 100);
571
+ i0.ɵɵelementStart(8, "span");
572
+ i0.ɵɵtext(9, "Unpin");
573
+ i0.ɵɵelementEnd()();
574
+ } if (rf & 2) {
575
+ const ctx_r1 = i0.ɵɵnextContext(4);
576
+ i0.ɵɵadvance();
577
+ i0.ɵɵtextInterpolate1("", ctx_r1.ContextMenu.targets.length, " selected");
578
+ i0.ɵɵadvance();
579
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets));
580
+ i0.ɵɵattribute("title", ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets) ? null : ctx_r1.ChangeRefusedReason);
463
581
  i0.ɵɵadvance(4);
464
- i0.ɵɵrepeater(ctx_r1.flatFolders);
582
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets));
583
+ i0.ɵɵattribute("title", ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets) ? null : ctx_r1.ChangeRefusedReason);
465
584
  } }
466
- function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
467
- const _r30 = i0.ɵɵgetCurrentView();
468
- i0.ɵɵelementStart(0, "button", 78);
469
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r30); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.togglePin(conversation_r24, $event)); });
470
- i0.ɵɵelement(1, "i", 81);
585
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
586
+ const _r33 = i0.ɵɵgetCurrentView();
587
+ i0.ɵɵelementStart(0, "button", 95);
588
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r33); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ContextTogglePin()); });
589
+ i0.ɵɵelement(1, "i", 20);
471
590
  i0.ɵɵelementStart(2, "span");
472
591
  i0.ɵɵtext(3);
473
592
  i0.ɵɵelementEnd()();
474
- i0.ɵɵelementStart(4, "button", 78);
475
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template_button_click_4_listener($event) { i0.ɵɵrestoreView(_r30); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openMoveSubmenu(conversation_r24.ID, $event)); });
476
- i0.ɵɵelement(5, "i", 82);
477
- i0.ɵɵelementStart(6, "span");
478
- i0.ɵɵtext(7, "Move to folder");
593
+ } if (rf & 2) {
594
+ const ctx_r1 = i0.ɵɵnextContext(4);
595
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets));
596
+ i0.ɵɵattribute("title", ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets) ? null : ctx_r1.ChangeRefusedReason);
597
+ i0.ɵɵadvance(3);
598
+ i0.ɵɵtextInterpolate((ctx_r1.ContextMenu.conversation == null ? null : ctx_r1.ContextMenu.conversation.IsPinned) ? "Unpin" : "Pin");
599
+ } }
600
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_11_Template(rf, ctx) { if (rf & 1) {
601
+ const _r34 = i0.ɵɵgetCurrentView();
602
+ i0.ɵɵelementStart(0, "button", 91);
603
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r34); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.ContextRename()); });
604
+ i0.ɵɵelement(1, "i", 101);
605
+ i0.ɵɵelementStart(2, "span");
606
+ i0.ɵɵtext(3, "Rename");
607
+ i0.ɵɵelementEnd()();
608
+ } }
609
+ function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
610
+ const _r31 = i0.ɵɵgetCurrentView();
611
+ i0.ɵɵconditionalCreate(0, ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_0_Template, 10, 5)(1, ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_1_Template, 4, 3, "button", 94);
612
+ i0.ɵɵelementStart(2, "button", 95);
613
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Template_button_click_2_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OpenMoveSubmenu($event)); });
614
+ i0.ɵɵelement(3, "i", 22);
615
+ i0.ɵɵelementStart(4, "span");
616
+ i0.ɵɵtext(5, "Move to folder");
479
617
  i0.ɵɵelementEnd();
480
- i0.ɵɵelement(8, "i", 83);
618
+ i0.ɵɵelement(6, "i", 96);
481
619
  i0.ɵɵelementEnd();
482
- i0.ɵɵelementStart(9, "button", 78);
483
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r30); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.renameConversation(conversation_r24); return i0.ɵɵresetView(ctx_r1.closeMenu()); });
484
- i0.ɵɵelement(10, "i", 84);
485
- i0.ɵɵelementStart(11, "span");
486
- i0.ɵɵtext(12, "Rename");
620
+ i0.ɵɵelementStart(7, "button", 95);
621
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ContextShare()); });
622
+ i0.ɵɵelement(8, "i", 24);
623
+ i0.ɵɵelementStart(9, "span");
624
+ i0.ɵɵtext(10);
487
625
  i0.ɵɵelementEnd()();
488
- i0.ɵɵelement(13, "div", 76);
489
- i0.ɵɵelementStart(14, "button", 85);
490
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r30); const conversation_r24 = i0.ɵɵnextContext(3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.deleteConversation(conversation_r24); return i0.ɵɵresetView(ctx_r1.closeMenu()); });
491
- i0.ɵɵelement(15, "i", 43);
492
- i0.ɵɵelementStart(16, "span");
493
- i0.ɵɵtext(17, "Delete");
626
+ i0.ɵɵconditionalCreate(11, ConversationListComponent_Conditional_13_Case_2_Conditional_1_Conditional_11_Template, 4, 0, "button", 97);
627
+ i0.ɵɵelement(12, "div", 89);
628
+ i0.ɵɵelementStart(13, "button", 98);
629
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_2_Conditional_1_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.ContextDelete()); });
630
+ i0.ɵɵelement(14, "i", 26);
631
+ i0.ɵɵelementStart(15, "span");
632
+ i0.ɵɵtext(16);
494
633
  i0.ɵɵelementEnd()();
495
634
  } if (rf & 2) {
496
- const conversation_r24 = i0.ɵɵnextContext(3).$implicit;
635
+ const ctx_r1 = i0.ɵɵnextContext(3);
636
+ i0.ɵɵconditional(ctx_r1.ContextMenu.targets.length > 1 ? 0 : 1);
637
+ i0.ɵɵadvance(2);
638
+ i0.ɵɵproperty("disabled", !ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets));
639
+ i0.ɵɵattribute("title", ctx_r1.CanChangeAny(ctx_r1.ContextMenu.targets) ? null : ctx_r1.ChangeRefusedReason);
640
+ i0.ɵɵadvance(5);
641
+ i0.ɵɵproperty("disabled", !ctx_r1.CanShareAny(ctx_r1.ContextMenu.targets));
642
+ i0.ɵɵattribute("title", ctx_r1.CanShareAny(ctx_r1.ContextMenu.targets) ? null : ctx_r1.ShareRefusedReason);
497
643
  i0.ɵɵadvance(3);
498
- i0.ɵɵtextInterpolate(conversation_r24.IsPinned ? "Unpin" : "Pin");
499
- } }
500
- function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Template(rf, ctx) { if (rf & 1) {
501
- i0.ɵɵelementStart(0, "div", 73);
502
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Template_div_click_0_listener($event) { return $event.stopPropagation(); });
503
- i0.ɵɵconditionalCreate(1, ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_1_Template, 17, 2)(2, ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Conditional_2_Template, 18, 1);
504
- i0.ɵɵelementEnd();
505
- } if (rf & 2) {
506
- const conversation_r24 = i0.ɵɵnextContext(2).$implicit;
507
- const ctx_r1 = i0.ɵɵnextContext();
644
+ i0.ɵɵtextInterpolate(ctx_r1.ContextMenu.targets.length > 1 ? "Share " + ctx_r1.ContextMenu.targets.length + " conversations" : "Share");
508
645
  i0.ɵɵadvance();
509
- i0.ɵɵconditional(ctx_r1.IsMoveSubmenuOpen(conversation_r24) ? 1 : 2);
646
+ i0.ɵɵconditional(ctx_r1.ContextMenu.targets.length === 1 ? 11 : -1);
647
+ i0.ɵɵadvance(5);
648
+ i0.ɵɵtextInterpolate(ctx_r1.ContextMenu.targets.length > 1 ? "Delete " + ctx_r1.ContextMenu.targets.length : "Delete");
510
649
  } }
511
- function ConversationListComponent_ng_template_10_Conditional_12_Template(rf, ctx) { if (rf & 1) {
512
- const _r26 = i0.ɵɵgetCurrentView();
513
- i0.ɵɵelementStart(0, "div", 67)(1, "button", 70);
514
- i0.ɵɵlistener("click", function ConversationListComponent_ng_template_10_Conditional_12_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r26); const conversation_r24 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleMenu(conversation_r24.ID, $event)); });
515
- i0.ɵɵelement(2, "i", 71);
516
- i0.ɵɵelementEnd();
517
- i0.ɵɵconditionalCreate(3, ConversationListComponent_ng_template_10_Conditional_12_Conditional_3_Template, 3, 1, "div", 72);
518
- i0.ɵɵelementEnd();
650
+ function ConversationListComponent_Conditional_13_Case_2_Template(rf, ctx) { if (rf & 1) {
651
+ i0.ɵɵconditionalCreate(0, ConversationListComponent_Conditional_13_Case_2_Conditional_0_Template, 17, 2)(1, ConversationListComponent_Conditional_13_Case_2_Conditional_1_Template, 17, 8);
519
652
  } if (rf & 2) {
520
- const conversation_r24 = i0.ɵɵnextContext().$implicit;
521
- const ctx_r1 = i0.ɵɵnextContext();
522
- i0.ɵɵadvance(3);
523
- i0.ɵɵconditional(ctx_r1.IsMenuOpen(conversation_r24) ? 3 : -1);
653
+ const ctx_r1 = i0.ɵɵnextContext(2);
654
+ i0.ɵɵconditional(ctx_r1.IsMoveSubmenuOpen ? 0 : 1);
524
655
  } }
525
- function ConversationListComponent_ng_template_10_Template(rf, ctx) { if (rf & 1) {
526
- const _r23 = i0.ɵɵgetCurrentView();
527
- i0.ɵɵelementStart(0, "div", 57);
528
- i0.ɵɵlistener("dragstart", function ConversationListComponent_ng_template_10_Template_div_dragstart_0_listener($event) { const conversation_r24 = i0.ɵɵrestoreView(_r23).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onConversationDragStart(conversation_r24, $event)); })("dragend", function ConversationListComponent_ng_template_10_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onConversationDragEnd()); })("click", function ConversationListComponent_ng_template_10_Template_div_click_0_listener() { const conversation_r24 = i0.ɵɵrestoreView(_r23).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.handleConversationClick(conversation_r24)); });
529
- i0.ɵɵconditionalCreate(1, ConversationListComponent_ng_template_10_Conditional_1_Template, 2, 1, "div", 58);
530
- i0.ɵɵelementStart(2, "div", 59);
531
- i0.ɵɵconditionalCreate(3, ConversationListComponent_ng_template_10_Conditional_3_Template, 2, 0, "div", 60);
532
- i0.ɵɵelementStart(4, "div", 61);
533
- i0.ɵɵelement(5, "mj-notification-badge", 62);
656
+ function ConversationListComponent_Conditional_13_Case_3_Template(rf, ctx) { if (rf & 1) {
657
+ const _r35 = i0.ɵɵgetCurrentView();
658
+ i0.ɵɵelementStart(0, "button", 91);
659
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_3_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextCreateSubfolder($event)); });
660
+ i0.ɵɵelement(1, "i", 55);
661
+ i0.ɵɵelementStart(2, "span");
662
+ i0.ɵɵtext(3, "New Subfolder");
534
663
  i0.ɵɵelementEnd()();
535
- i0.ɵɵelementStart(6, "div", 63)(7, "div", 64);
536
- i0.ɵɵtext(8);
537
- i0.ɵɵconditionalCreate(9, ConversationListComponent_ng_template_10_Conditional_9_Template, 1, 1, "i", 65);
538
- i0.ɵɵelementEnd();
539
- i0.ɵɵelementStart(10, "div", 66);
540
- i0.ɵɵtext(11);
664
+ i0.ɵɵelementStart(4, "button", 91);
665
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_3_Template_button_click_4_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextEditFolder($event)); });
666
+ i0.ɵɵelement(5, "i", 102);
667
+ i0.ɵɵelementStart(6, "span");
668
+ i0.ɵɵtext(7, "Rename");
669
+ i0.ɵɵelementEnd()();
670
+ i0.ɵɵelement(8, "div", 89);
671
+ i0.ɵɵelementStart(9, "button", 98);
672
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_3_Template_button_click_9_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextDeleteFolder($event)); });
673
+ i0.ɵɵelement(10, "i", 26);
674
+ i0.ɵɵelementStart(11, "span");
675
+ i0.ɵɵtext(12, "Delete");
676
+ i0.ɵɵelementEnd()();
677
+ } }
678
+ function ConversationListComponent_Conditional_13_Case_4_Template(rf, ctx) { if (rf & 1) {
679
+ const _r36 = i0.ɵɵgetCurrentView();
680
+ i0.ɵɵelementStart(0, "button", 91);
681
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextNewConversation()); });
682
+ i0.ɵɵelement(1, "i", 44);
683
+ i0.ɵɵelementStart(2, "span");
684
+ i0.ɵɵtext(3, "New Conversation");
685
+ i0.ɵɵelementEnd()();
686
+ i0.ɵɵelementStart(4, "button", 91);
687
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_4_Template_button_click_4_listener($event) { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextCreateRootFolder($event)); });
688
+ i0.ɵɵelement(5, "i", 55);
689
+ i0.ɵɵelementStart(6, "span");
690
+ i0.ɵɵtext(7, "New Folder");
691
+ i0.ɵɵelementEnd()();
692
+ i0.ɵɵelement(8, "div", 89);
693
+ i0.ɵɵelementStart(9, "button", 91);
694
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Case_4_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ContextSelectAll()); });
695
+ i0.ɵɵelement(10, "i", 103);
696
+ i0.ɵɵelementStart(11, "span");
697
+ i0.ɵɵtext(12, "Select All");
541
698
  i0.ɵɵelementEnd()();
542
- i0.ɵɵconditionalCreate(12, ConversationListComponent_ng_template_10_Conditional_12_Template, 4, 1, "div", 67);
699
+ } }
700
+ function ConversationListComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
701
+ const _r27 = i0.ɵɵgetCurrentView();
702
+ i0.ɵɵelementStart(0, "div", 86, 3);
703
+ i0.ɵɵlistener("click", function ConversationListComponent_Conditional_13_Template_div_click_0_listener($event) { return $event.stopPropagation(); })("contextmenu", function ConversationListComponent_Conditional_13_Template_div_contextmenu_0_listener($event) { i0.ɵɵrestoreView(_r27); $event.preventDefault(); return i0.ɵɵresetView($event.stopPropagation()); });
704
+ i0.ɵɵconditionalCreate(2, ConversationListComponent_Conditional_13_Case_2_Template, 2, 1)(3, ConversationListComponent_Conditional_13_Case_3_Template, 13, 0)(4, ConversationListComponent_Conditional_13_Case_4_Template, 13, 0);
543
705
  i0.ɵɵelementEnd();
544
706
  } if (rf & 2) {
545
- const conversation_r24 = ctx.$implicit;
546
- const depth_r31 = ctx.depth;
707
+ let tmp_6_0;
547
708
  const ctx_r1 = i0.ɵɵnextContext();
548
- i0.ɵɵstyleProp("padding-left", depth_r31 ? 16 + depth_r31 * 14 : 16, "px");
549
- i0.ɵɵclassProp("active", ctx_r1.IsConversationActive(conversation_r24))("renamed", ctx_r1.IsConversationRenamed(conversation_r24))("dragging", ctx_r1.IsConversationDragging(conversation_r24));
550
- i0.ɵɵproperty("draggable", !ctx_r1.isSelectionMode);
551
- i0.ɵɵadvance();
552
- i0.ɵɵconditional(ctx_r1.isSelectionMode ? 1 : -1);
553
- i0.ɵɵadvance(2);
554
- i0.ɵɵconditional(ctx_r1.hasActiveTasks(conversation_r24.ID) ? 3 : -1);
555
- i0.ɵɵadvance(2);
556
- i0.ɵɵproperty("conversationId", conversation_r24.ID);
557
- i0.ɵɵadvance();
558
- i0.ɵɵproperty("title", conversation_r24.Name + (conversation_r24.Description ? "\n" + conversation_r24.Description : ""));
559
- i0.ɵɵadvance(2);
560
- i0.ɵɵtextInterpolate1(" ", conversation_r24.Name, " ");
561
- i0.ɵɵadvance();
562
- i0.ɵɵconditional(ctx_r1.isSharedWithMe(conversation_r24) ? 9 : -1);
709
+ i0.ɵɵstyleProp("left", ctx_r1.ContextMenu.x, "px")("top", ctx_r1.ContextMenu.y, "px");
563
710
  i0.ɵɵadvance(2);
564
- i0.ɵɵtextInterpolate(conversation_r24.Description);
565
- i0.ɵɵadvance();
566
- i0.ɵɵconditional(!ctx_r1.isSelectionMode ? 12 : -1);
711
+ i0.ɵɵconditional((tmp_6_0 = ctx_r1.ContextMenu.kind) === "conversation" ? 2 : tmp_6_0 === "folder" ? 3 : 4);
567
712
  } }
713
+ /** Resource type the conversation share rows are written against. */
714
+ const CONVERSATIONS_RESOURCE_TYPE_ID = '81D4BC3D-9FEB-EF11-B01A-286B35C04427';
568
715
  export class ConversationListComponent {
569
716
  dialogService;
570
717
  notificationService;
571
718
  activeTasksService;
572
719
  mjDialogService;
573
720
  cdr;
574
- environmentId;
575
- currentUser;
576
- selectedConversationId = null;
577
- renamedConversationId = null;
578
- isSidebarPinned = true; // Whether sidebar is pinned (stays open after selection)
579
- isMobileView = false; // Whether we're on mobile (no pin options)
721
+ EnvironmentId;
722
+ CurrentUser;
723
+ SelectedConversationId = null;
724
+ RenamedConversationId = null;
725
+ IsSidebarPinned = true; // Whether sidebar is pinned (stays open after selection)
726
+ IsMobileView = false; // Whether we're on mobile (no pin options)
580
727
  // ── White-label chrome toggles (all default true = stock rendering) ──
581
728
  /** Show the search box in the list header. Flipping to false clears any active
582
729
  * search so a hidden filter can't keep silently narrowing the list. */
583
730
  set showSearch(value) {
584
731
  if (!value && this._searchQuery) {
585
- this.searchQuery = ''; // setter rebuilds the groupings
732
+ this.SearchQuery = ''; // setter rebuilds the groupings
586
733
  }
587
734
  this._showSearch = value;
588
735
  }
@@ -591,50 +738,140 @@ export class ConversationListComponent {
591
738
  }
592
739
  _showSearch = true;
593
740
  /** Show the "New Conversation" button. */
594
- showNewConversationButton = true;
741
+ ShowNewConversationButton = true;
595
742
  /** Show the ⋯ header options menu (refresh / select / group-by / hide sidebar). */
596
- showHeaderMenu = true;
743
+ ShowHeaderMenu = true;
597
744
  /** Show the collapsible Pinned / Folders / Messages section headers. When false,
598
745
  * the list renders FLAT and fully expanded: folder grouping is bypassed (the
599
746
  * folder tree's root drop-zone and New Folder action live in the section
600
747
  * header, so a headerless tree would allow one-way folder nesting) — the
601
748
  * chrome-less rendering for embedded hosts. */
602
- showSectionHeaders = true;
603
- conversationSelected = new EventEmitter();
604
- conversationDeleted = new EventEmitter(); // Emits the deleted conversation ID
605
- newConversationRequested = new EventEmitter();
606
- pinSidebarRequested = new EventEmitter(); // Request to pin sidebar
607
- unpinSidebarRequested = new EventEmitter(); // Request to unpin (collapse) sidebar
608
- refreshRequested = new EventEmitter(); // Emitted after list refresh so chat area can also reload
609
- directMessagesExpanded = true;
610
- pinnedExpanded = true;
611
- foldersExpanded = true;
612
- ungroupedExpanded = true;
613
- openMenuConversationId = null;
614
- conversationIdsWithTasks = new Set();
615
- isSelectionMode = false;
616
- selectedConversationIds = new Set();
617
- isHeaderMenuOpen = false;
618
- isRefreshing = false;
749
+ ShowSectionHeaders = true;
750
+ ConversationSelected = new EventEmitter();
751
+ /**
752
+ * @deprecated Use {@link ConversationSelected}.
753
+ *
754
+ * The same emitter under the old binding name, so a template still binding
755
+ * (conversationSelected) keeps working. Must stay AFTER ConversationSelected: class fields
756
+ * initialise in order, and the other way round this captures undefined.
757
+ */
758
+ conversationSelected = this.ConversationSelected;
759
+ ConversationDeleted = new EventEmitter(); // Emits the deleted conversation ID
760
+ /**
761
+ * @deprecated Use {@link ConversationDeleted}.
762
+ *
763
+ * The same emitter under the old binding name, so a template still binding
764
+ * (conversationDeleted) keeps working. Must stay AFTER ConversationDeleted: class fields
765
+ * initialise in order, and the other way round this captures undefined.
766
+ */
767
+ conversationDeleted = this.ConversationDeleted; // Emits the deleted conversation ID
768
+ NewConversationRequested = new EventEmitter();
769
+ /**
770
+ * @deprecated Use {@link NewConversationRequested}.
771
+ *
772
+ * The same emitter under the old binding name, so a template still binding
773
+ * (newConversationRequested) keeps working. Must stay AFTER NewConversationRequested: class fields
774
+ * initialise in order, and the other way round this captures undefined.
775
+ */
776
+ newConversationRequested = this.NewConversationRequested;
777
+ PinSidebarRequested = new EventEmitter(); // Request to pin sidebar
778
+ /**
779
+ * @deprecated Use {@link PinSidebarRequested}.
780
+ *
781
+ * The same emitter under the old binding name, so a template still binding
782
+ * (pinSidebarRequested) keeps working. Must stay AFTER PinSidebarRequested: class fields
783
+ * initialise in order, and the other way round this captures undefined.
784
+ */
785
+ pinSidebarRequested = this.PinSidebarRequested; // Request to pin sidebar
786
+ UnpinSidebarRequested = new EventEmitter(); // Request to unpin (collapse) sidebar
787
+ /**
788
+ * @deprecated Use {@link UnpinSidebarRequested}.
789
+ *
790
+ * The same emitter under the old binding name, so a template still binding
791
+ * (unpinSidebarRequested) keeps working. Must stay AFTER UnpinSidebarRequested: class fields
792
+ * initialise in order, and the other way round this captures undefined.
793
+ */
794
+ unpinSidebarRequested = this.UnpinSidebarRequested; // Request to unpin (collapse) sidebar
795
+ RefreshRequested = new EventEmitter(); // Emitted after list refresh so chat area can also reload
796
+ /**
797
+ * @deprecated Use {@link RefreshRequested}.
798
+ *
799
+ * The same emitter under the old binding name, so a template still binding
800
+ * (refreshRequested) keeps working. Must stay AFTER RefreshRequested: class fields
801
+ * initialise in order, and the other way round this captures undefined.
802
+ */
803
+ refreshRequested = this.RefreshRequested; // Emitted after list refresh so chat area can also reload
804
+ /**
805
+ * The user wants the current filter term searched across all of Chat, not just this list.
806
+ * Emits the term. This panel filters only loaded conversations by Name/Description, so it
807
+ * cannot answer "where did we discuss X" — the host owns that surface and the routing to it.
808
+ */
809
+ SearchEscalated = new EventEmitter();
810
+ DirectMessagesExpanded = true;
811
+ PinnedExpanded = true;
812
+ FoldersExpanded = true;
813
+ UngroupedExpanded = true;
814
+ /** The open right-click menu, or null. Positioned at the pointer. */
815
+ ContextMenu = null;
816
+ /** True while the open conversation menu is showing its folder picker. */
817
+ IsMoveSubmenuOpen = false;
818
+ /** Resources the share dialog is currently offering, one per conversation. */
819
+ ShareContexts = [];
820
+ ShareNotice = null;
821
+ IsShareDialogOpen = false;
822
+ ShareAdapter = new MJResourcePermissionShareAdapter(CONVERSATIONS_RESOURCE_TYPE_ID);
823
+ ConversationIdsWithTasks = new Set();
824
+ IsSelectionMode = false;
825
+ SelectedConversationIds = new Set();
826
+ /** Row a Shift-click ranges from — the last row picked without Shift. */
827
+ selectionAnchorId = null;
828
+ /** Why Share is unavailable, shown on its disabled button. */
829
+ ShareRefusedReason = 'Only the owner, or someone with Owner access, can share a conversation';
830
+ /** Why Move and Pin are unavailable, shown on their disabled buttons. */
831
+ ChangeRefusedReason = 'You need Edit access to move or pin a conversation shared with you';
832
+ /** How long a touch must rest on a row before it selects the row. */
833
+ static longPressDelayMs = 500;
834
+ /** How far a touch may drift, in pixels, before it counts as a scroll rather than a press. */
835
+ static longPressMoveTolerancePx = 10;
836
+ /** Space kept between the right-click menu and the edges of the window. */
837
+ static menuViewportMargin = 8;
838
+ /** The touch press waiting to become a long-press, or null. */
839
+ longPress = null;
840
+ /** Pointer type of the latest press on a row. On touch, a tap while selecting toggles the row. */
841
+ lastRowPointerType = 'mouse';
842
+ /** Set by a completed long-press, so the click that ends the same press does nothing. */
843
+ ignoreNextRowClick = false;
844
+ IsHeaderMenuOpen = false;
845
+ IsRefreshing = false;
846
+ searchInput;
847
+ contextMenuEl;
619
848
  /** UserInfoEngine key for persisting folder collapse state + group-by mode. */
620
- static FolderPrefsKey = 'mj.conversations.folderPrefs.v1';
849
+ static folderPrefsKey = 'mj.conversations.folderPrefs.v1';
621
850
  /** How the conversation list is grouped. 'project' = folders, 'none' = flat list. */
622
- groupBy = 'project';
851
+ GroupBy = 'project';
852
+ /** Field every section of the list is sorted on. */
853
+ SortBy = 'date';
854
+ /** Direction of the current sort. */
855
+ SortDirection = 'desc';
856
+ /** Direction each field falls back to when it becomes the active sort. */
857
+ static defaultSortDirections = {
858
+ date: 'desc',
859
+ name: 'asc'
860
+ };
623
861
  /** Precomputed groupings, rebuilt whenever conversations/projects/search change. */
624
- pinnedConversations = [];
625
- unpinnedConversations = [];
626
- ungroupedConversations = [];
627
- folderTree = [];
862
+ PinnedConversations = [];
863
+ UnpinnedConversations = [];
864
+ UngroupedConversations = [];
865
+ FolderTree = [];
628
866
  /** Flattened folder list (depth-ordered) for the "Move to folder" menu. */
629
- flatFolders = [];
867
+ FlatFolders = [];
630
868
  /** Folder IDs (normalized) whose children are collapsed. Absent = expanded. */
631
869
  collapsedFolderIds = new Set();
632
870
  /** Drag-and-drop state. */
633
- draggedConversationId = null;
634
- draggedFolderId = null;
635
- dragOverTargetId = null;
636
- /** When set, the open conversation menu is showing its "Move to folder" picker. */
637
- moveSubmenuConversationId = null;
871
+ /** Conversations currently being dragged — the whole selection when the grabbed row is part of it. */
872
+ DraggedConversationIds = [];
873
+ DraggedFolderId = null;
874
+ DragOverTargetId = null;
638
875
  _searchQuery = '';
639
876
  destroy$ = new Subject();
640
877
  engine = ConversationEngine.Instance;
@@ -647,23 +884,36 @@ export class ConversationListComponent {
647
884
  this.mjDialogService = mjDialogService;
648
885
  this.cdr = cdr;
649
886
  }
650
- get searchQuery() {
887
+ get SearchQuery() {
651
888
  return this._searchQuery;
652
889
  }
653
- set searchQuery(value) {
890
+ set SearchQuery(value) {
654
891
  this._searchQuery = value ?? '';
655
892
  this.rebuildGroups();
893
+ this.dropHiddenRowsFromSelection();
656
894
  }
657
895
  /** True when a search filter is active. */
658
- get isSearching() {
896
+ get IsSearching() {
659
897
  return this._searchQuery.trim().length > 0;
660
898
  }
661
- /** Conversations matching the current search (used by selection-mode helpers). */
662
- get filteredConversations() {
663
- return this.filterConversations(this.engine.Conversations);
899
+ /** Hand the current filter term to the host to search across every Chat entity. */
900
+ EscalateSearch() {
901
+ this.SearchEscalated.emit(this._searchQuery.trim());
902
+ }
903
+ /** Clears the search box and returns focus to it. */
904
+ ClearSearch() {
905
+ this.SearchQuery = '';
906
+ this.searchInput?.nativeElement.focus();
907
+ }
908
+ /** Escape in the search box clears it without closing any host overlay. */
909
+ OnSearchKeydown(event) {
910
+ if (event.key === 'Escape' && this.IsSearching) {
911
+ event.stopPropagation();
912
+ this.ClearSearch();
913
+ }
664
914
  }
665
915
  filterConversations(conversations) {
666
- if (!this.isSearching) {
916
+ if (!this.IsSearching) {
667
917
  return conversations;
668
918
  }
669
919
  const lowerQuery = this._searchQuery.toLowerCase();
@@ -674,94 +924,106 @@ export class ConversationListComponent {
674
924
  // Restore persisted folder collapse state + group-by preference
675
925
  this.loadFolderPrefs();
676
926
  // Load conversations (and folders) on init
677
- this.engine.LoadConversations(this.environmentId, this.currentUser, false);
927
+ this.engine.LoadConversations(this.EnvironmentId, this.CurrentUser, false);
678
928
  // Rebuild the precomputed groupings whenever conversations OR projects change
679
929
  // (pin, archive, rename, move-to-folder, folder create/rename/delete, etc.).
680
- this.engine.Conversations$.pipe(takeUntil(this.destroy$)).subscribe(() => {
681
- this.rebuildGroups();
682
- this.cdr.detectChanges();
683
- });
930
+ this.engine.Conversations$.pipe(takeUntil(this.destroy$)).subscribe(() => this.onConversationListChanged());
684
931
  this.engine.Projects$.pipe(takeUntil(this.destroy$)).subscribe(() => {
685
932
  this.rebuildGroups();
686
933
  this.cdr.detectChanges();
687
934
  });
688
935
  // Subscribe to conversation IDs with active tasks (hot set)
689
936
  this.activeTasksService.conversationIdsWithTasks$.pipe(takeUntil(this.destroy$)).subscribe(conversationIds => {
690
- this.conversationIdsWithTasks = conversationIds;
937
+ this.ConversationIdsWithTasks = conversationIds;
691
938
  this.cdr.detectChanges(); // Force change detection to ensure spinner icons update reliably
692
939
  });
693
940
  }
694
941
  ngOnDestroy() {
942
+ this.CancelLongPress();
695
943
  this.destroy$.next();
696
944
  this.destroy$.complete();
697
945
  }
946
+ /** Rebuilds the groupings from the engine's list, first dropping selected conversations that left it. */
947
+ onConversationListChanged() {
948
+ this.dropRemovedConversationsFromSelection();
949
+ this.rebuildGroups();
950
+ this.cdr.detectChanges();
951
+ }
698
952
  onDocumentClick() {
699
953
  // Close menus when clicking outside
700
- if (this.openMenuConversationId) {
701
- this.closeMenu();
954
+ if (this.ContextMenu) {
955
+ this.CloseContextMenu();
702
956
  }
703
- if (this.isHeaderMenuOpen) {
704
- this.closeHeaderMenu();
957
+ if (this.IsHeaderMenuOpen) {
958
+ this.CloseHeaderMenu();
705
959
  }
706
960
  }
707
- toggleHeaderMenu(event) {
708
- event.stopPropagation();
709
- this.isHeaderMenuOpen = !this.isHeaderMenuOpen;
710
- }
711
- closeHeaderMenu() {
712
- this.isHeaderMenuOpen = false;
961
+ onDocumentEscape() {
962
+ if (this.ContextMenu) {
963
+ this.CloseContextMenu();
964
+ return;
965
+ }
966
+ if (this.IsSelectionMode) {
967
+ this.exitSelectionMode();
968
+ }
713
969
  }
714
- onSelectConversationsClick(event) {
970
+ ToggleHeaderMenu(event) {
715
971
  event.stopPropagation();
716
- this.toggleSelectionMode();
717
- this.closeHeaderMenu();
972
+ this.IsHeaderMenuOpen = !this.IsHeaderMenuOpen;
718
973
  }
719
- onToggleGroupByClick(event) {
974
+ CloseHeaderMenu() {
975
+ this.IsHeaderMenuOpen = false;
976
+ }
977
+ OnToggleGroupByClick(event) {
720
978
  event.stopPropagation();
721
- this.toggleGroupBy();
722
- this.closeHeaderMenu();
979
+ this.ToggleGroupBy();
980
+ this.CloseHeaderMenu();
723
981
  }
724
- async onRefreshConversationsClick(event) {
982
+ async OnRefreshConversationsClick(event) {
725
983
  event.stopPropagation();
726
- if (this.isRefreshing)
984
+ if (this.IsRefreshing)
727
985
  return;
728
- this.isRefreshing = true;
986
+ this.IsRefreshing = true;
729
987
  try {
730
- await this.engine.LoadConversations(this.environmentId, this.currentUser, true);
988
+ await this.engine.LoadConversations(this.EnvironmentId, this.CurrentUser, true);
731
989
  // Signal parent to also reload messages in the active conversation
732
- this.refreshRequested.emit();
990
+ this.RefreshRequested.emit();
733
991
  }
734
992
  catch (error) {
735
993
  console.error('Error refreshing conversations:', error);
736
994
  await this.dialogService.alert('Error', 'Failed to refresh conversations. Please try again.');
737
995
  }
738
996
  finally {
739
- this.isRefreshing = false;
997
+ this.IsRefreshing = false;
740
998
  this.cdr.detectChanges();
741
- this.closeHeaderMenu();
999
+ this.CloseHeaderMenu();
742
1000
  }
743
1001
  }
744
- onPinSidebarClick(event) {
1002
+ OnPinSidebarClick(event) {
745
1003
  event.stopPropagation();
746
- this.closeHeaderMenu();
747
- this.pinSidebarRequested.emit();
1004
+ this.CloseHeaderMenu();
1005
+ this.PinSidebarRequested.emit();
748
1006
  }
749
- onUnpinSidebarClick(event) {
1007
+ OnUnpinSidebarClick(event) {
750
1008
  event.stopPropagation();
751
- this.closeHeaderMenu();
752
- this.unpinSidebarRequested.emit();
1009
+ this.CloseHeaderMenu();
1010
+ this.UnpinSidebarRequested.emit();
753
1011
  }
754
- toggleDirectMessages() {
755
- this.directMessagesExpanded = !this.directMessagesExpanded;
1012
+ ToggleDirectMessages() {
1013
+ this.DirectMessagesExpanded = !this.DirectMessagesExpanded;
1014
+ this.dropHiddenRowsFromSelection();
756
1015
  }
757
- togglePinned() {
758
- this.pinnedExpanded = !this.pinnedExpanded;
1016
+ TogglePinned() {
1017
+ this.PinnedExpanded = !this.PinnedExpanded;
1018
+ this.dropHiddenRowsFromSelection();
759
1019
  }
760
- toggleFolders() {
761
- this.foldersExpanded = !this.foldersExpanded;
1020
+ ToggleFolders() {
1021
+ this.FoldersExpanded = !this.FoldersExpanded;
1022
+ this.dropHiddenRowsFromSelection();
762
1023
  }
763
- toggleUngrouped() {
764
- this.ungroupedExpanded = !this.ungroupedExpanded;
1024
+ ToggleUngrouped() {
1025
+ this.UngroupedExpanded = !this.UngroupedExpanded;
1026
+ this.dropHiddenRowsFromSelection();
765
1027
  }
766
1028
  // ========================================================================
767
1029
  // FOLDER GROUPING
@@ -770,17 +1032,71 @@ export class ConversationListComponent {
770
1032
  * Recomputes pinned/unpinned/ungrouped lists and the folder tree from the
771
1033
  * engine's conversation + project caches and the current search filter.
772
1034
  */
1035
+ /**
1036
+ * Makes `field` the active sort. Choosing the field that is already active
1037
+ * flips the direction; switching fields starts from that field's natural
1038
+ * direction (newest first for date, A-Z for name).
1039
+ */
1040
+ SetSort(field) {
1041
+ if (this.SortBy === field) {
1042
+ this.SortDirection = this.SortDirection === 'asc' ? 'desc' : 'asc';
1043
+ }
1044
+ else {
1045
+ this.SortBy = field;
1046
+ this.SortDirection = ConversationListComponent.defaultSortDirections[field];
1047
+ }
1048
+ this.saveFolderPrefs();
1049
+ this.rebuildGroups();
1050
+ }
1051
+ /** Icon for a sort button: direction arrow when active, plain field icon otherwise. */
1052
+ SortIcon(field) {
1053
+ if (this.SortBy !== field) {
1054
+ return field === 'date' ? 'fa-clock' : 'fa-font';
1055
+ }
1056
+ if (field === 'date') {
1057
+ return this.SortDirection === 'asc' ? 'fa-arrow-up-1-9' : 'fa-arrow-down-9-1';
1058
+ }
1059
+ return this.SortDirection === 'asc' ? 'fa-arrow-up-a-z' : 'fa-arrow-down-z-a';
1060
+ }
1061
+ /**
1062
+ * Orders conversations by the active sort. Returns a new array so the caller's
1063
+ * source list is never mutated. Conversations with no name sort last.
1064
+ */
1065
+ sortConversations(conversations) {
1066
+ const factor = this.SortDirection === 'asc' ? 1 : -1;
1067
+ return [...conversations].sort((a, b) => {
1068
+ if (this.SortBy === 'name') {
1069
+ const aName = a.Name?.trim() ?? '';
1070
+ const bName = b.Name?.trim() ?? '';
1071
+ if (!aName || !bName) {
1072
+ return aName === bName ? 0 : (aName ? -1 : 1);
1073
+ }
1074
+ return aName.localeCompare(bName, undefined, { sensitivity: 'base' }) * factor;
1075
+ }
1076
+ return (this.updatedTime(a) - this.updatedTime(b)) * factor;
1077
+ });
1078
+ }
1079
+ /** Position of a conversation in a rendered-order list, or -1. Case-insensitive on the ID. */
1080
+ indexOfConversation(order, conversationId) {
1081
+ if (!conversationId)
1082
+ return -1;
1083
+ return order.findIndex(id => UUIDsEqual(id, conversationId));
1084
+ }
1085
+ updatedTime(conversation) {
1086
+ const updatedAt = conversation.__mj_UpdatedAt;
1087
+ return updatedAt ? new Date(updatedAt).getTime() : 0;
1088
+ }
773
1089
  rebuildGroups() {
774
- const matching = this.filterConversations(this.engine.Conversations);
775
- this.pinnedConversations = matching.filter(c => c.IsPinned);
776
- this.unpinnedConversations = matching.filter(c => !c.IsPinned);
1090
+ const matching = this.sortConversations(this.filterConversations(this.engine.Conversations));
1091
+ this.PinnedConversations = matching.filter(c => c.IsPinned);
1092
+ this.UnpinnedConversations = matching.filter(c => !c.IsPinned);
777
1093
  const projects = this.engine.Projects;
778
1094
  const projectIds = new Set(projects.map(p => NormalizeUUID(p.ID)));
779
1095
  // Bucket unpinned conversations by their folder (pinned ones live in the
780
1096
  // Pinned section). Conversations with no/unknown folder are "ungrouped".
781
1097
  const conversationsByProject = new Map();
782
1098
  const ungrouped = [];
783
- for (const c of this.unpinnedConversations) {
1099
+ for (const c of this.UnpinnedConversations) {
784
1100
  const pid = c.ProjectID ? NormalizeUUID(c.ProjectID) : null;
785
1101
  if (pid && projectIds.has(pid)) {
786
1102
  const arr = conversationsByProject.get(pid) ?? [];
@@ -791,7 +1107,7 @@ export class ConversationListComponent {
791
1107
  ungrouped.push(c);
792
1108
  }
793
1109
  }
794
- this.ungroupedConversations = ungrouped;
1110
+ this.UngroupedConversations = ungrouped;
795
1111
  // Index projects by parent. A project whose parent isn't loaded is treated
796
1112
  // as a root so it never disappears from the tree.
797
1113
  const childrenByParent = new Map();
@@ -812,8 +1128,8 @@ export class ConversationListComponent {
812
1128
  return { project: p, depth, conversations, children, totalCount, hasContent };
813
1129
  });
814
1130
  };
815
- this.folderTree = build(null, 0);
816
- this.flatFolders = this.flattenFolders(this.folderTree);
1131
+ this.FolderTree = build(null, 0);
1132
+ this.FlatFolders = this.flattenFolders(this.FolderTree);
817
1133
  }
818
1134
  flattenFolders(nodes) {
819
1135
  const out = [];
@@ -833,10 +1149,10 @@ export class ConversationListComponent {
833
1149
  }
834
1150
  return null;
835
1151
  }
836
- isFolderExpanded(projectId) {
1152
+ IsFolderExpanded(projectId) {
837
1153
  return !this.collapsedFolderIds.has(NormalizeUUID(projectId));
838
1154
  }
839
- toggleFolder(projectId) {
1155
+ ToggleFolder(projectId) {
840
1156
  const key = NormalizeUUID(projectId);
841
1157
  if (this.collapsedFolderIds.has(key)) {
842
1158
  this.collapsedFolderIds.delete(key);
@@ -845,21 +1161,29 @@ export class ConversationListComponent {
845
1161
  this.collapsedFolderIds.add(key);
846
1162
  }
847
1163
  this.saveFolderPrefs();
1164
+ this.dropHiddenRowsFromSelection();
848
1165
  }
849
- toggleGroupBy() {
850
- this.groupBy = this.groupBy === 'project' ? 'none' : 'project';
1166
+ ToggleGroupBy() {
1167
+ this.GroupBy = this.GroupBy === 'project' ? 'none' : 'project';
851
1168
  this.saveFolderPrefs();
852
1169
  this.rebuildGroups();
1170
+ this.dropHiddenRowsFromSelection();
853
1171
  }
854
1172
  loadFolderPrefs() {
855
1173
  try {
856
- const raw = UserInfoEngine.Instance.GetSetting(ConversationListComponent.FolderPrefsKey);
1174
+ const raw = UserInfoEngine.Instance.GetSetting(ConversationListComponent.folderPrefsKey);
857
1175
  if (!raw)
858
1176
  return;
859
1177
  const parsed = JSON.parse(raw);
860
1178
  this.collapsedFolderIds = new Set((parsed.collapsed ?? []).map(id => NormalizeUUID(id)));
861
1179
  if (parsed.groupBy === 'none' || parsed.groupBy === 'project') {
862
- this.groupBy = parsed.groupBy;
1180
+ this.GroupBy = parsed.groupBy;
1181
+ }
1182
+ if (parsed.sortBy === 'date' || parsed.sortBy === 'name') {
1183
+ this.SortBy = parsed.sortBy;
1184
+ }
1185
+ if (parsed.sortDirection === 'asc' || parsed.sortDirection === 'desc') {
1186
+ this.SortDirection = parsed.sortDirection;
863
1187
  }
864
1188
  }
865
1189
  catch {
@@ -869,46 +1193,59 @@ export class ConversationListComponent {
869
1193
  saveFolderPrefs() {
870
1194
  const payload = JSON.stringify({
871
1195
  collapsed: Array.from(this.collapsedFolderIds),
872
- groupBy: this.groupBy
1196
+ groupBy: this.GroupBy,
1197
+ sortBy: this.SortBy,
1198
+ sortDirection: this.SortDirection
873
1199
  });
874
- UserInfoEngine.Instance.SetSettingDebounced(ConversationListComponent.FolderPrefsKey, payload);
1200
+ UserInfoEngine.Instance.SetSettingDebounced(ConversationListComponent.folderPrefsKey, payload);
875
1201
  }
876
1202
  // ========================================================================
877
1203
  // DRAG & DROP (move conversation into/out of a folder)
878
1204
  // ========================================================================
879
- onConversationDragStart(conversation, event) {
880
- if (this.isSelectionMode)
1205
+ /**
1206
+ * Starts a conversation drag. Grabbing a row that is part of the current
1207
+ * selection drags the whole selection; grabbing any other row drags that row
1208
+ * alone and leaves the selection untouched. A touch press that lifts the row
1209
+ * selects it instead, since on touch a long-press means select.
1210
+ */
1211
+ OnConversationDragStart(conversation, event) {
1212
+ if (this.lastRowPointerType === 'touch') {
1213
+ event.preventDefault();
1214
+ this.completeLongPress();
881
1215
  return;
882
- this.draggedFolderId = null;
883
- this.draggedConversationId = conversation.ID;
1216
+ }
1217
+ this.DraggedFolderId = null;
1218
+ this.DraggedConversationIds = this.SelectedConversationIds.has(conversation.ID)
1219
+ ? Array.from(this.SelectedConversationIds)
1220
+ : [conversation.ID];
884
1221
  if (event.dataTransfer) {
885
1222
  event.dataTransfer.effectAllowed = 'move';
886
- event.dataTransfer.setData('text/plain', conversation.ID);
1223
+ event.dataTransfer.setData('text/plain', this.DraggedConversationIds.join(','));
887
1224
  }
888
1225
  }
889
- onConversationDragEnd() {
890
- this.draggedConversationId = null;
891
- this.dragOverTargetId = null;
1226
+ OnConversationDragEnd() {
1227
+ this.DraggedConversationIds = [];
1228
+ this.DragOverTargetId = null;
892
1229
  }
893
- onFolderDragStart(node, event) {
1230
+ OnFolderDragStart(node, event) {
894
1231
  event.stopPropagation();
895
- this.draggedConversationId = null;
896
- this.draggedFolderId = node.project.ID;
1232
+ this.DraggedConversationIds = [];
1233
+ this.DraggedFolderId = node.project.ID;
897
1234
  if (event.dataTransfer) {
898
1235
  event.dataTransfer.effectAllowed = 'move';
899
1236
  event.dataTransfer.setData('text/plain', node.project.ID);
900
1237
  }
901
1238
  }
902
- onFolderDragEnd() {
903
- this.draggedFolderId = null;
904
- this.dragOverTargetId = null;
1239
+ OnFolderDragEnd() {
1240
+ this.DraggedFolderId = null;
1241
+ this.DragOverTargetId = null;
905
1242
  }
906
- onFolderDragOver(projectId, event) {
1243
+ OnFolderDragOver(projectId, event) {
907
1244
  // A conversation can drop onto any folder; a folder can drop onto any folder
908
1245
  // that isn't itself or one of its own descendants (which would create a cycle).
909
- const accepts = this.draggedConversationId
1246
+ const accepts = this.DraggedConversationIds.length > 0
910
1247
  ? true
911
- : this.draggedFolderId
1248
+ : this.DraggedFolderId
912
1249
  ? this.isValidFolderDropTarget(projectId)
913
1250
  : false;
914
1251
  if (!accepts)
@@ -916,58 +1253,95 @@ export class ConversationListComponent {
916
1253
  event.preventDefault();
917
1254
  if (event.dataTransfer)
918
1255
  event.dataTransfer.dropEffect = 'move';
919
- this.dragOverTargetId = projectId;
1256
+ this.DragOverTargetId = projectId;
920
1257
  }
921
- onUngroupedDragOver(event) {
922
- if (!this.draggedConversationId)
1258
+ /**
1259
+ * Drop target id for a conversation row: its folder, or the Ungrouped section
1260
+ * when it has none. Resolved through the folder tree so the highlight matches
1261
+ * the folder row's own ID regardless of how the conversation stores it.
1262
+ */
1263
+ ConversationDropTargetId(conversation) {
1264
+ if (!conversation.ProjectID)
1265
+ return 'ungrouped';
1266
+ const node = this.FlatFolders.find(f => UUIDsEqual(f.project.ID, conversation.ProjectID));
1267
+ return node ? node.project.ID : 'ungrouped';
1268
+ }
1269
+ /**
1270
+ * A conversation row accepts a conversation drag and stands in for its folder,
1271
+ * so dropping onto the rows inside a folder files the drag there too. A row
1272
+ * that is part of the drag itself is not a target.
1273
+ */
1274
+ OnConversationRowDragOver(conversation, event) {
1275
+ if (this.DraggedConversationIds.length === 0)
1276
+ return;
1277
+ if (this.DraggedConversationIds.some(id => UUIDsEqual(id, conversation.ID)))
923
1278
  return;
924
1279
  event.preventDefault();
1280
+ event.stopPropagation();
925
1281
  if (event.dataTransfer)
926
1282
  event.dataTransfer.dropEffect = 'move';
927
- this.dragOverTargetId = 'ungrouped';
1283
+ this.DragOverTargetId = this.ConversationDropTargetId(conversation);
928
1284
  }
929
- /** The Folders section header accepts a dragged folder to move it back to the top level. */
930
- onFoldersRootDragOver(event) {
931
- if (!this.draggedFolderId)
932
- return;
1285
+ async OnConversationRowDrop(conversation, event) {
1286
+ event.preventDefault();
1287
+ event.stopPropagation();
1288
+ const conversationIds = this.DraggedConversationIds.filter(id => !UUIDsEqual(id, conversation.ID));
1289
+ this.DragOverTargetId = null;
1290
+ this.DraggedConversationIds = [];
1291
+ if (conversationIds.length > 0) {
1292
+ await this.moveConversations(conversationIds, conversation.ProjectID ?? null);
1293
+ }
1294
+ }
1295
+ OnUngroupedDragOver(event) {
1296
+ if (this.DraggedConversationIds.length === 0)
1297
+ return;
933
1298
  event.preventDefault();
934
1299
  if (event.dataTransfer)
935
1300
  event.dataTransfer.dropEffect = 'move';
936
- this.dragOverTargetId = 'folders-root';
1301
+ this.DragOverTargetId = 'ungrouped';
937
1302
  }
938
- onDragLeave(targetId) {
939
- if (this.dragOverTargetId === targetId) {
940
- this.dragOverTargetId = null;
1303
+ /** The Folders section header accepts a dragged folder to move it back to the top level. */
1304
+ OnFoldersRootDragOver(event) {
1305
+ if (!this.DraggedFolderId)
1306
+ return;
1307
+ event.preventDefault();
1308
+ if (event.dataTransfer)
1309
+ event.dataTransfer.dropEffect = 'move';
1310
+ this.DragOverTargetId = 'folders-root';
1311
+ }
1312
+ OnDragLeave(targetId) {
1313
+ if (this.DragOverTargetId === targetId) {
1314
+ this.DragOverTargetId = null;
941
1315
  }
942
1316
  }
943
- onFolderDrop(project, event) {
1317
+ async OnFolderDrop(project, event) {
944
1318
  event.preventDefault();
945
- const conversationId = this.draggedConversationId;
946
- const folderId = this.draggedFolderId;
947
- this.dragOverTargetId = null;
948
- this.draggedConversationId = null;
949
- this.draggedFolderId = null;
950
- if (conversationId) {
951
- this.moveConversation(conversationId, project.ID);
1319
+ const conversationIds = this.DraggedConversationIds;
1320
+ const folderId = this.DraggedFolderId;
1321
+ this.DragOverTargetId = null;
1322
+ this.DraggedConversationIds = [];
1323
+ this.DraggedFolderId = null;
1324
+ if (conversationIds.length > 0) {
1325
+ await this.moveConversations(conversationIds, project.ID);
952
1326
  }
953
1327
  else if (folderId && this.isValidFolderDropTarget(project.ID, folderId)) {
954
- this.moveFolder(folderId, project.ID);
1328
+ await this.moveFolder(folderId, project.ID);
955
1329
  }
956
1330
  }
957
- onUngroupedDrop(event) {
1331
+ async OnUngroupedDrop(event) {
958
1332
  event.preventDefault();
959
- const conversationId = this.draggedConversationId;
960
- this.dragOverTargetId = null;
961
- this.draggedConversationId = null;
962
- if (conversationId) {
963
- this.moveConversation(conversationId, null);
1333
+ const conversationIds = this.DraggedConversationIds;
1334
+ this.DragOverTargetId = null;
1335
+ this.DraggedConversationIds = [];
1336
+ if (conversationIds.length > 0) {
1337
+ await this.moveConversations(conversationIds, null);
964
1338
  }
965
1339
  }
966
- onFoldersRootDrop(event) {
1340
+ OnFoldersRootDrop(event) {
967
1341
  event.preventDefault();
968
- const folderId = this.draggedFolderId;
969
- this.dragOverTargetId = null;
970
- this.draggedFolderId = null;
1342
+ const folderId = this.DraggedFolderId;
1343
+ this.DragOverTargetId = null;
1344
+ this.DraggedFolderId = null;
971
1345
  if (folderId) {
972
1346
  this.moveFolder(folderId, null);
973
1347
  }
@@ -976,7 +1350,7 @@ export class ConversationListComponent {
976
1350
  * A folder can be dropped onto a target folder only if the target isn't the dragged
977
1351
  * folder itself and isn't one of its descendants (otherwise we'd create a cycle).
978
1352
  */
979
- isValidFolderDropTarget(targetId, draggedId = this.draggedFolderId) {
1353
+ isValidFolderDropTarget(targetId, draggedId = this.DraggedFolderId) {
980
1354
  if (!draggedId)
981
1355
  return false;
982
1356
  if (UUIDsEqual(targetId, draggedId))
@@ -1001,20 +1375,41 @@ export class ConversationListComponent {
1001
1375
  }
1002
1376
  /** Assigns a conversation to a folder (or null to ungroup) and refreshes the view. */
1003
1377
  async moveConversation(conversationId, projectId) {
1378
+ await this.moveConversations([conversationId], projectId);
1379
+ }
1380
+ /**
1381
+ * Assigns several conversations to a folder (or null to ungroup) in one batch,
1382
+ * reveals the destination folder, and refreshes the view.
1383
+ */
1384
+ async moveConversations(conversationIds, projectId) {
1385
+ // Dropping onto a folder's own contents is easy to do by accident — skip the
1386
+ // conversations that already live there rather than re-saving them.
1387
+ const toMove = conversationIds.filter(id => !this.isInProject(id, projectId));
1388
+ if (toMove.length === 0)
1389
+ return;
1004
1390
  try {
1005
- await this.engine.MoveConversationToProject(conversationId, projectId, this.currentUser);
1006
- // Reveal the destination folder so the user sees where it landed
1391
+ const result = await this.engine.MoveMultipleConversationsToProject(toMove, projectId, this.CurrentUser);
1392
+ // Reveal the destination folder so the user sees where they landed
1007
1393
  if (projectId) {
1008
1394
  this.collapsedFolderIds.delete(NormalizeUUID(projectId));
1009
1395
  }
1396
+ await this.reportBulkOutcome(result, 'moved');
1010
1397
  this.rebuildGroups();
1011
1398
  this.cdr.detectChanges();
1012
1399
  }
1013
1400
  catch (error) {
1014
- console.error('Error moving conversation:', error);
1015
- await this.dialogService.alert('Error', 'Failed to move conversation. Please try again.');
1401
+ console.error('Error moving conversations:', error);
1402
+ await this.dialogService.alert('Error', `Failed to move the selected conversation${toMove.length === 1 ? '' : 's'}. Please try again.`);
1016
1403
  }
1017
1404
  }
1405
+ /** True when a conversation already sits in the given folder (or in no folder). */
1406
+ isInProject(conversationId, projectId) {
1407
+ const conversation = this.engine.GetConversation(conversationId);
1408
+ if (!conversation)
1409
+ return false;
1410
+ const current = conversation.ProjectID ?? null;
1411
+ return projectId ? !!current && UUIDsEqual(current, projectId) : !current;
1412
+ }
1018
1413
  /** Reparents a folder under another folder (or to the top level when projectId is null). */
1019
1414
  async moveFolder(folderId, parentId) {
1020
1415
  // No-op if it's already under that parent
@@ -1025,7 +1420,7 @@ export class ConversationListComponent {
1025
1420
  if (sameParent)
1026
1421
  return;
1027
1422
  try {
1028
- await this.engine.MoveProjectToParent(folderId, parentId, this.currentUser);
1423
+ await this.engine.MoveProjectToParent(folderId, parentId, this.CurrentUser);
1029
1424
  // Reveal the new parent so the moved folder is visible
1030
1425
  if (parentId) {
1031
1426
  this.collapsedFolderIds.delete(NormalizeUUID(parentId));
@@ -1039,42 +1434,246 @@ export class ConversationListComponent {
1039
1434
  }
1040
1435
  }
1041
1436
  // ========================================================================
1042
- // MOVE-TO-FOLDER MENU
1437
+ // RIGHT-CLICK MENU — one menu for rows, folders and empty space
1043
1438
  // ========================================================================
1044
- openMoveSubmenu(conversationId, event) {
1439
+ /**
1440
+ * Opens the conversation menu. It acts on the whole selection when the clicked
1441
+ * row is part of it, and on that row alone otherwise — so right-clicking
1442
+ * something you had not selected never disturbs the selection.
1443
+ */
1444
+ OnConversationContextMenu(conversation, event) {
1445
+ event.preventDefault();
1446
+ event.stopPropagation();
1447
+ if (this.lastRowPointerType === 'touch') {
1448
+ // Some touch browsers report a long-press as a right-click; it selects instead.
1449
+ this.completeLongPress();
1450
+ return;
1451
+ }
1452
+ const targets = this.SelectedConversationIds.has(conversation.ID)
1453
+ ? Array.from(this.SelectedConversationIds)
1454
+ : [conversation.ID];
1455
+ this.openContextMenu({ kind: 'conversation', conversation, folder: null, targets }, this.pointerAnchor(event));
1456
+ }
1457
+ /** The row's ⋯ button opens the same menu, anchored under the button. */
1458
+ OpenRowMenu(conversation, event) {
1045
1459
  event.stopPropagation();
1046
- this.moveSubmenuConversationId = conversationId;
1460
+ const targets = this.SelectedConversationIds.has(conversation.ID)
1461
+ ? Array.from(this.SelectedConversationIds)
1462
+ : [conversation.ID];
1463
+ this.openContextMenu({ kind: 'conversation', conversation, folder: null, targets }, this.buttonAnchor(event));
1047
1464
  }
1048
- closeMoveSubmenu(event) {
1465
+ OnFolderContextMenu(project, event) {
1466
+ event.preventDefault();
1467
+ event.stopPropagation();
1468
+ this.openContextMenu({ kind: 'folder', conversation: null, folder: project, targets: [] }, this.pointerAnchor(event));
1469
+ }
1470
+ /** Empty space: a click that landed on a row or folder is theirs, not the list's. */
1471
+ OnBackgroundContextMenu(event) {
1472
+ const target = event.target;
1473
+ if (target?.closest('.conversation-item, .folder-row'))
1474
+ return;
1475
+ event.preventDefault();
1476
+ this.openContextMenu({ kind: 'background', conversation: null, folder: null, targets: [] }, this.pointerAnchor(event));
1477
+ }
1478
+ /** A menu opened at the pointer opens upward from the pointer when it must. */
1479
+ pointerAnchor(event) {
1480
+ return { x: event.clientX, y: event.clientY, flipBottom: event.clientY };
1481
+ }
1482
+ /** A menu opened from a button sits under it, or above it when there is no room below. */
1483
+ buttonAnchor(event) {
1484
+ const rect = event.currentTarget?.getBoundingClientRect();
1485
+ if (!rect)
1486
+ return this.pointerAnchor(event);
1487
+ return { x: rect.left, y: rect.bottom + 2, flipBottom: rect.top - 2 };
1488
+ }
1489
+ openContextMenu(menu, anchor, showFolderPicker = false) {
1490
+ this.IsMoveSubmenuOpen = showFolderPicker;
1491
+ this.ContextMenu = { ...menu, anchor, x: anchor.x, y: anchor.y };
1492
+ this.fitContextMenuInViewport();
1493
+ }
1494
+ /**
1495
+ * Keeps the open menu inside the window: it opens upward from its anchor when
1496
+ * there is no room below, and moves left when there is no room to the right.
1497
+ * Runs again whenever the folder picker changes the menu's height.
1498
+ */
1499
+ fitContextMenuInViewport() {
1500
+ if (!this.ContextMenu)
1501
+ return;
1502
+ this.cdr.detectChanges(); // render the menu so it can be measured
1503
+ const menuElement = this.contextMenuEl?.nativeElement;
1504
+ if (!menuElement)
1505
+ return;
1506
+ const { width, height } = menuElement.getBoundingClientRect();
1507
+ const { anchor } = this.ContextMenu;
1508
+ const margin = ConversationListComponent.menuViewportMargin;
1509
+ let y = anchor.y;
1510
+ if (y + height > window.innerHeight - margin) {
1511
+ const above = anchor.flipBottom - height;
1512
+ y = above >= margin ? above : Math.max(margin, window.innerHeight - margin - height);
1513
+ }
1514
+ const x = Math.max(margin, Math.min(anchor.x, window.innerWidth - margin - width));
1515
+ this.ContextMenu = { ...this.ContextMenu, x, y };
1516
+ this.cdr.detectChanges();
1517
+ }
1518
+ CloseContextMenu() {
1519
+ this.ContextMenu = null;
1520
+ this.IsMoveSubmenuOpen = false;
1521
+ }
1522
+ OpenMoveSubmenu(event) {
1523
+ event.stopPropagation();
1524
+ this.IsMoveSubmenuOpen = true;
1525
+ this.fitContextMenuInViewport();
1526
+ }
1527
+ CloseMoveSubmenu(event) {
1528
+ event.stopPropagation();
1529
+ this.IsMoveSubmenuOpen = false;
1530
+ this.fitContextMenuInViewport();
1531
+ }
1532
+ /** Marks the folder a single conversation already sits in. Never marks a multi-target menu. */
1533
+ IsSingleTargetInFolder(projectId) {
1534
+ const conversation = this.ContextMenu?.conversation;
1535
+ if (!conversation || this.ContextMenu?.targets.length !== 1)
1536
+ return false;
1537
+ return projectId
1538
+ ? !!conversation.ProjectID && UUIDsEqual(conversation.ProjectID, projectId)
1539
+ : !conversation.ProjectID;
1540
+ }
1541
+ /** Conversations the menu's actions apply to — its targets, or the selection. */
1542
+ actionTargetIds() {
1543
+ const targets = this.ContextMenu?.targets ?? [];
1544
+ return targets.length > 0 ? targets : Array.from(this.SelectedConversationIds);
1545
+ }
1546
+ ContextMoveToFolder(projectId) {
1547
+ void this.BulkMoveToFolder(projectId);
1548
+ }
1549
+ ContextMoveToNewFolder(event) {
1049
1550
  event.stopPropagation();
1050
- this.moveSubmenuConversationId = null;
1551
+ const ids = this.actionTargetIds();
1552
+ this.CloseContextMenu();
1553
+ this.openFolderModal(null, null, (created) => this.moveConversations(ids, created.ID));
1554
+ }
1555
+ ContextSetPinned(isPinned) {
1556
+ void this.BulkSetPinned(isPinned);
1557
+ }
1558
+ ContextTogglePin() {
1559
+ const conversation = this.ContextMenu?.conversation;
1560
+ if (!conversation)
1561
+ return;
1562
+ void this.BulkSetPinned(!conversation.IsPinned);
1051
1563
  }
1052
- IsInFolder(conversation, projectId) {
1053
- return !!conversation.ProjectID && UUIDsEqual(conversation.ProjectID, projectId);
1564
+ /** Shares the menu's targets — the whole selection, or just the clicked row. */
1565
+ ContextShare() {
1566
+ const ids = this.actionTargetIds();
1567
+ this.CloseContextMenu();
1568
+ this.shareConversations(ids);
1054
1569
  }
1055
- selectMoveTarget(conversation, projectId) {
1056
- this.moveConversation(conversation.ID, projectId);
1057
- this.closeMenu();
1570
+ /**
1571
+ * Opens the dialog the chat header uses for the conversations the user may
1572
+ * share, and reports how many were left out. Says why when there are none.
1573
+ */
1574
+ shareConversations(ids) {
1575
+ const conversations = ids
1576
+ .map(id => this.engine.GetConversation(id))
1577
+ .filter((c) => !!c);
1578
+ const shareable = conversations.filter(c => this.canShare(c));
1579
+ if (shareable.length === 0) {
1580
+ void this.dialogService.alert('Cannot Share', `${this.ShareRefusedReason}.`);
1581
+ return;
1582
+ }
1583
+ const skipped = conversations.length - shareable.length;
1584
+ this.ShareContexts = shareable.map(c => ({
1585
+ ResourceID: c.ID,
1586
+ ResourceName: c.Name ?? 'Conversation',
1587
+ OwnerUserID: c.UserID ?? null,
1588
+ OwnerDisplayName: c.User ?? 'You',
1589
+ CurrentUserID: this.CurrentUser?.ID ?? null
1590
+ }));
1591
+ this.ShareNotice = skipped > 0
1592
+ ? `${skipped} of ${conversations.length} left out — ${this.ShareRefusedReason.toLowerCase()}.`
1593
+ : null;
1594
+ this.IsShareDialogOpen = true;
1595
+ }
1596
+ /** True when at least one of the conversations can be shared by the current user. */
1597
+ CanShareAny(ids) {
1598
+ return ids.some(id => this.canShare(this.engine.GetConversation(id)));
1599
+ }
1600
+ canShare(conversation) {
1601
+ if (!conversation || !this.CurrentUser)
1602
+ return false;
1603
+ return this.engine.CanShareConversation(conversation, this.CurrentUser.ID);
1604
+ }
1605
+ /** True when at least one of the conversations can be moved or pinned by the current user. */
1606
+ CanChangeAny(ids) {
1607
+ return ids.some(id => {
1608
+ const conversation = this.engine.GetConversation(id);
1609
+ return !!conversation && this.CanChange(conversation);
1610
+ });
1611
+ }
1612
+ /** True when the user may move or pin the conversation: they own it, or hold Edit or Owner access. */
1613
+ CanChange(conversation) {
1614
+ if (!this.CurrentUser)
1615
+ return false;
1616
+ return this.engine.CanEditConversation(conversation, this.CurrentUser.ID);
1617
+ }
1618
+ OnShareDialogResult(_result) {
1619
+ this.IsShareDialogOpen = false;
1620
+ this.ShareContexts = [];
1621
+ this.ShareNotice = null;
1622
+ this.cdr.detectChanges();
1623
+ }
1624
+ ContextRename() {
1625
+ const conversation = this.ContextMenu?.conversation;
1626
+ this.CloseContextMenu();
1627
+ if (conversation)
1628
+ this.RenameConversation(conversation);
1629
+ }
1630
+ ContextDelete() {
1631
+ void this.BulkDeleteConversations();
1632
+ }
1633
+ ContextCreateSubfolder(event) {
1634
+ const folder = this.ContextMenu?.folder;
1635
+ this.CloseContextMenu();
1636
+ if (folder)
1637
+ this.CreateFolder(folder.ID, event);
1638
+ }
1639
+ ContextEditFolder(event) {
1640
+ const folder = this.ContextMenu?.folder;
1641
+ this.CloseContextMenu();
1642
+ if (folder)
1643
+ this.EditFolder(folder, event);
1644
+ }
1645
+ ContextDeleteFolder(event) {
1646
+ const folder = this.ContextMenu?.folder;
1647
+ this.CloseContextMenu();
1648
+ if (folder)
1649
+ void this.DeleteFolder(folder, event);
1650
+ }
1651
+ ContextNewConversation() {
1652
+ this.CloseContextMenu();
1653
+ this.CreateNewConversation();
1654
+ }
1655
+ ContextCreateRootFolder(event) {
1656
+ this.CloseContextMenu();
1657
+ this.CreateFolder(null, event);
1658
+ }
1659
+ ContextSelectAll() {
1660
+ this.CloseContextMenu();
1661
+ this.IsSelectionMode = true;
1662
+ this.SelectAll();
1058
1663
  }
1059
1664
  // ========================================================================
1060
1665
  // FOLDER CRUD (reuses the existing project form modal)
1061
1666
  // ========================================================================
1062
- createFolder(parentId, event) {
1667
+ CreateFolder(parentId, event) {
1063
1668
  if (event)
1064
1669
  event.stopPropagation();
1065
1670
  this.openFolderModal(null, parentId);
1066
1671
  }
1067
- editFolder(project, event) {
1672
+ EditFolder(project, event) {
1068
1673
  if (event)
1069
1674
  event.stopPropagation();
1070
1675
  this.openFolderModal(project, null);
1071
1676
  }
1072
- createFolderForConversation(conversation, event) {
1073
- event.stopPropagation();
1074
- const conversationId = conversation.ID;
1075
- this.closeMenu();
1076
- this.openFolderModal(null, null, (created) => this.moveConversation(conversationId, created.ID));
1077
- }
1078
1677
  openFolderModal(project, parentId, onCreated) {
1079
1678
  const dialogRef = this.mjDialogService.open({
1080
1679
  content: ProjectFormModalComponent,
@@ -1083,8 +1682,8 @@ export class ConversationListComponent {
1083
1682
  });
1084
1683
  const instance = dialogRef.Content.instance;
1085
1684
  instance.dialogRef = dialogRef;
1086
- instance.environmentId = this.environmentId;
1087
- instance.currentUser = this.currentUser;
1685
+ instance.environmentId = this.EnvironmentId;
1686
+ instance.currentUser = this.CurrentUser;
1088
1687
  if (project)
1089
1688
  instance.project = project;
1090
1689
  if (parentId)
@@ -1101,10 +1700,10 @@ export class ConversationListComponent {
1101
1700
  onCreated(saved);
1102
1701
  });
1103
1702
  }
1104
- async deleteFolder(project, event) {
1703
+ async DeleteFolder(project, event) {
1105
1704
  if (event)
1106
1705
  event.stopPropagation();
1107
- const node = this.findFolderNode(this.folderTree, project.ID);
1706
+ const node = this.findFolderNode(this.FolderTree, project.ID);
1108
1707
  const total = node?.totalCount ?? 0;
1109
1708
  const childCount = node?.children.length ?? 0;
1110
1709
  let message = `Are you sure you want to delete the folder "${project.Name}"?`;
@@ -1123,7 +1722,7 @@ export class ConversationListComponent {
1123
1722
  if (!confirmed)
1124
1723
  return;
1125
1724
  try {
1126
- await this.engine.DeleteProject(project.ID, this.currentUser);
1725
+ await this.engine.DeleteProject(project.ID, this.CurrentUser);
1127
1726
  this.collapsedFolderIds.delete(NormalizeUUID(project.ID));
1128
1727
  this.rebuildGroups();
1129
1728
  this.cdr.detectChanges();
@@ -1134,31 +1733,29 @@ export class ConversationListComponent {
1134
1733
  }
1135
1734
  }
1136
1735
  IsConversationActive(conversation) {
1137
- return UUIDsEqual(conversation.ID, this.selectedConversationId);
1736
+ return UUIDsEqual(conversation.ID, this.SelectedConversationId);
1138
1737
  }
1139
- IsConversationRenamed(conversation) {
1140
- return UUIDsEqual(conversation.ID, this.renamedConversationId);
1738
+ /** True when this conversation is part of the current multi-selection. */
1739
+ IsConversationSelected(conversation) {
1740
+ return this.IsSelectionMode && this.SelectedConversationIds.has(conversation.ID);
1141
1741
  }
1142
- IsMenuOpen(conversation) {
1143
- return UUIDsEqual(this.openMenuConversationId, conversation.ID);
1742
+ IsConversationRenamed(conversation) {
1743
+ return UUIDsEqual(conversation.ID, this.RenamedConversationId);
1144
1744
  }
1145
1745
  IsConversationDragging(conversation) {
1146
- return UUIDsEqual(this.draggedConversationId, conversation.ID);
1147
- }
1148
- IsMoveSubmenuOpen(conversation) {
1149
- return UUIDsEqual(this.moveSubmenuConversationId, conversation.ID);
1746
+ return this.DraggedConversationIds.some(id => UUIDsEqual(id, conversation.ID));
1150
1747
  }
1151
- selectConversation(conversation) {
1152
- this.conversationSelected.emit(conversation.ID);
1748
+ SelectConversation(conversation) {
1749
+ this.ConversationSelected.emit(conversation.ID);
1153
1750
  // Clear unread notifications when conversation is opened
1154
1751
  this.notificationService.markConversationAsRead(conversation.ID);
1155
1752
  }
1156
- async createNewConversation() {
1753
+ async CreateNewConversation() {
1157
1754
  // Don't create DB record yet - just show the welcome screen
1158
1755
  // Conversation will be created when user sends first message
1159
- this.newConversationRequested.emit();
1756
+ this.NewConversationRequested.emit();
1160
1757
  }
1161
- async renameConversation(conversation) {
1758
+ async RenameConversation(conversation) {
1162
1759
  try {
1163
1760
  const result = await this.dialogService.input({
1164
1761
  title: 'Edit Conversation',
@@ -1178,7 +1775,7 @@ export class ConversationListComponent {
1178
1775
  const newName = typeof result === 'string' ? result : result.value;
1179
1776
  const newDescription = typeof result === 'string' ? conversation.Description : result.secondValue;
1180
1777
  if (newName !== conversation.Name || newDescription !== conversation.Description) {
1181
- await this.engine.SaveConversation(conversation.ID, { Name: newName, Description: newDescription || '' }, this.currentUser);
1778
+ await this.engine.SaveConversation(conversation.ID, { Name: newName, Description: newDescription || '' }, this.CurrentUser);
1182
1779
  }
1183
1780
  }
1184
1781
  }
@@ -1187,7 +1784,7 @@ export class ConversationListComponent {
1187
1784
  await this.dialogService.alert('Error', 'Failed to update conversation. Please try again.');
1188
1785
  }
1189
1786
  }
1190
- async deleteConversation(conversation) {
1787
+ async DeleteConversation(conversation) {
1191
1788
  try {
1192
1789
  const confirmed = await this.dialogService.confirm({
1193
1790
  title: 'Delete Conversation',
@@ -1197,9 +1794,9 @@ export class ConversationListComponent {
1197
1794
  });
1198
1795
  if (confirmed) {
1199
1796
  const deletedId = conversation.ID;
1200
- await this.engine.DeleteConversation(deletedId, this.currentUser);
1797
+ await this.engine.DeleteConversation(deletedId, this.CurrentUser);
1201
1798
  this.cdr.detectChanges();
1202
- this.conversationDeleted.emit(deletedId);
1799
+ this.ConversationDeleted.emit(deletedId);
1203
1800
  }
1204
1801
  }
1205
1802
  catch (error) {
@@ -1207,64 +1804,238 @@ export class ConversationListComponent {
1207
1804
  await this.dialogService.alert('Error', 'Failed to delete conversation. Please try again.');
1208
1805
  }
1209
1806
  }
1210
- toggleMenu(conversationId, event) {
1211
- event.stopPropagation();
1212
- this.openMenuConversationId = this.openMenuConversationId === conversationId ? null : conversationId;
1213
- }
1214
- closeMenu() {
1215
- this.openMenuConversationId = null;
1216
- this.moveSubmenuConversationId = null;
1217
- }
1218
- async togglePin(conversation, event) {
1807
+ async TogglePin(conversation, event) {
1219
1808
  if (event)
1220
1809
  event.stopPropagation();
1221
- this.closeMenu(); // Close immediately on user action — don't wait for the async op
1810
+ this.CloseContextMenu(); // Close immediately on user action — don't wait for the async op
1222
1811
  try {
1223
- await this.engine.PinConversation(conversation.ID, !conversation.IsPinned, this.currentUser);
1812
+ await this.engine.PinConversation(conversation.ID, !conversation.IsPinned, this.CurrentUser);
1224
1813
  }
1225
1814
  catch (error) {
1226
1815
  console.error('Error toggling pin:', error);
1227
1816
  await this.dialogService.alert('Error', 'Failed to pin/unpin conversation. Please try again.');
1228
1817
  }
1229
1818
  }
1230
- hasActiveTasks(conversationId) {
1231
- return this.conversationIdsWithTasks.has(conversationId);
1819
+ HasActiveTasks(conversationId) {
1820
+ return this.ConversationIdsWithTasks.has(conversationId);
1232
1821
  }
1233
1822
  /** True when this conversation was shared with the current user by someone else. */
1234
- isSharedWithMe(conversation) {
1823
+ IsSharedWithMe(conversation) {
1235
1824
  return this.engine.GetSharedByInfo(conversation.ID) !== null;
1236
1825
  }
1237
1826
  /** Tooltip for the sidebar share icon: "Shared by {email or name}". */
1238
- sharedWithMeTooltip(conversation) {
1827
+ SharedWithMeTooltip(conversation) {
1239
1828
  const info = this.engine.GetSharedByInfo(conversation.ID);
1240
1829
  if (!info)
1241
1830
  return 'Shared with you';
1242
1831
  return `Shared by ${info.Email ?? info.Name ?? 'another user'}`;
1243
1832
  }
1244
- toggleSelectionMode() {
1245
- this.isSelectionMode = !this.isSelectionMode;
1246
- if (!this.isSelectionMode) {
1247
- this.selectedConversationIds.clear();
1833
+ ToggleSelectionMode() {
1834
+ if (this.IsSelectionMode) {
1835
+ this.exitSelectionMode();
1836
+ }
1837
+ else {
1838
+ this.IsSelectionMode = true;
1248
1839
  }
1249
1840
  }
1250
- toggleConversationSelection(conversationId) {
1251
- if (this.selectedConversationIds.has(conversationId)) {
1252
- this.selectedConversationIds.delete(conversationId);
1841
+ /**
1842
+ * Clicking the empty space of the list drops the selection, the way clicking
1843
+ * blank space in a file browser does. A click that landed on a row, folder,
1844
+ * section header or button is handled by that element instead.
1845
+ */
1846
+ OnListBackgroundClick(event) {
1847
+ if (!this.IsSelectionMode)
1848
+ return;
1849
+ const target = event.target;
1850
+ if (target?.closest('.conversation-item, .folder-row, .section-header, button'))
1851
+ return;
1852
+ this.exitSelectionMode();
1853
+ }
1854
+ exitSelectionMode() {
1855
+ this.IsSelectionMode = false;
1856
+ this.SelectedConversationIds.clear();
1857
+ this.selectionAnchorId = null;
1858
+ }
1859
+ /** Ends selection mode from the selection bar's clear button. */
1860
+ ClearSelection() {
1861
+ this.exitSelectionMode();
1862
+ }
1863
+ /** Selection mode closes itself once the last row is deselected. */
1864
+ exitSelectionModeIfEmpty() {
1865
+ if (this.SelectedConversationIds.size === 0) {
1866
+ this.exitSelectionMode();
1867
+ }
1868
+ }
1869
+ /** Adds or removes one row and makes it the range anchor, ending the mode when nothing is left. */
1870
+ toggleRowSelection(conversationId) {
1871
+ this.ToggleConversationSelection(conversationId);
1872
+ this.selectionAnchorId = conversationId;
1873
+ this.exitSelectionModeIfEmpty();
1874
+ }
1875
+ /**
1876
+ * Drops selected rows the view no longer shows — after a search edit, a
1877
+ * collapse, or a grouping change — so no action can reach a row the user
1878
+ * cannot see. A list rebuild alone does not call this: a move into a
1879
+ * collapsed folder keeps its rows selected for a follow-up action.
1880
+ */
1881
+ dropHiddenRowsFromSelection() {
1882
+ if (this.SelectedConversationIds.size === 0)
1883
+ return;
1884
+ const visible = new Set(this.visibleConversationIds().map(id => NormalizeUUID(id)));
1885
+ this.removeFromSelection(id => !visible.has(NormalizeUUID(id)));
1886
+ }
1887
+ /** Drops selected conversations that are no longer in the engine's list at all. */
1888
+ dropRemovedConversationsFromSelection() {
1889
+ if (this.SelectedConversationIds.size === 0)
1890
+ return;
1891
+ const listed = new Set(this.engine.Conversations.map(c => NormalizeUUID(c.ID)));
1892
+ this.removeFromSelection(id => !listed.has(NormalizeUUID(id)));
1893
+ }
1894
+ /** Removes the selected IDs that match, and ends selection mode if none remain. */
1895
+ removeFromSelection(shouldRemove) {
1896
+ for (const id of Array.from(this.SelectedConversationIds)) {
1897
+ if (shouldRemove(id)) {
1898
+ this.SelectedConversationIds.delete(id);
1899
+ }
1900
+ }
1901
+ this.exitSelectionModeIfEmpty();
1902
+ }
1903
+ /**
1904
+ * Adds the open conversation to a selection that is just starting, so it moves
1905
+ * with the rows picked alongside it. Returns the id added, or null when nothing
1906
+ * is open or it is hidden inside a collapsed folder or section.
1907
+ */
1908
+ seedSelectionWithOpenConversation() {
1909
+ const openId = this.SelectedConversationId;
1910
+ if (!openId)
1911
+ return null;
1912
+ const visibleId = this.visibleConversationIds().find(id => UUIDsEqual(id, openId));
1913
+ if (!visibleId)
1914
+ return null;
1915
+ this.SelectedConversationIds.add(visibleId);
1916
+ return visibleId;
1917
+ }
1918
+ /** Conversation IDs in the order the list renders them, skipping collapsed sections and folders. */
1919
+ visibleConversationIds() {
1920
+ const ids = [];
1921
+ const sectionOpen = (expanded) => !this.ShowSectionHeaders || expanded;
1922
+ if (sectionOpen(this.PinnedExpanded)) {
1923
+ ids.push(...this.PinnedConversations.map(c => c.ID));
1924
+ }
1925
+ if (this.ShowSectionHeaders && this.GroupBy === 'project') {
1926
+ if (this.FoldersExpanded) {
1927
+ // Subfolders render above their parent folder's own conversations.
1928
+ const walk = (nodes) => {
1929
+ for (const node of nodes) {
1930
+ if (!this.IsFolderExpanded(node.project.ID))
1931
+ continue;
1932
+ walk(node.children);
1933
+ ids.push(...node.conversations.map(c => c.ID));
1934
+ }
1935
+ };
1936
+ walk(this.FolderTree);
1937
+ }
1938
+ if (this.UngroupedExpanded) {
1939
+ ids.push(...this.UngroupedConversations.map(c => c.ID));
1940
+ }
1941
+ }
1942
+ else if (sectionOpen(this.DirectMessagesExpanded)) {
1943
+ ids.push(...this.UnpinnedConversations.map(c => c.ID));
1944
+ }
1945
+ return ids;
1946
+ }
1947
+ /**
1948
+ * Adds every row between the anchor and `conversationId` to the selection.
1949
+ * Rows already picked stay picked — a range never takes a selection away.
1950
+ *
1951
+ * With nothing picked yet the open conversation stands in as the anchor, so a
1952
+ * single Shift-click highlights the span from it rather than one lone row.
1953
+ */
1954
+ selectRangeTo(conversationId) {
1955
+ const order = this.visibleConversationIds();
1956
+ const end = this.indexOfConversation(order, conversationId);
1957
+ if (end < 0)
1958
+ return;
1959
+ const anchorId = this.selectionAnchorId ?? this.SelectedConversationId;
1960
+ const start = this.indexOfConversation(order, anchorId);
1961
+ if (start < 0) {
1962
+ // No anchor and no open conversation on screen — pick this row alone.
1963
+ this.SelectedConversationIds.add(conversationId);
1964
+ this.selectionAnchorId = conversationId;
1965
+ return;
1966
+ }
1967
+ this.selectionAnchorId = order[start];
1968
+ const [from, to] = start <= end ? [start, end] : [end, start];
1969
+ for (let i = from; i <= to; i++) {
1970
+ this.SelectedConversationIds.add(order[i]);
1971
+ }
1972
+ }
1973
+ ToggleConversationSelection(conversationId) {
1974
+ if (this.SelectedConversationIds.has(conversationId)) {
1975
+ this.SelectedConversationIds.delete(conversationId);
1253
1976
  }
1254
1977
  else {
1255
- this.selectedConversationIds.add(conversationId);
1978
+ this.SelectedConversationIds.add(conversationId);
1256
1979
  }
1257
1980
  }
1258
- selectAll() {
1259
- this.filteredConversations.forEach(c => {
1260
- this.selectedConversationIds.add(c.ID);
1981
+ /** Selects every row on screen — never rows hidden by the search or a collapsed folder or section. */
1982
+ SelectAll() {
1983
+ this.visibleConversationIds().forEach(id => {
1984
+ this.SelectedConversationIds.add(id);
1261
1985
  });
1262
1986
  }
1263
- deselectAll() {
1264
- this.selectedConversationIds.clear();
1987
+ DeselectAll() {
1988
+ this.SelectedConversationIds.clear();
1989
+ }
1990
+ /**
1991
+ * Moves the conversations into one folder, or out of all folders when projectId
1992
+ * is null. The selection survives so a second bulk action can follow.
1993
+ */
1994
+ async BulkMoveToFolder(projectId, ids = this.actionTargetIds()) {
1995
+ this.CloseContextMenu();
1996
+ if (ids.length === 0)
1997
+ return;
1998
+ try {
1999
+ const result = await this.engine.MoveMultipleConversationsToProject(ids, projectId, this.CurrentUser);
2000
+ await this.reportBulkOutcome(result, 'moved');
2001
+ }
2002
+ catch (error) {
2003
+ console.error('Error moving conversations:', error);
2004
+ await this.dialogService.alert('Error', 'Failed to move the selected conversations. Please try again.');
2005
+ }
2006
+ this.cdr.detectChanges();
2007
+ }
2008
+ /** Pins or unpins the conversations, keeping the selection. */
2009
+ async BulkSetPinned(isPinned, ids = this.actionTargetIds()) {
2010
+ this.CloseContextMenu();
2011
+ if (ids.length === 0)
2012
+ return;
2013
+ try {
2014
+ const result = await this.engine.PinMultipleConversations(ids, isPinned, this.CurrentUser);
2015
+ await this.reportBulkOutcome(result, isPinned ? 'pinned' : 'unpinned');
2016
+ }
2017
+ catch (error) {
2018
+ console.error('Error pinning conversations:', error);
2019
+ await this.dialogService.alert('Error', `Failed to ${isPinned ? 'pin' : 'unpin'} the selected conversations. Please try again.`);
2020
+ }
2021
+ this.cdr.detectChanges();
1265
2022
  }
1266
- async bulkDeleteConversations() {
1267
- const count = this.selectedConversationIds.size;
2023
+ /** Reports the conversations a bulk action could not change. Silent on full success. */
2024
+ async reportBulkOutcome(result, verb) {
2025
+ if (result.Failed.length === 0)
2026
+ return;
2027
+ const failedNames = result.Failed.map(f => `"${f.Name}" (${f.Error})`).join(', ');
2028
+ await this.dialogService.alert('Partial Success', `${result.Successful.length} conversation${result.Successful.length === 1 ? '' : 's'} ${verb}.\n\n` +
2029
+ `${result.Failed.length} could not be ${verb}: ${failedNames}`);
2030
+ }
2031
+ /**
2032
+ * Deletes the conversations after confirmation. Only the deleted ones leave the
2033
+ * selection: deleting a row outside it leaves it alone, and rows that failed
2034
+ * stay selected so the user can try again.
2035
+ */
2036
+ async BulkDeleteConversations(ids = this.actionTargetIds()) {
2037
+ const count = ids.length;
2038
+ this.CloseContextMenu();
1268
2039
  if (count === 0)
1269
2040
  return;
1270
2041
  const confirmed = await this.dialogService.confirm({
@@ -1273,132 +2044,734 @@ export class ConversationListComponent {
1273
2044
  okText: 'Delete',
1274
2045
  cancelText: 'Cancel'
1275
2046
  });
1276
- if (confirmed) {
1277
- try {
1278
- const result = await this.engine.DeleteMultipleConversations(Array.from(this.selectedConversationIds), this.currentUser);
1279
- if (result.Failed.length > 0 && result.Successful.length > 0) {
1280
- // Partial success
1281
- const failedNames = result.Failed.map(f => `"${f.Name}"`).join(', ');
1282
- await this.dialogService.alert('Partial Success', `Deleted ${result.Successful.length} of ${count} conversations.\n\n` +
1283
- `${result.Failed.length} could not be deleted: ${failedNames}`);
1284
- }
1285
- else if (result.Failed.length > 0 && result.Successful.length === 0) {
1286
- // All failed
1287
- await this.dialogService.alert('Delete Failed', `None of the ${count} conversations could be deleted. They may have already been removed.`);
1288
- }
1289
- // Emit deleted events for successful deletions
1290
- for (const id of result.Successful) {
1291
- this.conversationDeleted.emit(id);
1292
- }
1293
- }
1294
- catch (error) {
1295
- console.error('Error deleting conversations:', error);
1296
- await this.dialogService.alert('Error', 'Failed to delete conversations. Please try again.');
1297
- }
1298
- finally {
1299
- // Always exit selection mode after an attempt, whether success or failure
1300
- this.selectedConversationIds.clear();
1301
- this.isSelectionMode = false;
1302
- this.cdr.detectChanges();
2047
+ if (!confirmed)
2048
+ return;
2049
+ try {
2050
+ const result = await this.engine.DeleteMultipleConversations(ids, this.CurrentUser);
2051
+ await this.reportDeleteOutcome(result, count);
2052
+ for (const id of result.Successful) {
2053
+ this.ConversationDeleted.emit(id);
1303
2054
  }
2055
+ const deleted = new Set(result.Successful.map(id => NormalizeUUID(id)));
2056
+ this.removeFromSelection(id => deleted.has(NormalizeUUID(id)));
2057
+ }
2058
+ catch (error) {
2059
+ console.error('Error deleting conversations:', error);
2060
+ await this.dialogService.alert('Error', 'Failed to delete conversations. Please try again.');
2061
+ }
2062
+ finally {
2063
+ this.cdr.detectChanges();
1304
2064
  }
1305
2065
  }
1306
- handleConversationClick(conversation) {
1307
- if (this.isSelectionMode) {
1308
- this.toggleConversationSelection(conversation.ID);
2066
+ /** Reports the conversations a bulk delete could not remove. Silent on full success. */
2067
+ async reportDeleteOutcome(result, count) {
2068
+ if (result.Failed.length === 0)
2069
+ return;
2070
+ if (result.Successful.length === 0) {
2071
+ await this.dialogService.alert('Delete Failed', `None of the ${count} conversations could be deleted. They may have already been removed.`);
2072
+ return;
1309
2073
  }
1310
- else {
1311
- this.selectConversation(conversation);
2074
+ const failedNames = result.Failed.map(f => `"${f.Name}"`).join(', ');
2075
+ await this.dialogService.alert('Partial Success', `Deleted ${result.Successful.length} of ${count} conversations.\n\n` +
2076
+ `${result.Failed.length} could not be deleted: ${failedNames}`);
2077
+ }
2078
+ // ========================================================================
2079
+ // SELECTION BAR — stands in for the search row while a selection exists
2080
+ // ========================================================================
2081
+ /** The selected conversation IDs, in the order they were picked. */
2082
+ get SelectedIds() {
2083
+ return Array.from(this.SelectedConversationIds);
2084
+ }
2085
+ /** True when any selected conversation is unpinned, so the bar's pin button pins rather than unpins. */
2086
+ SelectionHasUnpinned() {
2087
+ return this.SelectedIds.some(id => !this.engine.GetConversation(id)?.IsPinned);
2088
+ }
2089
+ /** The bar acts on the selection even while a menu for another row is open. */
2090
+ BarSetPinned() {
2091
+ void this.BulkSetPinned(this.SelectionHasUnpinned(), this.SelectedIds);
2092
+ }
2093
+ BarShare() {
2094
+ this.CloseContextMenu();
2095
+ this.shareConversations(this.SelectedIds);
2096
+ }
2097
+ BarDelete() {
2098
+ void this.BulkDeleteConversations(this.SelectedIds);
2099
+ }
2100
+ /** Opens the folder picker for the selection, under the bar's Move button. */
2101
+ BarOpenMoveMenu(event) {
2102
+ event.stopPropagation(); // the document click would close the picker straight away
2103
+ const ids = this.SelectedIds;
2104
+ const conversation = ids.length === 1 ? this.engine.GetConversation(ids[0]) ?? null : null;
2105
+ this.openContextMenu({ kind: 'conversation', conversation, folder: null, targets: ids }, this.buttonAnchor(event), true);
2106
+ }
2107
+ // ========================================================================
2108
+ // ROW CLICKS, CHECKBOXES AND TOUCH PRESSES
2109
+ // ========================================================================
2110
+ /**
2111
+ * The row checkbox adds or removes its row without opening it — the mouse
2112
+ * route to a selection that needs no keyboard. Shift-click extends a range.
2113
+ * Unlike a Ctrl-click it never takes the open conversation along, so the
2114
+ * checkboxes show exactly what is picked.
2115
+ */
2116
+ OnRowCheckboxClick(conversation, event) {
2117
+ event.stopPropagation();
2118
+ this.IsSelectionMode = true;
2119
+ if (event.shiftKey) {
2120
+ this.selectRangeTo(conversation.ID);
2121
+ return;
1312
2122
  }
2123
+ this.toggleRowSelection(conversation.ID);
2124
+ }
2125
+ /**
2126
+ * Starts timing a touch press on a row; held long enough, it selects the row.
2127
+ * Presses on the row's own buttons (the checkbox and ⋯) are theirs to handle.
2128
+ */
2129
+ OnRowPointerDown(conversation, event) {
2130
+ this.lastRowPointerType = event.pointerType;
2131
+ this.ignoreNextRowClick = false;
2132
+ this.CancelLongPress();
2133
+ if (event.pointerType !== 'touch')
2134
+ return;
2135
+ if (event.target?.closest('button'))
2136
+ return;
2137
+ this.longPress = {
2138
+ conversation,
2139
+ x: event.clientX,
2140
+ y: event.clientY,
2141
+ timer: setTimeout(() => this.completeLongPress(), ConversationListComponent.longPressDelayMs)
2142
+ };
2143
+ }
2144
+ /** A touch that drifts is a scroll, not a press. */
2145
+ OnRowPointerMove(event) {
2146
+ if (!this.longPress)
2147
+ return;
2148
+ const distance = Math.hypot(event.clientX - this.longPress.x, event.clientY - this.longPress.y);
2149
+ if (distance > ConversationListComponent.longPressMoveTolerancePx) {
2150
+ this.CancelLongPress();
2151
+ }
2152
+ }
2153
+ CancelLongPress() {
2154
+ if (this.longPress) {
2155
+ clearTimeout(this.longPress.timer);
2156
+ this.longPress = null;
2157
+ }
2158
+ }
2159
+ /**
2160
+ * Completes the press in progress, if any: selects its row and starts
2161
+ * selection mode, as a long-press does in Gmail. The click that ends the same
2162
+ * press is then ignored, so it does not undo the selection.
2163
+ */
2164
+ completeLongPress() {
2165
+ const press = this.longPress;
2166
+ if (!press)
2167
+ return;
2168
+ this.CancelLongPress();
2169
+ this.ignoreNextRowClick = true;
2170
+ this.IsSelectionMode = true;
2171
+ this.SelectedConversationIds.add(press.conversation.ID);
2172
+ this.selectionAnchorId = press.conversation.ID;
2173
+ this.cdr.detectChanges();
2174
+ }
2175
+ /**
2176
+ * Routes a row click. Ctrl/Cmd toggles one row and Shift extends from the
2177
+ * anchor, either one starting selection mode. On touch, while selecting, a tap
2178
+ * adds or removes the row. Any other click collapses the selection and opens
2179
+ * the conversation.
2180
+ */
2181
+ HandleConversationClick(conversation, event) {
2182
+ if (this.ignoreNextRowClick) {
2183
+ this.ignoreNextRowClick = false;
2184
+ return;
2185
+ }
2186
+ if (this.IsSelectionMode && this.lastRowPointerType === 'touch') {
2187
+ this.toggleRowSelection(conversation.ID);
2188
+ return;
2189
+ }
2190
+ const isRangeClick = !!event?.shiftKey;
2191
+ const isToggleClick = !!event && (event.ctrlKey || event.metaKey);
2192
+ if (isRangeClick || isToggleClick) {
2193
+ event?.preventDefault(); // a Shift-click would otherwise paint a text selection
2194
+ const entering = !this.IsSelectionMode;
2195
+ if (entering) {
2196
+ this.IsSelectionMode = true;
2197
+ }
2198
+ if (isRangeClick) {
2199
+ this.selectRangeTo(conversation.ID);
2200
+ }
2201
+ else {
2202
+ // The open conversation reads as picked, so a Ctrl-click that starts a
2203
+ // selection takes it along; a Shift-click already ranges from it.
2204
+ const seeded = entering ? this.seedSelectionWithOpenConversation() : null;
2205
+ if (!seeded || !UUIDsEqual(seeded, conversation.ID)) {
2206
+ this.ToggleConversationSelection(conversation.ID);
2207
+ }
2208
+ this.selectionAnchorId = conversation.ID;
2209
+ this.exitSelectionModeIfEmpty();
2210
+ }
2211
+ return;
2212
+ }
2213
+ // A plain click collapses the selection down to this one conversation, the
2214
+ // way a file browser does.
2215
+ if (this.IsSelectionMode) {
2216
+ this.exitSelectionMode();
2217
+ }
2218
+ this.SelectConversation(conversation);
2219
+ }
2220
+ /** @deprecated Use {@link EnvironmentId}. */
2221
+ set environmentId(value) {
2222
+ this.EnvironmentId = value;
2223
+ }
2224
+ /** @deprecated Use {@link EnvironmentId}. */
2225
+ get environmentId() {
2226
+ return this.EnvironmentId;
2227
+ }
2228
+ /** @deprecated Use {@link CurrentUser}. */
2229
+ set currentUser(value) {
2230
+ this.CurrentUser = value;
2231
+ }
2232
+ /** @deprecated Use {@link CurrentUser}. */
2233
+ get currentUser() {
2234
+ return this.CurrentUser;
2235
+ }
2236
+ /** @deprecated Use {@link SelectedConversationId}. */
2237
+ set selectedConversationId(value) {
2238
+ this.SelectedConversationId = value;
2239
+ }
2240
+ /** @deprecated Use {@link SelectedConversationId}. */
2241
+ get selectedConversationId() {
2242
+ return this.SelectedConversationId;
2243
+ }
2244
+ /** @deprecated Use {@link RenamedConversationId}. */
2245
+ set renamedConversationId(value) {
2246
+ this.RenamedConversationId = value;
2247
+ }
2248
+ /** @deprecated Use {@link RenamedConversationId}. */
2249
+ get renamedConversationId() {
2250
+ return this.RenamedConversationId;
2251
+ }
2252
+ /** @deprecated Use {@link IsSidebarPinned}. */
2253
+ set isSidebarPinned(value) {
2254
+ this.IsSidebarPinned = value;
2255
+ }
2256
+ /** @deprecated Use {@link IsSidebarPinned}. */
2257
+ get isSidebarPinned() {
2258
+ return this.IsSidebarPinned;
2259
+ } // Whether sidebar is pinned (stays open after selection)
2260
+ /** @deprecated Use {@link IsMobileView}. */
2261
+ set isMobileView(value) {
2262
+ this.IsMobileView = value;
2263
+ }
2264
+ /** @deprecated Use {@link IsMobileView}. */
2265
+ get isMobileView() {
2266
+ return this.IsMobileView;
2267
+ } // Whether we're on mobile (no pin options)
2268
+ /** @deprecated Use {@link ShowNewConversationButton}. */
2269
+ set showNewConversationButton(value) {
2270
+ this.ShowNewConversationButton = value;
2271
+ }
2272
+ /** @deprecated Use {@link ShowNewConversationButton}. */
2273
+ get showNewConversationButton() {
2274
+ return this.ShowNewConversationButton;
2275
+ }
2276
+ /** @deprecated Use {@link ShowHeaderMenu}. */
2277
+ set showHeaderMenu(value) {
2278
+ this.ShowHeaderMenu = value;
2279
+ }
2280
+ /** @deprecated Use {@link ShowHeaderMenu}. */
2281
+ get showHeaderMenu() {
2282
+ return this.ShowHeaderMenu;
2283
+ }
2284
+ /** @deprecated Use {@link ShowSectionHeaders}. */
2285
+ set showSectionHeaders(value) {
2286
+ this.ShowSectionHeaders = value;
2287
+ }
2288
+ /** @deprecated Use {@link ShowSectionHeaders}. */
2289
+ get showSectionHeaders() {
2290
+ return this.ShowSectionHeaders;
2291
+ }
2292
+ /** @deprecated Use {@link DirectMessagesExpanded}. */
2293
+ get directMessagesExpanded() {
2294
+ return this.DirectMessagesExpanded;
2295
+ }
2296
+ /** @deprecated Use {@link DirectMessagesExpanded}. */
2297
+ set directMessagesExpanded(value) {
2298
+ this.DirectMessagesExpanded = value;
2299
+ }
2300
+ /** @deprecated Use {@link PinnedExpanded}. */
2301
+ get pinnedExpanded() {
2302
+ return this.PinnedExpanded;
2303
+ }
2304
+ /** @deprecated Use {@link PinnedExpanded}. */
2305
+ set pinnedExpanded(value) {
2306
+ this.PinnedExpanded = value;
2307
+ }
2308
+ /** @deprecated Use {@link FoldersExpanded}. */
2309
+ get foldersExpanded() {
2310
+ return this.FoldersExpanded;
2311
+ }
2312
+ /** @deprecated Use {@link FoldersExpanded}. */
2313
+ set foldersExpanded(value) {
2314
+ this.FoldersExpanded = value;
2315
+ }
2316
+ /** @deprecated Use {@link UngroupedExpanded}. */
2317
+ get ungroupedExpanded() {
2318
+ return this.UngroupedExpanded;
2319
+ }
2320
+ /** @deprecated Use {@link UngroupedExpanded}. */
2321
+ set ungroupedExpanded(value) {
2322
+ this.UngroupedExpanded = value;
2323
+ }
2324
+ /** @deprecated Use {@link ConversationIdsWithTasks}. */
2325
+ get conversationIdsWithTasks() {
2326
+ return this.ConversationIdsWithTasks;
2327
+ }
2328
+ /** @deprecated Use {@link ConversationIdsWithTasks}. */
2329
+ set conversationIdsWithTasks(value) {
2330
+ this.ConversationIdsWithTasks = value;
2331
+ }
2332
+ /** @deprecated Use {@link IsSelectionMode}. */
2333
+ get isSelectionMode() {
2334
+ return this.IsSelectionMode;
2335
+ }
2336
+ /** @deprecated Use {@link IsSelectionMode}. */
2337
+ set isSelectionMode(value) {
2338
+ this.IsSelectionMode = value;
2339
+ }
2340
+ /** @deprecated Use {@link SelectedConversationIds}. */
2341
+ get selectedConversationIds() {
2342
+ return this.SelectedConversationIds;
2343
+ }
2344
+ /** @deprecated Use {@link SelectedConversationIds}. */
2345
+ set selectedConversationIds(value) {
2346
+ this.SelectedConversationIds = value;
2347
+ }
2348
+ /** @deprecated Use {@link IsHeaderMenuOpen}. */
2349
+ get isHeaderMenuOpen() {
2350
+ return this.IsHeaderMenuOpen;
2351
+ }
2352
+ /** @deprecated Use {@link IsHeaderMenuOpen}. */
2353
+ set isHeaderMenuOpen(value) {
2354
+ this.IsHeaderMenuOpen = value;
2355
+ }
2356
+ /** @deprecated Use {@link IsRefreshing}. */
2357
+ get isRefreshing() {
2358
+ return this.IsRefreshing;
2359
+ }
2360
+ /** @deprecated Use {@link IsRefreshing}. */
2361
+ set isRefreshing(value) {
2362
+ this.IsRefreshing = value;
2363
+ }
2364
+ /** @deprecated Use {@link GroupBy}. */
2365
+ get groupBy() {
2366
+ return this.GroupBy;
2367
+ }
2368
+ /** @deprecated Use {@link GroupBy}. */
2369
+ set groupBy(value) {
2370
+ this.GroupBy = value;
2371
+ }
2372
+ /** @deprecated Use {@link PinnedConversations}. */
2373
+ get pinnedConversations() {
2374
+ return this.PinnedConversations;
2375
+ }
2376
+ /** @deprecated Use {@link PinnedConversations}. */
2377
+ set pinnedConversations(value) {
2378
+ this.PinnedConversations = value;
2379
+ }
2380
+ /** @deprecated Use {@link UnpinnedConversations}. */
2381
+ get unpinnedConversations() {
2382
+ return this.UnpinnedConversations;
2383
+ }
2384
+ /** @deprecated Use {@link UnpinnedConversations}. */
2385
+ set unpinnedConversations(value) {
2386
+ this.UnpinnedConversations = value;
2387
+ }
2388
+ /** @deprecated Use {@link UngroupedConversations}. */
2389
+ get ungroupedConversations() {
2390
+ return this.UngroupedConversations;
2391
+ }
2392
+ /** @deprecated Use {@link UngroupedConversations}. */
2393
+ set ungroupedConversations(value) {
2394
+ this.UngroupedConversations = value;
2395
+ }
2396
+ /** @deprecated Use {@link FolderTree}. */
2397
+ get folderTree() {
2398
+ return this.FolderTree;
2399
+ }
2400
+ /** @deprecated Use {@link FolderTree}. */
2401
+ set folderTree(value) {
2402
+ this.FolderTree = value;
2403
+ }
2404
+ /** @deprecated Use {@link FlatFolders}. */
2405
+ get flatFolders() {
2406
+ return this.FlatFolders;
2407
+ }
2408
+ /** @deprecated Use {@link FlatFolders}. */
2409
+ set flatFolders(value) {
2410
+ this.FlatFolders = value;
2411
+ }
2412
+ /** @deprecated Use {@link DraggedFolderId}. */
2413
+ get draggedFolderId() {
2414
+ return this.DraggedFolderId;
2415
+ }
2416
+ /** @deprecated Use {@link DraggedFolderId}. */
2417
+ set draggedFolderId(value) {
2418
+ this.DraggedFolderId = value;
2419
+ }
2420
+ /** @deprecated Use {@link DragOverTargetId}. */
2421
+ get dragOverTargetId() {
2422
+ return this.DragOverTargetId;
2423
+ }
2424
+ /** @deprecated Use {@link DragOverTargetId}. */
2425
+ set dragOverTargetId(value) {
2426
+ this.DragOverTargetId = value;
2427
+ }
2428
+ /** @deprecated Use {@link SearchQuery}. */
2429
+ get searchQuery() {
2430
+ return this.SearchQuery;
2431
+ }
2432
+ /** @deprecated Use {@link SearchQuery}. */
2433
+ set searchQuery(value) {
2434
+ this.SearchQuery = value;
2435
+ }
2436
+ /** @deprecated Use {@link IsSearching}. */
2437
+ get isSearching() {
2438
+ return this.IsSearching;
2439
+ }
2440
+ /** @deprecated Use {@link ToggleHeaderMenu}. */
2441
+ toggleHeaderMenu(event) {
2442
+ return this.ToggleHeaderMenu(event);
2443
+ }
2444
+ /** @deprecated Use {@link CloseHeaderMenu}. */
2445
+ closeHeaderMenu() {
2446
+ return this.CloseHeaderMenu();
2447
+ }
2448
+ /** @deprecated Use {@link OnToggleGroupByClick}. */
2449
+ onToggleGroupByClick(event) {
2450
+ return this.OnToggleGroupByClick(event);
2451
+ }
2452
+ /** @deprecated Use {@link OnRefreshConversationsClick}. */
2453
+ onRefreshConversationsClick(event) {
2454
+ return this.OnRefreshConversationsClick(event);
2455
+ }
2456
+ /** @deprecated Use {@link OnPinSidebarClick}. */
2457
+ onPinSidebarClick(event) {
2458
+ return this.OnPinSidebarClick(event);
2459
+ }
2460
+ /** @deprecated Use {@link OnUnpinSidebarClick}. */
2461
+ onUnpinSidebarClick(event) {
2462
+ return this.OnUnpinSidebarClick(event);
2463
+ }
2464
+ /** @deprecated Use {@link ToggleDirectMessages}. */
2465
+ toggleDirectMessages() {
2466
+ return this.ToggleDirectMessages();
2467
+ }
2468
+ /** @deprecated Use {@link TogglePinned}. */
2469
+ togglePinned() {
2470
+ return this.TogglePinned();
2471
+ }
2472
+ /** @deprecated Use {@link ToggleFolders}. */
2473
+ toggleFolders() {
2474
+ return this.ToggleFolders();
2475
+ }
2476
+ /** @deprecated Use {@link ToggleUngrouped}. */
2477
+ toggleUngrouped() {
2478
+ return this.ToggleUngrouped();
2479
+ }
2480
+ /** @deprecated Use {@link IsFolderExpanded}. */
2481
+ isFolderExpanded(projectId) {
2482
+ return this.IsFolderExpanded(projectId);
2483
+ }
2484
+ /** @deprecated Use {@link ToggleFolder}. */
2485
+ toggleFolder(projectId) {
2486
+ return this.ToggleFolder(projectId);
2487
+ }
2488
+ /** @deprecated Use {@link ToggleGroupBy}. */
2489
+ toggleGroupBy() {
2490
+ return this.ToggleGroupBy();
2491
+ }
2492
+ /** @deprecated Use {@link OnConversationDragStart}. */
2493
+ onConversationDragStart(conversation, event) {
2494
+ return this.OnConversationDragStart(conversation, event);
2495
+ }
2496
+ /** @deprecated Use {@link OnConversationDragEnd}. */
2497
+ onConversationDragEnd() {
2498
+ return this.OnConversationDragEnd();
2499
+ }
2500
+ /** @deprecated Use {@link OnFolderDragStart}. */
2501
+ onFolderDragStart(node, event) {
2502
+ return this.OnFolderDragStart(node, event);
2503
+ }
2504
+ /** @deprecated Use {@link OnFolderDragEnd}. */
2505
+ onFolderDragEnd() {
2506
+ return this.OnFolderDragEnd();
2507
+ }
2508
+ /** @deprecated Use {@link OnFolderDragOver}. */
2509
+ onFolderDragOver(projectId, event) {
2510
+ return this.OnFolderDragOver(projectId, event);
2511
+ }
2512
+ /** @deprecated Use {@link OnUngroupedDragOver}. */
2513
+ onUngroupedDragOver(event) {
2514
+ return this.OnUngroupedDragOver(event);
2515
+ }
2516
+ /** @deprecated Use {@link OnFoldersRootDragOver}. */
2517
+ onFoldersRootDragOver(event) {
2518
+ return this.OnFoldersRootDragOver(event);
2519
+ }
2520
+ /** @deprecated Use {@link OnDragLeave}. */
2521
+ onDragLeave(targetId) {
2522
+ return this.OnDragLeave(targetId);
2523
+ }
2524
+ /** @deprecated Use {@link OnFolderDrop}. */
2525
+ onFolderDrop(project, event) {
2526
+ return this.OnFolderDrop(project, event);
2527
+ }
2528
+ /** @deprecated Use {@link OnUngroupedDrop}. */
2529
+ onUngroupedDrop(event) {
2530
+ return this.OnUngroupedDrop(event);
2531
+ }
2532
+ /** @deprecated Use {@link OnFoldersRootDrop}. */
2533
+ onFoldersRootDrop(event) {
2534
+ return this.OnFoldersRootDrop(event);
2535
+ }
2536
+ /** @deprecated Use {@link OpenMoveSubmenu}. */
2537
+ openMoveSubmenu(event) {
2538
+ return this.OpenMoveSubmenu(event);
2539
+ }
2540
+ /** @deprecated Use {@link CloseMoveSubmenu}. */
2541
+ closeMoveSubmenu(event) {
2542
+ return this.CloseMoveSubmenu(event);
2543
+ }
2544
+ /** @deprecated Use {@link CreateFolder}. */
2545
+ createFolder(parentId, event) {
2546
+ return this.CreateFolder(parentId, event);
2547
+ }
2548
+ /** @deprecated Use {@link EditFolder}. */
2549
+ editFolder(project, event) {
2550
+ return this.EditFolder(project, event);
2551
+ }
2552
+ /** @deprecated Use {@link DeleteFolder}. */
2553
+ deleteFolder(project, event) {
2554
+ return this.DeleteFolder(project, event);
2555
+ }
2556
+ /** @deprecated Use {@link SelectConversation}. */
2557
+ selectConversation(conversation) {
2558
+ return this.SelectConversation(conversation);
2559
+ }
2560
+ /** @deprecated Use {@link CreateNewConversation}. */
2561
+ createNewConversation() {
2562
+ return this.CreateNewConversation();
2563
+ }
2564
+ /** @deprecated Use {@link RenameConversation}. */
2565
+ renameConversation(conversation) {
2566
+ return this.RenameConversation(conversation);
2567
+ }
2568
+ /** @deprecated Use {@link DeleteConversation}. */
2569
+ deleteConversation(conversation) {
2570
+ return this.DeleteConversation(conversation);
2571
+ }
2572
+ /** @deprecated Use {@link TogglePin}. */
2573
+ togglePin(conversation, event) {
2574
+ return this.TogglePin(conversation, event);
2575
+ }
2576
+ /** @deprecated Use {@link HasActiveTasks}. */
2577
+ hasActiveTasks(conversationId) {
2578
+ return this.HasActiveTasks(conversationId);
2579
+ }
2580
+ /** @deprecated Use {@link IsSharedWithMe}. */
2581
+ isSharedWithMe(conversation) {
2582
+ return this.IsSharedWithMe(conversation);
2583
+ }
2584
+ /** @deprecated Use {@link SharedWithMeTooltip}. */
2585
+ sharedWithMeTooltip(conversation) {
2586
+ return this.SharedWithMeTooltip(conversation);
2587
+ }
2588
+ /** @deprecated Use {@link ToggleSelectionMode}. */
2589
+ toggleSelectionMode() {
2590
+ return this.ToggleSelectionMode();
2591
+ }
2592
+ /** @deprecated Use {@link ToggleConversationSelection}. */
2593
+ toggleConversationSelection(conversationId) {
2594
+ return this.ToggleConversationSelection(conversationId);
2595
+ }
2596
+ /** @deprecated Use {@link SelectAll}. */
2597
+ selectAll() {
2598
+ return this.SelectAll();
2599
+ }
2600
+ /** @deprecated Use {@link DeselectAll}. */
2601
+ deselectAll() {
2602
+ return this.DeselectAll();
2603
+ }
2604
+ /** @deprecated Use {@link BulkDeleteConversations}. */
2605
+ bulkDeleteConversations(ids) {
2606
+ return this.BulkDeleteConversations(ids);
2607
+ }
2608
+ /** @deprecated Use {@link HandleConversationClick}. */
2609
+ handleConversationClick(conversation, event) {
2610
+ return this.HandleConversationClick(conversation, event);
1313
2611
  }
1314
2612
  static ɵfac = function ConversationListComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ConversationListComponent)(i0.ɵɵdirectiveInject(i1.DialogService), i0.ɵɵdirectiveInject(i2.NotificationService), i0.ɵɵdirectiveInject(i3.ActiveTasksService), i0.ɵɵdirectiveInject(i4.MJDialogService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1315
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationListComponent, selectors: [["mj-conversation-list"]], hostBindings: function ConversationListComponent_HostBindings(rf, ctx) { if (rf & 1) {
1316
- i0.ɵɵlistener("click", function ConversationListComponent_click_HostBindingHandler() { return ctx.onDocumentClick(); }, i0.ɵɵresolveDocument);
1317
- } }, inputs: { environmentId: "environmentId", currentUser: "currentUser", selectedConversationId: "selectedConversationId", renamedConversationId: "renamedConversationId", isSidebarPinned: "isSidebarPinned", isMobileView: "isMobileView", showSearch: "showSearch", showNewConversationButton: "showNewConversationButton", showHeaderMenu: "showHeaderMenu", showSectionHeaders: "showSectionHeaders" }, outputs: { conversationSelected: "conversationSelected", conversationDeleted: "conversationDeleted", newConversationRequested: "newConversationRequested", pinSidebarRequested: "pinSidebarRequested", unpinSidebarRequested: "unpinSidebarRequested", refreshRequested: "refreshRequested" }, standalone: false, decls: 12, vars: 5, consts: [["folderNode", ""], ["conversationItem", ""], [1, "conversation-list"], [1, "list-header"], ["title", "New Conversation", 1, "btn-new-conversation"], [1, "list-content"], [1, "sidebar-section", "pinned-section"], [1, "sidebar-section"], [1, "selection-action-bar"], [1, "header-top"], ["type", "text", "placeholder", "Search conversations...", 1, "search-input", 3, "ngModel"], [1, "header-menu-container"], ["type", "text", "placeholder", "Search conversations...", 1, "search-input", 3, "ngModelChange", "ngModel"], ["title", "Options", 1, "btn-menu", 3, "click"], [1, "fas", "fa-ellipsis-v"], [1, "header-dropdown-menu"], [1, "dropdown-item", 3, "click", "disabled"], [1, "fas", "fa-sync-alt"], [1, "dropdown-item", 3, "click"], [1, "fas", "fa-check-square"], [1, "fas"], [1, "dropdown-item"], [1, "fas", "fa-table-columns"], ["title", "New Conversation", 1, "btn-new-conversation", 3, "click"], [1, "fas", "fa-plus"], [1, "section-header", 3, "expanded"], [1, "chat-list"], [3, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "section-header", 3, "click"], [1, "section-title"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-thumbtack", "section-icon"], [1, "sidebar-section", "folders-section"], [1, "section-header", 3, "click", "dragover", "dragleave", "drop"], ["title", "New Folder", 1, "section-action-btn", 3, "click"], [1, "fas", "fa-folder-plus"], [1, "folder-empty-hint"], [1, "sidebar-section", "ungrouped-section", 3, "dragover", "dragleave", "drop"], [1, "selection-info"], [1, "selection-count"], [1, "link-btn"], [1, "selection-actions"], [1, "btn-delete-bulk", 3, "click", "disabled"], [1, "fas", "fa-trash"], [1, "btn-cancel", 3, "click"], [1, "link-btn", 3, "click"], [1, "folder-row", 3, "dragstart", "dragend", "click", "dragover", "dragleave", "drop", "draggable", "title"], [1, "fas", "fa-chevron-right", "folder-chevron"], [1, "folder-name"], [1, "folder-count"], [1, "folder-actions", 3, "click"], ["title", "New Subfolder", 1, "folder-action-btn", 3, "click"], ["title", "Edit Folder", 1, "folder-action-btn", 3, "click"], [1, "fas", "fa-pen"], ["title", "Delete Folder", 1, "folder-action-btn", "danger", 3, "click"], [1, "folder-children"], [1, "folder-empty-hint", 3, "paddingLeft"], [1, "conversation-item", 3, "dragstart", "dragend", "click", "draggable"], [1, "conversation-checkbox"], [1, "conversation-icon-wrapper"], [1, "conversation-icon", "has-tasks"], [1, "badge-overlay"], [3, "conversationId"], [1, "conversation-info", 3, "title"], [1, "conversation-name"], [1, "fas", "fa-share-nodes", "shared-indicator", 3, "title"], [1, "conversation-preview"], [1, "conversation-actions"], ["type", "checkbox", 3, "click", "checked"], [1, "fas", "fa-spinner", "fa-pulse"], ["title", "More options", 1, "menu-btn", 3, "click"], [1, "fas", "fa-ellipsis"], [1, "context-menu"], [1, "context-menu", 3, "click"], [1, "menu-item", "back", 3, "click"], [1, "fas", "fa-chevron-left"], [1, "menu-divider"], [1, "move-folder-list"], [1, "menu-item", 3, "click"], [1, "fas", "fa-inbox"], [1, "menu-item", 3, "current", "paddingLeft"], [1, "fas", "fa-thumbtack"], [1, "fas", "fa-folder-tree"], [1, "fas", "fa-chevron-right", "submenu-arrow"], [1, "fas", "fa-edit"], [1, "menu-item", "danger", 3, "click"]], template: function ConversationListComponent_Template(rf, ctx) { if (rf & 1) {
1318
- i0.ɵɵelementStart(0, "div", 2);
1319
- i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_1_Template, 4, 2, "div", 3);
1320
- i0.ɵɵconditionalCreate(2, ConversationListComponent_Conditional_2_Template, 4, 0, "button", 4);
1321
- i0.ɵɵelementStart(3, "div", 5);
1322
- i0.ɵɵconditionalCreate(4, ConversationListComponent_Conditional_4_Template, 5, 3, "div", 6);
1323
- i0.ɵɵconditionalCreate(5, ConversationListComponent_Conditional_5_Template, 21, 14)(6, ConversationListComponent_Conditional_6_Template, 5, 3, "div", 7);
2613
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ConversationListComponent, selectors: [["mj-conversation-list"]], viewQuery: function ConversationListComponent_Query(rf, ctx) { if (rf & 1) {
2614
+ i0.ɵɵviewQuery(_c0, 5)(_c1, 5);
2615
+ } if (rf & 2) {
2616
+ let _t;
2617
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.searchInput = _t.first);
2618
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.contextMenuEl = _t.first);
2619
+ } }, hostBindings: function ConversationListComponent_HostBindings(rf, ctx) { if (rf & 1) {
2620
+ i0.ɵɵlistener("click", function ConversationListComponent_click_HostBindingHandler() { return ctx.onDocumentClick(); }, i0.ɵɵresolveDocument)("keydown.escape", function ConversationListComponent_keydown_escape_HostBindingHandler() { return ctx.onDocumentEscape(); }, i0.ɵɵresolveDocument);
2621
+ } }, inputs: { EnvironmentId: "EnvironmentId", CurrentUser: "CurrentUser", SelectedConversationId: "SelectedConversationId", RenamedConversationId: "RenamedConversationId", IsSidebarPinned: "IsSidebarPinned", IsMobileView: "IsMobileView", showSearch: "showSearch", ShowNewConversationButton: "ShowNewConversationButton", ShowHeaderMenu: "ShowHeaderMenu", ShowSectionHeaders: "ShowSectionHeaders", environmentId: "environmentId", currentUser: "currentUser", selectedConversationId: "selectedConversationId", renamedConversationId: "renamedConversationId", isSidebarPinned: "isSidebarPinned", isMobileView: "isMobileView", showNewConversationButton: "showNewConversationButton", showHeaderMenu: "showHeaderMenu", showSectionHeaders: "showSectionHeaders" }, outputs: { ConversationSelected: "ConversationSelected", conversationSelected: "conversationSelected", ConversationDeleted: "ConversationDeleted", conversationDeleted: "conversationDeleted", NewConversationRequested: "NewConversationRequested", newConversationRequested: "newConversationRequested", PinSidebarRequested: "PinSidebarRequested", pinSidebarRequested: "pinSidebarRequested", UnpinSidebarRequested: "UnpinSidebarRequested", unpinSidebarRequested: "unpinSidebarRequested", RefreshRequested: "RefreshRequested", refreshRequested: "refreshRequested", SearchEscalated: "SearchEscalated" }, standalone: false, decls: 14, vars: 12, consts: [["folderNode", ""], ["conversationItem", ""], ["searchInput", ""], ["contextMenuEl", ""], [1, "conversation-list"], [1, "list-header"], ["title", "New Conversation", 1, "btn-new-conversation"], [1, "list-content", 3, "click", "contextmenu"], [1, "sidebar-section", "pinned-section"], [1, "sidebar-section"], [1, "search-escalate"], ["ResourceLabel", "conversation", 3, "Result", "Visible", "Contexts", "Adapter", "Notice"], [1, "list-context-menu", 3, "left", "top"], [1, "header-top"], ["role", "toolbar", "aria-label", "Selected conversations", 1, "selection-bar"], [1, "sort-row"], ["title", "Clear selection", "aria-label", "Clear selection", 1, "selection-bar-btn", 3, "click"], [1, "fas", "fa-xmark"], [1, "selection-count"], [1, "selection-bar-btn", 3, "click", "disabled", "title"], [1, "fas", "fa-thumbtack"], ["aria-label", "Move to folder", 1, "selection-bar-btn", 3, "click", "disabled", "title"], [1, "fas", "fa-folder-tree"], ["aria-label", "Share", 1, "selection-bar-btn", 3, "click", "disabled", "title"], [1, "fas", "fa-user-plus"], ["title", "Delete", "aria-label", "Delete", 1, "selection-bar-btn", "danger", 3, "click"], [1, "fas", "fa-trash"], [1, "search-box"], [1, "header-menu-container"], ["type", "text", "placeholder", "Search conversations...", 1, "search-input", 3, "ngModelChange", "keydown", "ngModel"], ["title", "Clear search", 1, "search-clear"], ["title", "Clear search", 1, "search-clear", 3, "click"], ["title", "Options", 1, "btn-menu", 3, "click"], [1, "fas", "fa-ellipsis-v"], [1, "header-dropdown-menu"], [1, "dropdown-item", 3, "click", "disabled"], [1, "fas", "fa-sync-alt"], [1, "dropdown-item", 3, "click"], [1, "fas"], [1, "dropdown-item"], [1, "fas", "fa-table-columns"], [1, "sort-btn", 3, "click", "title"], [1, "fas", 3, "ngClass"], ["title", "New Conversation", 1, "btn-new-conversation", 3, "click"], [1, "fas", "fa-plus"], [1, "section-header", 3, "expanded"], [1, "chat-list"], [3, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "section-header", 3, "click"], [1, "section-title"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-thumbtack", "section-icon"], [1, "sidebar-section", "folders-section"], [1, "section-header", 3, "click", "dragover", "dragleave", "drop"], ["title", "New Folder", 1, "section-action-btn", 3, "click"], [1, "fas", "fa-folder-plus"], [1, "folder-empty-hint"], [1, "sidebar-section", "ungrouped-section", 3, "dragover", "dragleave", "drop"], [1, "search-escalate", 3, "click"], [1, "fa-solid", "fa-magnifying-glass"], [1, "search-escalate-label"], [1, "fa-solid", "fa-arrow-right", "search-escalate-go"], [1, "folder-row", 3, "dragstart", "dragend", "click", "dragover", "dragleave", "drop", "contextmenu", "draggable", "title"], [1, "fas", "fa-chevron-right", "folder-chevron"], [1, "folder-name"], ["role", "img", "title", "Shared \u2014 everyone can see this folder and its name, but not the conversations in it", "aria-label", "Shared folder", 1, "folder-shared"], [1, "folder-spacer"], [1, "folder-count"], [1, "folder-children"], ["aria-hidden", "true", 1, "fas", "fa-users"], [1, "folder-empty-hint", 3, "paddingLeft"], [1, "conversation-item", 3, "dragstart", "dragend", "dragover", "dragleave", "drop", "pointerdown", "pointermove", "pointerup", "pointercancel", "click", "contextmenu", "draggable"], ["role", "checkbox", 1, "row-check", 3, "click"], [1, "fas", "fa-check"], [1, "conversation-icon-wrapper"], [1, "conversation-icon", "has-tasks"], [1, "badge-overlay"], [3, "conversationId"], [1, "conversation-info", 3, "title"], [1, "conversation-name"], [1, "fas", "fa-share-nodes", "shared-indicator", 3, "title"], [1, "conversation-preview"], [1, "conversation-actions"], ["title", "More options", 1, "menu-btn", 3, "click"], [1, "fas", "fa-ellipsis"], [1, "fas", "fa-spinner", "fa-pulse"], [1, "list-context-menu", 3, "click", "contextmenu"], [1, "menu-item", "back", 3, "click"], [1, "fas", "fa-chevron-left"], [1, "menu-divider"], [1, "move-folder-list"], [1, "menu-item", 3, "click"], [1, "fas", "fa-inbox"], [1, "menu-item", 3, "current", "paddingLeft"], [1, "menu-item", 3, "disabled"], [1, "menu-item", 3, "click", "disabled"], [1, "fas", "fa-chevron-right", "submenu-arrow"], [1, "menu-item"], [1, "menu-item", "danger", 3, "click"], [1, "context-menu-header"], [1, "fas", "fa-thumbtack", "fa-rotate-90"], [1, "fas", "fa-edit"], [1, "fas", "fa-pen"], [1, "fas", "fa-check-double"]], template: function ConversationListComponent_Template(rf, ctx) { if (rf & 1) {
2622
+ i0.ɵɵelementStart(0, "div", 4);
2623
+ i0.ɵɵconditionalCreate(1, ConversationListComponent_Conditional_1_Template, 5, 2, "div", 5);
2624
+ i0.ɵɵconditionalCreate(2, ConversationListComponent_Conditional_2_Template, 4, 0, "button", 6);
2625
+ i0.ɵɵelementStart(3, "div", 7);
2626
+ i0.ɵɵlistener("click", function ConversationListComponent_Template_div_click_3_listener($event) { return ctx.OnListBackgroundClick($event); })("contextmenu", function ConversationListComponent_Template_div_contextmenu_3_listener($event) { return ctx.OnBackgroundContextMenu($event); });
2627
+ i0.ɵɵconditionalCreate(4, ConversationListComponent_Conditional_4_Template, 5, 3, "div", 8);
2628
+ i0.ɵɵconditionalCreate(5, ConversationListComponent_Conditional_5_Template, 21, 14)(6, ConversationListComponent_Conditional_6_Template, 5, 3, "div", 9);
2629
+ i0.ɵɵelementEnd();
2630
+ i0.ɵɵconditionalCreate(7, ConversationListComponent_Conditional_7_Template, 5, 1, "button", 10);
1324
2631
  i0.ɵɵelementEnd();
1325
- i0.ɵɵconditionalCreate(7, ConversationListComponent_Conditional_7_Template, 12, 4, "div", 8);
2632
+ i0.ɵɵtemplate(8, ConversationListComponent_ng_template_8_Template, 10, 19, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor)(10, ConversationListComponent_ng_template_10_Template, 16, 23, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
2633
+ i0.ɵɵelementStart(12, "mj-resource-share-dialog", 11);
2634
+ i0.ɵɵlistener("Result", function ConversationListComponent_Template_mj_resource_share_dialog_Result_12_listener($event) { return ctx.OnShareDialogResult($event); });
1326
2635
  i0.ɵɵelementEnd();
1327
- i0.ɵɵtemplate(8, ConversationListComponent_ng_template_8_Template, 15, 18, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor)(10, ConversationListComponent_ng_template_10_Template, 13, 17, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
2636
+ i0.ɵɵconditionalCreate(13, ConversationListComponent_Conditional_13_Template, 5, 5, "div", 12);
1328
2637
  } if (rf & 2) {
2638
+ i0.ɵɵclassProp("is-selecting", ctx.IsSelectionMode);
1329
2639
  i0.ɵɵadvance();
1330
- i0.ɵɵconditional(ctx.showSearch || ctx.showHeaderMenu && !ctx.isSelectionMode ? 1 : -1);
2640
+ i0.ɵɵconditional(ctx.showSearch || ctx.ShowHeaderMenu || ctx.IsSelectionMode ? 1 : -1);
1331
2641
  i0.ɵɵadvance();
1332
- i0.ɵɵconditional(ctx.showNewConversationButton ? 2 : -1);
2642
+ i0.ɵɵconditional(ctx.ShowNewConversationButton ? 2 : -1);
1333
2643
  i0.ɵɵadvance(2);
1334
- i0.ɵɵconditional(ctx.pinnedConversations.length > 0 ? 4 : -1);
2644
+ i0.ɵɵconditional(ctx.PinnedConversations.length > 0 ? 4 : -1);
1335
2645
  i0.ɵɵadvance();
1336
- i0.ɵɵconditional(ctx.showSectionHeaders && ctx.groupBy === "project" ? 5 : 6);
2646
+ i0.ɵɵconditional(ctx.ShowSectionHeaders && ctx.GroupBy === "project" ? 5 : 6);
1337
2647
  i0.ɵɵadvance(2);
1338
- i0.ɵɵconditional(ctx.isSelectionMode ? 7 : -1);
1339
- } }, dependencies: [i5.NgTemplateOutlet, i6.DefaultValueAccessor, i6.NgControlStatus, i6.NgModel, i7.NotificationBadgeComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n --conv-list-bg: var(--mj-chat-list-bg, var(--mj-brand-secondary));\n --conv-list-ink: var(--mj-chat-list-ink, var(--mj-brand-on-secondary));\n --conv-list-active-bg: var(--mj-chat-list-active-bg, var(--mj-brand-primary));\n --conv-list-active-ink: var(--mj-chat-list-active-ink, var(--mj-brand-on-secondary));\n --conv-list-active-hover-bg: var(--mj-chat-list-active-hover-bg, var(--mj-brand-primary-hover));\n --conv-list-accent: var(--mj-chat-list-accent, var(--mj-brand-primary));\n --conv-list-accent-ink: var(--mj-chat-list-accent-ink, var(--mj-text-inverse));\n --conv-list-accent-hover: var(--mj-chat-list-accent-hover, var(--mj-brand-primary-hover));\n --conv-list-hover-bg: var(--mj-chat-list-hover-bg, color-mix(in srgb, var(--conv-list-ink) 8%, transparent));\n }\n .conversation-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; height: 100%; background: var(--conv-list-bg); }\n .list-header[_ngcontent-%COMP%] { padding: 8px; border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent); }\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n transition: all 0.2s;\n }\n .search-input[_ngcontent-%COMP%]::placeholder { color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); }\n .search-input[_ngcontent-%COMP%]:focus { outline: none; background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent); border-color: var(--conv-list-accent); }\n .btn-new-conversation[_ngcontent-%COMP%] {\n width: calc(100% - 16px);\n margin: 8px;\n padding: 10px;\n background: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.2s;\n flex-shrink: 0;\n }\n .btn-new-conversation[_ngcontent-%COMP%]:hover { background: var(--conv-list-accent-hover); }\n .btn-new-conversation[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 14px; }\n .list-content[_ngcontent-%COMP%] { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 0; }\n\n \n .sidebar-section[_ngcontent-%COMP%] { margin-bottom: 20px; }\n .pinned-section[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] .section-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 11px;\n margin-left: 2px;\n }\n .section-header[_ngcontent-%COMP%] {\n padding: 4px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 500;\n transition: background 0.2s;\n user-select: none;\n }\n .section-header[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n }\n .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:not(.section-icon) {\n transition: transform 0.2s;\n }\n .section-header.expanded[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:not(.section-icon) { transform: rotate(90deg); }\n .chat-list[_ngcontent-%COMP%] {\n padding: 4px 0;\n display: none;\n }\n .chat-list.expanded[_ngcontent-%COMP%] { display: block; }\n\n .conversation-item[_ngcontent-%COMP%] {\n padding: 6px 5px 6px 16px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: all 0.2s;\n position: relative;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 14px;\n min-height: 45px;\n }\n .conversation-item[_ngcontent-%COMP%]:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .conversation-item[_ngcontent-%COMP%]:hover .conversation-actions[_ngcontent-%COMP%] { opacity: 1; }\n .conversation-item.active[_ngcontent-%COMP%] { background: var(--conv-list-active-bg); color: var(--conv-list-active-ink); }\n .conversation-icon-wrapper[_ngcontent-%COMP%] { position: relative; flex-shrink: 0; }\n .conversation-icon[_ngcontent-%COMP%] { font-size: 12px; width: 16px; text-align: center; }\n .conversation-icon.has-tasks[_ngcontent-%COMP%] { color: var(--mj-status-warning); }\n .badge-overlay[_ngcontent-%COMP%] { position: absolute; top: -4px; right: -4px; }\n .conversation-info[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .conversation-name[_ngcontent-%COMP%] { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; }\n .shared-indicator[_ngcontent-%COMP%] { font-size: 10px; color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent); flex-shrink: 0; }\n .conversation-item.active[_ngcontent-%COMP%] .shared-indicator[_ngcontent-%COMP%] { color: color-mix(in srgb, var(--conv-list-active-ink) 85%, transparent); }\n .conversation-preview[_ngcontent-%COMP%] { font-size: 12px; color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .conversation-item.active[_ngcontent-%COMP%] .conversation-preview[_ngcontent-%COMP%] { color: color-mix(in srgb, var(--conv-list-active-ink) 80%, transparent); }\n .conversation-meta[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }\n\n \n .project-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n margin-left: auto;\n background-color: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .conversation-item[_ngcontent-%COMP%]:hover .project-badge[_ngcontent-%COMP%] {\n background-color: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n }\n .conversation-item.active[_ngcontent-%COMP%] .project-badge[_ngcontent-%COMP%] {\n background-color: color-mix(in srgb, var(--conv-list-active-ink) 20%, transparent);\n color: var(--conv-list-active-ink);\n }\n\n .conversation-actions[_ngcontent-%COMP%] {\n position: absolute;\n right: 5px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 10;\n }\n .conversation-item[_ngcontent-%COMP%]:hover .conversation-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n .conversation-item.active[_ngcontent-%COMP%] .conversation-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n .conversation-actions[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] { pointer-events: auto; }\n .pinned-icon[_ngcontent-%COMP%] { color: var(--mj-brand-accent); font-size: 12px; }\n\n \n .task-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 12px;\n margin-right: 8px;\n flex-shrink: 0;\n animation: _ngcontent-%COMP%_pulse-glow 2s ease-in-out infinite;\n }\n @keyframes _ngcontent-%COMP%_pulse-glow {\n 0%, 100% {\n opacity: 1;\n filter: drop-shadow(0 0 2px var(--mj-status-warning));\n }\n 50% {\n opacity: 0.6;\n filter: drop-shadow(0 0 4px var(--mj-status-warning));\n }\n }\n .conversation-item.active[_ngcontent-%COMP%] .task-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n }\n\n .menu-btn[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n background: var(--conv-list-bg) !important;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n }\n .menu-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent) !important;\n color: var(--conv-list-ink);\n }\n .conversation-item.active[_ngcontent-%COMP%] .menu-btn[_ngcontent-%COMP%] {\n background: var(--conv-list-active-hover-bg) !important;\n color: var(--conv-list-active-ink);\n }\n .menu-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 14px; }\n\n .context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 160px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n pointer-events: auto;\n }\n\n .menu-item[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .menu-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .menu-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--conv-list-ink);\n }\n\n .menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin: 4px 0;\n }\n\n \n .conversation-item.renamed[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_renameHighlight 1500ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n \n\n\n @keyframes _ngcontent-%COMP%_renameHighlight {\n 0% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 40%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 40%, transparent));\n transform: scale(1.03);\n box-shadow: 0 0 20px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n }\n 25% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 35%, transparent));\n box-shadow: 0 0 15px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n }\n 50% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 30%, transparent));\n transform: scale(1.02);\n box-shadow: 0 0 10px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n 75% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 20%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 20%, transparent));\n box-shadow: 0 0 5px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n }\n 100% {\n background: transparent;\n transform: scale(1);\n box-shadow: none;\n }\n }\n\n \n .header-top[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n \n .header-menu-container[_ngcontent-%COMP%] {\n position: relative;\n flex-shrink: 0;\n }\n\n .btn-menu[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-menu[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n padding: 4px 0;\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] .shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: color-mix(in srgb, var(--conv-list-ink) 40%, transparent);\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n .btn-select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n .btn-select[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .conversation-checkbox[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-right: 8px;\n flex-shrink: 0;\n }\n\n .conversation-checkbox[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n accent-color: var(--conv-list-accent);\n }\n\n .selection-action-bar[_ngcontent-%COMP%] {\n position: sticky;\n bottom: 0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--conv-list-bg);\n border-top: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n gap: 12px;\n flex-wrap: wrap;\n flex-shrink: 0;\n }\n\n .selection-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n color: color-mix(in srgb, var(--conv-list-ink) 90%, transparent);\n font-size: 14px;\n font-weight: 500;\n flex: 1 1 auto;\n min-width: 150px;\n }\n\n .selection-count[_ngcontent-%COMP%] {\n color: var(--conv-list-ink);\n }\n\n .link-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-brand-accent);\n cursor: pointer;\n font-size: 13px;\n text-decoration: underline;\n padding: 0;\n transition: color 0.2s;\n }\n\n .link-btn[_ngcontent-%COMP%]:hover {\n color: var(--conv-list-ink);\n }\n\n .selection-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex: 0 0 auto;\n }\n\n .btn-cancel[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .btn-cancel[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .btn-delete-bulk[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-error);\n border: none;\n border-radius: 6px;\n \n\n\n color: var(--mj-brand-on-secondary);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: all 0.2s;\n }\n\n .btn-delete-bulk[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 80%, black);\n }\n\n .btn-delete-bulk[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .btn-delete-bulk[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n \n .section-action-btn[_ngcontent-%COMP%] {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n .section-action-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: var(--conv-list-ink);\n }\n .section-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; }\n\n .folder-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n cursor: pointer;\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n font-size: 13px;\n transition: background 0.15s;\n user-select: none;\n position: relative;\n }\n .folder-row[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .folder-row.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 25%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n }\n .folder-row.dragging[_ngcontent-%COMP%] { opacity: 0.4; }\n .section-header.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n .folder-chevron[_ngcontent-%COMP%] {\n font-size: 9px;\n width: 10px;\n flex-shrink: 0;\n transition: transform 0.2s;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n }\n .folder-chevron.expanded[_ngcontent-%COMP%] { transform: rotate(90deg); }\n .folder-icon[_ngcontent-%COMP%] { font-size: 12px; width: 16px; text-align: center; flex-shrink: 0; }\n .folder-name[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: 600;\n }\n .folder-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n flex-shrink: 0;\n margin-left: auto;\n padding-left: 6px;\n text-align: right;\n }\n .folder-actions[_ngcontent-%COMP%] {\n position: absolute;\n right: 6px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n gap: 2px;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 5;\n }\n .folder-row[_ngcontent-%COMP%]:hover .folder-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n .folder-row[_ngcontent-%COMP%]:hover .folder-count[_ngcontent-%COMP%] { opacity: 0; }\n .folder-action-btn[_ngcontent-%COMP%] {\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.15s;\n }\n .folder-action-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 18%, transparent);\n color: var(--conv-list-ink);\n }\n .folder-action-btn.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n color: var(--mj-status-error);\n }\n .folder-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 11px; }\n .folder-children[_ngcontent-%COMP%] { display: block; }\n .folder-empty-hint[_ngcontent-%COMP%] {\n padding: 6px 16px;\n font-size: 11px;\n font-style: italic;\n color: color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n }\n .ungrouped-section.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 12%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n\n \n .conversation-item[_ngcontent-%COMP%] { user-select: none; }\n .conversation-item.dragging[_ngcontent-%COMP%] { opacity: 0.4; }\n\n \n .menu-item.back[_ngcontent-%COMP%] { font-weight: 600; }\n .menu-item[_ngcontent-%COMP%] .submenu-arrow[_ngcontent-%COMP%] { margin-left: auto; font-size: 10px; }\n .menu-item.current[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent); }\n .move-folder-list[_ngcontent-%COMP%] { max-height: 240px; overflow-y: auto; }"] });
2648
+ i0.ɵɵconditional(ctx.IsSearching && !ctx.IsSelectionMode ? 7 : -1);
2649
+ i0.ɵɵadvance(5);
2650
+ i0.ɵɵproperty("Visible", ctx.IsShareDialogOpen)("Contexts", ctx.ShareContexts)("Adapter", ctx.ShareAdapter)("Notice", ctx.ShareNotice);
2651
+ i0.ɵɵadvance();
2652
+ i0.ɵɵconditional(ctx.ContextMenu ? 13 : -1);
2653
+ } }, dependencies: [i5.NgClass, i5.NgTemplateOutlet, i6.DefaultValueAccessor, i6.NgControlStatus, i6.NgModel, i7.GenericShareDialogComponent, i8.NotificationBadgeComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n --conv-list-bg: var(--mj-chat-list-bg, var(--mj-brand-secondary));\n --conv-list-ink: var(--mj-chat-list-ink, var(--mj-brand-on-secondary));\n --conv-list-active-bg: var(--mj-chat-list-active-bg, var(--mj-brand-primary));\n --conv-list-active-ink: var(--mj-chat-list-active-ink, var(--mj-brand-on-secondary));\n --conv-list-active-hover-bg: var(--mj-chat-list-active-hover-bg, var(--mj-brand-primary-hover));\n --conv-list-accent: var(--mj-chat-list-accent, var(--mj-brand-primary));\n --conv-list-accent-ink: var(--mj-chat-list-accent-ink, var(--mj-text-inverse));\n --conv-list-accent-hover: var(--mj-chat-list-accent-hover, var(--mj-brand-primary-hover));\n --conv-list-hover-bg: var(--mj-chat-list-hover-bg, color-mix(in srgb, var(--conv-list-ink) 8%, transparent));\n }\n .conversation-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; height: 100%; background: var(--conv-list-bg); }\n .list-header[_ngcontent-%COMP%] { padding: 8px; border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent); }\n .search-box[_ngcontent-%COMP%] { position: relative; flex: 1; min-width: 0; display: flex; }\n .search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .sort-row[_ngcontent-%COMP%] { display: flex; gap: 6px; margin-top: 8px; }\n .sort-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .sort-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 11px; }\n .sort-btn[_ngcontent-%COMP%]:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .sort-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n border-color: var(--conv-list-accent);\n color: var(--conv-list-ink);\n font-weight: 600;\n }\n .search-clear[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-ink) 12%, transparent); color: var(--conv-list-ink); }\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 28px 8px 12px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n transition: all 0.2s;\n }\n .search-input[_ngcontent-%COMP%]::placeholder { color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); }\n .search-input[_ngcontent-%COMP%]:focus { outline: none; background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent); border-color: var(--conv-list-accent); }\n .btn-new-conversation[_ngcontent-%COMP%] {\n width: calc(100% - 16px);\n margin: 8px;\n padding: 10px;\n background: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.2s;\n flex-shrink: 0;\n }\n .btn-new-conversation[_ngcontent-%COMP%]:hover { background: var(--conv-list-accent-hover); }\n .btn-new-conversation[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 14px; }\n .list-content[_ngcontent-%COMP%] { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 0; }\n\n \n .sidebar-section[_ngcontent-%COMP%] { margin-bottom: 20px; }\n\n \n\n .search-escalate[_ngcontent-%COMP%] {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n border-top: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n background: transparent;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .search-escalate[_ngcontent-%COMP%]:hover {\n background: var(--conv-list-hover-bg);\n color: var(--conv-list-ink);\n }\n\n \n .search-escalate-label[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .search-escalate-go[_ngcontent-%COMP%] { opacity: 0.6; }\n .pinned-section[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] .section-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 11px;\n margin-left: 2px;\n }\n .section-header[_ngcontent-%COMP%] {\n padding: 4px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 500;\n transition: background 0.2s;\n user-select: none;\n }\n .section-header[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n }\n .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:not(.section-icon) {\n transition: transform 0.2s;\n }\n .section-header.expanded[_ngcontent-%COMP%] .section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%]:not(.section-icon) { transform: rotate(90deg); }\n .chat-list[_ngcontent-%COMP%] {\n padding: 4px 0;\n display: none;\n }\n .chat-list.expanded[_ngcontent-%COMP%] { display: block; }\n\n .conversation-item[_ngcontent-%COMP%] {\n padding: 6px 5px 6px 16px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: all 0.2s;\n position: relative;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 14px;\n min-height: 45px;\n }\n .conversation-item[_ngcontent-%COMP%]:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .conversation-item[_ngcontent-%COMP%]:hover .conversation-actions[_ngcontent-%COMP%] { opacity: 1; }\n .conversation-item.active[_ngcontent-%COMP%] { background: var(--conv-list-active-bg); color: var(--conv-list-active-ink); }\n \n\n\n .conversation-item.selected[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--conv-list-accent) 16%, transparent); }\n .conversation-item.selected[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-accent) 24%, transparent); }\n .conversation-item.active.selected[_ngcontent-%COMP%] { background: var(--conv-list-active-bg); }\n \n\n\n .row-check[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 14px;\n height: 14px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1.5px solid color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n border-radius: 3px;\n color: transparent;\n cursor: pointer;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n z-index: 2;\n }\n .row-check[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 8px; }\n .conversation-list.is-selecting[_ngcontent-%COMP%] .row-check[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n @media (hover: hover) {\n .conversation-item[_ngcontent-%COMP%]:hover .row-check[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n }\n .row-check.checked[_ngcontent-%COMP%] {\n background: var(--conv-list-accent);\n border-color: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n }\n .conversation-item.active[_ngcontent-%COMP%] .row-check[_ngcontent-%COMP%]:not(.checked) {\n border-color: color-mix(in srgb, var(--conv-list-active-ink) 70%, transparent);\n }\n .conversation-icon-wrapper[_ngcontent-%COMP%] { position: relative; flex-shrink: 0; }\n .conversation-icon[_ngcontent-%COMP%] { font-size: 12px; width: 16px; text-align: center; }\n .conversation-icon.has-tasks[_ngcontent-%COMP%] { color: var(--mj-status-warning); }\n .badge-overlay[_ngcontent-%COMP%] { position: absolute; top: -4px; right: -4px; }\n .conversation-info[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n .conversation-name[_ngcontent-%COMP%] { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; }\n .shared-indicator[_ngcontent-%COMP%] { font-size: 10px; color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent); flex-shrink: 0; }\n .conversation-item.active[_ngcontent-%COMP%] .shared-indicator[_ngcontent-%COMP%] { color: color-mix(in srgb, var(--conv-list-active-ink) 85%, transparent); }\n .conversation-preview[_ngcontent-%COMP%] { font-size: 12px; color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .conversation-item.active[_ngcontent-%COMP%] .conversation-preview[_ngcontent-%COMP%] { color: color-mix(in srgb, var(--conv-list-active-ink) 80%, transparent); }\n .conversation-meta[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }\n\n \n .project-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n margin-left: auto;\n background-color: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .conversation-item[_ngcontent-%COMP%]:hover .project-badge[_ngcontent-%COMP%] {\n background-color: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n }\n .conversation-item.active[_ngcontent-%COMP%] .project-badge[_ngcontent-%COMP%] {\n background-color: color-mix(in srgb, var(--conv-list-active-ink) 20%, transparent);\n color: var(--conv-list-active-ink);\n }\n\n .conversation-actions[_ngcontent-%COMP%] {\n position: absolute;\n right: 5px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 10;\n }\n .conversation-item[_ngcontent-%COMP%]:hover .conversation-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n .conversation-item.active[_ngcontent-%COMP%] .conversation-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n .conversation-actions[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] { pointer-events: auto; }\n \n @media (hover: none) {\n .conversation-actions[_ngcontent-%COMP%] { opacity: 1; pointer-events: auto; }\n }\n .pinned-icon[_ngcontent-%COMP%] { color: var(--mj-brand-accent); font-size: 12px; }\n\n \n .task-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 12px;\n margin-right: 8px;\n flex-shrink: 0;\n animation: _ngcontent-%COMP%_pulse-glow 2s ease-in-out infinite;\n }\n @keyframes _ngcontent-%COMP%_pulse-glow {\n 0%, 100% {\n opacity: 1;\n filter: drop-shadow(0 0 2px var(--mj-status-warning));\n }\n 50% {\n opacity: 0.6;\n filter: drop-shadow(0 0 4px var(--mj-status-warning));\n }\n }\n .conversation-item.active[_ngcontent-%COMP%] .task-indicator[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n }\n\n .menu-btn[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n background: var(--conv-list-bg) !important;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n }\n .menu-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent) !important;\n color: var(--conv-list-ink);\n }\n .conversation-item.active[_ngcontent-%COMP%] .menu-btn[_ngcontent-%COMP%] {\n background: var(--conv-list-active-hover-bg) !important;\n color: var(--conv-list-active-ink);\n }\n .menu-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 14px; }\n\n \n\n .list-context-menu[_ngcontent-%COMP%] {\n position: fixed;\n min-width: 190px;\n max-height: 70vh;\n overflow-y: auto;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n padding: 4px 0;\n }\n\n .context-menu-header[_ngcontent-%COMP%] {\n padding: 6px 14px 8px;\n font-size: 12px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin-bottom: 4px;\n }\n\n .menu-item[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .menu-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .menu-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--conv-list-ink);\n }\n\n .menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin: 4px 0;\n }\n\n \n .conversation-item.renamed[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_renameHighlight 1500ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n \n\n\n @keyframes _ngcontent-%COMP%_renameHighlight {\n 0% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 40%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 40%, transparent));\n transform: scale(1.03);\n box-shadow: 0 0 20px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n }\n 25% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 35%, transparent));\n box-shadow: 0 0 15px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n }\n 50% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 30%, transparent));\n transform: scale(1.02);\n box-shadow: 0 0 10px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n 75% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 20%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 20%, transparent));\n box-shadow: 0 0 5px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n }\n 100% {\n background: transparent;\n transform: scale(1);\n box-shadow: none;\n }\n }\n\n \n\n\n .header-top[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n min-height: 36px;\n }\n\n .selection-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 2px;\n flex: 1;\n min-width: 0;\n }\n\n .selection-count[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n padding: 0 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .selection-bar-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 75%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .selection-bar-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 13px; }\n .selection-bar-btn[_ngcontent-%COMP%]:hover:not(:disabled) { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .selection-bar-btn[_ngcontent-%COMP%]:disabled { opacity: 0.4; cursor: not-allowed; }\n .selection-bar-btn.danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n \n .header-menu-container[_ngcontent-%COMP%] {\n position: relative;\n flex-shrink: 0;\n }\n\n .btn-menu[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-menu[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n padding: 4px 0;\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu[_ngcontent-%COMP%] .dropdown-item[_ngcontent-%COMP%] .shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: color-mix(in srgb, var(--conv-list-ink) 40%, transparent);\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n .btn-select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n .btn-select[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n\n \n .section-action-btn[_ngcontent-%COMP%] {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n .section-action-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: var(--conv-list-ink);\n }\n .section-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; }\n\n .folder-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n cursor: pointer;\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n font-size: 13px;\n transition: background 0.15s;\n user-select: none;\n position: relative;\n }\n .folder-row[_ngcontent-%COMP%]:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .folder-row.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 25%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n }\n .folder-row.dragging[_ngcontent-%COMP%] { opacity: 0.4; }\n .section-header.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n .folder-chevron[_ngcontent-%COMP%] {\n font-size: 9px;\n width: 10px;\n flex-shrink: 0;\n transition: transform 0.2s;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n }\n .folder-chevron.expanded[_ngcontent-%COMP%] { transform: rotate(90deg); }\n .folder-icon[_ngcontent-%COMP%] { font-size: 12px; width: 16px; text-align: center; flex-shrink: 0; }\n .folder-name[_ngcontent-%COMP%] {\n \n\n\n\n flex: 0 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: 600;\n }\n .folder-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n flex-shrink: 0;\n margin-left: auto;\n padding-left: 6px;\n text-align: right;\n }\n .folder-spacer[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n }\n .folder-shared[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin-left: 6px;\n font-size: 10px;\n line-height: 1;\n \n\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n }\n .folder-children[_ngcontent-%COMP%] { display: block; }\n .folder-empty-hint[_ngcontent-%COMP%] {\n padding: 6px 16px;\n font-size: 11px;\n font-style: italic;\n color: color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n }\n .ungrouped-section.drag-over[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--conv-list-accent) 12%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n\n \n\n .conversation-item[_ngcontent-%COMP%] { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }\n .conversation-item.dragging[_ngcontent-%COMP%] { opacity: 0.4; }\n\n \n .menu-item.back[_ngcontent-%COMP%] { font-weight: 600; }\n .menu-item[_ngcontent-%COMP%] .submenu-arrow[_ngcontent-%COMP%] { margin-left: auto; font-size: 10px; }\n .menu-item.current[_ngcontent-%COMP%] { background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent); }\n .move-folder-list[_ngcontent-%COMP%] { max-height: 240px; overflow-y: auto; }"] });
1340
2654
  }
1341
2655
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ConversationListComponent, [{
1342
2656
  type: Component,
1343
2657
  args: [{ standalone: false, selector: 'mj-conversation-list', template: `
1344
- <div class="conversation-list">
1345
- <!-- Header strip gated as a whole so an empty bordered band never renders:
1346
- the ⋯ menu also hides during selection mode, so it only counts toward
1347
- the strip when actually visible. -->
1348
- @if (showSearch || (showHeaderMenu && !isSelectionMode)) {
2658
+ <div class="conversation-list" [class.is-selecting]="IsSelectionMode">
2659
+ <!-- Header strip gated as a whole so an empty bordered band never renders.
2660
+ While a selection exists its top row becomes the selection bar, which
2661
+ shows even for a host that hides the rest of the chrome. -->
2662
+ @if (showSearch || ShowHeaderMenu || IsSelectionMode) {
1349
2663
  <div class="list-header">
1350
2664
  <div class="header-top">
1351
- @if (showSearch) {
1352
- <input
1353
- type="text"
1354
- class="search-input"
1355
- placeholder="Search conversations..."
1356
- [(ngModel)]="searchQuery">
1357
- }
1358
- @if (showHeaderMenu && !isSelectionMode) {
1359
- <div class="header-menu-container">
1360
- <button class="btn-menu" (click)="toggleHeaderMenu($event)" title="Options">
1361
- <i class="fas fa-ellipsis-v"></i>
2665
+ @if (IsSelectionMode) {
2666
+ <div class="selection-bar" role="toolbar" aria-label="Selected conversations">
2667
+ <button class="selection-bar-btn" (click)="ClearSelection()" title="Clear selection" aria-label="Clear selection">
2668
+ <i class="fas fa-xmark"></i>
1362
2669
  </button>
1363
- @if (isHeaderMenuOpen) {
1364
- <div class="header-dropdown-menu">
1365
- <button class="dropdown-item" (click)="onRefreshConversationsClick($event)" [disabled]="isRefreshing">
1366
- <i class="fas fa-sync-alt" [class.fa-spin]="isRefreshing"></i>
1367
- <span>{{ isRefreshing ? 'Refreshing...' : 'Refresh' }}</span>
1368
- </button>
1369
- <button class="dropdown-item" (click)="onSelectConversationsClick($event)">
1370
- <i class="fas fa-check-square"></i>
1371
- <span>Select Conversations</span>
1372
- </button>
1373
- <button class="dropdown-item" (click)="onToggleGroupByClick($event)">
1374
- <i class="fas" [class.fa-folder-tree]="groupBy !== 'project'" [class.fa-list]="groupBy === 'project'"></i>
1375
- <span>{{ groupBy === 'project' ? 'Show as flat list' : 'Group by folder' }}</span>
2670
+ <span class="selection-count">{{ SelectedConversationIds.size }} selected</span>
2671
+ <button class="selection-bar-btn"
2672
+ (click)="BarSetPinned()"
2673
+ [disabled]="!CanChangeAny(SelectedIds)"
2674
+ [title]="CanChangeAny(SelectedIds) ? (SelectionHasUnpinned() ? 'Pin' : 'Unpin') : ChangeRefusedReason"
2675
+ [attr.aria-label]="SelectionHasUnpinned() ? 'Pin' : 'Unpin'">
2676
+ <i class="fas fa-thumbtack" [class.fa-rotate-90]="!SelectionHasUnpinned()"></i>
2677
+ </button>
2678
+ <button class="selection-bar-btn"
2679
+ (click)="BarOpenMoveMenu($event)"
2680
+ [disabled]="!CanChangeAny(SelectedIds)"
2681
+ [title]="CanChangeAny(SelectedIds) ? 'Move to folder' : ChangeRefusedReason"
2682
+ aria-label="Move to folder">
2683
+ <i class="fas fa-folder-tree"></i>
2684
+ </button>
2685
+ <button class="selection-bar-btn"
2686
+ (click)="BarShare()"
2687
+ [disabled]="!CanShareAny(SelectedIds)"
2688
+ [title]="CanShareAny(SelectedIds) ? 'Share' : ShareRefusedReason"
2689
+ aria-label="Share">
2690
+ <i class="fas fa-user-plus"></i>
2691
+ </button>
2692
+ <button class="selection-bar-btn danger" (click)="BarDelete()" title="Delete" aria-label="Delete">
2693
+ <i class="fas fa-trash"></i>
2694
+ </button>
2695
+ </div>
2696
+ } @else {
2697
+ @if (showSearch) {
2698
+ <div class="search-box">
2699
+ <input
2700
+ #searchInput
2701
+ type="text"
2702
+ class="search-input"
2703
+ placeholder="Search conversations..."
2704
+ [(ngModel)]="SearchQuery"
2705
+ (keydown)="OnSearchKeydown($event)">
2706
+ @if (IsSearching) {
2707
+ <button class="search-clear" (click)="ClearSearch()" title="Clear search">
2708
+ <i class="fas fa-xmark"></i>
1376
2709
  </button>
1377
- @if (!isMobileView) {
1378
- <button class="dropdown-item" (click)="onUnpinSidebarClick($event)">
1379
- <i class="fas fa-table-columns"></i>
1380
- <span>Hide Sidebar</span>
2710
+ }
2711
+ </div>
2712
+ }
2713
+ @if (ShowHeaderMenu) {
2714
+ <div class="header-menu-container">
2715
+ <button class="btn-menu" (click)="ToggleHeaderMenu($event)" title="Options">
2716
+ <i class="fas fa-ellipsis-v"></i>
2717
+ </button>
2718
+ @if (IsHeaderMenuOpen) {
2719
+ <div class="header-dropdown-menu">
2720
+ <button class="dropdown-item" (click)="OnRefreshConversationsClick($event)" [disabled]="IsRefreshing">
2721
+ <i class="fas fa-sync-alt" [class.fa-spin]="IsRefreshing"></i>
2722
+ <span>{{ IsRefreshing ? 'Refreshing...' : 'Refresh' }}</span>
1381
2723
  </button>
1382
- }
1383
- </div>
1384
- }
1385
- </div>
2724
+ <button class="dropdown-item" (click)="OnToggleGroupByClick($event)">
2725
+ <i class="fas" [class.fa-folder-tree]="GroupBy !== 'project'" [class.fa-list]="GroupBy === 'project'"></i>
2726
+ <span>{{ GroupBy === 'project' ? 'Show as flat list' : 'Group by folder' }}</span>
2727
+ </button>
2728
+ @if (!IsMobileView) {
2729
+ <button class="dropdown-item" (click)="OnUnpinSidebarClick($event)">
2730
+ <i class="fas fa-table-columns"></i>
2731
+ <span>Hide Sidebar</span>
2732
+ </button>
2733
+ }
2734
+ </div>
2735
+ }
2736
+ </div>
2737
+ }
1386
2738
  }
1387
2739
  </div>
2740
+ <!-- Sort controls. Live in the header strip, so a host that hides all
2741
+ chrome (showSearch + ShowHeaderMenu both false) gets no sort row.
2742
+ They stay put while selecting, so the list does not jump. -->
2743
+ @if (showSearch || ShowHeaderMenu) {
2744
+ <div class="sort-row">
2745
+ <button class="sort-btn" [class.active]="SortBy === 'date'"
2746
+ (click)="SetSort('date')"
2747
+ [title]="SortBy === 'date' ? (SortDirection === 'asc' ? 'Oldest first' : 'Newest first') : 'Sort by date'">
2748
+ <i class="fas" [ngClass]="SortIcon('date')"></i>
2749
+ <span>Date</span>
2750
+ </button>
2751
+ <button class="sort-btn" [class.active]="SortBy === 'name'"
2752
+ (click)="SetSort('name')"
2753
+ [title]="SortBy === 'name' ? (SortDirection === 'asc' ? 'A to Z' : 'Z to A') : 'Sort by name'">
2754
+ <i class="fas" [ngClass]="SortIcon('name')"></i>
2755
+ <span>Name</span>
2756
+ </button>
2757
+ </div>
2758
+ }
1388
2759
  </div>
1389
2760
  }
1390
- @if (showNewConversationButton) {
1391
- <button class="btn-new-conversation" (click)="createNewConversation()" title="New Conversation">
2761
+ @if (ShowNewConversationButton) {
2762
+ <button class="btn-new-conversation" (click)="CreateNewConversation()" title="New Conversation">
1392
2763
  <i class="fas fa-plus"></i>
1393
2764
  <span>New Conversation</span>
1394
2765
  </button>
1395
2766
  }
1396
- <div class="list-content">
2767
+ <div class="list-content"
2768
+ (click)="OnListBackgroundClick($event)"
2769
+ (contextmenu)="OnBackgroundContextMenu($event)">
1397
2770
  <!-- Pinned Section (only show if there are pinned conversations) -->
1398
- @if (pinnedConversations.length > 0) {
2771
+ @if (PinnedConversations.length > 0) {
1399
2772
  <div class="sidebar-section pinned-section">
1400
- @if (showSectionHeaders) {
1401
- <div class="section-header" [class.expanded]="pinnedExpanded" (click)="togglePinned()">
2773
+ @if (ShowSectionHeaders) {
2774
+ <div class="section-header" [class.expanded]="PinnedExpanded" (click)="TogglePinned()">
1402
2775
  <div class="section-title">
1403
2776
  <i class="fas fa-chevron-right"></i>
1404
2777
  <i class="fas fa-thumbtack section-icon"></i>
@@ -1406,46 +2779,46 @@ export class ConversationListComponent {
1406
2779
  </div>
1407
2780
  </div>
1408
2781
  }
1409
- <div class="chat-list" [class.expanded]="!showSectionHeaders || pinnedExpanded">
1410
- @for (conversation of pinnedConversations; track conversation.ID) {
2782
+ <div class="chat-list" [class.expanded]="!ShowSectionHeaders || PinnedExpanded">
2783
+ @for (conversation of PinnedConversations; track conversation.ID) {
1411
2784
  <ng-container [ngTemplateOutlet]="conversationItem" [ngTemplateOutletContext]="{ $implicit: conversation }"></ng-container>
1412
2785
  }
1413
2786
  </div>
1414
2787
  </div>
1415
2788
  }
1416
2789
 
1417
- <!-- showSectionHeaders=false forces the FLAT branch even in project
2790
+ <!-- ShowSectionHeaders=false forces the FLAT branch even in project
1418
2791
  grouping: the folder tree's root drop-zone and New Folder action
1419
2792
  live in the section header, so rendering the tree without headers
1420
2793
  would let a user drag a folder INTO another folder with no way to
1421
2794
  ever drag it back out (a one-way door). Flat + headerless is the
1422
2795
  coherent chrome-less rendering. -->
1423
- @if (showSectionHeaders && groupBy === 'project') {
2796
+ @if (ShowSectionHeaders && GroupBy === 'project') {
1424
2797
  <!-- Folders Section. NOTE: this whole branch is already gated on
1425
- showSectionHeaders above, so the header + collapse state here are
2798
+ ShowSectionHeaders above, so the header + collapse state here are
1426
2799
  unconditional — a headerless folder tree never renders. -->
1427
2800
  <div class="sidebar-section folders-section">
1428
- <div class="section-header" [class.expanded]="foldersExpanded"
1429
- [class.drag-over]="dragOverTargetId === 'folders-root'"
1430
- (click)="toggleFolders()"
1431
- (dragover)="onFoldersRootDragOver($event)"
1432
- (dragleave)="onDragLeave('folders-root')"
1433
- (drop)="onFoldersRootDrop($event)">
2801
+ <div class="section-header" [class.expanded]="FoldersExpanded"
2802
+ [class.drag-over]="DragOverTargetId === 'folders-root'"
2803
+ (click)="ToggleFolders()"
2804
+ (dragover)="OnFoldersRootDragOver($event)"
2805
+ (dragleave)="OnDragLeave('folders-root')"
2806
+ (drop)="OnFoldersRootDrop($event)">
1434
2807
  <div class="section-title">
1435
2808
  <i class="fas fa-chevron-right"></i>
1436
2809
  <span>Folders</span>
1437
2810
  </div>
1438
- <button class="section-action-btn" (click)="createFolder(null, $event)" title="New Folder">
2811
+ <button class="section-action-btn" (click)="CreateFolder(null, $event)" title="New Folder">
1439
2812
  <i class="fas fa-folder-plus"></i>
1440
2813
  </button>
1441
2814
  </div>
1442
- <div class="chat-list" [class.expanded]="foldersExpanded">
1443
- @for (node of folderTree; track node.project.ID) {
1444
- @if (!isSearching || node.hasContent) {
2815
+ <div class="chat-list" [class.expanded]="FoldersExpanded">
2816
+ @for (node of FolderTree; track node.project.ID) {
2817
+ @if (!IsSearching || node.hasContent) {
1445
2818
  <ng-container [ngTemplateOutlet]="folderNode" [ngTemplateOutletContext]="{ $implicit: node }"></ng-container>
1446
2819
  }
1447
2820
  }
1448
- @if (folderTree.length === 0) {
2821
+ @if (FolderTree.length === 0) {
1449
2822
  <div class="folder-empty-hint">No folders yet — create one to organize conversations.</div>
1450
2823
  }
1451
2824
  </div>
@@ -1453,19 +2826,19 @@ export class ConversationListComponent {
1453
2826
 
1454
2827
  <!-- Ungrouped Section (drop target to remove from folder) -->
1455
2828
  <div class="sidebar-section ungrouped-section"
1456
- [class.drag-over]="dragOverTargetId === 'ungrouped'"
1457
- (dragover)="onUngroupedDragOver($event)"
1458
- (dragleave)="onDragLeave('ungrouped')"
1459
- (drop)="onUngroupedDrop($event)">
1460
- <!-- Same as Folders above: reached only when showSectionHeaders is true. -->
1461
- <div class="section-header" [class.expanded]="ungroupedExpanded" (click)="toggleUngrouped()">
2829
+ [class.drag-over]="DragOverTargetId === 'ungrouped'"
2830
+ (dragover)="OnUngroupedDragOver($event)"
2831
+ (dragleave)="OnDragLeave('ungrouped')"
2832
+ (drop)="OnUngroupedDrop($event)">
2833
+ <!-- Same as Folders above: reached only when ShowSectionHeaders is true. -->
2834
+ <div class="section-header" [class.expanded]="UngroupedExpanded" (click)="ToggleUngrouped()">
1462
2835
  <div class="section-title">
1463
2836
  <i class="fas fa-chevron-right"></i>
1464
- <span>{{ folderTree.length > 0 ? 'Ungrouped' : 'Messages' }}</span>
2837
+ <span>{{ FolderTree.length > 0 ? 'Ungrouped' : 'Messages' }}</span>
1465
2838
  </div>
1466
2839
  </div>
1467
- <div class="chat-list" [class.expanded]="ungroupedExpanded">
1468
- @for (conversation of ungroupedConversations; track conversation.ID) {
2840
+ <div class="chat-list" [class.expanded]="UngroupedExpanded">
2841
+ @for (conversation of UngroupedConversations; track conversation.ID) {
1469
2842
  <ng-container [ngTemplateOutlet]="conversationItem" [ngTemplateOutletContext]="{ $implicit: conversation }"></ng-container>
1470
2843
  }
1471
2844
  </div>
@@ -1473,16 +2846,16 @@ export class ConversationListComponent {
1473
2846
  } @else {
1474
2847
  <!-- Flat Messages Section -->
1475
2848
  <div class="sidebar-section">
1476
- @if (showSectionHeaders) {
1477
- <div class="section-header" [class.expanded]="directMessagesExpanded" (click)="toggleDirectMessages()">
2849
+ @if (ShowSectionHeaders) {
2850
+ <div class="section-header" [class.expanded]="DirectMessagesExpanded" (click)="ToggleDirectMessages()">
1478
2851
  <div class="section-title">
1479
2852
  <i class="fas fa-chevron-right"></i>
1480
2853
  <span>Messages</span>
1481
2854
  </div>
1482
2855
  </div>
1483
2856
  }
1484
- <div class="chat-list" [class.expanded]="!showSectionHeaders || directMessagesExpanded">
1485
- @for (conversation of unpinnedConversations; track conversation.ID) {
2857
+ <div class="chat-list" [class.expanded]="!ShowSectionHeaders || DirectMessagesExpanded">
2858
+ @for (conversation of UnpinnedConversations; track conversation.ID) {
1486
2859
  <ng-container [ngTemplateOutlet]="conversationItem" [ngTemplateOutletContext]="{ $implicit: conversation }"></ng-container>
1487
2860
  }
1488
2861
  </div>
@@ -1490,73 +2863,68 @@ export class ConversationListComponent {
1490
2863
  }
1491
2864
  </div>
1492
2865
 
1493
- <!-- Selection Action Bar -->
1494
- @if (isSelectionMode) {
1495
- <div class="selection-action-bar">
1496
- <div class="selection-info">
1497
- <span class="selection-count">{{ selectedConversationIds.size }} selected</span>
1498
- @if (selectedConversationIds.size < filteredConversations.length) {
1499
- <button class="link-btn" (click)="selectAll()">Select All</button>
1500
- } @else {
1501
- <button class="link-btn" (click)="deselectAll()">Deselect All</button>
1502
- }
1503
- </div>
1504
- <div class="selection-actions">
1505
- <button class="btn-delete-bulk"
1506
- (click)="bulkDeleteConversations()"
1507
- [disabled]="selectedConversationIds.size === 0">
1508
- <i class="fas fa-trash"></i>
1509
- Delete ({{ selectedConversationIds.size }})
1510
- </button>
1511
- <button class="btn-cancel" (click)="toggleSelectionMode()">
1512
- Cancel
1513
- </button>
1514
- </div>
1515
- </div>
2866
+ <!-- Escalate the in-place filter to a full cross-entity search. Pinned below the
2867
+ scroll region rather than appended to the results so it stays reachable without
2868
+ scrolling past every match. Only meaningful while filtering. -->
2869
+ @if (IsSearching && !IsSelectionMode) {
2870
+ <button class="search-escalate" (click)="EscalateSearch()">
2871
+ <i class="fa-solid fa-magnifying-glass"></i>
2872
+ <span class="search-escalate-label">Search all of Chat for &ldquo;{{ SearchQuery }}&rdquo;</span>
2873
+ <i class="fa-solid fa-arrow-right search-escalate-go"></i>
2874
+ </button>
1516
2875
  }
1517
2876
  </div>
1518
2877
 
1519
2878
  <!-- Recursive folder node: header + nested children + direct conversations -->
1520
2879
  <ng-template #folderNode let-node>
1521
2880
  <div class="folder-row"
1522
- [class.drag-over]="dragOverTargetId === node.project.ID"
1523
- [class.dragging]="draggedFolderId === node.project.ID"
2881
+ [class.drag-over]="DragOverTargetId === node.project.ID"
2882
+ [class.dragging]="DraggedFolderId === node.project.ID"
1524
2883
  [style.paddingLeft.px]="12 + node.depth * 14"
1525
2884
  [draggable]="true"
1526
- (dragstart)="onFolderDragStart(node, $event)"
1527
- (dragend)="onFolderDragEnd()"
1528
- (click)="toggleFolder(node.project.ID)"
1529
- (dragover)="onFolderDragOver(node.project.ID, $event)"
1530
- (dragleave)="onDragLeave(node.project.ID)"
1531
- (drop)="onFolderDrop(node.project, $event)"
2885
+ (dragstart)="OnFolderDragStart(node, $event)"
2886
+ (dragend)="OnFolderDragEnd()"
2887
+ (click)="ToggleFolder(node.project.ID)"
2888
+ (dragover)="OnFolderDragOver(node.project.ID, $event)"
2889
+ (dragleave)="OnDragLeave(node.project.ID)"
2890
+ (drop)="OnFolderDrop(node.project, $event)"
2891
+ (contextmenu)="OnFolderContextMenu(node.project, $event)"
1532
2892
  [title]="node.project.Name">
1533
- <i class="fas fa-chevron-right folder-chevron" [class.expanded]="isFolderExpanded(node.project.ID)"></i>
2893
+ <i class="fas fa-chevron-right folder-chevron" [class.expanded]="IsFolderExpanded(node.project.ID)"></i>
1534
2894
  <i class="fas {{ node.project.Icon || 'fa-folder' }} folder-icon" [style.color]="node.project.Color || null"></i>
1535
2895
  <span class="folder-name">{{ node.project.Name }}</span>
2896
+ <!-- SHARED is the marked state, not personal. Two reasons: it is the state with
2897
+ consequences for other people ("anyone here can read this folder's name"),
2898
+ and personal is the create-time default, so marking personal would badge
2899
+ nearly every row in steady state while marking shared thins out over time.
2900
+ On an environment upgrading to this column every existing folder is shared
2901
+ and so every row is badged — which is exactly the disclosure people need at
2902
+ that moment. Sits beside the name it describes rather than at the right
2903
+ edge, which belongs to the count. -->
2904
+ @if (!node.project.OwnerUserID) {
2905
+ <!-- role="img" so the aria-label is actually announced: on a bare span with no
2906
+ role, an aria-label is not reliably exposed, and the <i> carrying the glyph
2907
+ is aria-hidden. -->
2908
+ <span class="folder-shared" role="img"
2909
+ title="Shared — everyone can see this folder and its name, but not the conversations in it"
2910
+ aria-label="Shared folder">
2911
+ <i class="fas fa-users" aria-hidden="true"></i>
2912
+ </span>
2913
+ }
2914
+ <span class="folder-spacer"></span>
1536
2915
  <span class="folder-count">{{ node.totalCount }}</span>
1537
- <div class="folder-actions" (click)="$event.stopPropagation()">
1538
- <button class="folder-action-btn" (click)="createFolder(node.project.ID, $event)" title="New Subfolder">
1539
- <i class="fas fa-folder-plus"></i>
1540
- </button>
1541
- <button class="folder-action-btn" (click)="editFolder(node.project, $event)" title="Edit Folder">
1542
- <i class="fas fa-pen"></i>
1543
- </button>
1544
- <button class="folder-action-btn danger" (click)="deleteFolder(node.project, $event)" title="Delete Folder">
1545
- <i class="fas fa-trash"></i>
1546
- </button>
1547
- </div>
1548
2916
  </div>
1549
- @if (isFolderExpanded(node.project.ID)) {
2917
+ @if (IsFolderExpanded(node.project.ID)) {
1550
2918
  <div class="folder-children">
1551
2919
  @for (child of node.children; track child.project.ID) {
1552
- @if (!isSearching || child.hasContent) {
2920
+ @if (!IsSearching || child.hasContent) {
1553
2921
  <ng-container [ngTemplateOutlet]="folderNode" [ngTemplateOutletContext]="{ $implicit: child }"></ng-container>
1554
2922
  }
1555
2923
  }
1556
2924
  @for (conversation of node.conversations; track conversation.ID) {
1557
2925
  <ng-container [ngTemplateOutlet]="conversationItem" [ngTemplateOutletContext]="{ $implicit: conversation, depth: node.depth + 1 }"></ng-container>
1558
2926
  }
1559
- @if (node.totalCount === 0 && !isSearching) {
2927
+ @if (node.totalCount === 0 && !IsSearching) {
1560
2928
  <div class="folder-empty-hint" [style.paddingLeft.px]="26 + node.depth * 14">Empty — drop a conversation here</div>
1561
2929
  }
1562
2930
  </div>
@@ -1567,22 +2935,33 @@ export class ConversationListComponent {
1567
2935
  <ng-template #conversationItem let-conversation let-depth="depth">
1568
2936
  <div class="conversation-item"
1569
2937
  [class.active]="IsConversationActive(conversation)"
2938
+ [class.selected]="IsConversationSelected(conversation)"
1570
2939
  [class.renamed]="IsConversationRenamed(conversation)"
1571
2940
  [class.dragging]="IsConversationDragging(conversation)"
1572
2941
  [style.paddingLeft.px]="depth ? 16 + depth * 14 : 16"
1573
- [draggable]="!isSelectionMode"
1574
- (dragstart)="onConversationDragStart(conversation, $event)"
1575
- (dragend)="onConversationDragEnd()"
1576
- (click)="handleConversationClick(conversation)">
1577
- @if (isSelectionMode) {
1578
- <div class="conversation-checkbox">
1579
- <input type="checkbox"
1580
- [checked]="selectedConversationIds.has(conversation.ID)"
1581
- (click)="$event.stopPropagation(); toggleConversationSelection(conversation.ID)">
1582
- </div>
1583
- }
2942
+ [draggable]="CanChange(conversation)"
2943
+ (dragstart)="OnConversationDragStart(conversation, $event)"
2944
+ (dragend)="OnConversationDragEnd()"
2945
+ (dragover)="OnConversationRowDragOver(conversation, $event)"
2946
+ (dragleave)="OnDragLeave(ConversationDropTargetId(conversation))"
2947
+ (drop)="OnConversationRowDrop(conversation, $event)"
2948
+ (pointerdown)="OnRowPointerDown(conversation, $event)"
2949
+ (pointermove)="OnRowPointerMove($event)"
2950
+ (pointerup)="CancelLongPress()"
2951
+ (pointercancel)="CancelLongPress()"
2952
+ (click)="HandleConversationClick(conversation, $event)"
2953
+ (contextmenu)="OnConversationContextMenu(conversation, $event)">
2954
+ <button class="row-check"
2955
+ role="checkbox"
2956
+ [class.checked]="IsConversationSelected(conversation)"
2957
+ [attr.aria-checked]="IsConversationSelected(conversation)"
2958
+ [attr.aria-label]="'Select ' + (conversation.Name || 'conversation')"
2959
+ [style.left.px]="(depth || 0) * 14 + 4"
2960
+ (click)="OnRowCheckboxClick(conversation, $event)">
2961
+ <i class="fas fa-check"></i>
2962
+ </button>
1584
2963
  <div class="conversation-icon-wrapper">
1585
- @if (hasActiveTasks(conversation.ID)) {
2964
+ @if (HasActiveTasks(conversation.ID)) {
1586
2965
  <div class="conversation-icon has-tasks">
1587
2966
  <i class="fas fa-spinner fa-pulse"></i>
1588
2967
  </div>
@@ -1594,107 +2973,227 @@ export class ConversationListComponent {
1594
2973
  <div class="conversation-info" [title]="conversation.Name + (conversation.Description ? '\n' + conversation.Description : '')">
1595
2974
  <div class="conversation-name">
1596
2975
  {{ conversation.Name }}
1597
- @if (isSharedWithMe(conversation)) {
2976
+ @if (IsSharedWithMe(conversation)) {
1598
2977
  <i class="fas fa-share-nodes shared-indicator"
1599
- [title]="sharedWithMeTooltip(conversation)"></i>
2978
+ [title]="SharedWithMeTooltip(conversation)"></i>
1600
2979
  }
1601
2980
  </div>
1602
2981
  <div class="conversation-preview">{{ conversation.Description }}</div>
1603
2982
  </div>
1604
- @if (!isSelectionMode) {
1605
- <div class="conversation-actions">
1606
- <button class="menu-btn" (click)="toggleMenu(conversation.ID, $event)" title="More options">
1607
- <i class="fas fa-ellipsis"></i>
1608
- </button>
1609
- @if (IsMenuOpen(conversation)) {
1610
- <div class="context-menu" (click)="$event.stopPropagation()">
1611
- @if (IsMoveSubmenuOpen(conversation)) {
1612
- <button class="menu-item back" (click)="closeMoveSubmenu($event)">
1613
- <i class="fas fa-chevron-left"></i>
1614
- <span>Move to folder</span>
1615
- </button>
1616
- <div class="menu-divider"></div>
1617
- <div class="move-folder-list">
1618
- <button class="menu-item" [class.current]="!conversation.ProjectID" (click)="selectMoveTarget(conversation, null)">
1619
- <i class="fas fa-inbox"></i>
1620
- <span>No folder</span>
1621
- </button>
1622
- @for (f of flatFolders; track f.project.ID) {
1623
- <button class="menu-item" [class.current]="IsInFolder(conversation, f.project.ID)"
1624
- [style.paddingLeft.px]="14 + f.depth * 12"
1625
- (click)="selectMoveTarget(conversation, f.project.ID)">
1626
- <i class="fas {{ f.project.Icon || 'fa-folder' }}" [style.color]="f.project.Color || null"></i>
1627
- <span>{{ f.project.Name }}</span>
1628
- </button>
1629
- }
1630
- </div>
1631
- <div class="menu-divider"></div>
1632
- <button class="menu-item" (click)="createFolderForConversation(conversation, $event)">
1633
- <i class="fas fa-folder-plus"></i>
1634
- <span>New folder…</span>
1635
- </button>
1636
- } @else {
1637
- <button class="menu-item" (click)="togglePin(conversation, $event)">
1638
- <i class="fas fa-thumbtack"></i>
1639
- <span>{{ conversation.IsPinned ? 'Unpin' : 'Pin' }}</span>
1640
- </button>
1641
- <button class="menu-item" (click)="openMoveSubmenu(conversation.ID, $event)">
1642
- <i class="fas fa-folder-tree"></i>
1643
- <span>Move to folder</span>
1644
- <i class="fas fa-chevron-right submenu-arrow"></i>
1645
- </button>
1646
- <button class="menu-item" (click)="renameConversation(conversation); closeMenu()">
1647
- <i class="fas fa-edit"></i>
1648
- <span>Rename</span>
1649
- </button>
1650
- <div class="menu-divider"></div>
1651
- <button class="menu-item danger" (click)="deleteConversation(conversation); closeMenu()">
1652
- <i class="fas fa-trash"></i>
1653
- <span>Delete</span>
2983
+ <div class="conversation-actions">
2984
+ <button class="menu-btn" (click)="OpenRowMenu(conversation, $event)" title="More options">
2985
+ <i class="fas fa-ellipsis"></i>
2986
+ </button>
2987
+ </div>
2988
+ </div>
2989
+ </ng-template>
2990
+
2991
+ <mj-resource-share-dialog
2992
+ [Visible]="IsShareDialogOpen"
2993
+ [Contexts]="ShareContexts"
2994
+ [Adapter]="ShareAdapter"
2995
+ [Notice]="ShareNotice"
2996
+ ResourceLabel="conversation"
2997
+ (Result)="OnShareDialogResult($event)">
2998
+ </mj-resource-share-dialog>
2999
+
3000
+ <!-- One menu for every right-click target: a conversation row (the clicked
3001
+ row, or the whole selection when it is part of it), a folder row, or the
3002
+ empty space of the list. Fixed-positioned at the pointer, and moved as
3003
+ needed to stay inside the window. -->
3004
+ @if (ContextMenu) {
3005
+ <div class="list-context-menu" #contextMenuEl
3006
+ [style.left.px]="ContextMenu.x"
3007
+ [style.top.px]="ContextMenu.y"
3008
+ (click)="$event.stopPropagation()"
3009
+ (contextmenu)="$event.preventDefault(); $event.stopPropagation()">
3010
+ @switch (ContextMenu.kind) {
3011
+ @case ('conversation') {
3012
+ @if (IsMoveSubmenuOpen) {
3013
+ <button class="menu-item back" (click)="CloseMoveSubmenu($event)">
3014
+ <i class="fas fa-chevron-left"></i>
3015
+ <span>Move to folder</span>
3016
+ </button>
3017
+ <div class="menu-divider"></div>
3018
+ <div class="move-folder-list">
3019
+ <button class="menu-item" [class.current]="IsSingleTargetInFolder(null)" (click)="ContextMoveToFolder(null)">
3020
+ <i class="fas fa-inbox"></i>
3021
+ <span>No folder</span>
3022
+ </button>
3023
+ @for (f of FlatFolders; track f.project.ID) {
3024
+ <button class="menu-item" [class.current]="IsSingleTargetInFolder(f.project.ID)"
3025
+ [style.paddingLeft.px]="14 + f.depth * 12"
3026
+ (click)="ContextMoveToFolder(f.project.ID)">
3027
+ <i class="fas {{ f.project.Icon || 'fa-folder' }}" [style.color]="f.project.Color || null"></i>
3028
+ <span>{{ f.project.Name }}</span>
1654
3029
  </button>
1655
3030
  }
1656
3031
  </div>
3032
+ <div class="menu-divider"></div>
3033
+ <button class="menu-item" (click)="ContextMoveToNewFolder($event)">
3034
+ <i class="fas fa-folder-plus"></i>
3035
+ <span>New folder&hellip;</span>
3036
+ </button>
3037
+ } @else {
3038
+ @if (ContextMenu.targets.length > 1) {
3039
+ <div class="context-menu-header">{{ ContextMenu.targets.length }} selected</div>
3040
+ <button class="menu-item" (click)="ContextSetPinned(true)"
3041
+ [disabled]="!CanChangeAny(ContextMenu.targets)"
3042
+ [attr.title]="CanChangeAny(ContextMenu.targets) ? null : ChangeRefusedReason">
3043
+ <i class="fas fa-thumbtack"></i>
3044
+ <span>Pin</span>
3045
+ </button>
3046
+ <button class="menu-item" (click)="ContextSetPinned(false)"
3047
+ [disabled]="!CanChangeAny(ContextMenu.targets)"
3048
+ [attr.title]="CanChangeAny(ContextMenu.targets) ? null : ChangeRefusedReason">
3049
+ <i class="fas fa-thumbtack fa-rotate-90"></i>
3050
+ <span>Unpin</span>
3051
+ </button>
3052
+ } @else {
3053
+ <button class="menu-item" (click)="ContextTogglePin()"
3054
+ [disabled]="!CanChangeAny(ContextMenu.targets)"
3055
+ [attr.title]="CanChangeAny(ContextMenu.targets) ? null : ChangeRefusedReason">
3056
+ <i class="fas fa-thumbtack"></i>
3057
+ <span>{{ ContextMenu.conversation?.IsPinned ? 'Unpin' : 'Pin' }}</span>
3058
+ </button>
3059
+ }
3060
+ <button class="menu-item" (click)="OpenMoveSubmenu($event)"
3061
+ [disabled]="!CanChangeAny(ContextMenu.targets)"
3062
+ [attr.title]="CanChangeAny(ContextMenu.targets) ? null : ChangeRefusedReason">
3063
+ <i class="fas fa-folder-tree"></i>
3064
+ <span>Move to folder</span>
3065
+ <i class="fas fa-chevron-right submenu-arrow"></i>
3066
+ </button>
3067
+ <button class="menu-item"
3068
+ (click)="ContextShare()"
3069
+ [disabled]="!CanShareAny(ContextMenu.targets)"
3070
+ [attr.title]="CanShareAny(ContextMenu.targets) ? null : ShareRefusedReason">
3071
+ <i class="fas fa-user-plus"></i>
3072
+ <span>{{ ContextMenu.targets.length > 1 ? 'Share ' + ContextMenu.targets.length + ' conversations' : 'Share' }}</span>
3073
+ </button>
3074
+ @if (ContextMenu.targets.length === 1) {
3075
+ <button class="menu-item" (click)="ContextRename()">
3076
+ <i class="fas fa-edit"></i>
3077
+ <span>Rename</span>
3078
+ </button>
3079
+ }
3080
+ <div class="menu-divider"></div>
3081
+ <button class="menu-item danger" (click)="ContextDelete()">
3082
+ <i class="fas fa-trash"></i>
3083
+ <span>{{ ContextMenu.targets.length > 1 ? 'Delete ' + ContextMenu.targets.length : 'Delete' }}</span>
3084
+ </button>
1657
3085
  }
1658
- </div>
3086
+ }
3087
+ @case ('folder') {
3088
+ <button class="menu-item" (click)="ContextCreateSubfolder($event)">
3089
+ <i class="fas fa-folder-plus"></i>
3090
+ <span>New Subfolder</span>
3091
+ </button>
3092
+ <button class="menu-item" (click)="ContextEditFolder($event)">
3093
+ <i class="fas fa-pen"></i>
3094
+ <span>Rename</span>
3095
+ </button>
3096
+ <div class="menu-divider"></div>
3097
+ <button class="menu-item danger" (click)="ContextDeleteFolder($event)">
3098
+ <i class="fas fa-trash"></i>
3099
+ <span>Delete</span>
3100
+ </button>
3101
+ }
3102
+ @default {
3103
+ <button class="menu-item" (click)="ContextNewConversation()">
3104
+ <i class="fas fa-plus"></i>
3105
+ <span>New Conversation</span>
3106
+ </button>
3107
+ <button class="menu-item" (click)="ContextCreateRootFolder($event)">
3108
+ <i class="fas fa-folder-plus"></i>
3109
+ <span>New Folder</span>
3110
+ </button>
3111
+ <div class="menu-divider"></div>
3112
+ <button class="menu-item" (click)="ContextSelectAll()">
3113
+ <i class="fas fa-check-double"></i>
3114
+ <span>Select All</span>
3115
+ </button>
3116
+ }
1659
3117
  }
1660
3118
  </div>
1661
- </ng-template>
1662
- `, styles: ["\n :host {\n display: block;\n height: 100%;\n /* White-label theming tokens for the list panel. The public\n --mj-chat-list-* custom properties are host-overridable (set\n them at :root or on any ancestor); the private --conv-list-* names\n resolve the fallback ONCE here so the 70+ usages below stay simple.\n (A self-referential var() fallback would be a custom-property cycle,\n so the two-name indirection is required, not stylistic.) Defaults\n preserve the stock look exactly: a brand-secondary panel with\n on-secondary ink. Hover/border/divider states derive from the ink via\n color-mix, so they follow automatically when the ink is remapped.\n The accent trio drives the panel's ACTION surfaces (New Conversation\n button, search-focus ring, checkbox tick, drag-over highlights) \u2014\n independent of the active-row pair so a host can tint actions on their\n own; defaults to the brand-primary action color, unchanged.\n --conv-list-hover-bg is the row-hover wash: it defaults to the same\n ink-derived tint as before (so a bg/ink remap still gives a neutral\n hover), but a host can point it at a brand tint to make hover an accent\n cue while keeping the panel itself on a neutral surface. */\n --conv-list-bg: var(--mj-chat-list-bg, var(--mj-brand-secondary));\n --conv-list-ink: var(--mj-chat-list-ink, var(--mj-brand-on-secondary));\n --conv-list-active-bg: var(--mj-chat-list-active-bg, var(--mj-brand-primary));\n --conv-list-active-ink: var(--mj-chat-list-active-ink, var(--mj-brand-on-secondary));\n --conv-list-active-hover-bg: var(--mj-chat-list-active-hover-bg, var(--mj-brand-primary-hover));\n --conv-list-accent: var(--mj-chat-list-accent, var(--mj-brand-primary));\n --conv-list-accent-ink: var(--mj-chat-list-accent-ink, var(--mj-text-inverse));\n --conv-list-accent-hover: var(--mj-chat-list-accent-hover, var(--mj-brand-primary-hover));\n --conv-list-hover-bg: var(--mj-chat-list-hover-bg, color-mix(in srgb, var(--conv-list-ink) 8%, transparent));\n }\n .conversation-list { display: flex; flex-direction: column; height: 100%; background: var(--conv-list-bg); }\n .list-header { padding: 8px; border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent); }\n .search-input {\n width: 100%;\n padding: 8px 12px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n transition: all 0.2s;\n }\n .search-input::placeholder { color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); }\n .search-input:focus { outline: none; background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent); border-color: var(--conv-list-accent); }\n .btn-new-conversation {\n width: calc(100% - 16px);\n margin: 8px;\n padding: 10px;\n background: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.2s;\n flex-shrink: 0;\n }\n .btn-new-conversation:hover { background: var(--conv-list-accent-hover); }\n .btn-new-conversation i { font-size: 14px; }\n .list-content { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 0; }\n\n /* Collapsible Sections */\n .sidebar-section { margin-bottom: 20px; }\n .pinned-section .section-title .section-icon {\n color: var(--mj-status-warning);\n font-size: 11px;\n margin-left: 2px;\n }\n .section-header {\n padding: 4px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 500;\n transition: background 0.2s;\n user-select: none;\n }\n .section-header:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .section-title {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .section-title i {\n font-size: 10px;\n }\n .section-title i:not(.section-icon) {\n transition: transform 0.2s;\n }\n .section-header.expanded .section-title i:not(.section-icon) { transform: rotate(90deg); }\n .chat-list {\n padding: 4px 0;\n display: none;\n }\n .chat-list.expanded { display: block; }\n\n .conversation-item {\n padding: 6px 5px 6px 16px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: all 0.2s;\n position: relative;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 14px;\n min-height: 45px;\n }\n .conversation-item:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .conversation-item:hover .conversation-actions { opacity: 1; }\n .conversation-item.active { background: var(--conv-list-active-bg); color: var(--conv-list-active-ink); }\n .conversation-icon-wrapper { position: relative; flex-shrink: 0; }\n .conversation-icon { font-size: 12px; width: 16px; text-align: center; }\n .conversation-icon.has-tasks { color: var(--mj-status-warning); }\n .badge-overlay { position: absolute; top: -4px; right: -4px; }\n .conversation-info { flex: 1; min-width: 0; }\n .conversation-name { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; }\n .shared-indicator { font-size: 10px; color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent); flex-shrink: 0; }\n .conversation-item.active .shared-indicator { color: color-mix(in srgb, var(--conv-list-active-ink) 85%, transparent); }\n .conversation-preview { font-size: 12px; color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .conversation-item.active .conversation-preview { color: color-mix(in srgb, var(--conv-list-active-ink) 80%, transparent); }\n .conversation-meta { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }\n\n /* Project Badge */\n .project-badge {\n display: inline-block;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n margin-left: auto;\n background-color: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .conversation-item:hover .project-badge {\n background-color: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n }\n .conversation-item.active .project-badge {\n background-color: color-mix(in srgb, var(--conv-list-active-ink) 20%, transparent);\n color: var(--conv-list-active-ink);\n }\n\n .conversation-actions {\n position: absolute;\n right: 5px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 10;\n }\n .conversation-item:hover .conversation-actions { opacity: 1; pointer-events: auto; }\n .conversation-item.active .conversation-actions { opacity: 1; pointer-events: auto; }\n .conversation-actions > * { pointer-events: auto; }\n .pinned-icon { color: var(--mj-brand-accent); font-size: 12px; }\n\n /* Task Indicator */\n .task-indicator {\n color: var(--mj-status-warning);\n font-size: 12px;\n margin-right: 8px;\n flex-shrink: 0;\n animation: pulse-glow 2s ease-in-out infinite;\n }\n @keyframes pulse-glow {\n 0%, 100% {\n opacity: 1;\n filter: drop-shadow(0 0 2px var(--mj-status-warning));\n }\n 50% {\n opacity: 0.6;\n filter: drop-shadow(0 0 4px var(--mj-status-warning));\n }\n }\n .conversation-item.active .task-indicator {\n color: var(--mj-status-warning);\n }\n\n .menu-btn {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n background: var(--conv-list-bg) !important;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n }\n .menu-btn:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent) !important;\n color: var(--conv-list-ink);\n }\n .conversation-item.active .menu-btn {\n background: var(--conv-list-active-hover-bg) !important;\n color: var(--conv-list-active-ink);\n }\n .menu-btn i { font-size: 14px; }\n\n .context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 160px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n pointer-events: auto;\n }\n\n .menu-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .menu-item:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .menu-item i {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .menu-item:hover i {\n color: var(--conv-list-ink);\n }\n\n .menu-item.danger {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n .menu-item.danger i {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger:hover i {\n color: var(--mj-status-error);\n }\n\n .menu-divider {\n height: 1px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin: 4px 0;\n }\n\n /* Rename Animation */\n .conversation-item.renamed {\n animation: renameHighlight 1500ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* Brand-token ramp (was hardcoded tailwind blue/purple/emerald rgba values,\n which ignored theming): primary/accent open the flash, success/primary\n carry the fade, at the original alpha ramp (40/35/30/20; glows 50-20). */\n @keyframes renameHighlight {\n 0% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 40%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 40%, transparent));\n transform: scale(1.03);\n box-shadow: 0 0 20px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n }\n 25% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 35%, transparent));\n box-shadow: 0 0 15px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n }\n 50% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 30%, transparent));\n transform: scale(1.02);\n box-shadow: 0 0 10px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n 75% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 20%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 20%, transparent));\n box-shadow: 0 0 5px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n }\n 100% {\n background: transparent;\n transform: scale(1);\n box-shadow: none;\n }\n }\n\n /* Selection Mode Styles */\n .header-top {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n /* Header menu button and dropdown */\n .header-menu-container {\n position: relative;\n flex-shrink: 0;\n }\n\n .btn-menu {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-menu:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .header-dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n padding: 4px 0;\n }\n\n .header-dropdown-menu .dropdown-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .header-dropdown-menu .dropdown-item:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu .dropdown-item i {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .header-dropdown-menu .dropdown-item:hover i {\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu .dropdown-item .shortcut {\n margin-left: auto;\n font-size: 11px;\n color: color-mix(in srgb, var(--conv-list-ink) 40%, transparent);\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n .btn-select {\n padding: 8px 12px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n .btn-select:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .conversation-checkbox {\n display: flex;\n align-items: center;\n margin-right: 8px;\n flex-shrink: 0;\n }\n\n .conversation-checkbox input[type=\"checkbox\"] {\n width: 18px;\n height: 18px;\n cursor: pointer;\n accent-color: var(--conv-list-accent);\n }\n\n .selection-action-bar {\n position: sticky;\n bottom: 0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--conv-list-bg);\n border-top: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n gap: 12px;\n flex-wrap: wrap;\n flex-shrink: 0;\n }\n\n .selection-info {\n display: flex;\n align-items: center;\n gap: 12px;\n color: color-mix(in srgb, var(--conv-list-ink) 90%, transparent);\n font-size: 14px;\n font-weight: 500;\n flex: 1 1 auto;\n min-width: 150px;\n }\n\n .selection-count {\n color: var(--conv-list-ink);\n }\n\n .link-btn {\n background: none;\n border: none;\n color: var(--mj-brand-accent);\n cursor: pointer;\n font-size: 13px;\n text-decoration: underline;\n padding: 0;\n transition: color 0.2s;\n }\n\n .link-btn:hover {\n color: var(--conv-list-ink);\n }\n\n .selection-actions {\n display: flex;\n gap: 8px;\n flex: 0 0 auto;\n }\n\n .btn-cancel {\n padding: 8px 16px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: all 0.2s;\n }\n\n .btn-cancel:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .btn-delete-bulk {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-error);\n border: none;\n border-radius: 6px;\n /* Deliberately NOT --conv-list-ink: this ink sits on the error-red button,\n not the panel, so it must not follow a panel remap. (brand-on-secondary\n stays light in both modes; text-inverse flips dark in dark mode.) */\n color: var(--mj-brand-on-secondary);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: all 0.2s;\n }\n\n .btn-delete-bulk:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 80%, black);\n }\n\n .btn-delete-bulk:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .btn-delete-bulk i {\n font-size: 12px;\n }\n\n /* Folders */\n .section-action-btn {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n .section-action-btn:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: var(--conv-list-ink);\n }\n .section-action-btn i { font-size: 12px; }\n\n .folder-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n cursor: pointer;\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n font-size: 13px;\n transition: background 0.15s;\n user-select: none;\n position: relative;\n }\n .folder-row:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .folder-row.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 25%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n }\n .folder-row.dragging { opacity: 0.4; }\n .section-header.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n .folder-chevron {\n font-size: 9px;\n width: 10px;\n flex-shrink: 0;\n transition: transform 0.2s;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n }\n .folder-chevron.expanded { transform: rotate(90deg); }\n .folder-icon { font-size: 12px; width: 16px; text-align: center; flex-shrink: 0; }\n .folder-name {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: 600;\n }\n .folder-count {\n font-size: 11px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n flex-shrink: 0;\n margin-left: auto;\n padding-left: 6px;\n text-align: right;\n }\n .folder-actions {\n position: absolute;\n right: 6px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n gap: 2px;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 5;\n }\n .folder-row:hover .folder-actions { opacity: 1; pointer-events: auto; }\n .folder-row:hover .folder-count { opacity: 0; }\n .folder-action-btn {\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.15s;\n }\n .folder-action-btn:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 18%, transparent);\n color: var(--conv-list-ink);\n }\n .folder-action-btn.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n color: var(--mj-status-error);\n }\n .folder-action-btn i { font-size: 11px; }\n .folder-children { display: block; }\n .folder-empty-hint {\n padding: 6px 16px;\n font-size: 11px;\n font-style: italic;\n color: color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n }\n .ungrouped-section.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 12%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n\n /* Dragging state */\n .conversation-item { user-select: none; }\n .conversation-item.dragging { opacity: 0.4; }\n\n /* Move-to-folder submenu */\n .menu-item.back { font-weight: 600; }\n .menu-item .submenu-arrow { margin-left: auto; font-size: 10px; }\n .menu-item.current { background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent); }\n .move-folder-list { max-height: 240px; overflow-y: auto; }\n "] }]
1663
- }], () => [{ type: i1.DialogService }, { type: i2.NotificationService }, { type: i3.ActiveTasksService }, { type: i4.MJDialogService }, { type: i0.ChangeDetectorRef }], { environmentId: [{
3119
+ }
3120
+ `, styles: ["\n :host {\n display: block;\n height: 100%;\n /* White-label theming tokens for the list panel. The public\n --mj-chat-list-* custom properties are host-overridable (set\n them at :root or on any ancestor); the private --conv-list-* names\n resolve the fallback ONCE here so the 70+ usages below stay simple.\n (A self-referential var() fallback would be a custom-property cycle,\n so the two-name indirection is required, not stylistic.) Defaults\n preserve the stock look exactly: a brand-secondary panel with\n on-secondary ink. Hover/border/divider states derive from the ink via\n color-mix, so they follow automatically when the ink is remapped.\n The accent trio drives the panel's ACTION surfaces (New Conversation\n button, search-focus ring, checkbox tick, drag-over highlights) \u2014\n independent of the active-row pair so a host can tint actions on their\n own; defaults to the brand-primary action color, unchanged.\n --conv-list-hover-bg is the row-hover wash: it defaults to the same\n ink-derived tint as before (so a bg/ink remap still gives a neutral\n hover), but a host can point it at a brand tint to make hover an accent\n cue while keeping the panel itself on a neutral surface. */\n --conv-list-bg: var(--mj-chat-list-bg, var(--mj-brand-secondary));\n --conv-list-ink: var(--mj-chat-list-ink, var(--mj-brand-on-secondary));\n --conv-list-active-bg: var(--mj-chat-list-active-bg, var(--mj-brand-primary));\n --conv-list-active-ink: var(--mj-chat-list-active-ink, var(--mj-brand-on-secondary));\n --conv-list-active-hover-bg: var(--mj-chat-list-active-hover-bg, var(--mj-brand-primary-hover));\n --conv-list-accent: var(--mj-chat-list-accent, var(--mj-brand-primary));\n --conv-list-accent-ink: var(--mj-chat-list-accent-ink, var(--mj-text-inverse));\n --conv-list-accent-hover: var(--mj-chat-list-accent-hover, var(--mj-brand-primary-hover));\n --conv-list-hover-bg: var(--mj-chat-list-hover-bg, color-mix(in srgb, var(--conv-list-ink) 8%, transparent));\n }\n .conversation-list { display: flex; flex-direction: column; height: 100%; background: var(--conv-list-bg); }\n .list-header { padding: 8px; border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent); }\n .search-box { position: relative; flex: 1; min-width: 0; display: flex; }\n .search-clear {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n width: 22px;\n height: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .sort-row { display: flex; gap: 6px; margin-top: 8px; }\n .sort-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .sort-btn i { font-size: 11px; }\n .sort-btn:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .sort-btn.active {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n border-color: var(--conv-list-accent);\n color: var(--conv-list-ink);\n font-weight: 600;\n }\n .search-clear:hover { background: color-mix(in srgb, var(--conv-list-ink) 12%, transparent); color: var(--conv-list-ink); }\n .search-input {\n width: 100%;\n padding: 8px 28px 8px 12px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n transition: all 0.2s;\n }\n .search-input::placeholder { color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); }\n .search-input:focus { outline: none; background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent); border-color: var(--conv-list-accent); }\n .btn-new-conversation {\n width: calc(100% - 16px);\n margin: 8px;\n padding: 10px;\n background: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n transition: background 0.2s;\n flex-shrink: 0;\n }\n .btn-new-conversation:hover { background: var(--conv-list-accent-hover); }\n .btn-new-conversation i { font-size: 14px; }\n .list-content { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 0; }\n\n /* Collapsible Sections */\n .sidebar-section { margin-bottom: 20px; }\n\n /* Reads as a continuation of the list rather than a second control: full-width row,\n ink-derived like every other affordance in this panel, no input styling. */\n .search-escalate {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n border: none;\n border-top: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n background: transparent;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .search-escalate:hover {\n background: var(--conv-list-hover-bg);\n color: var(--conv-list-ink);\n }\n\n /* Truncate rather than wrap \u2014 the query is user text of unbounded length. */\n .search-escalate-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .search-escalate-go { opacity: 0.6; }\n .pinned-section .section-title .section-icon {\n color: var(--mj-status-warning);\n font-size: 11px;\n margin-left: 2px;\n }\n .section-header {\n padding: 4px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 500;\n transition: background 0.2s;\n user-select: none;\n }\n .section-header:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .section-title {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .section-title i {\n font-size: 10px;\n }\n .section-title i:not(.section-icon) {\n transition: transform 0.2s;\n }\n .section-header.expanded .section-title i:not(.section-icon) { transform: rotate(90deg); }\n .chat-list {\n padding: 4px 0;\n display: none;\n }\n .chat-list.expanded { display: block; }\n\n .conversation-item {\n padding: 6px 5px 6px 16px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: all 0.2s;\n position: relative;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 14px;\n min-height: 45px;\n }\n .conversation-item:hover { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .conversation-item:hover .conversation-actions { opacity: 1; }\n .conversation-item.active { background: var(--conv-list-active-bg); color: var(--conv-list-active-ink); }\n /* A selected row is marked by its ticked checkbox and an accent tint. The\n open conversation keeps its solid .active fill, so a row that is both\n still reads as the open one. */\n .conversation-item.selected { background: color-mix(in srgb, var(--conv-list-accent) 16%, transparent); }\n .conversation-item.selected:hover { background: color-mix(in srgb, var(--conv-list-accent) 24%, transparent); }\n .conversation-item.active.selected { background: var(--conv-list-active-bg); }\n /* Row checkbox: the mouse route to a selection. It sits in the row's left\n padding, hidden until the row is hovered, and shows on every row while a\n selection exists (on touch too, where there is no hover). */\n .row-check {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 14px;\n height: 14px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1.5px solid color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n border-radius: 3px;\n color: transparent;\n cursor: pointer;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n z-index: 2;\n }\n .row-check i { font-size: 8px; }\n .conversation-list.is-selecting .row-check { opacity: 1; pointer-events: auto; }\n @media (hover: hover) {\n .conversation-item:hover .row-check { opacity: 1; pointer-events: auto; }\n }\n .row-check.checked {\n background: var(--conv-list-accent);\n border-color: var(--conv-list-accent);\n color: var(--conv-list-accent-ink);\n }\n .conversation-item.active .row-check:not(.checked) {\n border-color: color-mix(in srgb, var(--conv-list-active-ink) 70%, transparent);\n }\n .conversation-icon-wrapper { position: relative; flex-shrink: 0; }\n .conversation-icon { font-size: 12px; width: 16px; text-align: center; }\n .conversation-icon.has-tasks { color: var(--mj-status-warning); }\n .badge-overlay { position: absolute; top: -4px; right: -4px; }\n .conversation-info { flex: 1; min-width: 0; }\n .conversation-name { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; }\n .shared-indicator { font-size: 10px; color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent); flex-shrink: 0; }\n .conversation-item.active .shared-indicator { color: color-mix(in srgb, var(--conv-list-active-ink) 85%, transparent); }\n .conversation-preview { font-size: 12px; color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .conversation-item.active .conversation-preview { color: color-mix(in srgb, var(--conv-list-active-ink) 80%, transparent); }\n .conversation-meta { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }\n\n /* Project Badge */\n .project-badge {\n display: inline-block;\n padding: 2px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n margin-left: auto;\n background-color: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n white-space: nowrap;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .conversation-item:hover .project-badge {\n background-color: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n }\n .conversation-item.active .project-badge {\n background-color: color-mix(in srgb, var(--conv-list-active-ink) 20%, transparent);\n color: var(--conv-list-active-ink);\n }\n\n .conversation-actions {\n position: absolute;\n right: 5px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s;\n z-index: 10;\n }\n .conversation-item:hover .conversation-actions { opacity: 1; pointer-events: auto; }\n .conversation-item.active .conversation-actions { opacity: 1; pointer-events: auto; }\n .conversation-actions > * { pointer-events: auto; }\n /* No hover on touch, so the \u22EF button is always shown there. */\n @media (hover: none) {\n .conversation-actions { opacity: 1; pointer-events: auto; }\n }\n .pinned-icon { color: var(--mj-brand-accent); font-size: 12px; }\n\n /* Task Indicator */\n .task-indicator {\n color: var(--mj-status-warning);\n font-size: 12px;\n margin-right: 8px;\n flex-shrink: 0;\n animation: pulse-glow 2s ease-in-out infinite;\n }\n @keyframes pulse-glow {\n 0%, 100% {\n opacity: 1;\n filter: drop-shadow(0 0 2px var(--mj-status-warning));\n }\n 50% {\n opacity: 0.6;\n filter: drop-shadow(0 0 4px var(--mj-status-warning));\n }\n }\n .conversation-item.active .task-indicator {\n color: var(--mj-status-warning);\n }\n\n .menu-btn {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n background: var(--conv-list-bg) !important;\n border: none;\n cursor: pointer;\n transition: all 0.2s;\n }\n .menu-btn:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent) !important;\n color: var(--conv-list-ink);\n }\n .conversation-item.active .menu-btn {\n background: var(--conv-list-active-hover-bg) !important;\n color: var(--conv-list-active-ink);\n }\n .menu-btn i { font-size: 14px; }\n\n /* The one right-click menu. Fixed to the viewport so it escapes the list's\n scroll container and is never clipped by a row. */\n .list-context-menu {\n position: fixed;\n min-width: 190px;\n max-height: 70vh;\n overflow-y: auto;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n padding: 4px 0;\n }\n\n .context-menu-header {\n padding: 6px 14px 8px;\n font-size: 12px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n border-bottom: 1px solid color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin-bottom: 4px;\n }\n\n .menu-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 14px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .menu-item:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .menu-item i {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .menu-item:hover i {\n color: var(--conv-list-ink);\n }\n\n .menu-item.danger {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n .menu-item.danger i {\n color: var(--mj-status-error);\n }\n\n .menu-item.danger:hover i {\n color: var(--mj-status-error);\n }\n\n .menu-divider {\n height: 1px;\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n margin: 4px 0;\n }\n\n /* Rename Animation */\n .conversation-item.renamed {\n animation: renameHighlight 1500ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* Brand-token ramp (was hardcoded tailwind blue/purple/emerald rgba values,\n which ignored theming): primary/accent open the flash, success/primary\n carry the fade, at the original alpha ramp (40/35/30/20; glows 50-20). */\n @keyframes renameHighlight {\n 0% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 40%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 40%, transparent));\n transform: scale(1.03);\n box-shadow: 0 0 20px color-mix(in srgb, var(--mj-brand-primary) 50%, transparent);\n }\n 25% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n color-mix(in srgb, var(--mj-brand-accent) 35%, transparent));\n box-shadow: 0 0 15px color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n }\n 50% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 30%, transparent));\n transform: scale(1.02);\n box-shadow: 0 0 10px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n }\n 75% {\n background: linear-gradient(90deg,\n color-mix(in srgb, var(--mj-status-success) 20%, transparent),\n color-mix(in srgb, var(--mj-brand-primary) 20%, transparent));\n box-shadow: 0 0 5px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n }\n 100% {\n background: transparent;\n transform: scale(1);\n box-shadow: none;\n }\n }\n\n /* Header top row: the search box and \u22EF menu, or the selection bar while a\n selection exists. A fixed minimum height keeps the list from jumping\n when one replaces the other. */\n .header-top {\n display: flex;\n gap: 8px;\n align-items: center;\n min-height: 36px;\n }\n\n .selection-bar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex: 1;\n min-width: 0;\n }\n\n .selection-count {\n flex: 1;\n min-width: 0;\n padding: 0 6px;\n color: var(--conv-list-ink);\n font-size: 13px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .selection-bar-btn {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 75%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .selection-bar-btn i { font-size: 13px; }\n .selection-bar-btn:hover:not(:disabled) { background: var(--conv-list-hover-bg); color: var(--conv-list-ink); }\n .selection-bar-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n .selection-bar-btn.danger:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 15%, transparent);\n color: var(--mj-status-error);\n }\n\n /* Header menu button and dropdown */\n .header-menu-container {\n position: relative;\n flex-shrink: 0;\n }\n\n .btn-menu {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .btn-menu:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n .header-dropdown-menu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: var(--conv-list-bg);\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1001;\n overflow: hidden;\n padding: 4px 0;\n }\n\n .header-dropdown-menu .dropdown-item {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n background: transparent;\n border: none;\n color: color-mix(in srgb, var(--conv-list-ink) 85%, transparent);\n font-size: 13px;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s;\n }\n\n .header-dropdown-menu .dropdown-item:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu .dropdown-item i {\n width: 16px;\n font-size: 13px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n }\n\n .header-dropdown-menu .dropdown-item:hover i {\n color: var(--conv-list-ink);\n }\n\n .header-dropdown-menu .dropdown-item .shortcut {\n margin-left: auto;\n font-size: 11px;\n color: color-mix(in srgb, var(--conv-list-ink) 40%, transparent);\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n .btn-select {\n padding: 8px 12px;\n background: transparent;\n border: 1px solid color-mix(in srgb, var(--conv-list-ink) 20%, transparent);\n border-radius: 6px;\n color: color-mix(in srgb, var(--conv-list-ink) 70%, transparent);\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n .btn-select:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 10%, transparent);\n color: var(--conv-list-ink);\n border-color: color-mix(in srgb, var(--conv-list-ink) 30%, transparent);\n }\n\n\n /* Folders */\n .section-action-btn {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 4px;\n color: color-mix(in srgb, var(--conv-list-ink) 60%, transparent);\n cursor: pointer;\n transition: all 0.2s;\n }\n .section-action-btn:hover {\n background: color-mix(in srgb, var(--conv-list-ink) 15%, transparent);\n color: var(--conv-list-ink);\n }\n .section-action-btn i { font-size: 12px; }\n\n .folder-row {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n cursor: pointer;\n color: color-mix(in srgb, var(--conv-list-ink) 80%, transparent);\n font-size: 13px;\n transition: background 0.15s;\n user-select: none;\n position: relative;\n }\n .folder-row:hover { background: color-mix(in srgb, var(--conv-list-ink) 8%, transparent); }\n .folder-row.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 25%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n }\n .folder-row.dragging { opacity: 0.4; }\n .section-header.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n .folder-chevron {\n font-size: 9px;\n width: 10px;\n flex-shrink: 0;\n transition: transform 0.2s;\n color: color-mix(in srgb, var(--conv-list-ink) 55%, transparent);\n }\n .folder-chevron.expanded { transform: rotate(90deg); }\n .folder-icon { font-size: 12px; width: 16px; text-align: center; flex-shrink: 0; }\n .folder-name {\n /* NOT flex: 1. Growing to fill the row would push the shared badge to the right\n edge, beside the count, instead of beside the name it describes. The\n .folder-spacer after the badge takes the slack instead. Shrink + min-width:0\n keeps the ellipsis behaviour on a long name. */\n flex: 0 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-weight: 600;\n }\n .folder-count {\n font-size: 11px;\n font-weight: 600;\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n flex-shrink: 0;\n margin-left: auto;\n padding-left: 6px;\n text-align: right;\n }\n .folder-spacer {\n flex: 1 1 auto;\n min-width: 0;\n }\n .folder-shared {\n flex-shrink: 0;\n margin-left: 6px;\n font-size: 10px;\n line-height: 1;\n /* Same muted treatment as .folder-count, so it reads as metadata and does not\n compete with the folder's own colour. */\n color: color-mix(in srgb, var(--conv-list-ink) 50%, transparent);\n }\n .folder-children { display: block; }\n .folder-empty-hint {\n padding: 6px 16px;\n font-size: 11px;\n font-style: italic;\n color: color-mix(in srgb, var(--conv-list-ink) 45%, transparent);\n }\n .ungrouped-section.drag-over {\n background: color-mix(in srgb, var(--conv-list-accent) 12%, transparent);\n box-shadow: inset 0 0 0 1px var(--conv-list-accent);\n border-radius: 6px;\n }\n\n /* Dragging state. Rows never select text or raise the touch callout, so a\n long-press can select the row instead. */\n .conversation-item { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }\n .conversation-item.dragging { opacity: 0.4; }\n\n /* Move-to-folder submenu */\n .menu-item.back { font-weight: 600; }\n .menu-item .submenu-arrow { margin-left: auto; font-size: 10px; }\n .menu-item.current { background: color-mix(in srgb, var(--conv-list-accent) 18%, transparent); }\n .move-folder-list { max-height: 240px; overflow-y: auto; }\n "] }]
3121
+ }], () => [{ type: i1.DialogService }, { type: i2.NotificationService }, { type: i3.ActiveTasksService }, { type: i4.MJDialogService }, { type: i0.ChangeDetectorRef }], { EnvironmentId: [{
1664
3122
  type: Input
1665
- }], currentUser: [{
3123
+ }], CurrentUser: [{
1666
3124
  type: Input
1667
- }], selectedConversationId: [{
3125
+ }], SelectedConversationId: [{
1668
3126
  type: Input
1669
- }], renamedConversationId: [{
3127
+ }], RenamedConversationId: [{
1670
3128
  type: Input
1671
- }], isSidebarPinned: [{
3129
+ }], IsSidebarPinned: [{
1672
3130
  type: Input
1673
- }], isMobileView: [{
3131
+ }], IsMobileView: [{
1674
3132
  type: Input
1675
3133
  }], showSearch: [{
1676
3134
  type: Input
1677
- }], showNewConversationButton: [{
3135
+ }], ShowNewConversationButton: [{
1678
3136
  type: Input
1679
- }], showHeaderMenu: [{
3137
+ }], ShowHeaderMenu: [{
1680
3138
  type: Input
1681
- }], showSectionHeaders: [{
3139
+ }], ShowSectionHeaders: [{
1682
3140
  type: Input
3141
+ }], ConversationSelected: [{
3142
+ type: Output
1683
3143
  }], conversationSelected: [{
1684
3144
  type: Output
3145
+ }], ConversationDeleted: [{
3146
+ type: Output
1685
3147
  }], conversationDeleted: [{
1686
3148
  type: Output
3149
+ }], NewConversationRequested: [{
3150
+ type: Output
1687
3151
  }], newConversationRequested: [{
1688
3152
  type: Output
3153
+ }], PinSidebarRequested: [{
3154
+ type: Output
1689
3155
  }], pinSidebarRequested: [{
1690
3156
  type: Output
3157
+ }], UnpinSidebarRequested: [{
3158
+ type: Output
1691
3159
  }], unpinSidebarRequested: [{
1692
3160
  type: Output
3161
+ }], RefreshRequested: [{
3162
+ type: Output
1693
3163
  }], refreshRequested: [{
1694
3164
  type: Output
3165
+ }], SearchEscalated: [{
3166
+ type: Output
3167
+ }], searchInput: [{
3168
+ type: ViewChild,
3169
+ args: ['searchInput']
3170
+ }], contextMenuEl: [{
3171
+ type: ViewChild,
3172
+ args: ['contextMenuEl']
1695
3173
  }], onDocumentClick: [{
1696
3174
  type: HostListener,
1697
3175
  args: ['document:click']
3176
+ }], onDocumentEscape: [{
3177
+ type: HostListener,
3178
+ args: ['document:keydown.escape']
3179
+ }], environmentId: [{
3180
+ type: Input
3181
+ }], currentUser: [{
3182
+ type: Input
3183
+ }], selectedConversationId: [{
3184
+ type: Input
3185
+ }], renamedConversationId: [{
3186
+ type: Input
3187
+ }], isSidebarPinned: [{
3188
+ type: Input
3189
+ }], isMobileView: [{
3190
+ type: Input
3191
+ }], showNewConversationButton: [{
3192
+ type: Input
3193
+ }], showHeaderMenu: [{
3194
+ type: Input
3195
+ }], showSectionHeaders: [{
3196
+ type: Input
1698
3197
  }] }); })();
1699
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationListComponent, { className: "ConversationListComponent", filePath: "src/lib/components/conversation/conversation-list.component.ts", lineNumber: 1029 }); })();
3198
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConversationListComponent, { className: "ConversationListComponent", filePath: "src/lib/components/conversation/conversation-list.component.ts", lineNumber: 1260 }); })();
1700
3199
  //# sourceMappingURL=conversation-list.component.js.map