@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
@@ -0,0 +1,159 @@
1
+ import { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue';
2
+ import { objectUrlOf, patchObject } from '../../utils/objectWrite.js';
3
+ import { readPath } from '../../utils/readPath.js';
4
+ import { serverErrorMessage } from '../../utils/serverErrorMessage.js';
5
+
6
+ /**
7
+ * CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with
8
+ * a label and a hint, bound to boolean fields of the CURRENT object. A toggle
9
+ * saves at once with ONE PATCH of that field; a refused PATCH puts the switch
10
+ * back and shows the server's words.
11
+ *
12
+ * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md
13
+ */
14
+ var script = {
15
+ name: 'CnSwitchRowsWidget',
16
+
17
+ components: { NcCheckboxRadioSwitch, NcNoteCard },
18
+
19
+ inject: {
20
+ cnTranslate: { default: () => (key) => key },
21
+ },
22
+
23
+ props: {
24
+ /**
25
+ * The widget configuration.
26
+ *
27
+ * - `rows` (required) — `[{ key, label, hint?, invert? }]`; `key` is a top-level boolean field. `invert` shows the switch on when the field is false (a stored `disabled` read as "enabled").
28
+ * - `readOnly`.
29
+ *
30
+ * @type {object}
31
+ */
32
+ content: {
33
+ type: Object,
34
+ default: () => ({}),
35
+ },
36
+
37
+ /** The current detail-page object. */
38
+ objectData: {
39
+ type: Object,
40
+ default: null,
41
+ },
42
+
43
+ /** The current object id. */
44
+ objectId: {
45
+ type: [String, Number],
46
+ default: '',
47
+ },
48
+
49
+ /** OpenRegister register slug of the surface. */
50
+ register: {
51
+ type: [String, Object],
52
+ default: '',
53
+ },
54
+
55
+ /** OpenRegister schema slug of the surface. */
56
+ schema: {
57
+ type: [String, Object],
58
+ default: '',
59
+ },
60
+ },
61
+
62
+ emits: ['saved'],
63
+
64
+ data() {
65
+ return {
66
+ /** The switch states as last saved (by key, as the switch shows them). */
67
+ saved: {},
68
+ values: {},
69
+ busy: '',
70
+ notice: '',
71
+ }
72
+ },
73
+
74
+ computed: {
75
+ rows() {
76
+ const list = Array.isArray(this.content.rows) ? this.content.rows : [];
77
+ return list
78
+ .filter((row) => row && row.key)
79
+ .map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))
80
+ },
81
+
82
+ readOnly() {
83
+ return this.content.readOnly === true
84
+ },
85
+
86
+ objectUrl() {
87
+ return objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))
88
+ },
89
+ },
90
+
91
+ watch: {
92
+ objectData() {
93
+ this.adopt();
94
+ },
95
+ },
96
+
97
+ created() {
98
+ this.adopt();
99
+ },
100
+
101
+ methods: {
102
+ tr(text) {
103
+ if (typeof text !== 'string' || text === '') {
104
+ return ''
105
+ }
106
+ return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
107
+ },
108
+
109
+ /** Read every switch off the object. */
110
+ adopt() {
111
+ const values = {};
112
+ for (const row of this.rows) {
113
+ const stored = readPath(this.objectData || {}, row.key) === true;
114
+ values[row.key] = row.invert ? !stored : stored;
115
+ }
116
+ this.saved = values;
117
+ this.values = { ...values };
118
+ },
119
+
120
+ /**
121
+ * Flip one switch and save that one field.
122
+ *
123
+ * @param {object} row The row.
124
+ * @param {boolean} on The new switch state.
125
+ * @return {Promise<void>}
126
+ * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field
127
+ */
128
+ async toggle(row, on) {
129
+ if (!this.objectUrl) {
130
+ this.notice = this.tr('This switch cannot be saved here.');
131
+ return
132
+ }
133
+ this.notice = '';
134
+ this.busy = row.key;
135
+ this.values = { ...this.values, [row.key]: on };
136
+ const stored = row.invert ? !on : on;
137
+ try {
138
+ const data = await patchObject(this.objectUrl, { [row.key]: stored });
139
+ const written = data[row.key] !== undefined ? data[row.key] === true : stored;
140
+ const shown = row.invert ? !written : written;
141
+ this.saved = { ...this.saved, [row.key]: shown };
142
+ this.values = { ...this.values, [row.key]: shown };
143
+ /**
144
+ * @event saved A switch was written.
145
+ * @type {{field: string, value: boolean}}
146
+ */
147
+ this.$emit('saved', { field: row.key, value: written });
148
+ } catch (e) {
149
+ this.values = { ...this.values, [row.key]: this.saved[row.key] };
150
+ this.notice = serverErrorMessage(e);
151
+ } finally {
152
+ this.busy = '';
153
+ }
154
+ },
155
+ },
156
+ };
157
+
158
+ export { script as default };
159
+ //# sourceMappingURL=CnSwitchRowsWidget.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSwitchRowsWidget.vue2.js","sources":["../../../../src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-switch-rows\" data-testid=\"cn-switch-rows\">\n\t\t<ul class=\"cn-switch-rows__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-switch-rows__row\"\n\t\t\t\t:data-testid=\"`cn-switch-rows-row-${row.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t:modelValue=\"values[row.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\">\n\t\t\t\t\t<span class=\"cn-switch-rows__label\">{{ row.label }}</span>\n\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-switch-rows__hint\">{{ row.hint }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-switch-rows-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { objectUrlOf, patchObject } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with\n * a label and a hint, bound to boolean fields of the CURRENT object. A toggle\n * saves at once with ONE PATCH of that field; a refused PATCH puts the switch\n * back and shows the server's words.\n *\n * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md\n */\nexport default {\n\tname: 'CnSwitchRowsWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `rows` (required) — `[{ key, label, hint?, invert? }]`; `key` is a top-level boolean field. `invert` shows the switch on when the field is false (a stored `disabled` read as \"enabled\").\n\t\t * - `readOnly`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The switch states as last saved (by key, as the switch shows them). */\n\t\t\tsaved: {},\n\t\t\tvalues: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\trows() {\n\t\t\tconst list = Array.isArray(this.content.rows) ? this.content.rows : []\n\t\t\treturn list\n\t\t\t\t.filter((row) => row && row.key)\n\t\t\t\t.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read every switch off the object. */\n\t\tadopt() {\n\t\t\tconst values = {}\n\t\t\tfor (const row of this.rows) {\n\t\t\t\tconst stored = readPath(this.objectData || {}, row.key) === true\n\t\t\t\tvalues[row.key] = row.invert ? !stored : stored\n\t\t\t}\n\t\t\tthis.saved = values\n\t\t\tthis.values = { ...values }\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\tthis.values = { ...this.values, [row.key]: on }\n\t\t\tconst stored = row.invert ? !on : on\n\t\t\ttry {\n\t\t\t\tconst data = await patchObject(this.objectUrl, { [row.key]: stored })\n\t\t\t\tconst written = data[row.key] !== undefined ? data[row.key] === true : stored\n\t\t\t\tconst shown = row.invert ? !written : written\n\t\t\t\tthis.saved = { ...this.saved, [row.key]: shown }\n\t\t\t\tthis.values = { ...this.values, [row.key]: shown }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: row.key, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.values = { ...this.values, [row.key]: this.saved[row.key] }\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-switch-rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-switch-rows__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-switch-rows__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-switch-rows__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-switch-rows__label {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-switch-rows__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { resolveComponent, openBlock, createElementBlock, createElementVNode, Fragment, renderList, createVNode, withCtx, toDisplayString, createCommentVNode, createBlock, createTextVNode } from 'vue';
2
+
3
+ const _hoisted_1 = {
4
+ class: "cn-switch-rows",
5
+ "data-testid": "cn-switch-rows"
6
+ };
7
+ const _hoisted_2 = { class: "cn-switch-rows__list" };
8
+ const _hoisted_3 = ["data-testid"];
9
+ const _hoisted_4 = { class: "cn-switch-rows__label" };
10
+ const _hoisted_5 = {
11
+ key: 0,
12
+ class: "cn-switch-rows__hint"
13
+ };
14
+
15
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
16
+ const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
17
+ const _component_NcNoteCard = resolveComponent("NcNoteCard");
18
+
19
+ return (openBlock(), createElementBlock("div", _hoisted_1, [
20
+ createElementVNode("ul", _hoisted_2, [
21
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
22
+ return (openBlock(), createElementBlock("li", {
23
+ key: row.key,
24
+ class: "cn-switch-rows__row",
25
+ "data-testid": `cn-switch-rows-row-${row.key}`
26
+ }, [
27
+ createVNode(_component_NcCheckboxRadioSwitch, {
28
+ modelValue: $data.values[row.key] === true,
29
+ type: "switch",
30
+ disabled: $options.readOnly || $data.busy === row.key,
31
+ "onUpdate:modelValue": $event => ($options.toggle(row, $event))
32
+ }, {
33
+ default: withCtx(() => [
34
+ createElementVNode("span", _hoisted_4, toDisplayString(row.label), 1 /* TEXT */),
35
+ (row.hint)
36
+ ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(row.hint), 1 /* TEXT */))
37
+ : createCommentVNode("v-if", true)
38
+ ]),
39
+ _: 2 /* DYNAMIC */
40
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "disabled", "onUpdate:modelValue"])
41
+ ], 8 /* PROPS */, _hoisted_3))
42
+ }), 128 /* KEYED_FRAGMENT */))
43
+ ]),
44
+ ($data.notice)
45
+ ? (openBlock(), createBlock(_component_NcNoteCard, {
46
+ key: 0,
47
+ type: "error",
48
+ "data-testid": "cn-switch-rows-notice"
49
+ }, {
50
+ default: withCtx(() => [
51
+ createTextVNode(toDisplayString($data.notice), 1 /* TEXT */)
52
+ ]),
53
+ _: 1 /* STABLE */
54
+ }))
55
+ : createCommentVNode("v-if", true)
56
+ ]))
57
+ }
58
+
59
+ export { render };
60
+ //# sourceMappingURL=CnSwitchRowsWidget.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSwitchRowsWidget.vue3.js","sources":["../../../../src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue?vue&type=template&id=9dd5b4e2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-switch-rows\" data-testid=\"cn-switch-rows\">\n\t\t<ul class=\"cn-switch-rows__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-switch-rows__row\"\n\t\t\t\t:data-testid=\"`cn-switch-rows-row-${row.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t:modelValue=\"values[row.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\">\n\t\t\t\t\t<span class=\"cn-switch-rows__label\">{{ row.label }}</span>\n\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-switch-rows__hint\">{{ row.hint }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-switch-rows-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { objectUrlOf, patchObject } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with\n * a label and a hint, bound to boolean fields of the CURRENT object. A toggle\n * saves at once with ONE PATCH of that field; a refused PATCH puts the switch\n * back and shows the server's words.\n *\n * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md\n */\nexport default {\n\tname: 'CnSwitchRowsWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `rows` (required) — `[{ key, label, hint?, invert? }]`; `key` is a top-level boolean field. `invert` shows the switch on when the field is false (a stored `disabled` read as \"enabled\").\n\t\t * - `readOnly`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The switch states as last saved (by key, as the switch shows them). */\n\t\t\tsaved: {},\n\t\t\tvalues: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\trows() {\n\t\t\tconst list = Array.isArray(this.content.rows) ? this.content.rows : []\n\t\t\treturn list\n\t\t\t\t.filter((row) => row && row.key)\n\t\t\t\t.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read every switch off the object. */\n\t\tadopt() {\n\t\t\tconst values = {}\n\t\t\tfor (const row of this.rows) {\n\t\t\t\tconst stored = readPath(this.objectData || {}, row.key) === true\n\t\t\t\tvalues[row.key] = row.invert ? !stored : stored\n\t\t\t}\n\t\t\tthis.saved = values\n\t\t\tthis.values = { ...values }\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\tthis.values = { ...this.values, [row.key]: on }\n\t\t\tconst stored = row.invert ? !on : on\n\t\t\ttry {\n\t\t\t\tconst data = await patchObject(this.objectUrl, { [row.key]: stored })\n\t\t\t\tconst written = data[row.key] !== undefined ? data[row.key] === true : stored\n\t\t\t\tconst shown = row.invert ? !written : written\n\t\t\t\tthis.saved = { ...this.saved, [row.key]: shown }\n\t\t\t\tthis.values = { ...this.values, [row.key]: shown }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: row.key, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.values = { ...this.values, [row.key]: this.saved[row.key] }\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-switch-rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-switch-rows__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-switch-rows__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-switch-rows__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-switch-rows__label {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-switch-rows__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createElementBlock","_Fragment","_renderList","_createElementVNode","_toDisplayString"],"mappings":";;;AAWM,EAAA,KAAK,EAAC,gBAAgB;AAAC,EAAA,aAAC,EAAA,gBAAA;;AACxB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;AAWvB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,uBAAwB,GAAA;;;AAC3B,EAAA,KAAA,EAAA,sBAAA;;;;;;;;;wBAXVA,kBAaE,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CAZY,QAAI,CAAA,IAAA,EAAA,CAAX,GAAG,KAAA;6BADVF,kBAaE,CAAA,IAAA,EAAA;UAXD,GAAG,EAAE,GAAG,CAAC,GAAG;AACZ,UAAA,KAAI,EAAC,qBAAqB;UAC1B,aAAW,EAAA,CAAA,mBAAA,EAAwB,GAAG,CAAC,GAAC,CAAA,CAAA;;qBAQ/B,CAAA,gCAAA,EAAA;AANR,YAAA,UAAU,EAAE,KAAA,CAAA,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,KAAA,IAAA;AAC3B,YAAA,IAAI,EAAC,QAAQ;AACZ,YAAA,QAAC,EAAA,QAAA,CAAA,QAAA,IAAA,UAAA,KAAA,GAAA,CAAA,GAAA;AACD,YAAA,qBAAA,EAAA,MAAA,KAAA,QAAA,CAAA,MAAA,CAAA,GAAA,EAAA,MAAA,CAAA,CAAA;;6BACD,MAA0D;AAA1D,cAAAG,kBAAA,CAA0D,MAA1D,EAAA,UAA0D,EAAnBC,eAAA,CAAA,GAAG,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;AACvC,cAAA,CAAA,GAAA,CAAA,IAAA;mDAAA,kBAAA,EAAAA,eAAA,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,26 @@
1
+ import __sfc_main from './CnSwitchRowsWidget.vue.js';
2
+ import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
3
+
4
+ /**
5
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
6
+ * SPDX-License-Identifier: EUPL-1.2
7
+ *
8
+ * CnSwitchRowsWidget — self-registers the `switch-rows` widget type (a card of
9
+ * switches, each with a label and a hint, bound to boolean fields of the
10
+ * current object and saved on toggle) into the shared dashboardWidgetRegistry.
11
+ */
12
+
13
+
14
+ registerDashboardWidget('switch-rows', {
15
+ renderer: __sfc_main,
16
+ form: null,
17
+ defaultContent: {
18
+ rows: [],
19
+ },
20
+ displayName: 'Switch rows',
21
+ icon: 'ToggleSwitch',
22
+ surfaces: ['detail-page'],
23
+ });
24
+
25
+ export { __sfc_main as CnSwitchRowsWidget, __sfc_main as default };
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/CnSwitchRowsWidget/index.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * CnSwitchRowsWidget — self-registers the `switch-rows` widget type (a card of\n * switches, each with a label and a hint, bound to boolean fields of the\n * current object and saved on toggle) into the shared dashboardWidgetRegistry.\n */\n\nimport CnSwitchRowsWidget from './CnSwitchRowsWidget.vue'\nimport { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js'\n\nregisterDashboardWidget('switch-rows', {\n\trenderer: CnSwitchRowsWidget,\n\tform: null,\n\tdefaultContent: {\n\t\trows: [],\n\t},\n\tdisplayName: 'Switch rows',\n\ticon: 'ToggleSwitch',\n\tsurfaces: ['detail-page'],\n})\n\nexport { CnSwitchRowsWidget }\nexport default CnSwitchRowsWidget\n"],"names":["CnSwitchRowsWidget"],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA,uBAAuB,CAAC,aAAa,EAAE;AACvC,CAAC,QAAQ,EAAEA,UAAkB;AAC7B,CAAC,IAAI,EAAE,IAAI;AACX,CAAC,cAAc,EAAE;AACjB,EAAE,IAAI,EAAE,EAAE;AACV,EAAE;AACF,CAAC,WAAW,EAAE,aAAa;AAC3B,CAAC,IAAI,EAAE,cAAc;AACrB,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC;AAC1B,CAAC;;;;"}
@@ -8,6 +8,7 @@ import __sfc_main$3 from '../CnTabs/CnTab.vue.js';
8
8
  import __sfc_main$4 from '../CnTabs/CnTabs.vue.js';
9
9
  import { normalizeLook } from '../../composables/useLook.js';
10
10
  import { resolveTabCount } from '../../utils/detailActionModel.js';
11
+ import { fetchListTotal } from '../../utils/fetchFilterCounts.js';
11
12
  import { isActivityWidget } from '../../utils/headerMeta.js';
12
13
  import { PANEL_ACTION_SINK } from '../../utils/panelActions.js';
13
14
  import { isLocallyDecidableVisibleWhen, evaluateVisibleWhenLocal, evaluateVisibleWhen } from '../../utils/visibleWhen.js';
@@ -162,15 +163,24 @@ var script = {
162
163
  * `tabs[]` entries are `{ widgetId, label?, icon?, count?, countField?, overflow? }`.
163
164
  * `label` and `icon` fall back to the referenced widget's own title and
164
165
  * icon. `count` is a number shown after the label; `countField` reads
165
- * it off the record instead (a list counts its items). `overflow: true`
166
+ * it off the record instead (a list counts its items). `countFrom`
167
+ * counts a list on the server: `"widget"` counts the child widget's
168
+ * own list (`content.register`, `schema`, `filter`, tokens such as
169
+ * `@objectId` resolved), an object `{ register, schema, filter? }`
170
+ * names the list; `count` and `countField` win over it. `overflow: true`
166
171
  * lists the tab under "More".
167
172
  *
173
+ * A tab with `widgetIds` can lay them out in a grid instead of one under
174
+ * the other: `columns: 4` gives each a quarter of the row, and
175
+ * `layout: [{ widgetId, gridWidth }]` sets a width (of 12) per widget, as
176
+ * the page grid does. Widgets wrap onto the next row.
177
+ *
168
178
  * `maxVisibleTabs` caps the strip: later tabs go under "More".
169
179
  * `hideEmpty: true` moves a tab whose count is 0 there too.
170
180
  * `moreLabel` names that menu. `variant: "segmented"` draws the strip
171
181
  * as a pill switch (CnTabs' segmented variant); `line` is the default.
172
182
  *
173
- * @type {{ tabs?: Array<{widgetId: string, label?: string, icon?: string, count?: number, countField?: string, overflow?: boolean}>, ariaLabel?: string, maxVisibleTabs?: number, hideEmpty?: boolean, moreLabel?: string, variant?: ('line'|'segmented') }}
183
+ * @type {{ tabs?: Array<{widgetId?: string, widgetIds?: string[], label?: string, icon?: string, count?: number, countField?: string, countFrom?: ('widget'|{register: string, schema: string, filter?: object}), overflow?: boolean, columns?: number, layout?: Array<{widgetId: string, gridWidth: number}>}>, ariaLabel?: string, maxVisibleTabs?: number, hideEmpty?: boolean, moreLabel?: string, variant?: ('line'|'segmented') }}
174
184
  */
175
185
  content: {
176
186
  type: Object,
@@ -290,6 +300,9 @@ var script = {
290
300
  sourceVisibility: {},
291
301
  // Bumped per evaluation round, so a slow answer from an earlier round is dropped.
292
302
  visibilitySeq: 0,
303
+ // Totals counted for tabs with `countFrom`, by position in `content.tabs`.
304
+ widgetCounts: {},
305
+ countSeq: 0,
293
306
  // Tab id named by the route hash that has not appeared yet (still pending).
294
307
  hashTargetId: '',
295
308
  // Items published by the panels, keyed by widget id. Keyed rather
@@ -332,7 +345,7 @@ var script = {
332
345
  // whatever its place in the manifest. `index` stays the position in
333
346
  // `content.tabs`, which the source-mode conditions are keyed on.
334
347
  const isActivityTab = (tab) => {
335
- const id = typeof tab === 'string' ? tab : tab?.widgetId;
348
+ const id = this.tabWidgetIds(tab)[0];
336
349
  return isActivityWidget(this.availableWidgets.find((w) => w && w.id === id))
337
350
  };
338
351
  const ordered = authored.map((tab, index) => ({ tab, index }));
@@ -354,9 +367,19 @@ var script = {
354
367
  if (visibility === 'hidden') {
355
368
  return
356
369
  }
357
- const widgetId = typeof tab === 'string' ? tab : tab?.widgetId;
358
- const widget = this.availableWidgets.find((w) => w && w.id === widgetId) || null;
359
- const count = resolveTabCount(typeof tab === 'object' ? tab : null, this.objectData);
370
+ // A stack (`widgetIds`) resolves every id; one that names no
371
+ // widget is skipped. The first that resolves is the panel's.
372
+ const ids = this.tabWidgetIds(tab);
373
+ const widgets = ids.length > 1
374
+ ? ids.map((id) => this.availableWidgets.find((w) => w && w.id === id) || null).filter(Boolean)
375
+ : [];
376
+ const widget = ids.length > 1
377
+ ? (widgets[0] || null)
378
+ : (this.availableWidgets.find((w) => w && w.id === ids[0]) || null);
379
+ const widgetId = widget ? widget.id : ids[0];
380
+ const declared = resolveTabCount(typeof tab === 'object' ? tab : null, this.objectData);
381
+ const counted = this.widgetCounts[index];
382
+ const count = declared === null && typeof counted === 'number' ? counted : declared;
360
383
  // The board strip has no "More": every tab is in the strip.
361
384
  let overflow = !this.isBoard && ((tab && tab.overflow === true) || (hideEmpty && count === 0));
362
385
  if (!overflow && !this.isBoard) {
@@ -373,6 +396,8 @@ var script = {
373
396
  label: this.tabLabel(tab, widget, widgetId),
374
397
  icon: (tab && tab.icon) || widget?.icon || '',
375
398
  widget,
399
+ stack: widgets.slice(1),
400
+ grid: this.stackGrid(tab, widgets),
376
401
  count,
377
402
  overflow,
378
403
  pending: visibility === 'pending',
@@ -391,6 +416,17 @@ var script = {
391
416
  return translate('nextcloud-vue', 'Loading …')
392
417
  },
393
418
 
419
+ /**
420
+ * The lists the tabs count (`countFrom`), serialised, to count again
421
+ * when they change.
422
+ *
423
+ * @return {string} The key.
424
+ */
425
+ countSourcesKey() {
426
+ const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
427
+ return JSON.stringify(tabs.map((tab) => this.countSourceOf(tab)))
428
+ },
429
+
394
430
  /** @return {string} The source-mode conditions, serialised, to re-evaluate when they change. */
395
431
  sourceConditionsKey() {
396
432
  const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
@@ -503,6 +539,12 @@ var script = {
503
539
  objectId() {
504
540
  this.sourceVisibility = {};
505
541
  this.refreshSourceVisibility();
542
+ this.widgetCounts = {};
543
+ this.refreshWidgetCounts();
544
+ },
545
+
546
+ countSourcesKey() {
547
+ this.refreshWidgetCounts();
506
548
  },
507
549
 
508
550
  sourceConditionsKey() {
@@ -537,10 +579,14 @@ var script = {
537
579
  }
538
580
  this.activeKey = this.resolvedTabs[this.activeIndex]?.key || '';
539
581
  this.refreshSourceVisibility();
582
+ this.refreshWidgetCounts();
540
583
  },
541
584
 
542
585
  mounted() {
543
- this._onRefresh = () => this.refreshSourceVisibility();
586
+ this._onRefresh = () => {
587
+ this.refreshSourceVisibility();
588
+ this.refreshWidgetCounts();
589
+ };
544
590
  subscribe('cn:page:refresh', this._onRefresh);
545
591
  subscribe('cn:widget:refresh', this._onRefresh);
546
592
  },
@@ -551,6 +597,67 @@ var script = {
551
597
  },
552
598
 
553
599
  methods: {
600
+ /**
601
+ * The grid a stack lays its widgets out in, as one column span (of 12)
602
+ * per widget in order, or null for the plain vertical stack. A tab says
603
+ * `columns: 4` (every widget spans a quarter of the row) and/or
604
+ * `layout: [{ widgetId, gridWidth }]`, the page grid's width key per
605
+ * widget (of 12; a widget it does not name takes the `columns` share, or
606
+ * the whole row). Widgets wrap onto the next row. Heights follow the
607
+ * content.
608
+ *
609
+ * @param {object|string} tab The `content.tabs[]` entry.
610
+ * @param {Array<object>} widgets The widgets of the stack, in order.
611
+ * @return {number[]|null} The column span of each widget, or null.
612
+ */
613
+ stackGrid(tab, widgets) {
614
+ if (!tab || typeof tab !== 'object' || widgets.length < 2) {
615
+ return null
616
+ }
617
+ const clamp = (value) => Math.min(12, Math.max(1, Math.floor(Number(value))));
618
+ const columns = Number(tab.columns);
619
+ const share = Number.isFinite(columns) && columns >= 1 ? clamp(12 / Math.min(12, Math.floor(columns))) : 12;
620
+ const placed = new Map((Array.isArray(tab.layout) ? tab.layout : [])
621
+ .filter((entry) => entry && typeof entry.widgetId === 'string' && Number.isFinite(Number(entry.gridWidth)))
622
+ .map((entry) => [entry.widgetId, clamp(entry.gridWidth)]));
623
+ if (placed.size === 0 && share === 12) {
624
+ return null
625
+ }
626
+ return widgets.map((widget) => placed.get(widget.id) ?? share)
627
+ },
628
+
629
+ /**
630
+ * The inline column span of one widget of a gridded stack.
631
+ *
632
+ * @param {number[]|null} grid The spans of the stack, or null.
633
+ * @param {number} index The widget's position in the stack.
634
+ * @return {object|undefined} The style, or undefined without a grid.
635
+ */
636
+ spanStyle(grid, index) {
637
+ return grid ? { gridColumn: `span ${grid[index] || 12}` } : undefined
638
+ },
639
+
640
+ /**
641
+ * The widget ids a tab names: `widgetIds` (a stack) when it holds at
642
+ * least one id, else `widgetId`, or the bare string.
643
+ *
644
+ * @param {object|string} tab The `content.tabs[]` entry.
645
+ * @return {string[]} The ids, at least one entry (possibly undefined).
646
+ * @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-tab-can-hold-a-stack-of-widgets
647
+ */
648
+ tabWidgetIds(tab) {
649
+ if (typeof tab === 'string') {
650
+ return [tab]
651
+ }
652
+ if (tab && Array.isArray(tab.widgetIds)) {
653
+ const ids = tab.widgetIds.filter((id) => typeof id === 'string' && id !== '');
654
+ if (ids.length) {
655
+ return ids
656
+ }
657
+ }
658
+ return [tab?.widgetId]
659
+ },
660
+
554
661
  /**
555
662
  * The label a tab shows: the authored `label`, else (board look) History
556
663
  * for the activity widget, else the child widget's title, else its id.
@@ -627,6 +734,60 @@ var script = {
627
734
  }));
628
735
  },
629
736
 
737
+ /**
738
+ * The list a tab counts (`countFrom`): `"widget"` counts the child
739
+ * widget's own list (its `content.register`, `content.schema` and
740
+ * `content.filter`); an object `{ register, schema, filter? }` names
741
+ * the list itself. Null for a tab that does not ask, or a child with
742
+ * no list.
743
+ *
744
+ * @param {object|string} tab The `content.tabs[]` entry.
745
+ * @return {{register: string, schema: string, filter: object}|null} The list.
746
+ * @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
747
+ */
748
+ countSourceOf(tab) {
749
+ const from = tab && typeof tab === 'object' ? tab.countFrom : null;
750
+ let source = null;
751
+ if (from === 'widget') {
752
+ // A stack counts its first widget that has a list.
753
+ const lists = this.tabWidgetIds(tab)
754
+ .map((id) => this.availableWidgets.find((w) => w && w.id === id))
755
+ .filter((w) => w && w.content && typeof w.content === 'object' && w.content.register && w.content.schema);
756
+ source = lists.length ? lists[0].content : null;
757
+ } else if (from && typeof from === 'object') {
758
+ source = from;
759
+ }
760
+ if (!source || typeof source.register !== 'string' || source.register === '' || typeof source.schema !== 'string' || source.schema === '') {
761
+ return null
762
+ }
763
+ const filter = source.filter && typeof source.filter === 'object' && !Array.isArray(source.filter) ? source.filter : {};
764
+ return { register: source.register, schema: source.schema, filter }
765
+ },
766
+
767
+ /**
768
+ * Count the list behind every tab with `countFrom`: once on mount,
769
+ * when the record changes and after a refresh. A tab keeps its last
770
+ * total while the new one is on its way; a failed count shows none.
771
+ *
772
+ * @return {Promise<void>}
773
+ * @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
774
+ */
775
+ async refreshWidgetCounts() {
776
+ const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
777
+ const seq = ++this.countSeq;
778
+ const ctx = { objectId: this.objectId, object: this.objectData || undefined };
779
+ await Promise.all(tabs.map(async (tab, index) => {
780
+ const source = this.countSourceOf(tab);
781
+ if (!source) {
782
+ return
783
+ }
784
+ const total = await fetchListTotal(source.register, source.schema, source.filter, ctx).catch(() => null);
785
+ if (seq === this.countSeq) {
786
+ this.widgetCounts = { ...this.widgetCounts, [index]: total };
787
+ }
788
+ }));
789
+ },
790
+
630
791
  /** @return {string} The route hash without its `#`, or ''. */
631
792
  currentHash() {
632
793
  const fromRoute = this.$route && typeof this.$route.hash === 'string' ? this.$route.hash : '';