@conduction/nextcloud-vue 2.79.0 → 2.81.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 (390) hide show
  1. package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
  2. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +3 -1
  3. package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +32 -3
  5. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +13 -11
  7. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +80 -4
  9. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  10. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +95 -91
  11. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  12. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +179 -13
  13. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +52 -16
  15. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  16. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +96 -4
  17. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  18. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +158 -110
  19. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  20. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
  21. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
  22. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
  23. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
  24. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
  25. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
  26. package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
  27. package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
  28. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
  29. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
  30. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
  31. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
  32. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
  33. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
  34. package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
  35. package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
  36. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +1 -1
  37. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +2 -2
  40. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  41. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  42. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +65 -5
  43. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  44. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
  45. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +19 -11
  47. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  48. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +4 -2
  49. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  50. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +134 -4
  51. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  52. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +21 -4
  53. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  54. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +24 -0
  55. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  56. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +43 -4
  57. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  58. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +1 -1
  59. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -1
  60. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js +7 -7
  62. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js.map +1 -1
  63. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue3.js.map +1 -1
  64. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +11 -0
  65. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js.map +1 -0
  66. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +867 -0
  67. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -0
  68. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +238 -0
  69. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -0
  70. package/dist/esm/components/CnFactsWidget/index.js +30 -0
  71. package/dist/esm/components/CnFactsWidget/index.js.map +1 -0
  72. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +10 -0
  73. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js.map +1 -0
  74. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +626 -0
  75. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -0
  76. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +396 -0
  77. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -0
  78. package/dist/esm/components/CnFieldListWidget/index.js +29 -0
  79. package/dist/esm/components/CnFieldListWidget/index.js.map +1 -0
  80. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +302 -4
  81. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  82. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +417 -244
  83. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  84. package/dist/esm/components/CnFilesBrowser/filesBrowser.js +101 -1
  85. package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
  86. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +141 -1
  87. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
  88. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +65 -17
  89. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  90. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +4 -4
  91. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  92. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +78 -3
  93. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
  94. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js +74 -49
  95. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
  96. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +333 -73
  97. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  98. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +79 -17
  99. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  100. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +10 -0
  101. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js.map +1 -0
  102. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +99 -0
  103. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -0
  104. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +48 -0
  105. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -0
  106. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +7 -7
  107. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  108. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  109. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +1 -1
  110. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -1
  111. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
  112. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  113. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
  114. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  115. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +63 -1
  116. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  117. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +8 -1
  118. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  119. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +14 -0
  120. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  121. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js +5 -1
  122. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  123. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js +29 -1
  124. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  125. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  126. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
  127. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
  128. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
  129. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
  130. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
  131. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
  132. package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
  133. package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
  134. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +10 -0
  135. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js.map +1 -0
  136. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +411 -0
  137. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -0
  138. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +178 -0
  139. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -0
  140. package/dist/esm/components/CnRecordListWidget/index.js +31 -0
  141. package/dist/esm/components/CnRecordListWidget/index.js.map +1 -0
  142. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
  143. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
  144. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
  145. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
  146. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
  147. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
  148. package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
  149. package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
  150. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +10 -0
  151. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js.map +1 -0
  152. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +351 -0
  153. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -0
  154. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +71 -0
  155. package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -0
  156. package/dist/esm/components/CnSectionsWidget/index.js +35 -0
  157. package/dist/esm/components/CnSectionsWidget/index.js.map +1 -0
  158. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  159. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  160. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
  161. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
  162. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
  163. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
  164. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
  165. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
  166. package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
  167. package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
  168. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +81 -2
  169. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  170. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  171. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
  172. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  173. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +1 -0
  174. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  175. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +84 -1
  176. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  177. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +85 -41
  178. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  179. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
  180. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
  181. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
  182. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
  183. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
  184. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
  185. package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
  186. package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
  187. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +168 -7
  188. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  189. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +86 -23
  190. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  191. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
  192. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  193. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
  194. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  195. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
  196. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
  197. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
  198. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
  199. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
  200. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
  201. package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
  202. package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
  203. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
  204. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  205. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +7 -2
  206. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  207. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  208. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  209. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js.map +1 -1
  210. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +301 -6
  211. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  212. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +153 -55
  213. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  214. package/dist/esm/composables/useFormDraft.js +140 -9
  215. package/dist/esm/composables/useFormDraft.js.map +1 -1
  216. package/dist/esm/composables/useListView.js +4 -4
  217. package/dist/esm/composables/useListView.js.map +1 -1
  218. package/dist/esm/index.js +21 -1
  219. package/dist/esm/index.js.map +1 -1
  220. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +28 -20
  221. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
  222. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js +9 -0
  223. package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
  224. package/dist/esm/integrations/builtin/field-inspection.js +21 -0
  225. package/dist/esm/integrations/builtin/field-inspection.js.map +1 -1
  226. package/dist/esm/integrations/offline/checklistSubmission.js +141 -0
  227. package/dist/esm/integrations/offline/checklistSubmission.js.map +1 -0
  228. package/dist/esm/integrations/offline/fieldCollectionHelpers.js +70 -5
  229. package/dist/esm/integrations/offline/fieldCollectionHelpers.js.map +1 -1
  230. package/dist/esm/integrations/offline/index.js +2 -1
  231. package/dist/esm/integrations/offline/index.js.map +1 -1
  232. package/dist/esm/integrations/offline/offlineDb.js +6 -1
  233. package/dist/esm/integrations/offline/offlineDb.js.map +1 -1
  234. package/dist/esm/integrations/offline/syncReplayService.js +8 -2
  235. package/dist/esm/integrations/offline/syncReplayService.js.map +1 -1
  236. package/dist/esm/l10n/en.json.js +20 -1
  237. package/dist/esm/l10n/en.json.js.map +1 -1
  238. package/dist/esm/l10n/nl.json.js +70 -2
  239. package/dist/esm/l10n/nl.json.js.map +1 -1
  240. package/dist/esm/nextcloud-vue.css +2192 -222
  241. package/dist/esm/utils/contentHeaderLink.js +51 -0
  242. package/dist/esm/utils/contentHeaderLink.js.map +1 -0
  243. package/dist/esm/utils/detailActionModel.js +60 -3
  244. package/dist/esm/utils/detailActionModel.js.map +1 -1
  245. package/dist/esm/utils/facets.js +75 -3
  246. package/dist/esm/utils/facets.js.map +1 -1
  247. package/dist/esm/utils/fetchFilterCounts.js +40 -5
  248. package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
  249. package/dist/esm/utils/fillTemplate.js +120 -0
  250. package/dist/esm/utils/fillTemplate.js.map +1 -0
  251. package/dist/esm/utils/initials.js +32 -0
  252. package/dist/esm/utils/initials.js.map +1 -0
  253. package/dist/esm/utils/libraryWidgetKeys.js +11 -0
  254. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  255. package/dist/esm/utils/objectWrite.js +59 -0
  256. package/dist/esm/utils/objectWrite.js.map +1 -0
  257. package/dist/esm/utils/pageControls.js +81 -0
  258. package/dist/esm/utils/pageControls.js.map +1 -0
  259. package/dist/esm/utils/personalLenses.js +40 -3
  260. package/dist/esm/utils/personalLenses.js.map +1 -1
  261. package/dist/esm/utils/queryPresets.js +96 -0
  262. package/dist/esm/utils/queryPresets.js.map +1 -0
  263. package/dist/esm/utils/resolveFilterTokens.js +12 -1
  264. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  265. package/dist/esm/utils/resolveManifestTokens.js +2 -0
  266. package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
  267. package/dist/esm/utils/schema.js +21 -0
  268. package/dist/esm/utils/schema.js.map +1 -1
  269. package/dist/esm/utils/sentinelTokens.js +22 -4
  270. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  271. package/dist/esm/utils/userGroupsPeek.js +91 -0
  272. package/dist/esm/utils/userGroupsPeek.js.map +1 -0
  273. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  274. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  275. package/dist/esm/utils/visibleWhen.js +57 -5
  276. package/dist/esm/utils/visibleWhen.js.map +1 -1
  277. package/dist/esm/utils/widgetDispatch.js +7 -1
  278. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  279. package/dist/esm/utils/widgetVisibility.js +4 -57
  280. package/dist/esm/utils/widgetVisibility.js.map +1 -1
  281. package/dist/nextcloud-vue.cjs.js +19708 -9301
  282. package/dist/nextcloud-vue.cjs.js.map +2 -2
  283. package/dist/nextcloud-vue.css +2192 -222
  284. package/l10n/en.json +20 -1
  285. package/l10n/nl.json +70 -2
  286. package/package.json +2 -1
  287. package/scripts/check-docs-mdx.mjs +108 -0
  288. package/src/components/CnActionButtons/CnActionButtons.vue +2 -0
  289. package/src/components/CnActionsBar/CnActionsBar.md +4 -0
  290. package/src/components/CnActionsBar/CnActionsBar.vue +48 -11
  291. package/src/components/CnAppRoot/CnAppRoot.md +4 -2
  292. package/src/components/CnAppRoot/CnAppRoot.vue +151 -59
  293. package/src/components/CnBannerWidget/CnBannerWidget.vue +244 -23
  294. package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
  295. package/src/components/CnCellRenderer/CnCellRenderer.vue +235 -5
  296. package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
  297. package/src/components/CnChipsFieldWidget/index.js +25 -0
  298. package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
  299. package/src/components/CnChoicePickerWidget/index.js +26 -0
  300. package/src/components/CnConversationThread/CnConversationWidget.vue +1 -1
  301. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +2 -2
  302. package/src/components/CnDashboardPage/CnDashboardPage.vue +78 -5
  303. package/src/components/CnDataTable/CnDataTable.vue +22 -12
  304. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  305. package/src/components/CnDetailPage/CnDetailPage.vue +152 -6
  306. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +66 -0
  307. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +1 -1
  308. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +7 -7
  309. package/src/components/CnFactsWidget/CnFactsWidget.vue +1190 -0
  310. package/src/components/CnFactsWidget/index.js +29 -0
  311. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +1008 -0
  312. package/src/components/CnFieldListWidget/index.js +28 -0
  313. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +588 -117
  314. package/src/components/CnFilesBrowser/filesBrowser.js +100 -0
  315. package/src/components/CnFilesBrowser/filesBrowserColumns.js +140 -0
  316. package/src/components/CnFormDialog/CnFormDialog.md +9 -3
  317. package/src/components/CnFormDialog/CnFormDialog.vue +69 -21
  318. package/src/components/CnFormPage/CnFormPage.vue +99 -3
  319. package/src/components/CnIndexPage/CnIndexPage.vue +309 -9
  320. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +169 -0
  321. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +7 -7
  322. package/src/components/CnNextStepCard/CnNextStepWidget.vue +1 -1
  323. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
  324. package/src/components/CnObjectSidebar/CnFilesTab.vue +70 -1
  325. package/src/components/CnObjectSidebar/CnNotesTab.vue +16 -0
  326. package/src/components/CnPageRenderer/CnPageRenderer.vue +29 -1
  327. package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
  328. package/src/components/CnRadioCardsWidget/index.js +27 -0
  329. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +652 -0
  330. package/src/components/CnRecordListWidget/index.js +30 -0
  331. package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
  332. package/src/components/CnSavedViewsWidget/index.js +29 -0
  333. package/src/components/CnSectionsWidget/CnSectionsWidget.vue +489 -0
  334. package/src/components/CnSectionsWidget/index.js +34 -0
  335. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
  336. package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
  337. package/src/components/CnSettingsFormWidget/index.js +26 -0
  338. package/src/components/CnStagesWidget/CnStagesWidget.vue +81 -2
  339. package/src/components/CnStatWidget/CnStatWidget.vue +88 -7
  340. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +180 -3
  341. package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
  342. package/src/components/CnSwitchRowsWidget/index.js +25 -0
  343. package/src/components/CnTabsWidget/CnTabsWidget.vue +263 -8
  344. package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
  345. package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
  346. package/src/components/CnToggleTableWidget/index.js +26 -0
  347. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
  348. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +7 -2
  349. package/src/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  350. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +493 -11
  351. package/src/components/index.js +19 -0
  352. package/src/composables/__tests__/useFormDraft.spec.js +69 -0
  353. package/src/composables/useFormDraft.js +139 -8
  354. package/src/composables/useListView.js +4 -4
  355. package/src/css/form-field.css +14 -0
  356. package/src/css/index-page.css +71 -0
  357. package/src/css/kpi-card.css +32 -0
  358. package/src/css/look-board-detail.css +113 -2
  359. package/src/css/look-board-index.css +90 -8
  360. package/src/css/look-board.css +109 -2
  361. package/src/css/table.css +19 -0
  362. package/src/index.js +19 -0
  363. package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +35 -20
  364. package/src/integrations/builtin/field-inspection.js +21 -0
  365. package/src/integrations/offline/checklistSubmission.js +137 -0
  366. package/src/integrations/offline/fieldCollectionHelpers.js +69 -4
  367. package/src/integrations/offline/index.js +3 -0
  368. package/src/integrations/offline/offlineDb.js +6 -1
  369. package/src/integrations/offline/syncReplayService.js +8 -2
  370. package/src/schemas/app-manifest-v2.schema.json +196 -13
  371. package/src/utils/contentHeaderLink.js +48 -0
  372. package/src/utils/detailActionModel.js +59 -2
  373. package/src/utils/facets.js +74 -2
  374. package/src/utils/fetchFilterCounts.js +39 -4
  375. package/src/utils/fillTemplate.js +116 -0
  376. package/src/utils/initials.js +29 -0
  377. package/src/utils/libraryWidgetKeys.js +11 -0
  378. package/src/utils/objectWrite.js +55 -0
  379. package/src/utils/pageControls.js +78 -0
  380. package/src/utils/personalLenses.js +39 -2
  381. package/src/utils/queryPresets.js +93 -0
  382. package/src/utils/resolveFilterTokens.js +14 -1
  383. package/src/utils/resolveManifestTokens.js +2 -0
  384. package/src/utils/schema.js +21 -0
  385. package/src/utils/sentinelTokens.js +22 -4
  386. package/src/utils/userGroupsPeek.js +87 -0
  387. package/src/utils/validateManifestV2.compiled.js +3 -3
  388. package/src/utils/visibleWhen.js +56 -4
  389. package/src/utils/widgetDispatch.js +7 -1
  390. package/src/utils/widgetVisibility.js +7 -56
@@ -452,6 +452,7 @@
452
452
  :layout="section.layout"
453
453
  :editable="section.editable"
454
454
  :columns="columns"
455
+ :columnOpts="gridColumnOpts"
455
456
  :cellHeight="cellHeight"
456
457
  :margin="gridMargin"
457
458
  :float="gridFloat"
@@ -933,7 +934,8 @@ import { normalizeLook } from '../../composables/useLook.js'
933
934
  import { pageViews } from '../../mixins/pageViews.js'
934
935
  import { mergeUserLayout, resolveUserLayoutApi } from '../../store/plugins/dashboardLayouts.js'
935
936
  import { isAppInstalled } from '../../utils/appInstalled.js'
936
- import { compareVisibleWhen, readVisibleWhenValue } from '../../utils/visibleWhen.js'
937
+ import { contentHeaderLink } from '../../utils/contentHeaderLink.js'
938
+ import { compareVisibleWhen, evaluateWorkspaceCondition, isWorkspaceCondition, readVisibleWhenValue } from '../../utils/visibleWhen.js'
937
939
  import { canonicalWidgetType } from '../../utils/widgetTypeAliases.js'
938
940
  import { CnActionButtons } from '../CnActionButtons/index.js'
939
941
  import { CnActionsMenu } from '../CnActionsMenu/index.js'
@@ -2082,6 +2084,22 @@ export default {
2082
2084
  return this.compactDisplayLayout(visible)
2083
2085
  },
2084
2086
 
2087
+ /**
2088
+ * The responsive columns of the grid. Under the board look a phone gets
2089
+ * one column: below 640px the widgets stack in reading order (top to
2090
+ * bottom, then left to right) instead of squeezing six columns into
2091
+ * 150px. Without the board look the grid keeps its fixed columns.
2092
+ *
2093
+ * @return {object|null} GridStack `columnOpts`, or null.
2094
+ * @spec openspec/changes/screens-dashboard-phone/specs/dashboard-phone/spec.md#requirement-a-board-dashboard-stacks-on-a-phone
2095
+ */
2096
+ gridColumnOpts() {
2097
+ if (!this.isBoardLook) {
2098
+ return null
2099
+ }
2100
+ return { columnMax: this.columns, breakpoints: [{ w: 640, c: 1 }], layout: 'list', breakpointForWindow: true }
2101
+ },
2102
+
2085
2103
  /**
2086
2104
  * The layout this page renders: the user's arrangement when they have
2087
2105
  * one, the manifest otherwise.
@@ -2256,6 +2274,10 @@ export default {
2256
2274
  const items = []
2257
2275
  for (const id of ids) {
2258
2276
  if (this.getWidgetDef(id) || this.hasWidgetSlot(id)) {
2277
+ // A tile a page control hides surrenders its cell.
2278
+ if (!this.gridEditable && this.isHiddenByWorkspace(id)) {
2279
+ continue
2280
+ }
2259
2281
  items.push({ widgetId: id })
2260
2282
  } else if (process.env.NODE_ENV !== 'production') {
2261
2283
  // eslint-disable-next-line no-console
@@ -3401,7 +3423,8 @@ export default {
3401
3423
  const layout = content.layout || props.layout || ''
3402
3424
  const title = layout === 'attention' ? (content.title || props.title || '') : ''
3403
3425
  return {
3404
- text: content.text || props.text || title || '',
3426
+ // A banner with only a bold `lead` has words to show too.
3427
+ text: content.text || props.text || content.lead || props.lead || title || '',
3405
3428
  visibleWhen: (def && def.visibleWhen) || content.visibleWhen || props.visibleWhen || null,
3406
3429
  layout,
3407
3430
  }
@@ -3435,6 +3458,11 @@ export default {
3435
3458
  if (!visibleWhen) {
3436
3459
  return false
3437
3460
  }
3461
+ // A workspace condition (a page control's choice) is answered at
3462
+ // once from the reactive bag; nothing is fetched for it.
3463
+ if (isWorkspaceCondition(visibleWhen)) {
3464
+ return !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)
3465
+ }
3438
3466
  const outcome = this.widgetConditionOutcome[item.widgetId]
3439
3467
  if (outcome && outcome.failed === true && layout === 'attention' && this.isBannerDef(def)) {
3440
3468
  return false
@@ -3442,6 +3470,23 @@ export default {
3442
3470
  return !outcome || outcome.met !== true
3443
3471
  },
3444
3472
 
3473
+ /**
3474
+ * Whether a page control (a workspace condition on `visibleWhen`)
3475
+ * hides this widget right now. Other conditions are not looked at.
3476
+ *
3477
+ * @param {string} widgetId The widget id.
3478
+ * @return {boolean} True when the widget must not draw.
3479
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-widget-can-be-shown-by-a-workspace-value
3480
+ */
3481
+ isHiddenByWorkspace(widgetId) {
3482
+ const def = this.getWidgetDef(widgetId)
3483
+ if (!def || !def.type) {
3484
+ return false
3485
+ }
3486
+ const { visibleWhen } = this.widgetDisplayConfig(def)
3487
+ return isWorkspaceCondition(visibleWhen) && !evaluateWorkspaceCondition(visibleWhen, this.workspaceContext)
3488
+ },
3489
+
3445
3490
  /**
3446
3491
  * Evaluate every conditional widget's `visibleWhen` into
3447
3492
  * `widgetConditionOutcome` — the verdict AND the raw field value,
@@ -3464,7 +3509,8 @@ export default {
3464
3509
  async evaluateWidgetConditions() {
3465
3510
  const defs = [...(this.widgets || []), ...this.normalizedViews.flatMap((view) => view.widgets)]
3466
3511
  const conditional = defs.filter((def) => def && def.id && def.type
3467
- && this.widgetDisplayConfig(def).visibleWhen)
3512
+ && this.widgetDisplayConfig(def).visibleWhen
3513
+ && !isWorkspaceCondition(this.widgetDisplayConfig(def).visibleWhen))
3468
3514
  // Skip when the CONDITIONAL SET is unchanged: the deep `widgets`
3469
3515
  // watch fires on any def edit, but only an added/removed/edited
3470
3516
  // predicate warrants refetching every conditional endpoint.
@@ -3484,8 +3530,13 @@ export default {
3484
3530
  const cond = this.widgetDisplayConfig(def).visibleWhen
3485
3531
  let outcome
3486
3532
  try {
3487
- const value = await readVisibleWhenValue(cond)
3533
+ // `sink` keeps the first row of a source query, for a banner that names it.
3534
+ const sink = {}
3535
+ const value = await readVisibleWhenValue(cond, undefined, sink)
3488
3536
  outcome = { met: compareVisibleWhen(value, cond.op || 'eq', cond.value), value }
3537
+ if (sink.row) {
3538
+ outcome.row = sink.row
3539
+ }
3489
3540
  } catch (error) {
3490
3541
  // Fail-safe: not met. But the failure is kept, and said
3491
3542
  // out loud: a failed count and "nothing to report" look
@@ -3985,6 +4036,11 @@ export default {
3985
4036
  const def = this.getWidgetDef(item.widgetId)
3986
4037
  const value = item.showTitle !== undefined ? item.showTitle : def?.showTitle
3987
4038
  if (value === undefined || value === null) {
4039
+ // A banner that names no title draws no title row: it used to show
4040
+ // its widget id ("attention-first") as the card title.
4041
+ if (this.isBannerDef(def) && !item.customTitle && !def?.customTitle && !def?.title) {
4042
+ return false
4043
+ }
3988
4044
  return !this.isCardWidget(item)
3989
4045
  }
3990
4046
  return value !== false
@@ -4093,7 +4149,12 @@ export default {
4093
4149
  return item.headerLink
4094
4150
  }
4095
4151
  const def = this.getWidgetDef(item.widgetId)
4096
- return (def?.headerLink && typeof def.headerLink === 'object') ? def.headerLink : null
4152
+ if (def?.headerLink && typeof def.headerLink === 'object') {
4153
+ return def.headerLink
4154
+ }
4155
+ // Last, what the widget's own content asks for (`headerLink`, or the
4156
+ // `viewAllRoute` / `viewAllLabel` of the tasks widget).
4157
+ return contentHeaderLink(item?.content) || contentHeaderLink(def?.content)
4097
4158
  },
4098
4159
 
4099
4160
  /**
@@ -4842,6 +4903,18 @@ export default {
4842
4903
  .cn-dashboard-page__content-item {
4843
4904
  width: 100%;
4844
4905
  }
4906
+ /* On a phone (screens-dashboard-phone) the touch targets of a board dashboard
4907
+ are 44px: the widget Actions menu and the KPI tiles. */
4908
+ @media (max-width: 640px) {
4909
+ .cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .action-item__menutoggle),
4910
+ .cn-dashboard-page--board :deep(.cn-widget-wrapper__actions .button-vue) {
4911
+ min-height: 44px;
4912
+ }
4913
+
4914
+ .cn-dashboard-page--board .cn-dashboard-page__kpi-cell {
4915
+ min-height: 44px;
4916
+ }
4917
+ }
4845
4918
  </style>
4846
4919
 
4847
4920
  <!-- Unscoped, anchored on the stable `data-testid` NcActions renders on both
@@ -130,6 +130,7 @@
130
130
  col.class || '',
131
131
  pinClass(leadingCount + colIndex),
132
132
  isGrowColumn(col) ? 'cn-table-col--grow' : '',
133
+ colIndex === 0 ? 'cn-table-head--title' : '',
133
134
  ]"
134
135
  :style="{ ...(col.width ? { width: col.width } : {}), ...pinStyle(leadingCount + colIndex) }"
135
136
  :aria-sort="ariaSortFor(col)"
@@ -320,6 +321,7 @@
320
321
  :formatterOptions="col.formatterOptions || null"
321
322
  :widget="col.widget || null"
322
323
  :widgetProps="col.widgetProps || undefined"
324
+ :secondary="col.widget === 'avatar' ? secondaryValue(row, col) : ''"
323
325
  :format="columnFormat(col)"
324
326
  :row="row"
325
327
  :rowKey="rowKey" />
@@ -329,7 +331,7 @@
329
331
  of the row. Lets one column read "title" over "number ·
330
332
  requester" without a custom cell. -->
331
333
  <span
332
- v-if="secondaryValue(row, col)"
334
+ v-if="col.widget !== 'avatar' && secondaryValue(row, col)"
333
335
  class="cn-table-cell__secondary"
334
336
  data-testid="cn-cell-secondary">{{ secondaryValue(row, col) }}</span>
335
337
  <!-- A row that entered a file-content search through an attached
@@ -1764,17 +1766,6 @@ export default {
1764
1766
  return (col && typeof col.format === 'object') ? col.format : null
1765
1767
  },
1766
1768
 
1767
- /**
1768
- * Value to render in a cell. For a column that declares `aggregate`
1769
- * (a count of related objects), returns the cached count once
1770
- * `loadAggregates()` has resolved it (or `'…'` while pending, `'—'`
1771
- * if it failed / there's nothing to count). Otherwise the row's
1772
- * property value via `getCellValue`.
1773
- *
1774
- * @param {object} row The row data.
1775
- * @param {object} col The column definition.
1776
- * @return {unknown} The value handed to the slot / CnCellRenderer.
1777
- */
1778
1769
  /**
1779
1770
  * The secondary line of a cell, from `col.secondary`: a function is
1780
1771
  * called with the row; a string with `{field}` placeholders is a
@@ -1805,6 +1796,21 @@ export default {
1805
1796
  return asText(this.getCellValue(row, spec))
1806
1797
  },
1807
1798
 
1799
+ /**
1800
+ * Value to render in a cell. For a column that declares `aggregate`
1801
+ * (a count of related objects), returns the cached count once
1802
+ * `loadAggregates()` has resolved it (or `'…'` while pending, `'—'`
1803
+ * if it failed / there's nothing to count). A count of zero reads as
1804
+ * `aggregate.zeroLabel` when the column sets one ("None", which the
1805
+ * app's `cnTranslate` turns into "Geen" as the boards draw it); without
1806
+ * it the cell shows `0` as before. Otherwise the row's property value
1807
+ * via `getCellValue`.
1808
+ *
1809
+ * @spec openspec/changes/aggregate-zero-label/specs/aggregate-zero-label/spec.md#requirement-a-count-column-can-name-zero
1810
+ * @param {object} row The row data.
1811
+ * @param {object} col The column definition.
1812
+ * @return {unknown} The value handed to the slot / CnCellRenderer.
1813
+ */
1808
1814
  cellValue(row, col) {
1809
1815
  if (col && col.aggregate) {
1810
1816
  const cached = this.aggregateValues[String(row[this.rowKey])]
@@ -1812,6 +1818,10 @@ export default {
1812
1818
  if (v === undefined) {
1813
1819
  return this.aggregateLoading ? '…' : '—'
1814
1820
  }
1821
+ const zeroLabel = col.aggregate.zeroLabel
1822
+ if ((v === 0 || v === '0') && typeof zeroLabel === 'string' && zeroLabel !== '') {
1823
+ return typeof this.cnTranslate === 'function' ? this.cnTranslate(zeroLabel) : zeroLabel
1824
+ }
1815
1825
  return v
1816
1826
  }
1817
1827
  return this.getCellValue(row, col.key)
@@ -422,7 +422,7 @@ Four levels of action and the case surfaces around them. All opt in. See [the re
422
422
  | `quickActions` | Array | `[]` | At most three always visible header buttons. |
423
423
  | `actionsMenu` | Object \| null | `null` | `{ showRefresh?, showHelpLinks?, label? }` for the overflow menu. |
424
424
  | `nextStep` | Object \| null | `null` | The "what now" card per stage, rendered by `CnNextStepCard`. |
425
- | `typePill` | Object \| null | `null` | `{ field, colorMap?, labels?, variant? }`, a pill above the title. |
425
+ | `typePill` | Object \| null | `null` | `{ field, colorMap?, labels?, variant? }`, a pill above the title. Instead of `field`: `text` (a constant) or `countFrom` + `countLabel` (a count of a related list). |
426
426
  | `statusPill` | Object \| null | `null` | A second pill, same shape. |
427
427
  | `headerFields` | Array | `[]` | Fields shown as chips under the title (manifest `config.headerFields`). Each entry is a property key, or `{ key, format, labelField, colorField, warnWhenPast }`; `format` is `text` (default), `mono`, `badge`, `user` or `date`. A `$ref` value shows `labelField` of the referenced object and falls back to the raw id in mono; a badge maps `colorField` (`success`, `warning`, `error`, `info`, `neutral`) to a variant; `warnWhenPast` gives a past date the error variant. An empty value shows no chip, a page without the key shows no row. Each chip reads "Title: value" to a screen reader, and the row prints as plain text. |
428
428
  | `sideColumn` | Array | `[]` | Widget definitions or widget ids, rendered as a column of cards beside the body. |
@@ -379,7 +379,7 @@
379
379
  :showDocumentation="showDocumentation && menuShowsHelpLinks"
380
380
  :actionsMenuLabel="boardMenuLabel"
381
381
  :variant="isBoard ? 'secondary' : undefined"
382
- :hasPrimaryItems="headerMenuGroups.length > 0 || showMarkUnread"
382
+ :hasPrimaryItems="headerMenuGroups.length > 0 || showMarkUnread || showOpenSidebar"
383
383
  :documentationUrl="documentationUrl"
384
384
  :docsAnchor="resolvedPageId"
385
385
  :documentationLabel="documentationLabel || undefined"
@@ -390,7 +390,7 @@
390
390
  testidBase="cn-detail-page"
391
391
  @refresh="onHeaderRefresh"
392
392
  @requestFeature="onHeaderRequestFeature">
393
- <template v-if="headerMenuGroups.length || showMarkUnread" #primary-items>
393
+ <template v-if="headerMenuGroups.length || showMarkUnread || showOpenSidebar" #primary-items>
394
394
  <!-- One block per group. A page that groups nothing has
395
395
  a single captionless group, and renders exactly the
396
396
  flat list it always did. -->
@@ -449,6 +449,20 @@
449
449
  </template>
450
450
  {{ markUnreadLabel }}
451
451
  </NcActionButton>
452
+ <!-- Board look: the sidebar's own open toggle is hidden (it sat
453
+ over the header's last button, where the board draws none), so
454
+ the menu opens it. -->
455
+ <NcActionButton
456
+ v-if="showOpenSidebar"
457
+ key="open-sidebar"
458
+ data-testid="cn-detail-page-open-sidebar"
459
+ :closeAfterClick="true"
460
+ @click="openSidebar">
461
+ <template #icon>
462
+ <DockRight :size="20" />
463
+ </template>
464
+ {{ openSidebarLabel }}
465
+ </NcActionButton>
452
466
  <!-- Divides the page's own actions from the help links
453
467
  below. With the help links switched off there is
454
468
  nothing below to divide from. -->
@@ -745,7 +759,7 @@
745
759
  :layout="section.layout"
746
760
  :editable="section.editable"
747
761
  :columns="12"
748
- :columnOpts="columnOpts"
762
+ :columnOpts="bodyColumnOpts"
749
763
  class="cn-detail-page__grid"
750
764
  @layoutChange="section.view ? onViewLayoutChange($event) : onBodyLayoutChange($event)">
751
765
  <template #widget="{ item }">
@@ -1191,6 +1205,7 @@ import Check from 'vue-material-design-icons/Check.vue'
1191
1205
  import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
1192
1206
  import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
1193
1207
  import Cog from 'vue-material-design-icons/Cog.vue'
1208
+ import DockRight from 'vue-material-design-icons/DockRight.vue'
1194
1209
  import EyeOffOutline from 'vue-material-design-icons/EyeOffOutline.vue'
1195
1210
  import FileQuestionOutline from 'vue-material-design-icons/FileQuestionOutline.vue'
1196
1211
  import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
@@ -1231,12 +1246,15 @@ import {
1231
1246
  groupMenuEntries,
1232
1247
  MAX_QUICK_ACTIONS,
1233
1248
  normalisePinnedAction,
1249
+ pillCountSource,
1250
+ resolveCountPill,
1234
1251
  resolveNextStep,
1235
1252
  resolvePill,
1236
1253
  stageEntry,
1237
1254
  stageOf,
1238
1255
  } from '../../utils/detailActionModel.js'
1239
1256
  import { reportBindingProblems } from '../../utils/diagnostics.js'
1257
+ import { fetchListTotal } from '../../utils/fetchFilterCounts.js'
1240
1258
  import { cnGridCellStyle, hasGridRow } from '../../utils/grid.js'
1241
1259
  import { isActivityWidget, resolveHeaderMeta } from '../../utils/headerMeta.js'
1242
1260
  import { patchStoredSelf } from '../../utils/patchStoredSelf.js'
@@ -1292,6 +1310,35 @@ const DEFAULT_DETAIL_COLUMN_OPTS = Object.freeze({
1292
1310
  breakpointForWindow: false,
1293
1311
  })
1294
1312
 
1313
+ /**
1314
+ * Where the default table stacks when a side column sits beside the body grid.
1315
+ *
1316
+ * The side column takes about 320px, so the grid it leaves is far narrower than
1317
+ * the page: 790px at a 1100px window. Stacking that at 1000px made a row of
1318
+ * small tiles (a KPI row of 5 or 6 stat tiles) impossible beside a side column.
1319
+ * 1000px exists to keep a `gridWidth: 3` side PANEL inside the grid readable; a
1320
+ * page with a real side column has no such panel, and 12 columns at 600px is
1321
+ * still 50px a column, enough for a tile. Below 600px it stacks as before.
1322
+ */
1323
+ const SIDE_COLUMN_STACK_WIDTH = 600
1324
+
1325
+ /**
1326
+ * Whether `opts` is the untouched default table, so a page that passed its own
1327
+ * `columnOpts` keeps exactly what it asked for.
1328
+ *
1329
+ * @param {object|null} opts The `columnOpts` value.
1330
+ * @return {boolean}
1331
+ */
1332
+ function isDefaultColumnOpts(opts) {
1333
+ const breakpoints = opts && opts.breakpoints
1334
+ return !!opts
1335
+ && opts.columnMax === DEFAULT_DETAIL_COLUMN_OPTS.columnMax
1336
+ && Array.isArray(breakpoints)
1337
+ && breakpoints.length === 1
1338
+ && breakpoints[0].w === DEFAULT_DETAIL_COLUMN_OPTS.breakpoints[0].w
1339
+ && breakpoints[0].c === 1
1340
+ }
1341
+
1295
1342
  /**
1296
1343
  * Event-bus channel a page-level refresh is announced on. The page's own
1297
1344
  * Actions menu emits it, the manifest `refresh` / `api-call` actions bump it,
@@ -1408,6 +1455,7 @@ export default {
1408
1455
  CnSummaryAggregates,
1409
1456
  CnDetailHeaderChips,
1410
1457
  CnFollowToggle,
1458
+ DockRight,
1411
1459
  EyeOffOutline,
1412
1460
  CnRelatedCollections,
1413
1461
  CnBodySections,
@@ -2393,9 +2441,13 @@ export default {
2393
2441
  * A pill above the title saying what kind of record this is
2394
2442
  * (manifest `config.typePill`): `{ field, colorMap?, labels?, variant? }`.
2395
2443
  * Rendered through `CnStatusBadge`; `colorMap` is keyed on the field's
2396
- * raw value, `labels` maps a raw value to the text to show.
2444
+ * raw value, `labels` maps a raw value to the text to show. Instead of
2445
+ * `field`: `text`, a constant ("Inwoner"), or `countFrom`
2446
+ * (`{ register, schema, filter? }`) with `countLabel` (`{ one, other }`
2447
+ * with `{count}`), a count of a related list ("1 lopende zaak") that
2448
+ * shows nothing at 0.
2397
2449
  *
2398
- * @type {{field: string, colorMap?: object, labels?: object, variant?: string}|null}
2450
+ * @type {{field?: string, text?: string, countFrom?: object, countLabel?: object, colorMap?: object, labels?: object, variant?: string}|null}
2399
2451
  */
2400
2452
  typePill: {
2401
2453
  type: Object,
@@ -2747,6 +2799,10 @@ export default {
2747
2799
 
2748
2800
  data() {
2749
2801
  return {
2802
+ /** The counts of the header's count pills (`countFrom`), by pill key (`type`, `status`). */
2803
+ pillCounts: {},
2804
+ /** Sequence of the last pill count round, so a late answer does not overwrite a newer one. */
2805
+ pillCountSeq: 0,
2750
2806
  /** `register/schema/id` the read-state call was last made for, so it is sent once per load. */
2751
2807
  readStateSentFor: '',
2752
2808
  /** Whether the user is arranging the chosen view (`userLayout`). */
@@ -3259,12 +3315,25 @@ export default {
3259
3315
  headerPills() {
3260
3316
  return [['type', this.typePill], ['status', this.statusPill]]
3261
3317
  .map(([key, config]) => {
3262
- const pill = resolvePill(config, this.resolvedObject)
3318
+ const pill = pillCountSource(config)
3319
+ ? resolveCountPill(config, this.pillCounts[key], (text) => this.effectiveTranslate(text))
3320
+ : resolvePill(config, this.resolvedObject)
3263
3321
  return pill ? { ...pill, key, label: this.effectiveTranslate(pill.label) } : null
3264
3322
  })
3265
3323
  .filter(Boolean)
3266
3324
  },
3267
3325
 
3326
+ /**
3327
+ * What the count pills depend on: the record id and the lists they
3328
+ * count. A change counts again.
3329
+ *
3330
+ * @return {string} The key.
3331
+ * @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-header-pill-can-be-a-constant-or-a-count
3332
+ */
3333
+ pillCountKey() {
3334
+ return JSON.stringify([this.objectId, pillCountSource(this.typePill), pillCountSource(this.statusPill)])
3335
+ },
3336
+
3268
3337
  /**
3269
3338
  * The widget the header holds (`headerWidget`): the definition in
3270
3339
  * `widgets` with that id, or null without the key or a match.
@@ -3311,6 +3380,20 @@ export default {
3311
3380
  .map(({ widget }) => widget)
3312
3381
  },
3313
3382
 
3383
+ /**
3384
+ * The `columnOpts` the body grid gets: the default table stacks at 1000px
3385
+ * of grid width, or at 600px when a side column narrows the grid. An
3386
+ * explicit `columnOpts` prop is passed through untouched.
3387
+ *
3388
+ * @return {object|null} The column options.
3389
+ */
3390
+ bodyColumnOpts() {
3391
+ if (!this.showsSideColumn || !isDefaultColumnOpts(this.columnOpts)) {
3392
+ return this.columnOpts
3393
+ }
3394
+ return { ...this.columnOpts, breakpoints: [{ w: SIDE_COLUMN_STACK_WIDTH, c: 1 }] }
3395
+ },
3396
+
3314
3397
  /**
3315
3398
  * Whether the side column renders.
3316
3399
  *
@@ -3842,6 +3925,22 @@ export default {
3842
3925
  && this.register !== '' && this.schema !== '' && this.objectId !== ''
3843
3926
  },
3844
3927
 
3928
+ /**
3929
+ * Whether the header menu offers "Open sidebar": the board look, where the
3930
+ * sidebar's own toggle is hidden, on a page whose sidebar is active and
3931
+ * closed.
3932
+ *
3933
+ * @return {boolean}
3934
+ */
3935
+ showOpenSidebar() {
3936
+ return this.isBoard && this.hasExternalSidebar && this.sidebarActive && this.objectSidebarState.open !== true
3937
+ },
3938
+
3939
+ /** @return {string} Label of the Open sidebar entry. */
3940
+ openSidebarLabel() {
3941
+ return t('nextcloud-vue', 'Open sidebar')
3942
+ },
3943
+
3845
3944
  /** @return {string} Label of the Mark as unread entry. */
3846
3945
  markUnreadLabel() {
3847
3946
  return t('nextcloud-vue', 'Mark as unread')
@@ -4337,6 +4436,14 @@ export default {
4337
4436
  },
4338
4437
 
4339
4438
  watch: {
4439
+ // The header's count pills count again for another record or other lists.
4440
+ pillCountKey: {
4441
+ immediate: true,
4442
+ handler() {
4443
+ this.refreshPillCounts()
4444
+ },
4445
+ },
4446
+
4340
4447
  // Opening a record marks it read, once, after its data has rendered.
4341
4448
  readStateDue: {
4342
4449
  immediate: true,
@@ -4544,6 +4651,17 @@ export default {
4544
4651
  },
4545
4652
 
4546
4653
  methods: {
4654
+ /**
4655
+ * Open the object sidebar through the shared channel.
4656
+ *
4657
+ * @return {void}
4658
+ */
4659
+ openSidebar() {
4660
+ if (this.objectSidebarState) {
4661
+ this.objectSidebarState.open = true
4662
+ }
4663
+ },
4664
+
4547
4665
  /**
4548
4666
  * Start or finish arranging the chosen view. Finishing stores the
4549
4667
  * arrangement of every view the user moved, once.
@@ -4754,6 +4872,33 @@ export default {
4754
4872
  }
4755
4873
  },
4756
4874
 
4875
+ /**
4876
+ * Count the lists behind the header's count pills (`countFrom`): one
4877
+ * list request each (`_limit=1`, the `total`). A failed count, or a
4878
+ * record without an id yet, shows no pill.
4879
+ *
4880
+ * @return {Promise<void>}
4881
+ * @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-header-pill-can-be-a-constant-or-a-count
4882
+ */
4883
+ async refreshPillCounts() {
4884
+ const pills = [['type', this.typePill], ['status', this.statusPill]]
4885
+ .map(([key, config]) => [key, pillCountSource(config)])
4886
+ .filter(([, source]) => source)
4887
+ const seq = ++this.pillCountSeq
4888
+ if (pills.length === 0 || this.objectId === null || this.objectId === undefined || this.objectId === '') {
4889
+ this.pillCounts = {}
4890
+ return
4891
+ }
4892
+ const ctx = { objectId: this.objectId, object: this.resolvedObject || undefined }
4893
+ const counts = {}
4894
+ await Promise.all(pills.map(async ([key, source]) => {
4895
+ counts[key] = await fetchListTotal(source.register, source.schema, source.filter, ctx).catch(() => null)
4896
+ }))
4897
+ if (seq === this.pillCountSeq) {
4898
+ this.pillCounts = counts
4899
+ }
4900
+ },
4901
+
4757
4902
  /**
4758
4903
  * A `cn:page:refresh` reached the page — re-read the object so every
4759
4904
  * object-bound widget re-renders from what the backend now holds.
@@ -4768,6 +4913,7 @@ export default {
4768
4913
  * @return {void}
4769
4914
  */
4770
4915
  onPageRefreshBus(payload) {
4916
+ this.refreshPillCounts()
4771
4917
  if (!this.hasSchemaDrivenFetch) {
4772
4918
  return
4773
4919
  }
@@ -169,10 +169,28 @@
169
169
  :showActions="actionsShown || catalogAddEnabled"
170
170
  :showRefresh="false"
171
171
  :showRequestFeature="false"
172
+ :headerLink="rendererHeader.link"
172
173
  class="cn-detail-page__catalog-card">
173
174
  <template v-if="widget.icon" #title-icon>
174
175
  <CnIcon :name="widget.icon" :size="20" />
175
176
  </template>
177
+ <!-- A renderer that reports its own header (`header` event:
178
+ `{ link, note }`, e.g. record-list's "3 in totaal"). -->
179
+ <template v-if="rendererHeader.note || rendererHeader.action" #actions>
180
+ <span
181
+ v-if="rendererHeader.note"
182
+ class="cn-detail-page__catalog-note"
183
+ data-testid="cn-detail-widget-header-note">{{ rendererHeader.note }}</span>
184
+ <button
185
+ v-if="rendererHeader.action"
186
+ type="button"
187
+ class="cn-detail-page__catalog-action"
188
+ data-testid="cn-detail-widget-header-action"
189
+ @click="rendererHeader.action.run()">
190
+ <CnIcon v-if="rendererHeader.action.icon" :name="rendererHeader.action.icon" :size="16" />
191
+ {{ rendererHeader.action.label }}
192
+ </button>
193
+ </template>
176
194
  <template v-if="catalogAddEnabled" #action-items>
177
195
  <NcActionButton @click="invokeCatalogAdd">
178
196
  <template #icon>
@@ -185,6 +203,7 @@
185
203
  :is="renderer"
186
204
  ref="renderer"
187
205
  v-bind="rendererProps"
206
+ @header="onRendererHeader"
188
207
  @selectObject="onSelectObject" />
189
208
  </CnWidgetWrapper>
190
209
 
@@ -534,6 +553,17 @@ export default {
534
553
  }
535
554
  },
536
555
 
556
+ data() {
557
+ return {
558
+ /**
559
+ * The card header a content-only renderer reports through its
560
+ * `header` event (screens-relation-pages): a link and a note,
561
+ * with the list's total already filled in.
562
+ */
563
+ rendererHeader: { link: null, note: '', action: null },
564
+ }
565
+ },
566
+
537
567
  computed: {
538
568
  /**
539
569
  * Whether the caller owns the title and card.
@@ -992,6 +1022,19 @@ export default {
992
1022
  },
993
1023
 
994
1024
  methods: {
1025
+ /**
1026
+ * Take the header a content-only renderer reports.
1027
+ *
1028
+ * @param {{link?: object|null, note?: string, action?: {label: string, icon?: string, run: () => unknown}|null}} header The header parts.
1029
+ * @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-record-list-shows-the-objects-that-point-at-this-record
1030
+ */
1031
+ onRendererHeader(header) {
1032
+ const link = header && header.link && typeof header.link === 'object' ? header.link : null
1033
+ const note = header && typeof header.note === 'string' ? header.note : ''
1034
+ const action = header && header.action && typeof header.action.run === 'function' && header.action.label ? header.action : null
1035
+ this.rendererHeader = { link, note, action }
1036
+ },
1037
+
995
1038
  /**
996
1039
  * A manifest label through the host's translate; '' stays ''.
997
1040
  *
@@ -1110,6 +1153,29 @@ export default {
1110
1153
  </script>
1111
1154
 
1112
1155
  <style scoped>
1156
+ .cn-detail-page__catalog-action {
1157
+ align-items: center;
1158
+ background: var(--color-primary-element-light);
1159
+ border: 0;
1160
+ border-radius: 16px;
1161
+ color: var(--color-primary-element-light-text, var(--color-primary-element));
1162
+ cursor: pointer;
1163
+ display: inline-flex;
1164
+ font: inherit;
1165
+ font-size: 13px;
1166
+ font-weight: 700;
1167
+ gap: 6px;
1168
+ min-height: 32px;
1169
+ padding: 0 14px;
1170
+ white-space: nowrap;
1171
+ }
1172
+
1173
+ .cn-detail-page__catalog-note {
1174
+ color: var(--color-text-maxcontrast);
1175
+ font-size: 14px;
1176
+ white-space: nowrap;
1177
+ }
1178
+
1113
1179
  .cn-detail-widget-host,
1114
1180
  .cn-detail-widget-host > * {
1115
1181
  height: 100%;
@@ -31,7 +31,7 @@ import { readPath } from '../../utils/readPath.js'
31
31
  * Renders CnDocumentReviewList from a list on the bound record:
32
32
  * `content: { field, title?, statusField?, statuses?, rowAction?: { label, route } }`.
33
33
  * A row action with a `route` opens that route with the row's key as `id`.
34
- * Resolved by its registry key, not exported.
34
+ * Resolved by its registry key, and exported for an app that renders it itself.
35
35
  */
36
36
  export default {
37
37
  name: 'CnDocumentReviewWidget',
@@ -62,7 +62,7 @@
62
62
  <script>
63
63
  import { translate as t } from '@nextcloud/l10n'
64
64
  import { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextField } from '@nextcloud/vue'
65
- import { facetOptionLabel } from '../../utils/facets.js'
65
+ import { facetOptions } from '../../utils/facets.js'
66
66
  import { filtersFromSchema } from '../../utils/schema.js'
67
67
 
68
68
  /**
@@ -175,12 +175,12 @@ export default {
175
175
 
176
176
  getFilterOptions(filter) {
177
177
  // Use facet data if available (live values with counts)
178
- const facet = this.facetData[filter.key]
179
- if (facet?.values?.length > 0) {
180
- return facet.values.map((v) => ({
181
- id: v.value,
182
- label: facetOptionLabel(v),
183
- }))
178
+ const live = facetOptions(
179
+ this.facetData[filter.key],
180
+ (count) => t('nextcloud-vue', 'No value ({count})', { count }),
181
+ )
182
+ if (live !== null) {
183
+ return live
184
184
  }
185
185
  // Fall back to static enum options from schema
186
186
  return filter.options || []