@conduction/nextcloud-vue 2.58.0 → 2.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +14 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  8. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  11. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +39 -0
  13. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +46 -4
  15. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  16. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +224 -9
  17. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +79 -25
  19. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  20. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js +42 -3
  21. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js.map +1 -1
  22. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js +39 -6
  23. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js.map +1 -1
  24. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +58 -5
  25. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  26. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +13 -5
  27. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  28. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js +10 -0
  29. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js.map +1 -0
  30. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +39 -0
  31. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -0
  32. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +16 -0
  33. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js.map +1 -0
  34. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  35. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  36. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  37. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -1
  38. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  39. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +147 -89
  40. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  41. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  42. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  43. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  44. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +10 -0
  45. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js.map +1 -0
  46. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +259 -0
  47. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -0
  48. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +131 -0
  49. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -0
  50. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +10 -0
  51. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js.map +1 -0
  52. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +116 -0
  53. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -0
  54. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +24 -0
  55. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -0
  56. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  57. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  58. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  59. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  60. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  61. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  62. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  63. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  64. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +532 -29
  65. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +300 -142
  67. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js +10 -0
  69. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js.map +1 -0
  70. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js +237 -0
  71. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js.map +1 -0
  72. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js +120 -0
  73. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js.map +1 -0
  74. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js +10 -0
  75. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js.map +1 -0
  76. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +77 -0
  77. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -0
  78. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js +27 -0
  79. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -0
  80. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  81. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  82. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  83. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  84. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  85. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  86. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  87. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  88. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  89. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  90. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  91. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  92. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  93. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  94. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  95. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  96. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  97. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +169 -12
  98. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +15 -7
  100. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  101. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js +37 -3
  102. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js.map +1 -1
  103. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js +44 -16
  104. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js.map +1 -1
  105. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +199 -16
  106. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  107. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +20 -10
  108. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  109. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  110. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  111. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  112. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  113. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  114. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  115. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  116. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  117. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  118. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  119. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  120. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  121. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  122. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  123. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  124. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js +10 -0
  125. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js.map +1 -0
  126. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js +150 -0
  127. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -0
  128. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js +106 -0
  129. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -0
  130. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js +9 -0
  131. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js.map +1 -0
  132. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +47 -0
  133. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -0
  134. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js +17 -0
  135. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js.map +1 -0
  136. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  137. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  138. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  139. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  140. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +49 -0
  141. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  142. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  143. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js +6 -0
  144. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js.map +1 -1
  145. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue3.js.map +1 -1
  146. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js +46 -0
  147. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js.map +1 -1
  148. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js +15 -3
  149. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js.map +1 -1
  150. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  151. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  152. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  153. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  154. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  155. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  156. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  157. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  158. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  159. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  160. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  161. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  162. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  163. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  164. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  165. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  166. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  167. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +37 -1
  168. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  169. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +29 -13
  170. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  171. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +100 -3
  172. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  173. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  174. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  175. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  176. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  177. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +50 -3
  178. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
  179. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
  180. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +10 -0
  181. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js.map +1 -0
  182. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +186 -0
  183. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -0
  184. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +46 -0
  185. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -0
  186. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  187. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  188. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  189. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +11 -0
  190. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js.map +1 -0
  191. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +298 -0
  192. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -0
  193. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +77 -0
  194. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -0
  195. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js +10 -0
  196. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js.map +1 -0
  197. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js +169 -0
  198. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js.map +1 -0
  199. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js +48 -0
  200. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js.map +1 -0
  201. package/dist/esm/components/CnTabs/CnTab.vue2.js +35 -0
  202. package/dist/esm/components/CnTabs/CnTab.vue2.js.map +1 -1
  203. package/dist/esm/components/CnTabs/CnTab.vue3.js.map +1 -1
  204. package/dist/esm/components/CnTabs/CnTabs.vue2.js +120 -7
  205. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  206. package/dist/esm/components/CnTabs/CnTabs.vue3.js +57 -5
  207. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  208. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +59 -4
  209. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  210. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +6 -2
  211. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  212. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  213. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  214. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  215. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  216. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +10 -0
  217. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js.map +1 -0
  218. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +484 -0
  219. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -0
  220. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +115 -0
  221. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -0
  222. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js +10 -0
  223. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js.map +1 -0
  224. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js +189 -0
  225. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js.map +1 -0
  226. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js +74 -0
  227. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js.map +1 -0
  228. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +82 -8
  229. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  230. package/dist/esm/index.js +10 -0
  231. package/dist/esm/index.js.map +1 -1
  232. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  233. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  234. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  235. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  236. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  237. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  238. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  239. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  240. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  241. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  242. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  243. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  244. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  245. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  246. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  247. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  248. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  249. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  250. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  251. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  252. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  253. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  254. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  255. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  256. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  257. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  258. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  259. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  260. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  261. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  262. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  263. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  264. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  265. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  266. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  267. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  268. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  269. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  270. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  271. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  272. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  273. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  274. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  275. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  276. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  277. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  278. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  279. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  280. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  281. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  282. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  283. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  284. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  285. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  286. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  287. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  288. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  289. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  290. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  291. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  292. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  293. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  294. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  295. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  296. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  297. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  298. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  299. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  300. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  301. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  302. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  303. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  304. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  305. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  306. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  307. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  308. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  309. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  310. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  311. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  312. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  313. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  314. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  315. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  316. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  317. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  318. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  319. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  320. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  321. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  322. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  323. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  324. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  325. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  326. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  327. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  328. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  329. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  330. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  331. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  332. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  333. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  334. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  335. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  336. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  337. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  338. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  339. package/dist/esm/l10n/en.json.js +55 -1
  340. package/dist/esm/l10n/en.json.js.map +1 -1
  341. package/dist/esm/l10n/nl.json.js +55 -1
  342. package/dist/esm/l10n/nl.json.js.map +1 -1
  343. package/dist/esm/nextcloud-vue.css +998 -7
  344. package/dist/esm/utils/actionLink.js +5 -0
  345. package/dist/esm/utils/actionLink.js.map +1 -1
  346. package/dist/esm/utils/actionsDispatcher.js +16 -1
  347. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  348. package/dist/esm/utils/dateVariant.js +124 -0
  349. package/dist/esm/utils/dateVariant.js.map +1 -0
  350. package/dist/esm/utils/detailActionModel.js +260 -0
  351. package/dist/esm/utils/detailActionModel.js.map +1 -0
  352. package/dist/esm/utils/dueRule.js +84 -0
  353. package/dist/esm/utils/dueRule.js.map +1 -0
  354. package/dist/esm/utils/fetchAggregate.js +37 -1
  355. package/dist/esm/utils/fetchAggregate.js.map +1 -1
  356. package/dist/esm/utils/fetchFilterCounts.js +186 -0
  357. package/dist/esm/utils/fetchFilterCounts.js.map +1 -0
  358. package/dist/esm/utils/libraryWidgetKeys.js +5 -0
  359. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  360. package/dist/esm/utils/linkNavigation.js +6 -3
  361. package/dist/esm/utils/linkNavigation.js.map +1 -1
  362. package/dist/esm/utils/readPath.js +30 -0
  363. package/dist/esm/utils/readPath.js.map +1 -0
  364. package/dist/esm/utils/rowAuxClick.js +30 -5
  365. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  366. package/dist/esm/utils/safeHref.js +18 -3
  367. package/dist/esm/utils/safeHref.js.map +1 -1
  368. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  369. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  370. package/dist/nextcloud-vue.cjs.js +15855 -9353
  371. package/dist/nextcloud-vue.cjs.js.map +2 -2
  372. package/dist/nextcloud-vue.css +998 -7
  373. package/l10n/en.json +55 -1
  374. package/l10n/nl.json +55 -1
  375. package/package.json +1 -1
  376. package/scripts/.jsdoc-baselines.json +3 -0
  377. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  378. package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -4
  379. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  380. package/src/components/CnAppNav/CnAppNav.md +26 -0
  381. package/src/components/CnAppNav/CnAppNav.vue +104 -1
  382. package/src/components/CnBannerWidget/CnBannerWidget.vue +365 -10
  383. package/src/components/CnBannerWidgetForm/CnBannerWidgetForm.vue +65 -3
  384. package/src/components/CnBoardView/CnBoardView.vue +90 -5
  385. package/src/components/CnBrandStripe/CnBrandStripe.md +22 -0
  386. package/src/components/CnBrandStripe/CnBrandStripe.vue +100 -0
  387. package/src/components/CnBrandStripe/index.js +4 -0
  388. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  389. package/src/components/CnCellRenderer/CnCellRenderer.vue +207 -1
  390. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  391. package/src/components/CnConversationThread/CnConversationThread.md +51 -0
  392. package/src/components/CnConversationThread/CnConversationThread.vue +457 -0
  393. package/src/components/CnConversationThread/CnConversationWidget.vue +144 -0
  394. package/src/components/CnConversationThread/index.js +4 -0
  395. package/src/components/CnDataTable/CnDataTable.md +1 -1
  396. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  397. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  398. package/src/components/CnDetailPage/CnDetailPage.md +17 -1
  399. package/src/components/CnDetailPage/CnDetailPage.vue +712 -49
  400. package/src/components/CnDocumentReviewList/CnDocumentReviewList.md +55 -0
  401. package/src/components/CnDocumentReviewList/CnDocumentReviewList.vue +384 -0
  402. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +108 -0
  403. package/src/components/CnDocumentReviewList/index.js +4 -0
  404. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  405. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  406. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  407. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  408. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  409. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +189 -14
  410. package/src/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue +53 -3
  411. package/src/components/CnIndexPage/CnIndexPage.vue +210 -17
  412. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  413. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  414. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  415. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  416. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  417. package/src/components/CnNextStepCard/CnNextStepCard.md +40 -0
  418. package/src/components/CnNextStepCard/CnNextStepCard.vue +319 -0
  419. package/src/components/CnNextStepCard/CnNextStepWidget.vue +59 -0
  420. package/src/components/CnNextStepCard/index.js +4 -0
  421. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  422. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +49 -0
  423. package/src/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue +6 -0
  424. package/src/components/CnObjectKanban/CnObjectKanban.vue +86 -2
  425. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  426. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  427. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  428. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  429. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  430. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +3 -0
  431. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +60 -1
  432. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +100 -3
  433. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  434. package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +50 -3
  435. package/src/components/CnSegmentedControl/CnSegmentedControl.md +46 -0
  436. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +291 -0
  437. package/src/components/CnSegmentedControl/index.js +4 -0
  438. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  439. package/src/components/CnStackedBarWidget/CnStackedBarWidget.md +15 -0
  440. package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +414 -0
  441. package/src/components/CnStackedBarWidget/index.js +14 -0
  442. package/src/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue +224 -0
  443. package/src/components/CnStackedBarWidgetForm/index.js +4 -0
  444. package/src/components/CnTabs/CnTab.vue +35 -0
  445. package/src/components/CnTabs/CnTabs.vue +251 -13
  446. package/src/components/CnTabsWidget/CnTabsWidget.vue +63 -4
  447. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  448. package/src/components/CnWeekStripWidget/CnWeekStripWidget.md +31 -0
  449. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +668 -0
  450. package/src/components/CnWeekStripWidget/index.js +14 -0
  451. package/src/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue +265 -0
  452. package/src/components/CnWeekStripWidgetForm/index.js +4 -0
  453. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +74 -0
  454. package/src/components/index.js +11 -0
  455. package/src/css/detail-page.css +47 -0
  456. package/src/css/table.css +26 -0
  457. package/src/index.js +9 -0
  458. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  459. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  460. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  461. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  462. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  463. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  464. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  465. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  466. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  467. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  468. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  469. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  470. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  471. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  472. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  473. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  474. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  475. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  476. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  477. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  478. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  479. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  480. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  481. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  482. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  483. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  484. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  485. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  486. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  487. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  488. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  489. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  490. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  491. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  492. package/src/schemas/app-manifest-v2.schema.json +389 -1
  493. package/src/schemas/app-manifest.schema.json +2 -1
  494. package/src/utils/actionLink.js +5 -0
  495. package/src/utils/actionsDispatcher.js +15 -0
  496. package/src/utils/dateVariant.js +120 -0
  497. package/src/utils/detailActionModel.js +256 -0
  498. package/src/utils/dueRule.js +94 -0
  499. package/src/utils/fetchAggregate.js +36 -0
  500. package/src/utils/fetchFilterCounts.js +182 -0
  501. package/src/utils/index.js +1 -0
  502. package/src/utils/libraryWidgetKeys.js +5 -0
  503. package/src/utils/linkNavigation.js +6 -3
  504. package/src/utils/readPath.js +27 -0
  505. package/src/utils/rowAuxClick.js +29 -4
  506. package/src/utils/safeHref.js +18 -3
  507. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -0,0 +1,259 @@
1
+ import axios__default from '@nextcloud/axios';
2
+ import { translate } from '@nextcloud/l10n';
3
+ import { NcButton } from '@nextcloud/vue';
4
+ import { prefixUrl } from '../../utils/headers.js';
5
+
6
+ let conversationThreadUid = 0;
7
+
8
+ /**
9
+ * CnConversationThread: the messages between you and the other party, and a box to answer.
10
+ *
11
+ * Each message has an author, a time and a side: `us` for the organisation,
12
+ * `them` for the resident or customer. The reply box emits `send`, and also
13
+ * posts to `endpoint` when one is set. It needs no Talk and no other app:
14
+ * where the messages are stored is the host's business.
15
+ *
16
+ * ```vue
17
+ * <CnConversationThread
18
+ * title="Contact with the resident"
19
+ * reply-label="Answer to the resident"
20
+ * :messages="[
21
+ * { id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',
22
+ * text: 'Thank you. I would like to see all documents.' },
23
+ * { id: 2, time: '2026-10-04T10:24:00', side: 'us',
24
+ * text: 'Construction starts in March.' },
25
+ * ]"
26
+ * @send="saveReply" />
27
+ * ```
28
+ *
29
+ * The `conversation` detail widget type renders this thread from a field on
30
+ * the record.
31
+ */
32
+ var script = {
33
+ name: 'CnConversationThread',
34
+
35
+ components: {
36
+ NcButton,
37
+ },
38
+
39
+ props: {
40
+ /**
41
+ * The messages, oldest first: `{ id?, author?, time?, text, side? }`.
42
+ * `side` is `us` or `them` (default `them`). `time` is an ISO
43
+ * date, or any text to show as is.
44
+ */
45
+ messages: {
46
+ type: Array,
47
+ default: () => [],
48
+ },
49
+
50
+ /** Heading of the thread. */
51
+ title: {
52
+ type: String,
53
+ default: '',
54
+ },
55
+
56
+ /** Element the heading renders as. */
57
+ titleTag: {
58
+ type: String,
59
+ default: 'h3',
60
+ },
61
+
62
+ /** Whether the reply box renders. Turn it off for a closed or read-only record. */
63
+ allowReply: {
64
+ type: Boolean,
65
+ default: true,
66
+ },
67
+
68
+ /** Label of the reply box. */
69
+ replyLabel: {
70
+ type: String,
71
+ default: () => translate('nextcloud-vue', 'Reply'),
72
+ },
73
+
74
+ /** Placeholder inside the reply box. */
75
+ placeholder: {
76
+ type: String,
77
+ default: '',
78
+ },
79
+
80
+ /** Label of the send button. */
81
+ sendLabel: {
82
+ type: String,
83
+ default: () => translate('nextcloud-vue', 'Send'),
84
+ },
85
+
86
+ /** Author shown on an `us` message that names none. */
87
+ usLabel: {
88
+ type: String,
89
+ default: () => translate('nextcloud-vue', 'You'),
90
+ },
91
+
92
+ /**
93
+ * URL the reply is POSTed to as `{ message }`. Empty means the host
94
+ * handles `send` itself and nothing is requested.
95
+ */
96
+ endpoint: {
97
+ type: String,
98
+ default: '',
99
+ },
100
+
101
+ /** Extra fields sent along with `message` when `endpoint` is set. */
102
+ payload: {
103
+ type: Object,
104
+ default: () => ({}),
105
+ },
106
+
107
+ /** Shown when there are no messages yet. */
108
+ emptyText: {
109
+ type: String,
110
+ default: () => translate('nextcloud-vue', 'No messages yet.'),
111
+ },
112
+ },
113
+
114
+ emits: [
115
+ /** A reply was submitted. Payload: the text. */
116
+ 'send',
117
+ /** The endpoint accepted the reply. Payload: the response body. */
118
+ 'sent',
119
+ /** The endpoint refused the reply. Payload: the error. */
120
+ 'error',
121
+ ],
122
+
123
+ data() {
124
+ conversationThreadUid += 1;
125
+ return {
126
+ draft: '',
127
+ sending: false,
128
+ errorMessage: '',
129
+ titleId: `cn-conversation-title-${conversationThreadUid}`,
130
+ inputId: `cn-conversation-input-${conversationThreadUid}`,
131
+ errorId: `cn-conversation-error-${conversationThreadUid}`,
132
+ }
133
+ },
134
+
135
+ computed: {
136
+ /**
137
+ * The messages, with author, side, time and initials resolved.
138
+ *
139
+ * @return {Array<{key: string, author: string, initials: string, side: string, text: string, timeLabel: string, datetime: string}>} The rows.
140
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
141
+ */
142
+ rows() {
143
+ return (Array.isArray(this.messages) ? this.messages : [])
144
+ .filter((message) => message && typeof message === 'object')
145
+ .map((message, index) => {
146
+ const side = message.side === 'us' ? 'us' : 'them';
147
+ const author = typeof message.author === 'string' && message.author !== ''
148
+ ? message.author
149
+ : (side === 'us' ? this.usLabel : '');
150
+ const time = this.formatTime(message.time);
151
+ return {
152
+ key: message.id === undefined || message.id === null ? `message-${index}` : String(message.id),
153
+ author,
154
+ initials: this.initialsOf(author),
155
+ side,
156
+ text: message.text === undefined || message.text === null ? '' : String(message.text),
157
+ timeLabel: time.label,
158
+ datetime: time.datetime,
159
+ }
160
+ })
161
+ },
162
+
163
+ /**
164
+ * Whether there is something to send and nothing in flight.
165
+ *
166
+ * @return {boolean} True when Send is enabled.
167
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
168
+ */
169
+ canSend() {
170
+ return !this.sending && this.draft.trim() !== ''
171
+ },
172
+
173
+ /**
174
+ * Accessible name for a thread without a title.
175
+ *
176
+ * @return {string} The label.
177
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
178
+ */
179
+ fallbackLabel() {
180
+ return translate('nextcloud-vue', 'Conversation')
181
+ },
182
+ },
183
+
184
+ methods: {
185
+ /**
186
+ * Up to two initials of a name, for the avatar.
187
+ *
188
+ * @param {string} name The author.
189
+ * @return {string} The initials, upper case.
190
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
191
+ */
192
+ initialsOf(name) {
193
+ const parts = String(name || '').trim().split(/\s+/).filter(Boolean);
194
+ if (parts.length === 0) {
195
+ return ''
196
+ }
197
+ const first = parts[0].charAt(0);
198
+ const last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : '';
199
+ return (first + last).toUpperCase()
200
+ },
201
+
202
+ /**
203
+ * Turn a message time into what the reader sees and what `<time>` carries.
204
+ *
205
+ * @param {unknown} value An ISO date, a Date, or text to show as is.
206
+ * @return {{label: string, datetime: string}} The visible label and the machine value.
207
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
208
+ */
209
+ formatTime(value) {
210
+ if (value === null || value === undefined || value === '') {
211
+ return { label: '', datetime: '' }
212
+ }
213
+ const date = value instanceof Date ? value : new Date(value);
214
+ const looksLikeDate = value instanceof Date || typeof value === 'number' || /^\d{4}-\d{2}-\d{2}/.test(String(value));
215
+ if (!looksLikeDate || Number.isNaN(date.getTime())) {
216
+ return { label: String(value), datetime: '' }
217
+ }
218
+ const label = date.toLocaleString(undefined, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });
219
+ return { label, datetime: date.toISOString() }
220
+ },
221
+
222
+ /**
223
+ * Submit the reply: tell the host, and post it when an endpoint is set.
224
+ *
225
+ * Without an endpoint the box clears straight away, because the host
226
+ * owns the send. With one it clears only when the request succeeds, so
227
+ * a refused reply is still there to try again.
228
+ *
229
+ * @return {Promise<void>}
230
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
231
+ */
232
+ async onSend() {
233
+ if (!this.canSend) {
234
+ return
235
+ }
236
+ const text = this.draft.trim();
237
+ this.errorMessage = '';
238
+ this.$emit('send', text);
239
+ if (!this.endpoint) {
240
+ this.draft = '';
241
+ return
242
+ }
243
+ this.sending = true;
244
+ try {
245
+ const response = await axios__default.post(prefixUrl(this.endpoint), { ...this.payload, message: text });
246
+ this.draft = '';
247
+ this.$emit('sent', response?.data);
248
+ } catch (error) {
249
+ this.errorMessage = translate('nextcloud-vue', 'The message could not be sent. Try again.');
250
+ this.$emit('error', error);
251
+ } finally {
252
+ this.sending = false;
253
+ }
254
+ },
255
+ },
256
+ };
257
+
258
+ export { script as default };
259
+ //# sourceMappingURL=CnConversationThread.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnConversationThread.vue2.js","sources":["../../../../src/components/CnConversationThread/CnConversationThread.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<section\n\t\tclass=\"cn-conversation-thread\"\n\t\tdata-testid=\"cn-conversation-thread\"\n\t\t:aria-labelledby=\"title ? titleId : null\"\n\t\t:aria-label=\"title ? null : fallbackLabel\">\n\t\t<component\n\t\t\t:is=\"titleTag\"\n\t\t\tv-if=\"title\"\n\t\t\t:id=\"titleId\"\n\t\t\tclass=\"cn-conversation-thread__title\">\n\t\t\t{{ title }}\n\t\t</component>\n\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<ol v-else class=\"cn-conversation-thread__messages\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-conversation-thread__message\"\n\t\t\t\t:class=\"`cn-conversation-thread__message--${row.side}`\"\n\t\t\t\tdata-testid=\"cn-conversation-message\"\n\t\t\t\t:data-side=\"row.side\">\n\t\t\t\t<span class=\"cn-conversation-thread__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t<div class=\"cn-conversation-thread__bubble\">\n\t\t\t\t\t<span class=\"cn-conversation-thread__meta\">\n\t\t\t\t\t\t<span class=\"cn-conversation-thread__author\">{{ row.author }}</span>\n\t\t\t\t\t\t<time v-if=\"row.timeLabel\" :datetime=\"row.datetime || null\">{{ row.timeLabel }}</time>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-conversation-thread__text\">{{ row.text }}</span>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ol>\n\n\t\t<form\n\t\t\tv-if=\"allowReply\"\n\t\t\tclass=\"cn-conversation-thread__reply\"\n\t\t\tdata-testid=\"cn-conversation-reply\"\n\t\t\t@submit.prevent=\"onSend\">\n\t\t\t<label :for=\"inputId\" class=\"cn-conversation-thread__reply-label\">{{ replyLabel }}</label>\n\t\t\t<textarea\n\t\t\t\t:id=\"inputId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-conversation-thread__input\"\n\t\t\t\trows=\"2\"\n\t\t\t\t:placeholder=\"placeholder || null\"\n\t\t\t\t:disabled=\"sending\"\n\t\t\t\t:aria-describedby=\"errorMessage ? errorId : null\"\n\t\t\t\tdata-testid=\"cn-conversation-input\"\n\t\t\t\t@keydown.ctrl.enter.prevent=\"onSend\"\n\t\t\t\t@keydown.meta.enter.prevent=\"onSend\" />\n\t\t\t<p\n\t\t\t\tv-if=\"errorMessage\"\n\t\t\t\t:id=\"errorId\"\n\t\t\t\tclass=\"cn-conversation-thread__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-conversation-error\">\n\t\t\t\t{{ errorMessage }}\n\t\t\t</p>\n\t\t\t<div class=\"cn-conversation-thread__reply-actions\">\n\t\t\t\t<!-- @slot reply-actions Extra buttons before Send, for example \"Save draft\". -->\n\t\t\t\t<!-- @binding {string} draft The text in the reply box. -->\n\t\t\t\t<slot name=\"reply-actions\" :draft=\"draft\" />\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"!canSend\"\n\t\t\t\t\tdata-testid=\"cn-conversation-send\">\n\t\t\t\t\t{{ sendLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\t</section>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet conversationThreadUid = 0\n\n/**\n * CnConversationThread: the messages between you and the other party, and a box to answer.\n *\n * Each message has an author, a time and a side: `us` for the organisation,\n * `them` for the resident or customer. The reply box emits `send`, and also\n * posts to `endpoint` when one is set. It needs no Talk and no other app:\n * where the messages are stored is the host's business.\n *\n * ```vue\n * <CnConversationThread\n * title=\"Contact with the resident\"\n * reply-label=\"Answer to the resident\"\n * :messages=\"[\n * { id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',\n * text: 'Thank you. I would like to see all documents.' },\n * { id: 2, time: '2026-10-04T10:24:00', side: 'us',\n * text: 'Construction starts in March.' },\n * ]\"\n * @send=\"saveReply\" />\n * ```\n *\n * The `conversation` detail widget type renders this thread from a field on\n * the record.\n */\nexport default {\n\tname: 'CnConversationThread',\n\n\tcomponents: {\n\t\tNcButton,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The messages, oldest first: `{ id?, author?, time?, text, side? }`.\n\t\t * `side` is `us` or `them` (default `them`). `time` is an ISO\n\t\t * date, or any text to show as is.\n\t\t */\n\t\tmessages: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Heading of the thread. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Element the heading renders as. */\n\t\ttitleTag: {\n\t\t\ttype: String,\n\t\t\tdefault: 'h3',\n\t\t},\n\n\t\t/** Whether the reply box renders. Turn it off for a closed or read-only record. */\n\t\tallowReply: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label of the reply box. */\n\t\treplyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Reply'),\n\t\t},\n\n\t\t/** Placeholder inside the reply box. */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Label of the send button. */\n\t\tsendLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Send'),\n\t\t},\n\n\t\t/** Author shown on an `us` message that names none. */\n\t\tusLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'You'),\n\t\t},\n\n\t\t/**\n\t\t * URL the reply is POSTed to as `{ message }`. Empty means the host\n\t\t * handles `send` itself and nothing is requested.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Extra fields sent along with `message` when `endpoint` is set. */\n\t\tpayload: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Shown when there are no messages yet. */\n\t\temptyText: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No messages yet.'),\n\t\t},\n\t},\n\n\temits: [\n\t\t/** A reply was submitted. Payload: the text. */\n\t\t'send',\n\t\t/** The endpoint accepted the reply. Payload: the response body. */\n\t\t'sent',\n\t\t/** The endpoint refused the reply. Payload: the error. */\n\t\t'error',\n\t],\n\n\tdata() {\n\t\tconversationThreadUid += 1\n\t\treturn {\n\t\t\tdraft: '',\n\t\t\tsending: false,\n\t\t\terrorMessage: '',\n\t\t\ttitleId: `cn-conversation-title-${conversationThreadUid}`,\n\t\t\tinputId: `cn-conversation-input-${conversationThreadUid}`,\n\t\t\terrorId: `cn-conversation-error-${conversationThreadUid}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The messages, with author, side, time and initials resolved.\n\t\t *\n\t\t * @return {Array<{key: string, author: string, initials: string, side: string, text: string, timeLabel: string, datetime: string}>} The rows.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\trows() {\n\t\t\treturn (Array.isArray(this.messages) ? this.messages : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => {\n\t\t\t\t\tconst side = message.side === 'us' ? 'us' : 'them'\n\t\t\t\t\tconst author = typeof message.author === 'string' && message.author !== ''\n\t\t\t\t\t\t? message.author\n\t\t\t\t\t\t: (side === 'us' ? this.usLabel : '')\n\t\t\t\t\tconst time = this.formatTime(message.time)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: message.id === undefined || message.id === null ? `message-${index}` : String(message.id),\n\t\t\t\t\t\tauthor,\n\t\t\t\t\t\tinitials: this.initialsOf(author),\n\t\t\t\t\t\tside,\n\t\t\t\t\t\ttext: message.text === undefined || message.text === null ? '' : String(message.text),\n\t\t\t\t\t\ttimeLabel: time.label,\n\t\t\t\t\t\tdatetime: time.datetime,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether there is something to send and nothing in flight.\n\t\t *\n\t\t * @return {boolean} True when Send is enabled.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tcanSend() {\n\t\t\treturn !this.sending && this.draft.trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Accessible name for a thread without a title.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tfallbackLabel() {\n\t\t\treturn t('nextcloud-vue', 'Conversation')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Up to two initials of a name, for the avatar.\n\t\t *\n\t\t * @param {string} name The author.\n\t\t * @return {string} The initials, upper case.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tinitialsOf(name) {\n\t\t\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\t\t\tif (parts.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst first = parts[0].charAt(0)\n\t\t\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\t\t\treturn (first + last).toUpperCase()\n\t\t},\n\n\t\t/**\n\t\t * Turn a message time into what the reader sees and what `<time>` carries.\n\t\t *\n\t\t * @param {unknown} value An ISO date, a Date, or text to show as is.\n\t\t * @return {{label: string, datetime: string}} The visible label and the machine value.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tformatTime(value) {\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn { label: '', datetime: '' }\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\tconst looksLikeDate = value instanceof Date || typeof value === 'number' || /^\\d{4}-\\d{2}-\\d{2}/.test(String(value))\n\t\t\tif (!looksLikeDate || Number.isNaN(date.getTime())) {\n\t\t\t\treturn { label: String(value), datetime: '' }\n\t\t\t}\n\t\t\tconst label = date.toLocaleString(undefined, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })\n\t\t\treturn { label, datetime: date.toISOString() }\n\t\t},\n\n\t\t/**\n\t\t * Submit the reply: tell the host, and post it when an endpoint is set.\n\t\t *\n\t\t * Without an endpoint the box clears straight away, because the host\n\t\t * owns the send. With one it clears only when the request succeeds, so\n\t\t * a refused reply is still there to try again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tasync onSend() {\n\t\t\tif (!this.canSend) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = this.draft.trim()\n\t\t\tthis.errorMessage = ''\n\t\t\tthis.$emit('send', text)\n\t\t\tif (!this.endpoint) {\n\t\t\t\tthis.draft = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.sending = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.endpoint), { ...this.payload, message: text })\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.$emit('sent', response?.data)\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'The message could not be sent. Try again.')\n\t\t\t\tthis.$emit('error', error)\n\t\t\t} finally {\n\t\t\t\tthis.sending = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-thread {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__title {\n\tfont-size: 1.1em;\n\tfont-weight: 700;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-conversation-thread__messages {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-conversation-thread__message {\n\tdisplay: flex;\n\tgap: calc(3 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us {\n\tflex-direction: row-reverse;\n}\n\n.cn-conversation-thread__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-dark);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 0.8em;\n\tfont-weight: 700;\n\theight: 34px;\n\tjustify-content: center;\n\twidth: 34px;\n}\n\n.cn-conversation-thread__bubble {\n\tbackground: var(--color-background-hover);\n\tborder-radius: var(--border-radius-large);\n\tborder-start-start-radius: var(--border-radius-small, 4px);\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\tmin-width: 0;\n\tpadding: calc(3 * var(--default-grid-baseline)) calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us .cn-conversation-thread__bubble {\n\tbackground: var(--color-primary-element-light);\n\tborder-start-end-radius: var(--border-radius-small, 4px);\n\tborder-start-start-radius: var(--border-radius-large);\n\tcolor: var(--color-primary-element-light-text);\n}\n\n.cn-conversation-thread__meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tfont-size: 0.9em;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__author {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__text {\n\toverflow-wrap: anywhere;\n\twhite-space: pre-wrap;\n}\n\n.cn-conversation-thread__reply {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__reply-label {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__input {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tresize: vertical;\n\twidth: 100%;\n}\n\n.cn-conversation-thread__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: 0;\n}\n\n.cn-conversation-thread__reply-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ import { resolveComponent, openBlock, createElementBlock, createBlock, resolveDynamicComponent, withCtx, createTextVNode, toDisplayString, createCommentVNode, Fragment, renderList, normalizeClass, createElementVNode, withModifiers, withDirectives, withKeys, vModelText, renderSlot, createVNode } from 'vue';
2
+
3
+ const _hoisted_1 = ["aria-labelledby", "aria-label"];
4
+ const _hoisted_2 = {
5
+ key: 1,
6
+ class: "cn-conversation-thread__empty",
7
+ "data-testid": "cn-conversation-empty"
8
+ };
9
+ const _hoisted_3 = {
10
+ key: 2,
11
+ class: "cn-conversation-thread__messages"
12
+ };
13
+ const _hoisted_4 = ["data-side"];
14
+ const _hoisted_5 = {
15
+ class: "cn-conversation-thread__avatar",
16
+ "aria-hidden": "true"
17
+ };
18
+ const _hoisted_6 = { class: "cn-conversation-thread__bubble" };
19
+ const _hoisted_7 = { class: "cn-conversation-thread__meta" };
20
+ const _hoisted_8 = { class: "cn-conversation-thread__author" };
21
+ const _hoisted_9 = ["datetime"];
22
+ const _hoisted_10 = { class: "cn-conversation-thread__text" };
23
+ const _hoisted_11 = ["for"];
24
+ const _hoisted_12 = ["id", "placeholder", "disabled", "aria-describedby"];
25
+ const _hoisted_13 = ["id"];
26
+ const _hoisted_14 = { class: "cn-conversation-thread__reply-actions" };
27
+
28
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
29
+ const _component_NcButton = resolveComponent("NcButton");
30
+
31
+ return (openBlock(), createElementBlock("section", {
32
+ class: "cn-conversation-thread",
33
+ "data-testid": "cn-conversation-thread",
34
+ "aria-labelledby": $props.title ? $data.titleId : null,
35
+ "aria-label": $props.title ? null : $options.fallbackLabel
36
+ }, [
37
+ ($props.title)
38
+ ? (openBlock(), createBlock(resolveDynamicComponent($props.titleTag), {
39
+ key: 0,
40
+ id: $data.titleId,
41
+ class: "cn-conversation-thread__title"
42
+ }, {
43
+ default: withCtx(() => [
44
+ createTextVNode(toDisplayString($props.title), 1 /* TEXT */)
45
+ ]),
46
+ _: 1 /* STABLE */
47
+ }, 8 /* PROPS */, ["id"]))
48
+ : createCommentVNode("v-if", true),
49
+ ($options.rows.length === 0)
50
+ ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($props.emptyText), 1 /* TEXT */))
51
+ : (openBlock(), createElementBlock("ol", _hoisted_3, [
52
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
53
+ return (openBlock(), createElementBlock("li", {
54
+ key: row.key,
55
+ class: normalizeClass(["cn-conversation-thread__message", `cn-conversation-thread__message--${row.side}`]),
56
+ "data-testid": "cn-conversation-message",
57
+ "data-side": row.side
58
+ }, [
59
+ createElementVNode("span", _hoisted_5, toDisplayString(row.initials), 1 /* TEXT */),
60
+ createElementVNode("div", _hoisted_6, [
61
+ createElementVNode("span", _hoisted_7, [
62
+ createElementVNode("span", _hoisted_8, toDisplayString(row.author), 1 /* TEXT */),
63
+ (row.timeLabel)
64
+ ? (openBlock(), createElementBlock("time", {
65
+ key: 0,
66
+ datetime: row.datetime || null
67
+ }, toDisplayString(row.timeLabel), 9 /* TEXT, PROPS */, _hoisted_9))
68
+ : createCommentVNode("v-if", true)
69
+ ]),
70
+ createElementVNode("span", _hoisted_10, toDisplayString(row.text), 1 /* TEXT */)
71
+ ])
72
+ ], 10 /* CLASS, PROPS */, _hoisted_4))
73
+ }), 128 /* KEYED_FRAGMENT */))
74
+ ])),
75
+ ($props.allowReply)
76
+ ? (openBlock(), createElementBlock("form", {
77
+ key: 3,
78
+ class: "cn-conversation-thread__reply",
79
+ "data-testid": "cn-conversation-reply",
80
+ onSubmit: _cache[3] || (_cache[3] = withModifiers((...args) => ($options.onSend && $options.onSend(...args)), ["prevent"]))
81
+ }, [
82
+ createElementVNode("label", {
83
+ for: $data.inputId,
84
+ class: "cn-conversation-thread__reply-label"
85
+ }, toDisplayString($props.replyLabel), 9 /* TEXT, PROPS */, _hoisted_11),
86
+ withDirectives(createElementVNode("textarea", {
87
+ id: $data.inputId,
88
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($data.draft) = $event)),
89
+ class: "cn-conversation-thread__input",
90
+ rows: "2",
91
+ placeholder: $props.placeholder || null,
92
+ disabled: $data.sending,
93
+ "aria-describedby": $data.errorMessage ? $data.errorId : null,
94
+ "data-testid": "cn-conversation-input",
95
+ onKeydown: [
96
+ _cache[1] || (_cache[1] = withKeys(withModifiers((...args) => ($options.onSend && $options.onSend(...args)), ["ctrl","prevent"]), ["enter"])),
97
+ _cache[2] || (_cache[2] = withKeys(withModifiers((...args) => ($options.onSend && $options.onSend(...args)), ["meta","prevent"]), ["enter"]))
98
+ ]
99
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_12), [
100
+ [vModelText, $data.draft]
101
+ ]),
102
+ ($data.errorMessage)
103
+ ? (openBlock(), createElementBlock("p", {
104
+ key: 0,
105
+ id: $data.errorId,
106
+ class: "cn-conversation-thread__error",
107
+ role: "alert",
108
+ "data-testid": "cn-conversation-error"
109
+ }, toDisplayString($data.errorMessage), 9 /* TEXT, PROPS */, _hoisted_13))
110
+ : createCommentVNode("v-if", true),
111
+ createElementVNode("div", _hoisted_14, [
112
+ renderSlot(_ctx.$slots, "reply-actions", { draft: $data.draft }),
113
+ createVNode(_component_NcButton, {
114
+ variant: "primary",
115
+ type: "submit",
116
+ disabled: !$options.canSend,
117
+ "data-testid": "cn-conversation-send"
118
+ }, {
119
+ default: withCtx(() => [
120
+ createTextVNode(toDisplayString($props.sendLabel), 1 /* TEXT */)
121
+ ]),
122
+ _: 1 /* STABLE */
123
+ }, 8 /* PROPS */, ["disabled"])
124
+ ])
125
+ ], 32 /* NEED_HYDRATION */))
126
+ : createCommentVNode("v-if", true)
127
+ ], 8 /* PROPS */, _hoisted_1))
128
+ }
129
+
130
+ export { render };
131
+ //# sourceMappingURL=CnConversationThread.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnConversationThread.vue3.js","sources":["../../../../src/components/CnConversationThread/CnConversationThread.vue?vue&type=template&id=22b6724f&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<section\n\t\tclass=\"cn-conversation-thread\"\n\t\tdata-testid=\"cn-conversation-thread\"\n\t\t:aria-labelledby=\"title ? titleId : null\"\n\t\t:aria-label=\"title ? null : fallbackLabel\">\n\t\t<component\n\t\t\t:is=\"titleTag\"\n\t\t\tv-if=\"title\"\n\t\t\t:id=\"titleId\"\n\t\t\tclass=\"cn-conversation-thread__title\">\n\t\t\t{{ title }}\n\t\t</component>\n\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<ol v-else class=\"cn-conversation-thread__messages\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-conversation-thread__message\"\n\t\t\t\t:class=\"`cn-conversation-thread__message--${row.side}`\"\n\t\t\t\tdata-testid=\"cn-conversation-message\"\n\t\t\t\t:data-side=\"row.side\">\n\t\t\t\t<span class=\"cn-conversation-thread__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t<div class=\"cn-conversation-thread__bubble\">\n\t\t\t\t\t<span class=\"cn-conversation-thread__meta\">\n\t\t\t\t\t\t<span class=\"cn-conversation-thread__author\">{{ row.author }}</span>\n\t\t\t\t\t\t<time v-if=\"row.timeLabel\" :datetime=\"row.datetime || null\">{{ row.timeLabel }}</time>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-conversation-thread__text\">{{ row.text }}</span>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ol>\n\n\t\t<form\n\t\t\tv-if=\"allowReply\"\n\t\t\tclass=\"cn-conversation-thread__reply\"\n\t\t\tdata-testid=\"cn-conversation-reply\"\n\t\t\t@submit.prevent=\"onSend\">\n\t\t\t<label :for=\"inputId\" class=\"cn-conversation-thread__reply-label\">{{ replyLabel }}</label>\n\t\t\t<textarea\n\t\t\t\t:id=\"inputId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-conversation-thread__input\"\n\t\t\t\trows=\"2\"\n\t\t\t\t:placeholder=\"placeholder || null\"\n\t\t\t\t:disabled=\"sending\"\n\t\t\t\t:aria-describedby=\"errorMessage ? errorId : null\"\n\t\t\t\tdata-testid=\"cn-conversation-input\"\n\t\t\t\t@keydown.ctrl.enter.prevent=\"onSend\"\n\t\t\t\t@keydown.meta.enter.prevent=\"onSend\" />\n\t\t\t<p\n\t\t\t\tv-if=\"errorMessage\"\n\t\t\t\t:id=\"errorId\"\n\t\t\t\tclass=\"cn-conversation-thread__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-conversation-error\">\n\t\t\t\t{{ errorMessage }}\n\t\t\t</p>\n\t\t\t<div class=\"cn-conversation-thread__reply-actions\">\n\t\t\t\t<!-- @slot reply-actions Extra buttons before Send, for example \"Save draft\". -->\n\t\t\t\t<!-- @binding {string} draft The text in the reply box. -->\n\t\t\t\t<slot name=\"reply-actions\" :draft=\"draft\" />\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"!canSend\"\n\t\t\t\t\tdata-testid=\"cn-conversation-send\">\n\t\t\t\t\t{{ sendLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\t</section>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet conversationThreadUid = 0\n\n/**\n * CnConversationThread: the messages between you and the other party, and a box to answer.\n *\n * Each message has an author, a time and a side: `us` for the organisation,\n * `them` for the resident or customer. The reply box emits `send`, and also\n * posts to `endpoint` when one is set. It needs no Talk and no other app:\n * where the messages are stored is the host's business.\n *\n * ```vue\n * <CnConversationThread\n * title=\"Contact with the resident\"\n * reply-label=\"Answer to the resident\"\n * :messages=\"[\n * { id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',\n * text: 'Thank you. I would like to see all documents.' },\n * { id: 2, time: '2026-10-04T10:24:00', side: 'us',\n * text: 'Construction starts in March.' },\n * ]\"\n * @send=\"saveReply\" />\n * ```\n *\n * The `conversation` detail widget type renders this thread from a field on\n * the record.\n */\nexport default {\n\tname: 'CnConversationThread',\n\n\tcomponents: {\n\t\tNcButton,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The messages, oldest first: `{ id?, author?, time?, text, side? }`.\n\t\t * `side` is `us` or `them` (default `them`). `time` is an ISO\n\t\t * date, or any text to show as is.\n\t\t */\n\t\tmessages: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Heading of the thread. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Element the heading renders as. */\n\t\ttitleTag: {\n\t\t\ttype: String,\n\t\t\tdefault: 'h3',\n\t\t},\n\n\t\t/** Whether the reply box renders. Turn it off for a closed or read-only record. */\n\t\tallowReply: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label of the reply box. */\n\t\treplyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Reply'),\n\t\t},\n\n\t\t/** Placeholder inside the reply box. */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Label of the send button. */\n\t\tsendLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Send'),\n\t\t},\n\n\t\t/** Author shown on an `us` message that names none. */\n\t\tusLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'You'),\n\t\t},\n\n\t\t/**\n\t\t * URL the reply is POSTed to as `{ message }`. Empty means the host\n\t\t * handles `send` itself and nothing is requested.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Extra fields sent along with `message` when `endpoint` is set. */\n\t\tpayload: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Shown when there are no messages yet. */\n\t\temptyText: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No messages yet.'),\n\t\t},\n\t},\n\n\temits: [\n\t\t/** A reply was submitted. Payload: the text. */\n\t\t'send',\n\t\t/** The endpoint accepted the reply. Payload: the response body. */\n\t\t'sent',\n\t\t/** The endpoint refused the reply. Payload: the error. */\n\t\t'error',\n\t],\n\n\tdata() {\n\t\tconversationThreadUid += 1\n\t\treturn {\n\t\t\tdraft: '',\n\t\t\tsending: false,\n\t\t\terrorMessage: '',\n\t\t\ttitleId: `cn-conversation-title-${conversationThreadUid}`,\n\t\t\tinputId: `cn-conversation-input-${conversationThreadUid}`,\n\t\t\terrorId: `cn-conversation-error-${conversationThreadUid}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The messages, with author, side, time and initials resolved.\n\t\t *\n\t\t * @return {Array<{key: string, author: string, initials: string, side: string, text: string, timeLabel: string, datetime: string}>} The rows.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\trows() {\n\t\t\treturn (Array.isArray(this.messages) ? this.messages : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => {\n\t\t\t\t\tconst side = message.side === 'us' ? 'us' : 'them'\n\t\t\t\t\tconst author = typeof message.author === 'string' && message.author !== ''\n\t\t\t\t\t\t? message.author\n\t\t\t\t\t\t: (side === 'us' ? this.usLabel : '')\n\t\t\t\t\tconst time = this.formatTime(message.time)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: message.id === undefined || message.id === null ? `message-${index}` : String(message.id),\n\t\t\t\t\t\tauthor,\n\t\t\t\t\t\tinitials: this.initialsOf(author),\n\t\t\t\t\t\tside,\n\t\t\t\t\t\ttext: message.text === undefined || message.text === null ? '' : String(message.text),\n\t\t\t\t\t\ttimeLabel: time.label,\n\t\t\t\t\t\tdatetime: time.datetime,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether there is something to send and nothing in flight.\n\t\t *\n\t\t * @return {boolean} True when Send is enabled.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tcanSend() {\n\t\t\treturn !this.sending && this.draft.trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Accessible name for a thread without a title.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tfallbackLabel() {\n\t\t\treturn t('nextcloud-vue', 'Conversation')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Up to two initials of a name, for the avatar.\n\t\t *\n\t\t * @param {string} name The author.\n\t\t * @return {string} The initials, upper case.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tinitialsOf(name) {\n\t\t\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\t\t\tif (parts.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst first = parts[0].charAt(0)\n\t\t\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\t\t\treturn (first + last).toUpperCase()\n\t\t},\n\n\t\t/**\n\t\t * Turn a message time into what the reader sees and what `<time>` carries.\n\t\t *\n\t\t * @param {unknown} value An ISO date, a Date, or text to show as is.\n\t\t * @return {{label: string, datetime: string}} The visible label and the machine value.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tformatTime(value) {\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn { label: '', datetime: '' }\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\tconst looksLikeDate = value instanceof Date || typeof value === 'number' || /^\\d{4}-\\d{2}-\\d{2}/.test(String(value))\n\t\t\tif (!looksLikeDate || Number.isNaN(date.getTime())) {\n\t\t\t\treturn { label: String(value), datetime: '' }\n\t\t\t}\n\t\t\tconst label = date.toLocaleString(undefined, { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })\n\t\t\treturn { label, datetime: date.toISOString() }\n\t\t},\n\n\t\t/**\n\t\t * Submit the reply: tell the host, and post it when an endpoint is set.\n\t\t *\n\t\t * Without an endpoint the box clears straight away, because the host\n\t\t * owns the send. With one it clears only when the request succeeds, so\n\t\t * a refused reply is still there to try again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tasync onSend() {\n\t\t\tif (!this.canSend) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = this.draft.trim()\n\t\t\tthis.errorMessage = ''\n\t\t\tthis.$emit('send', text)\n\t\t\tif (!this.endpoint) {\n\t\t\t\tthis.draft = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.sending = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.endpoint), { ...this.payload, message: text })\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.$emit('sent', response?.data)\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'The message could not be sent. Try again.')\n\t\t\t\tthis.$emit('error', error)\n\t\t\t} finally {\n\t\t\t\tthis.sending = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-thread {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__title {\n\tfont-size: 1.1em;\n\tfont-weight: 700;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-conversation-thread__messages {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-conversation-thread__message {\n\tdisplay: flex;\n\tgap: calc(3 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us {\n\tflex-direction: row-reverse;\n}\n\n.cn-conversation-thread__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-dark);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 0.8em;\n\tfont-weight: 700;\n\theight: 34px;\n\tjustify-content: center;\n\twidth: 34px;\n}\n\n.cn-conversation-thread__bubble {\n\tbackground: var(--color-background-hover);\n\tborder-radius: var(--border-radius-large);\n\tborder-start-start-radius: var(--border-radius-small, 4px);\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\tmin-width: 0;\n\tpadding: calc(3 * var(--default-grid-baseline)) calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us .cn-conversation-thread__bubble {\n\tbackground: var(--color-primary-element-light);\n\tborder-start-end-radius: var(--border-radius-small, 4px);\n\tborder-start-start-radius: var(--border-radius-large);\n\tcolor: var(--color-primary-element-light-text);\n}\n\n.cn-conversation-thread__meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tfont-size: 0.9em;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__author {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__text {\n\toverflow-wrap: anywhere;\n\twhite-space: pre-wrap;\n}\n\n.cn-conversation-thread__reply {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__reply-label {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__input {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tresize: vertical;\n\twidth: 100%;\n}\n\n.cn-conversation-thread__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: 0;\n}\n\n.cn-conversation-thread__reply-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["_createElementBlock","_openBlock","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass","_createElementVNode","_renderSlot"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import script from './CnConversationWidget.vue2.js';
2
+ import { render } from './CnConversationWidget.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-57081189";
6
+ script.__file = "src/components/CnConversationThread/CnConversationWidget.vue";
7
+ const __sfc_main = script;
8
+
9
+ export { __sfc_main as default };
10
+ //# sourceMappingURL=CnConversationWidget.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnConversationWidget.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -0,0 +1,116 @@
1
+ import __sfc_main from './CnConversationThread.vue.js';
2
+ import { readPath } from '../../utils/readPath.js';
3
+
4
+ /**
5
+ * CnConversationWidget: the `conversation` detail widget type.
6
+ *
7
+ * Renders CnConversationThread from a list on the bound record:
8
+ * `content: { field, endpoint?, authorField?, timeField?, textField?, sideField?, usValue? }`.
9
+ * `@objectId` in `endpoint` is replaced by the record's id. A reply the
10
+ * endpoint accepts is shown at once, until the record is read again.
11
+ * Resolved by its registry key, not exported.
12
+ */
13
+ var script = {
14
+ name: 'CnConversationWidget',
15
+
16
+ components: {
17
+ CnConversationThread: __sfc_main,
18
+ },
19
+
20
+ props: {
21
+ /** The widget's content. `field` is the dot-path to the messages on the record. */
22
+ content: {
23
+ type: Object,
24
+ default: () => ({}),
25
+ },
26
+
27
+ /** The bound record. */
28
+ objectData: {
29
+ type: Object,
30
+ default: null,
31
+ },
32
+
33
+ /** The bound record's id. */
34
+ objectId: {
35
+ type: [String, Number],
36
+ default: '',
37
+ },
38
+ },
39
+
40
+ data() {
41
+ return {
42
+ /** Replies sent from this widget that the record does not hold yet. */
43
+ sentHere: [],
44
+ }
45
+ },
46
+
47
+ computed: {
48
+ /**
49
+ * The record's messages in the thread's shape, plus the replies sent here.
50
+ *
51
+ * @return {Array<object>} The messages.
52
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
53
+ */
54
+ messages() {
55
+ const c = this.content;
56
+ const value = readPath(this.objectData || {}, c.field || 'messages');
57
+ const usValue = String(c.usValue === undefined ? 'us' : c.usValue);
58
+ const stored = (Array.isArray(value) ? value : [])
59
+ .filter((message) => message && typeof message === 'object')
60
+ .map((message) => ({
61
+ id: message.id,
62
+ author: readPath(message, c.authorField || 'author'),
63
+ time: readPath(message, c.timeField || 'time'),
64
+ text: readPath(message, c.textField || 'text'),
65
+ side: String(readPath(message, c.sideField || 'side')) === usValue ? 'us' : 'them',
66
+ }));
67
+ return [...stored, ...this.sentHere]
68
+ },
69
+
70
+ /**
71
+ * The endpoint with the record's id filled in.
72
+ *
73
+ * @return {string} The URL, or '' when the content names none.
74
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
75
+ */
76
+ endpoint() {
77
+ const url = this.content.endpoint;
78
+ if (typeof url !== 'string' || url === '') {
79
+ return ''
80
+ }
81
+ return url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))
82
+ },
83
+ },
84
+
85
+ watch: {
86
+ // The record was read again, so it now holds what was sent from here.
87
+ objectData() {
88
+ this.sentHere = [];
89
+ },
90
+ },
91
+
92
+ methods: {
93
+ /**
94
+ * Show an accepted reply at once, without waiting for the record.
95
+ *
96
+ * @param {object} data The endpoint's response.
97
+ * @return {void}
98
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread
99
+ */
100
+ onSent(data) {
101
+ const text = data?.message ?? data?.text;
102
+ if (typeof text !== 'string' || text === '') {
103
+ return
104
+ }
105
+ this.sentHere.push({
106
+ id: `sent-${this.sentHere.length}`,
107
+ time: new Date().toISOString(),
108
+ text,
109
+ side: 'us',
110
+ });
111
+ },
112
+ },
113
+ };
114
+
115
+ export { script as default };
116
+ //# sourceMappingURL=CnConversationWidget.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnConversationWidget.vue2.js","sources":["../../../../src/components/CnConversationThread/CnConversationWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-case-widget-card\">\n\t\t<CnConversationThread\n\t\t\t:messages=\"messages\"\n\t\t\t:title=\"content.title || ''\"\n\t\t\t:allowReply=\"content.allowReply !== false\"\n\t\t\t:replyLabel=\"content.replyLabel || undefined\"\n\t\t\t:placeholder=\"content.placeholder || ''\"\n\t\t\t:sendLabel=\"content.sendLabel || undefined\"\n\t\t\t:endpoint=\"endpoint\"\n\t\t\t:emptyText=\"content.emptyText || undefined\"\n\t\t\t@sent=\"onSent\" />\n\t</div>\n</template>\n\n<script>\nimport CnConversationThread from './CnConversationThread.vue'\nimport { readPath } from '../../utils/readPath.js'\n\n/**\n * CnConversationWidget: the `conversation` detail widget type.\n *\n * Renders CnConversationThread from a list on the bound record:\n * `content: { field, endpoint?, authorField?, timeField?, textField?, sideField?, usValue? }`.\n * `@objectId` in `endpoint` is replaced by the record's id. A reply the\n * endpoint accepts is shown at once, until the record is read again.\n * Resolved by its registry key, not exported.\n */\nexport default {\n\tname: 'CnConversationWidget',\n\n\tcomponents: {\n\t\tCnConversationThread,\n\t},\n\n\tprops: {\n\t\t/** The widget's content. `field` is the dot-path to the messages on the record. */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The bound record. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Replies sent from this widget that the record does not hold yet. */\n\t\t\tsentHere: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The record's messages in the thread's shape, plus the replies sent here.\n\t\t *\n\t\t * @return {Array<object>} The messages.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tmessages() {\n\t\t\tconst c = this.content\n\t\t\tconst value = readPath(this.objectData || {}, c.field || 'messages')\n\t\t\tconst usValue = String(c.usValue === undefined ? 'us' : c.usValue)\n\t\t\tconst stored = (Array.isArray(value) ? value : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message) => ({\n\t\t\t\t\tid: message.id,\n\t\t\t\t\tauthor: readPath(message, c.authorField || 'author'),\n\t\t\t\t\ttime: readPath(message, c.timeField || 'time'),\n\t\t\t\t\ttext: readPath(message, c.textField || 'text'),\n\t\t\t\t\tside: String(readPath(message, c.sideField || 'side')) === usValue ? 'us' : 'them',\n\t\t\t\t}))\n\t\t\treturn [...stored, ...this.sentHere]\n\t\t},\n\n\t\t/**\n\t\t * The endpoint with the record's id filled in.\n\t\t *\n\t\t * @return {string} The URL, or '' when the content names none.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tendpoint() {\n\t\t\tconst url = this.content.endpoint\n\t\t\tif (typeof url !== 'string' || url === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t},\n\t},\n\n\twatch: {\n\t\t// The record was read again, so it now holds what was sent from here.\n\t\tobjectData() {\n\t\t\tthis.sentHere = []\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Show an accepted reply at once, without waiting for the record.\n\t\t *\n\t\t * @param {object} data The endpoint's response.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tonSent(data) {\n\t\t\tconst text = data?.message ?? data?.text\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.sentHere.push({\n\t\t\t\tid: `sent-${this.sentHere.length}`,\n\t\t\t\ttime: new Date().toISOString(),\n\t\t\t\ttext,\n\t\t\t\tside: 'us',\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-case-widget-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: calc(5 * var(--default-grid-baseline));\n}\n</style>\n"],"names":["CnConversationThread"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { resolveComponent, openBlock, createElementBlock, createVNode } from 'vue';
2
+
3
+ const _hoisted_1 = { class: "cn-case-widget-card" };
4
+
5
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
6
+ const _component_CnConversationThread = resolveComponent("CnConversationThread");
7
+
8
+ return (openBlock(), createElementBlock("div", _hoisted_1, [
9
+ createVNode(_component_CnConversationThread, {
10
+ messages: $options.messages,
11
+ title: $props.content.title || '',
12
+ allowReply: $props.content.allowReply !== false,
13
+ replyLabel: $props.content.replyLabel || undefined,
14
+ placeholder: $props.content.placeholder || '',
15
+ sendLabel: $props.content.sendLabel || undefined,
16
+ endpoint: $options.endpoint,
17
+ emptyText: $props.content.emptyText || undefined,
18
+ onSent: $options.onSent
19
+ }, null, 8 /* PROPS */, ["messages", "title", "allowReply", "replyLabel", "placeholder", "sendLabel", "endpoint", "emptyText", "onSent"])
20
+ ]))
21
+ }
22
+
23
+ export { render };
24
+ //# sourceMappingURL=CnConversationWidget.vue3.js.map