@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
@@ -29,6 +29,7 @@ import { inject } from 'vue'
29
29
  import CnWidgetIcon from '../CnWidgetGrid/CnWidgetIcon.vue'
30
30
  import { getByPath } from '../../composables/useEndpointSource.js'
31
31
  import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
32
+ import { userLocale } from '../../utils/userLocale.js'
32
33
 
33
34
  const MS_PER_DAY = 24 * 60 * 60 * 1000
34
35
 
@@ -248,7 +249,7 @@ export default {
248
249
  if (!this.targetDate || this.content?.showDate === false) {
249
250
  return ''
250
251
  }
251
- return this.targetDate.toLocaleDateString(undefined, { day: 'numeric', month: 'long', year: 'numeric' })
252
+ return this.targetDate.toLocaleDateString(userLocale(), { day: 'numeric', month: 'long', year: 'numeric' })
252
253
  },
253
254
 
254
255
  /**
@@ -984,6 +984,7 @@ import { pageViews } from '../../mixins/pageViews.js'
984
984
  import { mergeUserLayout, resolveUserLayoutApi } from '../../store/plugins/dashboardLayouts.js'
985
985
  import { isAppInstalled } from '../../utils/appInstalled.js'
986
986
  import { contentHeaderLink } from '../../utils/contentHeaderLink.js'
987
+ import { userLocale } from '../../utils/userLocale.js'
987
988
  import { compareVisibleWhen, evaluateWorkspaceCondition, isWorkspaceCondition, readVisibleWhenValue } from '../../utils/visibleWhen.js'
988
989
  import { canonicalWidgetType } from '../../utils/widgetTypeAliases.js'
989
990
  import { CnActionButtons } from '../CnActionButtons/index.js'
@@ -2873,7 +2874,7 @@ export default {
2873
2874
  if (!d) {
2874
2875
  return ''
2875
2876
  }
2876
- return d.toLocaleDateString(undefined, {
2877
+ return d.toLocaleDateString(userLocale(), {
2877
2878
  day: 'numeric',
2878
2879
  month: 'short',
2879
2880
  ...(needsYear ? { year: 'numeric' } : {}),
@@ -83,6 +83,7 @@
83
83
  </template>
84
84
 
85
85
  <script>
86
+ import { userLocale } from '../../utils/userLocale.js'
86
87
  /**
87
88
  * CnDataMatrix — Inline-edit data grid for matrix-shaped data
88
89
  * (rows × columns). Each cell is click-to-edit; commits emit
@@ -239,7 +240,7 @@ export default {
239
240
  if (!Number.isFinite(n)) {
240
241
  return value
241
242
  }
242
- return n.toLocaleString()
243
+ return n.toLocaleString(userLocale())
243
244
  }
244
245
  return value
245
246
  },
@@ -58,6 +58,7 @@ import { useObjectStore } from '../../store/useObjectStore.js'
58
58
  import { resolveObjectOpType } from '../../utils/actionsDispatcher.js'
59
59
  import { isEmptyChipValue, isPastDate, normalizeHeaderFields, pickRefLabel, variantForColor } from '../../utils/headerFieldChips.js'
60
60
  import { schemaRefSlug } from '../../utils/schemaRefSlug.js'
61
+ import { userLocale } from '../../utils/userLocale.js'
61
62
 
62
63
  const DAY_MS = 86400000
63
64
 
@@ -239,7 +240,7 @@ export default {
239
240
  try {
240
241
  return new Intl.RelativeTimeFormat(this.locale(), { numeric: 'auto' }).format(days, 'day')
241
242
  } catch {
242
- return new Date(time).toLocaleDateString()
243
+ return new Date(time).toLocaleDateString(userLocale())
243
244
  }
244
245
  },
245
246
 
@@ -171,6 +171,7 @@ import { NcButton, NcDialog, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcTextFi
171
171
  import EmailOutline from 'vue-material-design-icons/EmailOutline.vue'
172
172
  import FolderOutline from 'vue-material-design-icons/FolderOutline.vue'
173
173
  import { buildHeaders, prefixUrl } from '../../utils/index.js'
174
+ import { userLocale } from '../../utils/userLocale.js'
174
175
 
175
176
  export default {
176
177
  name: 'CnEmailPicker',
@@ -404,7 +405,7 @@ export default {
404
405
  if (Number.isNaN(d.getTime())) {
405
406
  return String(raw)
406
407
  }
407
- return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })
408
+ return d.toLocaleDateString(userLocale(), { year: 'numeric', month: 'short', day: 'numeric' })
408
409
  },
409
410
  },
410
411
  }
@@ -81,6 +81,8 @@
81
81
  </template>
82
82
 
83
83
  <script>
84
+ import { userLocale } from '../../utils/userLocale.js'
85
+
84
86
  // The canonical KPI scale (`--cn-kpi-*`) lives in one stylesheet. Imported
85
87
  // here as well as from css/index.css so the tokens resolve even when the
86
88
  // consuming app pulls in components individually.
@@ -242,7 +244,7 @@ export default {
242
244
  if (Number.isNaN(d.getTime())) {
243
245
  return iso
244
246
  }
245
- return d.toLocaleString()
247
+ return d.toLocaleString(userLocale())
246
248
  } catch {
247
249
  return iso
248
250
  }
@@ -80,6 +80,7 @@
80
80
  </template>
81
81
 
82
82
  <script>
83
+ import { userLocale } from '../../utils/userLocale.js'
83
84
  /**
84
85
  * CnFileManager — File list widget with drag-drop upload, per-file
85
86
  * actions, and a click-emit for preview / detail.
@@ -223,7 +224,7 @@ export default {
223
224
  if (Number.isNaN(d.getTime())) {
224
225
  return iso
225
226
  }
226
- return d.toLocaleString()
227
+ return d.toLocaleString(userLocale())
227
228
  } catch {
228
229
  return iso
229
230
  }
@@ -72,6 +72,7 @@ import { NcButton, NcDialog, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'
72
72
  import { fileContentUrl, previewKindOf } from '../../composables/useFileOpener.js'
73
73
  import { buildHeaders, prefixUrl } from '../../utils/index.js'
74
74
  import { parseDelimited } from '../../utils/parseDelimited.js'
75
+ import { userLocale } from '../../utils/userLocale.js'
75
76
 
76
77
  /**
77
78
  * CnFilePreview — an in-page preview of a data file the Nextcloud Viewer does
@@ -203,7 +204,7 @@ export default {
203
204
  if (estimate > shown) {
204
205
  return t('nextcloud-vue', 'Showing the first {shown} of about {total} rows', {
205
206
  shown,
206
- total: estimate.toLocaleString(),
207
+ total: estimate.toLocaleString(userLocale()),
207
208
  })
208
209
  }
209
210
  return t('nextcloud-vue', 'Showing the first {shown} rows', { shown })
@@ -110,7 +110,7 @@
110
110
  <template #icon>
111
111
  <CnIcon :name="action.icon || 'Plus'" :size="20" />
112
112
  </template>
113
- {{ action.label }}
113
+ {{ hostLabel(action) }}
114
114
  </NcActionButton>
115
115
  </NcActions>
116
116
  <!-- A plain upload as its own button, when the host names it
@@ -193,7 +193,7 @@
193
193
  <template #icon>
194
194
  <CnIcon :name="action.icon || 'CheckboxMultipleMarkedOutline'" :size="20" />
195
195
  </template>
196
- {{ action.label }}
196
+ {{ hostLabel(action) }}
197
197
  </NcButton>
198
198
  <NcButton variant="tertiary"
199
199
  data-testid="cn-files-browser-bulk-clear"
@@ -366,7 +366,7 @@
366
366
  <template #icon>
367
367
  <CnIcon :name="action.icon || 'FileDocumentEditOutline'" :size="20" />
368
368
  </template>
369
- {{ action.label }}
369
+ {{ hostLabel(action) }}
370
370
  </NcActionButton>
371
371
  </template>
372
372
  <NcActionSeparator v-if="actionsFor(node).length > 0 || (!isFolder(node) && hostActionsFor(node).length > 0)" />
@@ -583,8 +583,6 @@
583
583
  <script>
584
584
  import { getCurrentUser } from '@nextcloud/auth'
585
585
  import axios from '@nextcloud/axios'
586
- import { FileType, formatFileSize, getFileActions, getNewFileMenuEntries, sortNodes, View } from '@nextcloud/files'
587
- import { getClient, getDefaultPropfind, getRemoteURL, getRootPath, resultToNode } from '@nextcloud/files/dav'
588
586
  /**
589
587
  * CnFilesBrowser — a folder of Nextcloud files, on any page, built from the
590
588
  * Files app's own primitives rather than a copy of its screen.
@@ -623,6 +621,9 @@ import { getClient, getDefaultPropfind, getRemoteURL, getRootPath, resultToNode
623
621
  * copy read `window._nc_fileactions`, which the server's plugins never write,
624
622
  * and saw nothing while the page held thirty actions.
625
623
  */
624
+ import { subscribe, unsubscribe } from '@nextcloud/event-bus'
625
+ import { FileType, formatFileSize, getFileActions, getNewFileMenuEntries, sortNodes, View } from '@nextcloud/files'
626
+ import { getClient, getDefaultPropfind, getRemoteURL, getRootPath, resultToNode } from '@nextcloud/files/dav'
626
627
  import { translatePlural as n, translate as t } from '@nextcloud/l10n'
627
628
  import { generateUrl } from '@nextcloud/router'
628
629
  import { NcActionButton, NcActionCheckbox, NcActionLink, NcActions, NcActionSeparator, NcBreadcrumb, NcBreadcrumbs, NcButton, NcDateTime, NcDialog, NcIconSvgWrapper, NcLoadingIcon, NcProgressBar, NcTextField } from '@nextcloud/vue'
@@ -660,6 +661,12 @@ let uploadSeq = 0
660
661
  /** A folder glyph, the icon the Files app's View constructor requires. */
661
662
  const VIEW_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>'
662
663
 
664
+ // Event-bus channels that mean the open folder may have changed: the page's
665
+ // Refresh signal, and the node events the Files app's actions and uploader emit.
666
+ const FOLDER_CHANGED_CHANNELS = ['cn:page:refresh', 'files:node:created', 'files:node:deleted', 'files:node:updated', 'files:node:moved']
667
+
668
+ const FOLDER_CHANGED_DEBOUNCE_MS = 300
669
+
663
670
  export default {
664
671
  name: 'CnFilesBrowser',
665
672
 
@@ -696,6 +703,10 @@ export default {
696
703
  // The page's pre-bound action runner (CnPageRenderer provides it);
697
704
  // absent outside a page tree, in which case the bare dispatcher runs.
698
705
  cnDispatchAction: { default: null },
706
+ // The host app's translate function (CnAppRoot provides it). A row
707
+ // action or column the manifest declares is authored in English as
708
+ // the catalogue key, and read through this in the user's language.
709
+ cnTranslate: { default: () => (key) => key },
699
710
  },
700
711
 
701
712
  props: {
@@ -1356,6 +1367,19 @@ export default {
1356
1367
  mounted() {
1357
1368
  this.loadColumnChoice()
1358
1369
  this.refresh()
1370
+ // Another surface on the page changed the folder: the page's Refresh,
1371
+ // a dialog that filed a document, or a Files action whose work ends
1372
+ // after its own call returned (the delete confirmation, an upload).
1373
+ for (const channel of FOLDER_CHANGED_CHANNELS) {
1374
+ subscribe(channel, this.onFolderChanged)
1375
+ }
1376
+ },
1377
+
1378
+ beforeUnmount() {
1379
+ for (const channel of FOLDER_CHANGED_CHANNELS) {
1380
+ unsubscribe(channel, this.onFolderChanged)
1381
+ }
1382
+ clearTimeout(this._folderChangedTimer)
1359
1383
  },
1360
1384
 
1361
1385
  methods: {
@@ -1643,6 +1667,30 @@ export default {
1643
1667
  * @param {object} node The node.
1644
1668
  * @return {string} The label.
1645
1669
  */
1670
+ /**
1671
+ * A host action's label in the user's language.
1672
+ *
1673
+ * @spec openspec/changes/files-browser-hears-the-page/specs/files-browser/spec.md#requirement-a-declared-row-action-reads-in-the-users-language
1674
+ * @param {object} action The manifest-declared action.
1675
+ * @return {string} The label.
1676
+ */
1677
+ hostLabel(action) {
1678
+ return this.cnTranslate(String(action?.label ?? ''))
1679
+ },
1680
+
1681
+ /**
1682
+ * Re-read the folder once after a burst of change signals. One upload
1683
+ * of ten files answers ten `files:node:created`, and one PROPFIND
1684
+ * covers them all.
1685
+ *
1686
+ * @spec openspec/changes/files-browser-hears-the-page/specs/files-browser/spec.md#requirement-the-files-browser-re-reads-when-the-page-says-files-changed
1687
+ * @return {void}
1688
+ */
1689
+ onFolderChanged() {
1690
+ clearTimeout(this._folderChangedTimer)
1691
+ this._folderChangedTimer = setTimeout(() => this.refresh(), FOLDER_CHANGED_DEBOUNCE_MS)
1692
+ },
1693
+
1646
1694
  labelOf(action, node) {
1647
1695
  try {
1648
1696
  return action.displayName(this.contextFor(node))
@@ -2034,7 +2082,7 @@ export default {
2034
2082
  */
2035
2083
  columnLabel(column) {
2036
2084
  if (column && typeof column.label === 'string' && column.label !== '') {
2037
- return column.label
2085
+ return this.cnTranslate(column.label)
2038
2086
  }
2039
2087
  return this.builtInColumnLabels[column && column.key] || (column && column.key) || ''
2040
2088
  },
@@ -108,6 +108,7 @@ import EyeOutline from 'vue-material-design-icons/EyeOutline.vue'
108
108
  import { patchStoredSelf } from '../../utils/patchStoredSelf.js'
109
109
  import { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'
110
110
  import { searchNextcloudUsers } from '../../utils/userAutocomplete.js'
111
+ import { userLocale } from '../../utils/userLocale.js'
111
112
 
112
113
  /**
113
114
  * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to
@@ -298,7 +299,7 @@ export default {
298
299
  const d = new Date(created)
299
300
  return Number.isNaN(d.getTime())
300
301
  ? ''
301
- : t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })
302
+ : t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })
302
303
  },
303
304
 
304
305
  removeFollowerLabel(watcher) {
@@ -1170,6 +1170,7 @@ import {
1170
1170
  columnFieldsOf,
1171
1171
  columnKeyOfRow,
1172
1172
  fetchReferenceObjects,
1173
+ fullTargetOf,
1173
1174
  referenceTargetOf,
1174
1175
  refIdOf,
1175
1176
  resolveDropValue,
@@ -4240,6 +4241,9 @@ export default {
4240
4241
  mergeBy: source.mergeBy || '',
4241
4242
  narrowBy,
4242
4243
  narrowValue: narrowBy ? this.boardNarrowValue : '',
4244
+ capacityField: source.capacityField || '',
4245
+ neutralColor: typeof source.neutralColor === 'string' ? source.neutralColor : '',
4246
+ colorMap: source.colorMap && typeof source.colorMap === 'object' ? source.colorMap : null,
4243
4247
  })
4244
4248
  },
4245
4249
 
@@ -4282,6 +4286,10 @@ export default {
4282
4286
  * row (PATCH). `readOnly` gives no move. A board on `statusField` with
4283
4287
  * neither keeps the `runTransition` prop.
4284
4288
  *
4289
+ * With `source.capacityField`, a drop that would fill the referenced
4290
+ * row past its limit is refused before the handler or the PATCH runs.
4291
+ * The server still guards; this only spares the round trip.
4292
+ *
4285
4293
  * @return {((move: {card: object, toKey: string}) => Promise<object>)|null} The move, or null for a read-only board.
4286
4294
  * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference
4287
4295
  */
@@ -4303,6 +4311,7 @@ export default {
4303
4311
  const field = this.boardColumnField
4304
4312
  const kind = active?.kind || 'schema'
4305
4313
  const narrowBy = active?.source?.narrowBy || null
4314
+ const capacityField = active?.source?.capacityField || ''
4306
4315
  return async ({ card, toKey }) => {
4307
4316
  const drop = stages
4308
4317
  ? resolveDropValue({ card, toKey, kind, refsByKey: stages.refsByKey, narrowBy })
@@ -4310,6 +4319,13 @@ export default {
4310
4319
  if (drop === null) {
4311
4320
  throw new Error(t('nextcloud-vue', 'This card cannot move to that column.'))
4312
4321
  }
4322
+ const full = capacityField && drop.target
4323
+ ? fullTargetOf({ target: drop.target, card, rows: this.displayObjects, field, capacityField, rowKey: this.rowKey })
4324
+ : null
4325
+ if (full) {
4326
+ const column = stages.states.find((state) => state.key === String(toKey))?.label || String(toKey)
4327
+ throw new Error(t('nextcloud-vue', '{column} is full: {count} of {capacity}.', { column, count: full.count, capacity: full.capacity }))
4328
+ }
4313
4329
  if (handler) {
4314
4330
  return handler({ card, toKey, field, value: drop.value, target: drop.target })
4315
4331
  }
@@ -4325,9 +4341,12 @@ export default {
4325
4341
  /**
4326
4342
  * Where a card may go, from the app's `moveTargetsHandler`: it gets
4327
4343
  * `{ card, field }` and answers the values (referenced ids) the card
4328
- * can reach; the board maps them to its columns.
4344
+ * can reach; the board maps them to its columns. An entry may also be
4345
+ * `{ key, allowed, reason }`: a target that is offered but blocked,
4346
+ * with the sentence that says why.
4329
4347
  *
4330
- * @return {((card: object) => Promise<Array<string>|null>)|null} The question, or null.
4348
+ * @return {((card: object) => Promise<Array<string|{key: string, allowed: boolean, reason: string}>|null>)|null} The question, or null.
4349
+ * @spec openspec/changes/board-move-block-reasons/specs/board-view/spec.md#requirement-a-move-target-can-be-blocked-with-a-reason
4331
4350
  * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-board-shows-where-a-card-can-go
4332
4351
  */
4333
4352
  boardAllowedMoves() {
@@ -4345,9 +4364,16 @@ export default {
4345
4364
  if (!Array.isArray(values)) {
4346
4365
  return null
4347
4366
  }
4367
+ const columnOf = (id) => (stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id)
4348
4368
  return values.map((value) => {
4349
- const id = refIdOf(value)
4350
- return stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id
4369
+ if (value && typeof value === 'object' && Object.hasOwn(value, 'key')) {
4370
+ return {
4371
+ key: columnOf(refIdOf(value.key)),
4372
+ allowed: value.allowed !== false,
4373
+ reason: typeof value.reason === 'string' ? value.reason : '',
4374
+ }
4375
+ }
4376
+ return columnOf(refIdOf(value))
4351
4377
  })
4352
4378
  }
4353
4379
  },
@@ -158,6 +158,7 @@ import { useFileComments } from '../../composables/useFileComments.js'
158
158
  import { buildHeaders, prefixUrl } from '../../utils/index.js'
159
159
  import { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'
160
160
  import { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'
161
+ import { userLocale } from '../../utils/userLocale.js'
161
162
 
162
163
  /**
163
164
  * CnNotesCard — Inline notes widget for detail pages.
@@ -655,7 +656,7 @@ export default {
655
656
  return ''
656
657
  }
657
658
  try {
658
- return new Date(dateStr).toLocaleString(undefined, {
659
+ return new Date(dateStr).toLocaleString(userLocale(), {
659
660
  year: 'numeric',
660
661
  month: 'short',
661
662
  day: 'numeric',
@@ -95,6 +95,7 @@ import { translate as t } from '@nextcloud/l10n'
95
95
  import { NcButton, NcLoadingIcon } from '@nextcloud/vue'
96
96
  import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
97
97
  import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
98
+ import { userLocale } from '../../utils/userLocale.js'
98
99
 
99
100
  /**
100
101
  * CnObjectCalendar — plots objects on a month calendar by a date property.
@@ -210,7 +211,7 @@ export default {
210
211
 
211
212
  computed: {
212
213
  monthLabel() {
213
- return this.internalDate.toLocaleDateString(undefined, { month: 'long', year: 'numeric' })
214
+ return this.internalDate.toLocaleDateString(userLocale(), { month: 'long', year: 'numeric' })
214
215
  },
215
216
 
216
217
  prevMonthLabel() {
@@ -460,7 +461,7 @@ export default {
460
461
  * @return {string}
461
462
  */
462
463
  dayLabel(day) {
463
- const date = this.parseDate(day.iso).toLocaleDateString(undefined, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })
464
+ const date = this.parseDate(day.iso).toLocaleDateString(userLocale(), { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })
464
465
  return day.objects.length === 0 ? date : `${date}, ${t('nextcloud-vue', '{count} records', { count: day.objects.length })}`
465
466
  },
466
467
 
@@ -291,6 +291,14 @@
291
291
  <CnGroupNameCell :gid="gid" />
292
292
  </template>
293
293
  </span>
294
+ <!-- A Nextcloud user (or list): the display name, the
295
+ uid while it loads or when it cannot be found. -->
296
+ <span
297
+ v-else-if="isUserPicker(field) && userIdsOf(field).length"
298
+ class="cn-object-data-widget__users"
299
+ :title="userIdsOf(field).join(', ')">
300
+ {{ userIdsOf(field).map((uid) => personLabel(field, uid)).join(', ') }}
301
+ </span>
294
302
  <img v-else-if="isImageField(field) && rawOf(field)"
295
303
  :src="rawOf(field)"
296
304
  :alt="field.label"
@@ -1132,12 +1140,14 @@ export default {
1132
1140
  }
1133
1141
  // Resolve relation display names whenever the object changes.
1134
1142
  this.resolveRelations()
1143
+ this.resolveUserNames()
1135
1144
  },
1136
1145
  },
1137
1146
 
1138
1147
  schema: {
1139
1148
  handler() {
1140
1149
  this.resolveRelations()
1150
+ this.resolveUserNames()
1141
1151
  },
1142
1152
  },
1143
1153
 
@@ -1161,6 +1171,7 @@ export default {
1161
1171
 
1162
1172
  mounted() {
1163
1173
  this.resolveRelations()
1174
+ this.resolveUserNames()
1164
1175
  this.publishPanelActions()
1165
1176
  this.observeCell()
1166
1177
  this.scheduleFit()
@@ -2189,6 +2200,31 @@ export default {
2189
2200
  return list.filter((v) => typeof v === 'string' && v !== '')
2190
2201
  },
2191
2202
 
2203
+ /**
2204
+ * The uids a user field holds, for the display mode. The same list
2205
+ * shape a group field holds.
2206
+ *
2207
+ * @spec openspec/changes/a-user-field-reads-its-display-name/specs/data-display/spec.md#requirement-a-user-field-shows-the-users-display-name
2208
+ * @param {object} field Field descriptor.
2209
+ * @return {string[]}
2210
+ */
2211
+ userIdsOf(field) {
2212
+ return this.groupIdsOf(field)
2213
+ },
2214
+
2215
+ /**
2216
+ * Look up the display names of every user field's value, so the read
2217
+ * mode shows "Thomas Kuiper" rather than `thomas.kuiper`. Each uid is
2218
+ * asked once per widget.
2219
+ *
2220
+ * @spec openspec/changes/a-user-field-reads-its-display-name/specs/data-display/spec.md#requirement-a-user-field-shows-the-users-display-name
2221
+ * @return {Promise<void>}
2222
+ */
2223
+ async resolveUserNames() {
2224
+ const fields = (this.resolvedFields || []).filter((field) => this.isUserPicker(field))
2225
+ await Promise.all(fields.map((field) => this.resolvePersonLabels(field, this.rawOf(field))))
2226
+ },
2227
+
2192
2228
  /**
2193
2229
  * The display name of a group id or uid, falling back to the id.
2194
2230
  *
@@ -55,6 +55,7 @@
55
55
  <script>
56
56
  import { translatePlural as n, translate as t } from '@nextcloud/l10n'
57
57
  import { generateUrl } from '@nextcloud/router'
58
+ import { userLocale } from '../../utils/userLocale.js'
58
59
  import { CnDetailCard } from '../CnDetailCard/index.js'
59
60
  import { CnDetailGrid } from '../CnDetailGrid/index.js'
60
61
 
@@ -516,7 +517,7 @@ export default {
516
517
  if (Number.isNaN(date.getTime())) {
517
518
  return String(value)
518
519
  }
519
- return date.toLocaleDateString(undefined, {
520
+ return date.toLocaleDateString(userLocale(), {
520
521
  day: '2-digit',
521
522
  month: '2-digit',
522
523
  year: 'numeric',
@@ -530,11 +531,11 @@ export default {
530
531
  if (Number.isNaN(date.getTime())) {
531
532
  return String(value)
532
533
  }
533
- return date.toLocaleDateString(undefined, {
534
+ return date.toLocaleDateString(userLocale(), {
534
535
  day: '2-digit',
535
536
  month: '2-digit',
536
537
  year: 'numeric',
537
- }) + ', ' + date.toLocaleTimeString(undefined, {
538
+ }) + ', ' + date.toLocaleTimeString(userLocale(), {
538
539
  hour: '2-digit',
539
540
  minute: '2-digit',
540
541
  second: '2-digit',
@@ -579,7 +580,7 @@ export default {
579
580
  if (holder && hasUntil) {
580
581
  return t('nextcloud-vue', 'Locked by {user} until {date}', {
581
582
  user: holder,
582
- date: until.toLocaleString(),
583
+ date: until.toLocaleString(userLocale()),
583
584
  })
584
585
  }
585
586
 
@@ -146,6 +146,7 @@ import CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'
146
146
  import { useRestoreVersion } from '../../composables/useRestoreVersion.js'
147
147
  import { buildHeaders } from '../../utils/index.js'
148
148
  import { isLockedByCurrentUser, isObjectLocked, lockHolder } from '../../utils/objectLock.js'
149
+ import { userLocale } from '../../utils/userLocale.js'
149
150
 
150
151
  export default {
151
152
  name: 'CnAuditTrailTab',
@@ -426,7 +427,7 @@ export default {
426
427
  return ''
427
428
  }
428
429
  try {
429
- return new Date(dateStr).toLocaleString(undefined, {
430
+ return new Date(dateStr).toLocaleString(userLocale(), {
430
431
  year: 'numeric',
431
432
  month: 'short',
432
433
  day: 'numeric',
@@ -118,6 +118,7 @@ import { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js'
118
118
  import { useTaskInboxStore } from '../../composables/useTaskInboxStore.js'
119
119
  import { searchGroupSharees } from '../../utils/searchGroupSharees.js'
120
120
  import { searchNextcloudUsers } from '../../utils/userAutocomplete.js'
121
+ import { userLocale } from '../../utils/userLocale.js'
121
122
 
122
123
  /** The verbs this panel has a control for, in the order a row shows them. */
123
124
  const VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel']
@@ -239,7 +240,7 @@ export default {
239
240
  return label
240
241
  }
241
242
  const d = new Date(task.dueAt)
242
- const date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString()
243
+ const date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString(userLocale())
243
244
  return this.isOverdue(task) ? t('nextcloud-vue', 'Overdue: {date}', { date }) : date
244
245
  },
245
246
 
@@ -169,6 +169,7 @@ import { buildHeaders, prefixUrl } from '../../utils/index.js'
169
169
  import { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'
170
170
  import { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'
171
171
  import { searchNextcloudUsers } from '../../utils/userAutocomplete.js'
172
+ import { userLocale } from '../../utils/userLocale.js'
172
173
 
173
174
  export default {
174
175
  name: 'CnNotesTab',
@@ -595,7 +596,7 @@ export default {
595
596
  return ''
596
597
  }
597
598
  try {
598
- return new Date(dateStr).toLocaleString(undefined, {
599
+ return new Date(dateStr).toLocaleString(userLocale(), {
599
600
  year: 'numeric',
600
601
  month: 'short',
601
602
  day: 'numeric',
@@ -145,6 +145,7 @@ import Pencil from 'vue-material-design-icons/Pencil.vue'
145
145
  import Plus from 'vue-material-design-icons/Plus.vue'
146
146
  import CnFlowTasksPanel from './CnFlowTasksPanel.vue'
147
147
  import { buildHeaders, prefixUrl } from '../../utils/index.js'
148
+ import { userLocale } from '../../utils/userLocale.js'
148
149
 
149
150
  export default {
150
151
  name: 'CnTasksTab',
@@ -471,7 +472,7 @@ export default {
471
472
  return ''
472
473
  }
473
474
  try {
474
- return new Date(dateStr).toLocaleDateString(undefined, {
475
+ return new Date(dateStr).toLocaleDateString(userLocale(), {
475
476
  day: 'numeric',
476
477
  month: 'short',
477
478
  })
@@ -45,6 +45,7 @@ import { translate as t } from '@nextcloud/l10n'
45
45
  import { generateUrl } from '@nextcloud/router'
46
46
  import { NcSelect, NcTextField } from '@nextcloud/vue'
47
47
  import { isAppInstalled } from '../../utils/appInstalled.js'
48
+ import { userLocale } from '../../utils/userLocale.js'
48
49
 
49
50
  const BASE = '/apps/integriq/api/property-sources'
50
51
 
@@ -207,7 +208,7 @@ export default {
207
208
  methods: {
208
209
  formatTime(iso) {
209
210
  const d = new Date(iso)
210
- return Number.isNaN(d.getTime()) ? String(iso) : d.toLocaleString()
211
+ return Number.isNaN(d.getTime()) ? String(iso) : d.toLocaleString(userLocale())
211
212
  },
212
213
 
213
214
  url(path) {
@@ -83,6 +83,7 @@ import ThumbUpOutline from 'vue-material-design-icons/ThumbUpOutline.vue'
83
83
  import { cnRenderMarkdown } from '../../composables/cnRenderMarkdown.js'
84
84
  import { ROADMAP_LABEL_BLOCKLIST } from '../../utils/roadmapLabelBlocklist.js'
85
85
  import { safeHref } from '../../utils/safeHref.js'
86
+ import { userLocale } from '../../utils/userLocale.js'
86
87
 
87
88
  export default {
88
89
  name: 'CnRoadmapItem',
@@ -138,7 +139,7 @@ export default {
138
139
  if (diffSec < 2592000) {
139
140
  return `${Math.floor(diffSec / 86400)}d`
140
141
  }
141
- return created.toLocaleDateString()
142
+ return created.toLocaleDateString(userLocale())
142
143
  },
143
144
  },
144
145
 
@@ -57,11 +57,11 @@
57
57
  </div>
58
58
  <div v-if="schemaItem.created" class="cn-schema-form__detail-item">
59
59
  <span class="cn-schema-form__detail-label">{{ t('nextcloud-vue', 'Created:') }}</span>
60
- <span class="cn-schema-form__detail-value">{{ new Date(schemaItem.created).toLocaleString() }}</span>
60
+ <span class="cn-schema-form__detail-value">{{ new Date(schemaItem.created).toLocaleString(userLocale()) }}</span>
61
61
  </div>
62
62
  <div v-if="schemaItem.updated" class="cn-schema-form__detail-item">
63
63
  <span class="cn-schema-form__detail-label">{{ t('nextcloud-vue', 'Updated:') }}</span>
64
- <span class="cn-schema-form__detail-value">{{ new Date(schemaItem.updated).toLocaleString() }}</span>
64
+ <span class="cn-schema-form__detail-value">{{ new Date(schemaItem.updated).toLocaleString(userLocale()) }}</span>
65
65
  </div>
66
66
  <div class="cn-schema-form__detail-item">
67
67
  <span class="cn-schema-form__detail-label">{{ t('nextcloud-vue', 'Version:') }}</span>
@@ -204,6 +204,7 @@ import CnSchemaConfigurationTab from './CnSchemaConfigurationTab.vue'
204
204
  import CnSchemaPropertiesTab from './CnSchemaPropertiesTab.vue'
205
205
  import CnSchemaSecurityTab from './CnSchemaSecurityTab.vue'
206
206
  import { dialogBoardMixin } from '../../mixins/dialogBoard.js'
207
+ import { userLocale } from '../../utils/userLocale.js'
207
208
 
208
209
  /**
209
210
  * CnSchemaFormDialog — Generic JSON Schema editor dialog.
@@ -552,6 +553,7 @@ export default {
552
553
 
553
554
  methods: {
554
555
  t,
556
+ userLocale,
555
557
  findSchemaBySlug(schemaSlug) {
556
558
  if (!schemaSlug) {
557
559
  return undefined