@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
@@ -86,6 +86,7 @@ import { useEndpointSource } from '../../composables/useEndpointSource.js'
86
86
  import { useObjectStore } from '../../store/useObjectStore.js'
87
87
  import { dispatchAction, resolveObjectOpType } from '../../utils/actionsDispatcher.js'
88
88
  import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
89
+ import { pageFilter, pageSort } from '../../utils/pageControls.js'
89
90
  import { dropOptionalUnresolved, hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
90
91
  import { compareVisibleWhen, readVisibleWhenPath } from '../../utils/visibleWhen.js'
91
92
  import { CnIcon } from '../CnIcon/index.js'
@@ -517,7 +518,8 @@ export default {
517
518
  * @return {object}
518
519
  */
519
520
  resolvedFilter() {
520
- return dropOptionalUnresolved(resolveFilterTokens((this.source && this.source.filter) || {}, this.tokenCtx))
521
+ const filter = pageFilter(this.source && this.source.pageControls, this.workspaceCtx, this.source && this.source.filter)
522
+ return dropOptionalUnresolved(resolveFilterTokens(filter, this.tokenCtx))
521
523
  },
522
524
 
523
525
  /**
@@ -590,7 +592,10 @@ export default {
590
592
  resolvedFetchParams() {
591
593
  const src = this.source || {}
592
594
  const params = {}
593
- for (const [field, dir] of Object.entries(src.order || {})) {
595
+ // A page sort control (`source.pageControls.sort`) replaces the order.
596
+ const chosen = pageSort(src.pageControls, this.workspaceCtx, null)
597
+ const order = chosen ? { [chosen.field]: chosen.dir } : (src.order || {})
598
+ for (const [field, dir] of Object.entries(order)) {
594
599
  params[`_order[${field}]`] = dir === 'desc' ? 'desc' : 'asc'
595
600
  }
596
601
  if (typeof src.limit === 'number' && src.limit > 0) {
@@ -73,6 +73,11 @@ export function objectTableContentToProps(content) {
73
73
  if (hasLimit) {
74
74
  source.limit = limit
75
75
  }
76
+ // The page controls the table listens to belong to its source.
77
+ if (rest.pageControls && typeof rest.pageControls === 'object') {
78
+ source.pageControls = rest.pageControls
79
+ delete rest.pageControls
80
+ }
76
81
  return { ...rest, source }
77
82
  }
78
83
 
@@ -4,28 +4,101 @@
4
4
  -->
5
5
 
6
6
  <template>
7
- <div class="cn-workspace-filter-widget" data-testid="cn-workspace-filter-widget">
8
- <p v-if="label" class="cn-workspace-filter-widget__label">
7
+ <div
8
+ class="cn-workspace-filter-widget"
9
+ :class="{
10
+ 'cn-workspace-filter-widget--start': isStart,
11
+ 'cn-workspace-filter-widget--chips': style === 'chips',
12
+ 'cn-workspace-filter-widget--bar': isBar,
13
+ 'cn-workspace-filter-widget--inline': content.inline === true,
14
+ 'cn-workspace-filter-widget--end': content.align === 'end',
15
+ }"
16
+ data-testid="cn-workspace-filter-widget">
17
+ <!-- The start card (`layout: "start"`): a title and one line of
18
+ guidance beside the control, as the "Contact starten" card. -->
19
+ <div v-if="isStart && (title || description)" class="cn-workspace-filter-widget__text">
20
+ <h3 v-if="title" class="cn-workspace-filter-widget__title">
21
+ {{ title }}
22
+ </h3>
23
+ <p v-if="description" class="cn-workspace-filter-widget__description">
24
+ {{ description }}
25
+ </p>
26
+ </div>
27
+
28
+ <!-- A bar (`layout: "bar"`): its `controls` side by side in one row,
29
+ each a workspace filter of its own (chips, a switch, a select). -->
30
+ <template v-if="isBar">
31
+ <CnWorkspaceFilterWidget
32
+ v-for="(control, index) in barControls"
33
+ :key="index"
34
+ :content="control"
35
+ @change="$emit('change', $event)" />
36
+ </template>
37
+
38
+ <p v-if="!isBar && label && style !== 'chips' && style !== 'toggle'" class="cn-workspace-filter-widget__label">
9
39
  {{ label }}
10
40
  </p>
11
41
 
12
- <div v-if="loading" class="cn-workspace-filter-widget__status">
42
+ <!-- An object picker (`objectSource`): searches OpenRegister on the
43
+ server, so it reaches every object, not a fetched page. -->
44
+ <CnResourceSelect
45
+ v-if="!isBar && objectSource"
46
+ class="cn-workspace-filter-widget__control"
47
+ :register="objectSource.register"
48
+ :schema="objectSource.schema"
49
+ :labelField="objectSource.labelField || 'title'"
50
+ :modelValue="selected === undefined || selected === null ? '' : String(selected)"
51
+ :placeholder="tr(objectSource.placeholder || '')"
52
+ :ariaLabelCombobox="tr(objectSource.ariaLabel || '') || title || label || writeKey"
53
+ :preload="objectSource.preload !== false"
54
+ :clearable="Boolean(content.allLabel)"
55
+ :allowCreate="false"
56
+ data-testid="cn-workspace-filter-object"
57
+ @update:modelValue="applySelection($event || '')" />
58
+
59
+ <div v-else-if="loading" class="cn-workspace-filter-widget__status">
13
60
  {{ loadingLabel }}
14
61
  </div>
15
62
 
63
+ <!-- Chips style (screens-page-lenses): one compact segmented group,
64
+ a count after each label, arrow keys move the choice. -->
65
+ <CnSegmentedControl
66
+ v-else-if="style === 'chips'"
67
+ class="cn-workspace-filter-widget__chips"
68
+ size="compact"
69
+ :options="chipOptions"
70
+ :modelValue="selected === undefined || selected === null ? null : String(selected)"
71
+ :ariaLabel="label || writeKey"
72
+ data-testid="cn-workspace-filter-chips"
73
+ @update:modelValue="applySelection" />
74
+
75
+ <!-- Toggle style (screens-page-controls): a switch that writes
76
+ `onValue` / `offValue` (true / false) to the key. -->
77
+ <NcCheckboxRadioSwitch
78
+ v-else-if="style === 'toggle'"
79
+ class="cn-workspace-filter-widget__toggle"
80
+ type="switch"
81
+ :modelValue="toggleOn"
82
+ data-testid="cn-workspace-filter-toggle"
83
+ @update:modelValue="onToggle">
84
+ {{ tr(label) }}
85
+ </NcCheckboxRadioSwitch>
86
+
16
87
  <!-- Select style -->
17
88
  <NcSelect
18
89
  v-else-if="style === 'select'"
19
90
  :modelValue="selectedOption"
20
91
  :options="displayOptions"
21
92
  :clearable="false"
22
- :inputLabel="label || writeKey"
93
+ :inputLabel="content.inline ? '' : (label || writeKey)"
94
+ :labelOutside="content.inline === true"
95
+ :ariaLabelCombobox="label || writeKey"
23
96
  label="label"
24
97
  data-testid="cn-workspace-filter-select"
25
98
  @update:modelValue="onSelect" />
26
99
 
27
100
  <!-- Radio-list style (default) -->
28
- <ul v-else
101
+ <ul v-else-if="!isBar"
29
102
  class="cn-workspace-filter-widget__list"
30
103
  role="radiogroup"
31
104
  :aria-label="label || writeKey">
@@ -47,13 +120,27 @@
47
120
  </NcCheckboxRadioSwitch>
48
121
  </li>
49
122
  </ul>
123
+
124
+ <component
125
+ :is="startLink.to ? 'router-link' : 'a'"
126
+ v-if="startLink"
127
+ :to="startLink.to || undefined"
128
+ :href="startLink.href || undefined"
129
+ class="cn-workspace-filter-widget__link"
130
+ data-testid="cn-workspace-filter-link">
131
+ {{ startLink.label }}
132
+ </component>
50
133
  </div>
51
134
  </template>
52
135
 
53
136
  <script>
137
+ import { subscribe, unsubscribe } from '@nextcloud/event-bus'
54
138
  import { translate as t } from '@nextcloud/l10n'
55
139
  import { NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'
140
+ import CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'
141
+ import CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'
56
142
  import { fetchEndpointSource } from '../../composables/useEndpointSource.js'
143
+ import { fetchListTotal } from '../../utils/fetchFilterCounts.js'
57
144
  import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
58
145
 
59
146
  /**
@@ -84,7 +171,7 @@ import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
84
171
  * content: {
85
172
  * label: 'Queue',
86
173
  * writes: '@workspace.queue',
87
- * style: 'radio', // 'radio' (default) | 'select'
174
+ * style: 'radio', // 'radio' (default) | 'select' | 'chips'
88
175
  * allLabel: 'All',
89
176
  * showCounts: true,
90
177
  * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },
@@ -94,7 +181,7 @@ import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
94
181
  export default {
95
182
  name: 'CnWorkspaceFilterWidget',
96
183
 
97
- components: { NcSelect, NcCheckboxRadioSwitch },
184
+ components: { CnResourceSelect, CnSegmentedControl, NcSelect, NcCheckboxRadioSwitch },
98
185
 
99
186
  inject: {
100
187
  /**
@@ -104,13 +191,35 @@ export default {
104
191
  * Null on pages without one (the widget then just emits `@change`).
105
192
  */
106
193
  cnWorkspaceContext: { default: null },
194
+ /** Host translate function, for the start card's texts. */
195
+ cnTranslate: { default: () => (key) => key },
107
196
  },
108
197
 
109
198
  props: {
110
199
  /**
111
200
  * Persisted configuration blob.
112
201
  *
113
- * @type {{label?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, default?: (string|number)}}
202
+ * Start card keys (abstract-start-card): `layout: "start"` draws
203
+ * `title` and `description` beside the control, and `link`
204
+ * (`{ label, route? | href? }`) after it. `objectSource`
205
+ * (`{ register, schema, labelField?, placeholder?, ariaLabel?, preload? }`)
206
+ * makes the control an OpenRegister object picker that searches on the
207
+ * server and writes the picked object's id; without a selection and
208
+ * without `allLabel` it selects the first object.
209
+ *
210
+ * Chips (screens-page-lenses): `style: "chips"` draws the options as one
211
+ * compact segmented group with a count after each label. An option's
212
+ * `countFrom` (`{ register, schema, filter? }`, or a list of them that
213
+ * are added up) counts that list; a static `count` is used otherwise.
214
+ * `urlKey` keeps the choice in the address (`?<urlKey>=<value>`), and
215
+ * the address wins over `default` on load.
216
+ *
217
+ * Page controls (screens-page-controls): `style: "toggle"` is a switch
218
+ * that writes `onValue` / `offValue` (true / false); `layout: "bar"`
219
+ * with `controls` draws several controls side by side in one row, and
220
+ * `align: "end"` pushes a control to the right edge.
221
+ *
222
+ * @type {{label?: string, controls?: Array<object>, onValue?: unknown, offValue?: unknown, align?: string, urlKey?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, objectSource?: object, default?: (string|number), layout?: string, title?: string, description?: string, link?: object}}
114
223
  */
115
224
  content: {
116
225
  type: Object,
@@ -128,6 +237,8 @@ export default {
128
237
  loading: false,
129
238
  /** The currently-selected value (mirrors the workspace key). */
130
239
  selected: undefined,
240
+ /** Counted totals of the options that ask (`countFrom`), by option position. */
241
+ optionCounts: {},
131
242
  }
132
243
  },
133
244
 
@@ -137,9 +248,117 @@ export default {
137
248
  return this.content.label || ''
138
249
  },
139
250
 
140
- /** Choice style: 'select' or 'radio' (default). */
251
+ /** Whether the widget draws the start card. */
252
+ isStart() {
253
+ return this.content.layout === 'start'
254
+ },
255
+
256
+ /** The start card's title, translated. */
257
+ title() {
258
+ return this.tr(this.content.title || '')
259
+ },
260
+
261
+ /** The start card's guidance line, translated. */
262
+ description() {
263
+ return this.tr(this.content.description || '')
264
+ },
265
+
266
+ /**
267
+ * The link after the control, or null.
268
+ *
269
+ * @return {{label: string, to?: object, href?: string}|null}
270
+ */
271
+ startLink() {
272
+ const link = this.content.link
273
+ if (!link || typeof link !== 'object' || !link.label) {
274
+ return null
275
+ }
276
+ if (link.route && typeof link.route === 'object' && link.route.name) {
277
+ return { label: this.tr(link.label), to: link.route }
278
+ }
279
+ if (typeof link.href === 'string' && link.href !== '') {
280
+ return { label: this.tr(link.label), href: link.href }
281
+ }
282
+ return null
283
+ },
284
+
285
+ /**
286
+ * The object picker declaration, or null.
287
+ *
288
+ * @return {{register: string, schema: string, labelField?: string}|null}
289
+ */
290
+ objectSource() {
291
+ const src = this.content.objectSource
292
+ return src && typeof src === 'object' && src.register && src.schema ? src : null
293
+ },
294
+
295
+ /** Choice style: 'chips', 'select' or 'radio' (default). */
141
296
  style() {
142
- return this.content.style === 'select' ? 'select' : 'radio'
297
+ return ['select', 'chips', 'toggle'].includes(this.content.style) ? this.content.style : 'radio'
298
+ },
299
+
300
+ /**
301
+ * The chips: each option with its label translated and its count,
302
+ * the static one or the counted one.
303
+ *
304
+ * @return {Array<{value: string, label: string, count?: number}>}
305
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts
306
+ */
307
+ chipOptions() {
308
+ return this.displayOptions.map((option, index) => {
309
+ const counted = this.optionCounts[index]
310
+ const count = counted !== undefined && counted !== null ? counted : option.count
311
+ const chip = { value: String(option.value), label: this.tr(option.label) }
312
+ if (this.showCounts && Number.isFinite(count)) {
313
+ chip.count = count
314
+ }
315
+ return chip
316
+ })
317
+ },
318
+
319
+ /**
320
+ * Whether the widget is a bar of controls (`layout: "bar"`).
321
+ *
322
+ * @return {boolean}
323
+ * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-bar-holds-the-pages-controls-in-one-row
324
+ */
325
+ isBar() {
326
+ return this.content.layout === 'bar' && Array.isArray(this.content.controls)
327
+ },
328
+
329
+ /**
330
+ * The bar's controls, each an inline workspace filter of its own.
331
+ *
332
+ * @return {Array<object>}
333
+ */
334
+ barControls() {
335
+ return this.content.controls
336
+ .filter((control) => control && typeof control === 'object')
337
+ .map((control) => ({ ...control, inline: true }))
338
+ },
339
+
340
+ /** @return {unknown} The value a switch writes when on. */
341
+ onValue() {
342
+ return this.content.onValue !== undefined ? this.content.onValue : true
343
+ },
344
+
345
+ /** @return {unknown} The value a switch writes when off. */
346
+ offValue() {
347
+ return this.content.offValue !== undefined ? this.content.offValue : false
348
+ },
349
+
350
+ /** @return {boolean} Whether the switch is on. */
351
+ toggleOn() {
352
+ return this.selected !== undefined && String(this.selected) === String(this.onValue)
353
+ },
354
+
355
+ /**
356
+ * The address key that carries the choice (`urlKey`), or ''.
357
+ *
358
+ * @return {string}
359
+ */
360
+ urlKey() {
361
+ return typeof this.content.urlKey === 'string' ? this.content.urlKey : ''
143
362
  },
144
363
 
145
364
  /** Whether to render per-option counts. */
@@ -220,17 +439,115 @@ export default {
220
439
  // Seed the selection: existing workspace value → content.default → the
221
440
  // "All" clear option (empty) when present, else the first option once
222
441
  // loaded (handled in loadOptions).
442
+ const fromAddress = this.readAddress()
223
443
  const existing = this.readWorkspace()
224
- if (existing !== undefined) {
444
+ if (fromAddress !== undefined) {
445
+ this.selected = fromAddress
446
+ this.writeWorkspace(fromAddress)
447
+ } else if (existing !== undefined) {
225
448
  this.selected = existing
226
449
  } else if (this.content.default !== undefined) {
227
450
  this.selected = this.content.default
228
451
  this.writeWorkspace(this.content.default)
452
+ } else if (this.style === 'toggle') {
453
+ // A switch starts off, and says so, so a condition on its key holds.
454
+ this.selected = this.offValue
455
+ this.writeWorkspace(this.offValue)
229
456
  }
230
457
  this.loadOptions()
231
458
  },
232
459
 
460
+ mounted() {
461
+ this.onPageRefresh = () => this.loadCounts()
462
+ subscribe('cn:page:refresh', this.onPageRefresh)
463
+ this.loadCounts()
464
+ },
465
+
466
+ beforeUnmount() {
467
+ unsubscribe('cn:page:refresh', this.onPageRefresh)
468
+ },
469
+
233
470
  methods: {
471
+ /**
472
+ * The choice named in the address (`?<urlKey>=…`), when it is one of
473
+ * the options; undefined otherwise.
474
+ *
475
+ * @return {string|undefined}
476
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address
477
+ */
478
+ readAddress() {
479
+ if (!this.urlKey || !this.$route || !this.$route.query) {
480
+ return undefined
481
+ }
482
+ const raw = this.$route.query[this.urlKey]
483
+ if (this.style === 'toggle') {
484
+ if (raw === undefined) {
485
+ return undefined
486
+ }
487
+ return [this.onValue, this.offValue].find((value) => String(value) === String(raw))
488
+ }
489
+ const known = this.displayOptions.some((option) => String(option.value) === String(raw))
490
+ return known ? String(raw) : undefined
491
+ },
492
+
493
+ /**
494
+ * Write the choice to the address, replacing the history entry and
495
+ * keeping the other query keys.
496
+ *
497
+ * @param {unknown} value The chosen value.
498
+ * @return {void}
499
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address
500
+ */
501
+ writeAddress(value) {
502
+ if (!this.urlKey || !this.$router || !this.$route) {
503
+ return
504
+ }
505
+ const query = this.$route.query || {}
506
+ if (String(query[this.urlKey]) === String(value)) {
507
+ return
508
+ }
509
+ const result = this.$router.replace({ query: { ...query, [this.urlKey]: String(value) } })
510
+ if (result && typeof result.catch === 'function') {
511
+ result.catch(() => {})
512
+ }
513
+ },
514
+
515
+ /**
516
+ * Count the lists behind the options that ask (`countFrom`: a list
517
+ * `{ register, schema, filter? }`, or several that are added up). One
518
+ * list request each; an option whose count failed shows none.
519
+ *
520
+ * @return {Promise<void>}
521
+ * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts
522
+ */
523
+ async loadCounts() {
524
+ const options = this.displayOptions
525
+ const seq = (this.countSeq = (this.countSeq || 0) + 1)
526
+ const ctx = { workspace: this.readWorkspaceBag() }
527
+ await Promise.all(options.map(async (option, index) => {
528
+ const raw = (Array.isArray(this.content.options) ? this.content.options : [])
529
+ .find((candidate) => candidate && typeof candidate === 'object' && String(candidate.value ?? candidate.id) === String(option.value))
530
+ const from = raw ? raw.countFrom : null
531
+ const lists = (Array.isArray(from) ? from : [from]).filter((list) => list && typeof list === 'object' && list.register && list.schema)
532
+ if (lists.length === 0) {
533
+ return
534
+ }
535
+ let total
536
+ try {
537
+ const parts = await Promise.all(lists.map((list) => fetchListTotal(list.register, list.schema, list.filter || {}, ctx)))
538
+ if (parts.some((part) => part === null)) {
539
+ throw new Error('no total')
540
+ }
541
+ total = parts.reduce((sum, part) => sum + part, 0)
542
+ } catch {
543
+ total = null
544
+ }
545
+ if (seq === this.countSeq) {
546
+ this.optionCounts = { ...this.optionCounts, [index]: total }
547
+ }
548
+ }))
549
+ },
550
+
234
551
  /**
235
552
  * Normalise a raw option into `{ value, label, count? }`. Accepts
236
553
  * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR
@@ -263,6 +580,10 @@ export default {
263
580
  * @return {Promise<void>}
264
581
  */
265
582
  async loadOptions() {
583
+ if (this.objectSource) {
584
+ await this.seedFirstObject()
585
+ return
586
+ }
266
587
  if (this.content.endpointSource && this.content.endpointSource.url) {
267
588
  await this.loadFromEndpoint()
268
589
  } else if (this.content.source && this.content.source.schema) {
@@ -281,6 +602,51 @@ export default {
281
602
  }
282
603
  },
283
604
 
605
+ /**
606
+ * Translate a manifest string through the host app.
607
+ *
608
+ * @param {string} text The text.
609
+ * @return {string}
610
+ */
611
+ tr(text) {
612
+ if (typeof text !== 'string' || text === '') {
613
+ return ''
614
+ }
615
+ return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
616
+ },
617
+
618
+ /**
619
+ * The object picker's default: with nothing selected, no `default` and
620
+ * no `allLabel`, select the first object the source lists, so the page
621
+ * always has one in focus. Fail-safe: a failed read selects nothing.
622
+ *
623
+ * @return {Promise<void>}
624
+ */
625
+ async seedFirstObject() {
626
+ if ((this.selected !== undefined && this.selected !== '') || this.content.allLabel || this.content.default !== undefined) {
627
+ return
628
+ }
629
+ const src = this.objectSource
630
+ try {
631
+ const [{ default: axios }, { generateUrl }] = await Promise.all([
632
+ import('@nextcloud/axios'),
633
+ import('@nextcloud/router'),
634
+ ])
635
+ const url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: src.register, schema: src.schema })
636
+ const res = await axios.get(url, { params: { _limit: 1 } })
637
+ const data = res && res.data
638
+ const rows = Array.isArray(data) ? data : ((data && data.results) || [])
639
+ const first = rows[0]
640
+ const id = first && (first.id || (first['@self'] && first['@self'].id))
641
+ if (id && (this.selected === undefined || this.selected === '') && this.readWorkspace() === undefined) {
642
+ this.selected = String(id)
643
+ this.writeWorkspace(String(id))
644
+ }
645
+ } catch {
646
+ // Nothing selected: the siblings wait for a pick.
647
+ }
648
+ },
649
+
284
650
  /**
285
651
  * Fetch options from an `endpointSource` (array of options at
286
652
  * responsePath). Fail-safe: a failed fetch leaves an empty list.
@@ -358,6 +724,17 @@ export default {
358
724
  this.applySelection(option.value)
359
725
  },
360
726
 
727
+ /**
728
+ * Switch handler: write `onValue` or `offValue`.
729
+ *
730
+ * @param {boolean} on Whether the switch is on.
731
+ * @return {void}
732
+ * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-toggle-and-a-select-are-page-controls
733
+ */
734
+ onToggle(on) {
735
+ this.applySelection(on ? this.onValue : this.offValue)
736
+ },
737
+
361
738
  /**
362
739
  * NcSelect input handler.
363
740
  *
@@ -378,6 +755,7 @@ export default {
378
755
  applySelection(value) {
379
756
  this.selected = value
380
757
  this.writeWorkspace(value)
758
+ this.writeAddress(value)
381
759
  /**
382
760
  * @event change Emitted when the selection changes. Payload: `{ key, value }`.
383
761
  */
@@ -465,6 +843,85 @@ export default {
465
843
  gap: 2px;
466
844
  }
467
845
 
846
+ /* The chips: the compact segmented group, left, in the card the grid draws. */
847
+ .cn-workspace-filter-widget--chips {
848
+ flex-direction: row;
849
+ flex-wrap: wrap;
850
+ align-items: center;
851
+ }
852
+
853
+ /* A bar: its controls in one row, an `align: "end"` control pushed right. */
854
+ .cn-workspace-filter-widget--bar {
855
+ flex-direction: row;
856
+ flex-wrap: wrap;
857
+ align-items: center;
858
+ gap: 12px 16px;
859
+ }
860
+
861
+ /* An inline control sits in a bar: label left of the control, width to its content. */
862
+ .cn-workspace-filter-widget--inline {
863
+ flex-direction: row;
864
+ align-items: center;
865
+ gap: 8px;
866
+ width: auto;
867
+ }
868
+
869
+ .cn-workspace-filter-widget--inline .cn-workspace-filter-widget__label {
870
+ font-weight: 400;
871
+ color: var(--color-text-maxcontrast);
872
+ }
873
+
874
+ .cn-workspace-filter-widget--end {
875
+ margin-inline-start: auto;
876
+ }
877
+
878
+ .cn-workspace-filter-widget--end ~ .cn-workspace-filter-widget--end {
879
+ margin-inline-start: 0;
880
+ }
881
+
882
+ .cn-workspace-filter-widget__toggle {
883
+ font-weight: 600;
884
+ }
885
+
886
+ /* The start card: text left, control (and link) right, as PqDashboard's "Contact starten". */
887
+ .cn-workspace-filter-widget--start {
888
+ flex-direction: row;
889
+ flex-wrap: wrap;
890
+ align-items: center;
891
+ gap: 16px 24px;
892
+ }
893
+
894
+ .cn-workspace-filter-widget__text {
895
+ flex: 1 1 320px;
896
+ min-width: 0;
897
+ }
898
+
899
+ .cn-workspace-filter-widget__title {
900
+ margin: 0 0 4px;
901
+ font-size: 17px;
902
+ font-weight: 700;
903
+ color: var(--color-main-text);
904
+ }
905
+
906
+ .cn-workspace-filter-widget__description {
907
+ margin: 0;
908
+ max-width: 420px;
909
+ color: var(--color-text-maxcontrast);
910
+ }
911
+
912
+ .cn-workspace-filter-widget--start .cn-workspace-filter-widget__control,
913
+ .cn-workspace-filter-widget--start > .v-select {
914
+ flex: 0 1 480px;
915
+ min-width: 240px;
916
+ }
917
+
918
+ .cn-workspace-filter-widget__link {
919
+ font-weight: 600;
920
+ color: var(--color-primary-element);
921
+ text-decoration: underline;
922
+ white-space: nowrap;
923
+ }
924
+
468
925
  .cn-workspace-filter-widget__count {
469
926
  margin-inline-start: 6px;
470
927
  padding: 0 6px;
@@ -473,4 +930,29 @@ export default {
473
930
  color: var(--color-text-maxcontrast);
474
931
  font-size: 0.85em;
475
932
  }
933
+
934
+ /* On a phone the bar's controls take a row each (the chips already wrap), and
935
+ a switch and a select are 44px touch targets. */
936
+ @media (max-width: 640px) {
937
+ .cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--inline {
938
+ flex: 1 1 100%;
939
+ }
940
+
941
+ .cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--end {
942
+ margin-inline-start: 0;
943
+ }
944
+
945
+ .cn-workspace-filter-widget--inline .cn-workspace-filter-widget__toggle {
946
+ min-height: 44px;
947
+ }
948
+
949
+ .cn-workspace-filter-widget--inline :deep(.v-select) {
950
+ flex: 1 1 auto;
951
+ min-width: 0;
952
+ }
953
+
954
+ .cn-workspace-filter-widget--inline :deep(.vs__dropdown-toggle) {
955
+ min-height: 44px;
956
+ }
957
+ }
476
958
  </style>