@conduction/nextcloud-vue 2.85.0 → 2.87.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 (301) hide show
  1. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue.js +1 -1
  2. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js +3 -2
  3. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
  6. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +5 -4
  7. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue.js +1 -1
  10. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js +2 -1
  11. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js.map +1 -1
  12. package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue3.js.map +1 -1
  13. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  14. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +2 -1
  15. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  16. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  17. package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
  18. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +156 -14
  19. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  20. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +105 -74
  21. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  22. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue.js +1 -1
  23. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js +2 -1
  24. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js.map +1 -1
  25. package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue3.js.map +1 -1
  26. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue.js +1 -1
  27. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +2 -1
  28. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
  29. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
  30. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  31. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +6 -5
  32. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  34. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js +1 -1
  35. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js +2 -1
  36. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js.map +1 -1
  37. package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue3.js.map +1 -1
  38. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  39. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +2 -1
  40. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  41. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  42. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
  43. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +2 -1
  44. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  47. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +2 -1
  48. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  49. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  50. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue.js +1 -1
  51. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js +3 -1
  52. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js.map +1 -1
  53. package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue3.js.map +1 -1
  54. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js +2 -1
  55. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js.map +1 -1
  56. package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue3.js.map +1 -1
  57. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue.js +1 -1
  58. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js +2 -1
  59. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js.map +1 -1
  60. package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue3.js.map +1 -1
  61. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue.js +1 -1
  62. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js +3 -1
  63. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js.map +1 -1
  64. package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue3.js.map +1 -1
  65. package/dist/esm/components/CnFileManager/CnFileManager.vue.js +1 -1
  66. package/dist/esm/components/CnFileManager/CnFileManager.vue2.js +3 -1
  67. package/dist/esm/components/CnFileManager/CnFileManager.vue2.js.map +1 -1
  68. package/dist/esm/components/CnFileManager/CnFileManager.vue3.js.map +1 -1
  69. package/dist/esm/components/CnFilePreview/CnFilePreview.vue.js +1 -1
  70. package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js +2 -1
  71. package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js.map +1 -1
  72. package/dist/esm/components/CnFilePreview/CnFilePreview.vue3.js.map +1 -1
  73. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  74. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +49 -1
  75. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  76. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +3 -3
  77. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  78. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue.js +1 -1
  79. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +2 -1
  80. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
  81. package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
  82. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -5
  83. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  84. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  85. package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
  86. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +2 -1
  87. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
  88. package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
  89. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue.js +1 -1
  90. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js +3 -2
  91. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js.map +1 -1
  92. package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue3.js.map +1 -1
  93. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  94. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -0
  95. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  96. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +82 -75
  97. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  98. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js +1 -1
  99. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js +5 -4
  100. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js.map +1 -1
  101. package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue3.js.map +1 -1
  102. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue.js +1 -1
  103. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js +2 -1
  104. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js.map +1 -1
  105. package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue3.js.map +1 -1
  106. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue.js +1 -1
  107. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js +2 -1
  108. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js.map +1 -1
  109. package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue3.js.map +1 -1
  110. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue.js +1 -1
  111. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +2 -1
  112. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  113. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  114. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue.js +1 -1
  115. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js +2 -1
  116. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js.map +1 -1
  117. package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue3.js.map +1 -1
  118. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue.js +1 -1
  119. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js +2 -1
  120. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js.map +1 -1
  121. package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue3.js.map +1 -1
  122. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue.js +1 -1
  123. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js +2 -1
  124. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js.map +1 -1
  125. package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue3.js.map +1 -1
  126. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js +2 -0
  127. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js.map +1 -1
  128. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js +2 -2
  129. package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js.map +1 -1
  130. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue.js +1 -1
  131. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +2 -1
  132. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
  133. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
  134. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue.js +1 -1
  135. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js +2 -1
  136. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js.map +1 -1
  137. package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue3.js.map +1 -1
  138. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  139. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
  140. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  141. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
  142. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  143. package/dist/esm/components/CnTasksCard/CnTasksCard.vue.js +1 -1
  144. package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js +2 -1
  145. package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js.map +1 -1
  146. package/dist/esm/components/CnTasksCard/CnTasksCard.vue3.js.map +1 -1
  147. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
  148. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +2 -1
  149. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
  150. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
  151. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue.js +1 -1
  152. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js +2 -1
  153. package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js.map +1 -1
  154. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue.js +1 -1
  155. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js +2 -1
  156. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js.map +1 -1
  157. package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue3.js.map +1 -1
  158. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
  159. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
  160. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  161. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  162. package/dist/esm/dialogs/CnNoteHistoryDialog.vue.js +1 -1
  163. package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js +2 -1
  164. package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js.map +1 -1
  165. package/dist/esm/dialogs/CnNoteHistoryDialog.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue.js +1 -1
  167. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js +3 -2
  168. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js.map +1 -1
  169. package/dist/esm/integrations/builtin/activity/CnActivityCard.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue.js +1 -1
  171. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js +4 -3
  172. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js.map +1 -1
  173. package/dist/esm/integrations/builtin/activity/CnActivityTab.vue3.js.map +1 -1
  174. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue.js +1 -1
  175. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -2
  176. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  177. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  178. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
  179. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +2 -1
  180. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
  181. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
  182. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
  183. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +6 -5
  184. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
  186. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue.js +1 -1
  187. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js +2 -1
  188. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue.js +1 -1
  191. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  192. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  193. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
  195. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  196. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  197. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  198. package/dist/esm/integrations/builtin/email/CnEmailCard.vue.js +1 -1
  199. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js +2 -1
  200. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  201. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  202. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue.js +1 -1
  203. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +2 -1
  204. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
  205. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
  206. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue.js +1 -1
  207. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js +2 -1
  208. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js.map +1 -1
  209. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue3.js.map +1 -1
  210. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue.js +1 -1
  211. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  212. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  213. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  214. package/dist/esm/l10n/en.json.js +35 -2
  215. package/dist/esm/l10n/en.json.js.map +1 -1
  216. package/dist/esm/l10n/nl.json.js +38 -2
  217. package/dist/esm/l10n/nl.json.js.map +1 -1
  218. package/dist/esm/library-style.js +1 -1
  219. package/dist/esm/nextcloud-vue.css +1068 -962
  220. package/dist/esm/store/useObjectStore.js +7 -2
  221. package/dist/esm/store/useObjectStore.js.map +1 -1
  222. package/dist/esm/utils/boardColumns.js +50 -1
  223. package/dist/esm/utils/boardColumns.js.map +1 -1
  224. package/dist/esm/utils/boardReferenceColumns.js +115 -4
  225. package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
  226. package/dist/esm/utils/contentHeaderLink.js +48 -1
  227. package/dist/esm/utils/contentHeaderLink.js.map +1 -1
  228. package/dist/esm/utils/schema.js +5 -4
  229. package/dist/esm/utils/schema.js.map +1 -1
  230. package/dist/esm/utils/userLocale.js +30 -0
  231. package/dist/esm/utils/userLocale.js.map +1 -0
  232. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  233. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  234. package/dist/nextcloud-vue.cjs.js +1088 -476
  235. package/dist/nextcloud-vue.cjs.js.map +2 -2
  236. package/dist/nextcloud-vue.css +1068 -962
  237. package/l10n/en.json +35 -2
  238. package/l10n/nl.json +38 -2
  239. package/package.json +1 -1
  240. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +3 -2
  241. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +5 -4
  242. package/src/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue +2 -1
  243. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +2 -1
  244. package/src/components/CnBoardView/CnBoardView.vue +189 -24
  245. package/src/components/CnCalendarEventPicker/CnCalendarEventPicker.vue +2 -1
  246. package/src/components/CnCalendarWidget/CnCalendarWidget.vue +2 -1
  247. package/src/components/CnChartWidget/CnChartWidget.vue +6 -5
  248. package/src/components/CnCollectivePagePicker/CnCollectivePagePicker.vue +2 -1
  249. package/src/components/CnConversationThread/CnConversationThread.vue +2 -1
  250. package/src/components/CnCountdownWidget/CnCountdownWidget.vue +2 -1
  251. package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -1
  252. package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
  253. package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
  254. package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
  255. package/src/components/CnFederationStatus/CnFederationStatus.vue +3 -1
  256. package/src/components/CnFileManager/CnFileManager.vue +2 -1
  257. package/src/components/CnFilePreview/CnFilePreview.vue +2 -1
  258. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -6
  259. package/src/components/CnFollowToggle/CnFollowToggle.vue +2 -1
  260. package/src/components/CnIndexPage/CnIndexPage.vue +30 -4
  261. package/src/components/CnNotesCard/CnNotesCard.vue +2 -1
  262. package/src/components/CnObjectCalendar/CnObjectCalendar.vue +3 -2
  263. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +36 -0
  264. package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +5 -4
  265. package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +2 -1
  266. package/src/components/CnObjectSidebar/CnFlowTasksPanel.vue +2 -1
  267. package/src/components/CnObjectSidebar/CnNotesTab.vue +2 -1
  268. package/src/components/CnObjectSidebar/CnTasksTab.vue +2 -1
  269. package/src/components/CnPropertySourceField/CnPropertySourceField.vue +2 -1
  270. package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
  271. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
  272. package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
  273. package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
  274. package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
  275. package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
  276. package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
  277. package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
  278. package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
  279. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
  280. package/src/css/board.css +40 -0
  281. package/src/dialogs/CnNoteHistoryDialog.vue +2 -1
  282. package/src/integrations/builtin/activity/CnActivityCard.vue +3 -2
  283. package/src/integrations/builtin/activity/CnActivityTab.vue +4 -3
  284. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +3 -2
  285. package/src/integrations/builtin/calendar/CnCalendarCard.vue +2 -1
  286. package/src/integrations/builtin/calendar/CnCalendarTab.vue +6 -5
  287. package/src/integrations/builtin/contactmoment/CnContactmomentCard.vue +2 -1
  288. package/src/integrations/builtin/cospend/CnCospendTab.vue +2 -1
  289. package/src/integrations/builtin/deck/CnDeckTab.vue +2 -1
  290. package/src/integrations/builtin/email/CnEmailCard.vue +2 -1
  291. package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +2 -1
  292. package/src/integrations/builtin/field-inspection/CnFieldInspectionTab.vue +2 -1
  293. package/src/integrations/builtin/photos/CnPhotosTab.vue +2 -1
  294. package/src/schemas/app-manifest-v2.schema.json +4 -1
  295. package/src/store/useObjectStore.js +7 -2
  296. package/src/utils/boardColumns.js +49 -0
  297. package/src/utils/boardReferenceColumns.js +114 -3
  298. package/src/utils/contentHeaderLink.js +47 -0
  299. package/src/utils/schema.js +5 -4
  300. package/src/utils/userLocale.js +26 -0
  301. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -2,7 +2,7 @@ import script from './CnFollowToggle.vue2.js';
2
2
  import { render } from './CnFollowToggle.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-17752367";
5
+ script.__scopeId = "data-v-8bff02a6";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -8,6 +8,7 @@ import EyeOutline from 'vue-material-design-icons/EyeOutline.vue';
8
8
  import { patchStoredSelf } from '../../utils/patchStoredSelf.js';
9
9
  import { setWatching, listWatchers, setWatcher } from '../../utils/recordInteractions.js';
10
10
  import { searchNextcloudUsers } from '../../utils/userAutocomplete.js';
11
+ import { userLocale } from '../../utils/userLocale.js';
11
12
 
12
13
  /**
13
14
  * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to
@@ -198,7 +199,7 @@ var script = {
198
199
  const d = new Date(created);
199
200
  return Number.isNaN(d.getTime())
200
201
  ? ''
201
- : translate('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })
202
+ : translate('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })
202
203
  },
203
204
 
204
205
  removeFollowerLabel(watcher) {
@@ -1 +1 @@
1
- {"version":3,"file":"CnFollowToggle.vue2.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["Bell","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnFollowToggle.vue2.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["Bell","t"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnFollowToggle.vue3.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue?vue&type=template&id=17752367&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createBlock","_createElementBlock","_Fragment","_createElementVNode","_openBlock","_renderList","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"CnFollowToggle.vue3.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue?vue&type=template&id=8bff02a6&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createBlock","_createElementBlock","_Fragment","_createElementVNode","_openBlock","_renderList","_toDisplayString"],"mappings":"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"}
@@ -28,7 +28,7 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js';
28
28
  import { useObjectStore } from '../../store/useObjectStore.js';
29
29
  import { routeHref, followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js';
30
30
  import { resolveRegisteredHandler, buildOnSuccessRoute } from '../../utils/actionsDispatcher.js';
31
- import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
31
+ import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, fullTargetOf, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
32
32
  import { reportBindingProblems } from '../../utils/diagnostics.js';
33
33
  import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js';
34
34
  import { buildExportUrl } from '../../utils/indexExportHelpers.js';
@@ -3099,6 +3099,9 @@ var script = {
3099
3099
  mergeBy: source.mergeBy || '',
3100
3100
  narrowBy,
3101
3101
  narrowValue: narrowBy ? this.boardNarrowValue : '',
3102
+ capacityField: source.capacityField || '',
3103
+ neutralColor: typeof source.neutralColor === 'string' ? source.neutralColor : '',
3104
+ colorMap: source.colorMap && typeof source.colorMap === 'object' ? source.colorMap : null,
3102
3105
  })
3103
3106
  },
3104
3107
 
@@ -3141,6 +3144,10 @@ var script = {
3141
3144
  * row (PATCH). `readOnly` gives no move. A board on `statusField` with
3142
3145
  * neither keeps the `runTransition` prop.
3143
3146
  *
3147
+ * With `source.capacityField`, a drop that would fill the referenced
3148
+ * row past its limit is refused before the handler or the PATCH runs.
3149
+ * The server still guards; this only spares the round trip.
3150
+ *
3144
3151
  * @return {((move: {card: object, toKey: string}) => Promise<object>)|null} The move, or null for a read-only board.
3145
3152
  * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference
3146
3153
  */
@@ -3162,6 +3169,7 @@ var script = {
3162
3169
  const field = this.boardColumnField;
3163
3170
  const kind = active?.kind || 'schema';
3164
3171
  const narrowBy = active?.source?.narrowBy || null;
3172
+ const capacityField = active?.source?.capacityField || '';
3165
3173
  return async ({ card, toKey }) => {
3166
3174
  const drop = stages
3167
3175
  ? resolveDropValue({ card, toKey, kind, refsByKey: stages.refsByKey, narrowBy })
@@ -3169,6 +3177,13 @@ var script = {
3169
3177
  if (drop === null) {
3170
3178
  throw new Error(translate('nextcloud-vue', 'This card cannot move to that column.'))
3171
3179
  }
3180
+ const full = capacityField && drop.target
3181
+ ? fullTargetOf({ target: drop.target, card, rows: this.displayObjects, field, capacityField, rowKey: this.rowKey })
3182
+ : null;
3183
+ if (full) {
3184
+ const column = stages.states.find((state) => state.key === String(toKey))?.label || String(toKey);
3185
+ throw new Error(translate('nextcloud-vue', '{column} is full: {count} of {capacity}.', { column, count: full.count, capacity: full.capacity }))
3186
+ }
3172
3187
  if (handler) {
3173
3188
  return handler({ card, toKey, field, value: drop.value, target: drop.target })
3174
3189
  }
@@ -3184,9 +3199,12 @@ var script = {
3184
3199
  /**
3185
3200
  * Where a card may go, from the app's `moveTargetsHandler`: it gets
3186
3201
  * `{ card, field }` and answers the values (referenced ids) the card
3187
- * can reach; the board maps them to its columns.
3202
+ * can reach; the board maps them to its columns. An entry may also be
3203
+ * `{ key, allowed, reason }`: a target that is offered but blocked,
3204
+ * with the sentence that says why.
3188
3205
  *
3189
- * @return {((card: object) => Promise<Array<string>|null>)|null} The question, or null.
3206
+ * @return {((card: object) => Promise<Array<string|{key: string, allowed: boolean, reason: string}>|null>)|null} The question, or null.
3207
+ * @spec openspec/changes/board-move-block-reasons/specs/board-view/spec.md#requirement-a-move-target-can-be-blocked-with-a-reason
3190
3208
  * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-board-shows-where-a-card-can-go
3191
3209
  */
3192
3210
  boardAllowedMoves() {
@@ -3204,9 +3222,16 @@ var script = {
3204
3222
  if (!Array.isArray(values)) {
3205
3223
  return null
3206
3224
  }
3225
+ const columnOf = (id) => (stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id);
3207
3226
  return values.map((value) => {
3208
- const id = refIdOf(value);
3209
- return stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id
3227
+ if (value && typeof value === 'object' && Object.hasOwn(value, 'key')) {
3228
+ return {
3229
+ key: columnOf(refIdOf(value.key)),
3230
+ allowed: value.allowed !== false,
3231
+ reason: typeof value.reason === 'string' ? value.reason : '',
3232
+ }
3233
+ }
3234
+ return columnOf(refIdOf(value))
3210
3235
  })
3211
3236
  }
3212
3237
  },