@conduction/nextcloud-vue 2.80.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 (290) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +3 -3
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  4. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +80 -4
  5. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +95 -91
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  8. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +140 -10
  9. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  10. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +52 -16
  11. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  12. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +17 -3
  13. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  14. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +63 -52
  15. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  16. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
  17. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
  18. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
  19. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
  20. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
  21. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
  22. package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
  23. package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
  24. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
  25. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
  26. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
  27. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
  28. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
  29. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
  30. package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
  31. package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
  32. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +1 -1
  33. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  34. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  35. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +2 -2
  36. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  37. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  38. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +65 -5
  39. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  40. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
  41. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  42. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +19 -11
  43. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  44. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +3 -2
  45. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +72 -0
  47. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  48. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +21 -4
  49. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  50. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +1 -1
  51. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -1
  52. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -1
  53. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js +7 -7
  54. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js.map +1 -1
  55. package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue3.js.map +1 -1
  56. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +131 -0
  57. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  58. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  59. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +80 -5
  60. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  61. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +282 -69
  62. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  63. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +302 -4
  64. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  65. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +417 -244
  66. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  67. package/dist/esm/components/CnFilesBrowser/filesBrowser.js +101 -1
  68. package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
  69. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +141 -1
  70. package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
  71. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +60 -0
  72. package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
  73. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js +74 -49
  74. package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
  75. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +29 -2
  76. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  77. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +48 -4
  78. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  79. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +7 -7
  80. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  81. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  82. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +1 -1
  83. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
  85. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  86. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
  87. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  88. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +63 -1
  89. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  90. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +8 -1
  91. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  92. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +14 -0
  93. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  94. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js +5 -1
  95. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  96. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
  97. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
  98. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
  99. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
  100. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
  101. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
  102. package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
  103. package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
  104. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +30 -6
  105. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  106. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +34 -25
  107. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  108. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
  109. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
  110. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
  111. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
  112. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
  113. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
  114. package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
  115. package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
  116. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  117. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  118. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
  119. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
  120. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
  121. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
  122. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
  123. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
  124. package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
  125. package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
  126. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
  127. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  128. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  129. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +84 -1
  130. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  131. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +85 -41
  132. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  133. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
  134. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
  135. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
  136. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
  137. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
  138. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
  139. package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
  140. package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
  141. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +47 -1
  142. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  143. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +16 -14
  144. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  145. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
  146. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  147. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
  148. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  149. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
  150. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
  151. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
  152. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
  153. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
  154. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
  155. package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
  156. package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
  157. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
  158. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  159. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +7 -2
  160. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  161. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  162. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  163. package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js.map +1 -1
  164. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +197 -6
  165. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  166. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +96 -50
  167. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  168. package/dist/esm/composables/useListView.js +4 -4
  169. package/dist/esm/composables/useListView.js.map +1 -1
  170. package/dist/esm/index.js +17 -1
  171. package/dist/esm/index.js.map +1 -1
  172. package/dist/esm/l10n/en.json.js +9 -1
  173. package/dist/esm/l10n/en.json.js.map +1 -1
  174. package/dist/esm/l10n/nl.json.js +55 -1
  175. package/dist/esm/l10n/nl.json.js.map +1 -1
  176. package/dist/esm/nextcloud-vue.css +1041 -12
  177. package/dist/esm/utils/contentHeaderLink.js +51 -0
  178. package/dist/esm/utils/contentHeaderLink.js.map +1 -0
  179. package/dist/esm/utils/facets.js +75 -3
  180. package/dist/esm/utils/facets.js.map +1 -1
  181. package/dist/esm/utils/fetchFilterCounts.js +40 -5
  182. package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
  183. package/dist/esm/utils/fillTemplate.js +7 -1
  184. package/dist/esm/utils/fillTemplate.js.map +1 -1
  185. package/dist/esm/utils/initials.js +32 -0
  186. package/dist/esm/utils/initials.js.map +1 -0
  187. package/dist/esm/utils/libraryWidgetKeys.js +7 -0
  188. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  189. package/dist/esm/utils/objectWrite.js +59 -0
  190. package/dist/esm/utils/objectWrite.js.map +1 -0
  191. package/dist/esm/utils/pageControls.js +81 -0
  192. package/dist/esm/utils/pageControls.js.map +1 -0
  193. package/dist/esm/utils/personalLenses.js +40 -3
  194. package/dist/esm/utils/personalLenses.js.map +1 -1
  195. package/dist/esm/utils/resolveFilterTokens.js +1 -1
  196. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  197. package/dist/esm/utils/resolveManifestTokens.js +2 -0
  198. package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
  199. package/dist/esm/utils/sentinelTokens.js +19 -1
  200. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  201. package/dist/esm/utils/userGroupsPeek.js +91 -0
  202. package/dist/esm/utils/userGroupsPeek.js.map +1 -0
  203. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  204. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  205. package/dist/esm/utils/visibleWhen.js +57 -5
  206. package/dist/esm/utils/visibleWhen.js.map +1 -1
  207. package/dist/esm/utils/widgetDispatch.js +1 -1
  208. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  209. package/dist/esm/utils/widgetVisibility.js +4 -57
  210. package/dist/esm/utils/widgetVisibility.js.map +1 -1
  211. package/dist/nextcloud-vue.cjs.js +13589 -7833
  212. package/dist/nextcloud-vue.cjs.js.map +2 -2
  213. package/dist/nextcloud-vue.css +1041 -12
  214. package/l10n/en.json +9 -1
  215. package/l10n/nl.json +55 -1
  216. package/package.json +2 -1
  217. package/scripts/check-docs-mdx.mjs +108 -0
  218. package/src/components/CnActionsBar/CnActionsBar.vue +6 -1
  219. package/src/components/CnAppRoot/CnAppRoot.md +4 -2
  220. package/src/components/CnAppRoot/CnAppRoot.vue +151 -59
  221. package/src/components/CnBannerWidget/CnBannerWidget.vue +205 -20
  222. package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
  223. package/src/components/CnCellRenderer/CnCellRenderer.vue +47 -4
  224. package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
  225. package/src/components/CnChipsFieldWidget/index.js +25 -0
  226. package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
  227. package/src/components/CnChoicePickerWidget/index.js +26 -0
  228. package/src/components/CnConversationThread/CnConversationWidget.vue +1 -1
  229. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +2 -2
  230. package/src/components/CnDashboardPage/CnDashboardPage.vue +78 -5
  231. package/src/components/CnDataTable/CnDataTable.vue +21 -12
  232. package/src/components/CnDetailPage/CnDetailPage.vue +89 -3
  233. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +1 -1
  234. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +7 -7
  235. package/src/components/CnFactsWidget/CnFactsWidget.vue +142 -2
  236. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +268 -6
  237. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +588 -117
  238. package/src/components/CnFilesBrowser/filesBrowser.js +100 -0
  239. package/src/components/CnFilesBrowser/filesBrowserColumns.js +140 -0
  240. package/src/components/CnFormPage/CnFormPage.vue +81 -0
  241. package/src/components/CnIndexPage/CnIndexPage.vue +56 -4
  242. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +7 -7
  243. package/src/components/CnNextStepCard/CnNextStepWidget.vue +1 -1
  244. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
  245. package/src/components/CnObjectSidebar/CnFilesTab.vue +70 -1
  246. package/src/components/CnObjectSidebar/CnNotesTab.vue +16 -0
  247. package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
  248. package/src/components/CnRadioCardsWidget/index.js +27 -0
  249. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +55 -6
  250. package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
  251. package/src/components/CnSavedViewsWidget/index.js +29 -0
  252. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
  253. package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
  254. package/src/components/CnSettingsFormWidget/index.js +26 -0
  255. package/src/components/CnStatWidget/CnStatWidget.vue +87 -6
  256. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +180 -3
  257. package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
  258. package/src/components/CnSwitchRowsWidget/index.js +25 -0
  259. package/src/components/CnTabsWidget/CnTabsWidget.vue +82 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
  261. package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
  262. package/src/components/CnToggleTableWidget/index.js +26 -0
  263. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
  264. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +7 -2
  265. package/src/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
  266. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +309 -11
  267. package/src/components/index.js +15 -0
  268. package/src/composables/useListView.js +4 -4
  269. package/src/css/look-board-detail.css +36 -2
  270. package/src/css/look-board-index.css +39 -8
  271. package/src/css/look-board.css +72 -0
  272. package/src/index.js +15 -0
  273. package/src/schemas/app-manifest-v2.schema.json +93 -9
  274. package/src/utils/contentHeaderLink.js +48 -0
  275. package/src/utils/facets.js +74 -2
  276. package/src/utils/fetchFilterCounts.js +39 -4
  277. package/src/utils/fillTemplate.js +7 -1
  278. package/src/utils/initials.js +29 -0
  279. package/src/utils/libraryWidgetKeys.js +7 -0
  280. package/src/utils/objectWrite.js +55 -0
  281. package/src/utils/pageControls.js +78 -0
  282. package/src/utils/personalLenses.js +39 -2
  283. package/src/utils/resolveFilterTokens.js +3 -1
  284. package/src/utils/resolveManifestTokens.js +2 -0
  285. package/src/utils/sentinelTokens.js +19 -1
  286. package/src/utils/userGroupsPeek.js +87 -0
  287. package/src/utils/validateManifestV2.compiled.js +3 -3
  288. package/src/utils/visibleWhen.js +56 -4
  289. package/src/utils/widgetDispatch.js +1 -1
  290. package/src/utils/widgetVisibility.js +7 -56
@@ -6,7 +6,13 @@
6
6
  <template>
7
7
  <div
8
8
  class="cn-workspace-filter-widget"
9
- :class="{ 'cn-workspace-filter-widget--start': isStart }"
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
+ }"
10
16
  data-testid="cn-workspace-filter-widget">
11
17
  <!-- The start card (`layout: "start"`): a title and one line of
12
18
  guidance beside the control, as the "Contact starten" card. -->
@@ -19,14 +25,24 @@
19
25
  </p>
20
26
  </div>
21
27
 
22
- <p v-if="label" class="cn-workspace-filter-widget__label">
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">
23
39
  {{ label }}
24
40
  </p>
25
41
 
26
42
  <!-- An object picker (`objectSource`): searches OpenRegister on the
27
43
  server, so it reaches every object, not a fetched page. -->
28
44
  <CnResourceSelect
29
- v-if="objectSource"
45
+ v-if="!isBar && objectSource"
30
46
  class="cn-workspace-filter-widget__control"
31
47
  :register="objectSource.register"
32
48
  :schema="objectSource.schema"
@@ -44,19 +60,45 @@
44
60
  {{ loadingLabel }}
45
61
  </div>
46
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
+
47
87
  <!-- Select style -->
48
88
  <NcSelect
49
89
  v-else-if="style === 'select'"
50
90
  :modelValue="selectedOption"
51
91
  :options="displayOptions"
52
92
  :clearable="false"
53
- :inputLabel="label || writeKey"
93
+ :inputLabel="content.inline ? '' : (label || writeKey)"
94
+ :labelOutside="content.inline === true"
95
+ :ariaLabelCombobox="label || writeKey"
54
96
  label="label"
55
97
  data-testid="cn-workspace-filter-select"
56
98
  @update:modelValue="onSelect" />
57
99
 
58
100
  <!-- Radio-list style (default) -->
59
- <ul v-else
101
+ <ul v-else-if="!isBar"
60
102
  class="cn-workspace-filter-widget__list"
61
103
  role="radiogroup"
62
104
  :aria-label="label || writeKey">
@@ -92,10 +134,13 @@
92
134
  </template>
93
135
 
94
136
  <script>
137
+ import { subscribe, unsubscribe } from '@nextcloud/event-bus'
95
138
  import { translate as t } from '@nextcloud/l10n'
96
139
  import { NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'
97
140
  import CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'
141
+ import CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'
98
142
  import { fetchEndpointSource } from '../../composables/useEndpointSource.js'
143
+ import { fetchListTotal } from '../../utils/fetchFilterCounts.js'
99
144
  import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
100
145
 
101
146
  /**
@@ -126,7 +171,7 @@ import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
126
171
  * content: {
127
172
  * label: 'Queue',
128
173
  * writes: '@workspace.queue',
129
- * style: 'radio', // 'radio' (default) | 'select'
174
+ * style: 'radio', // 'radio' (default) | 'select' | 'chips'
130
175
  * allLabel: 'All',
131
176
  * showCounts: true,
132
177
  * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },
@@ -136,7 +181,7 @@ import { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
136
181
  export default {
137
182
  name: 'CnWorkspaceFilterWidget',
138
183
 
139
- components: { CnResourceSelect, NcSelect, NcCheckboxRadioSwitch },
184
+ components: { CnResourceSelect, CnSegmentedControl, NcSelect, NcCheckboxRadioSwitch },
140
185
 
141
186
  inject: {
142
187
  /**
@@ -162,7 +207,19 @@ export default {
162
207
  * server and writes the picked object's id; without a selection and
163
208
  * without `allLabel` it selects the first object.
164
209
  *
165
- * @type {{label?: 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}}
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}}
166
223
  */
167
224
  content: {
168
225
  type: Object,
@@ -180,6 +237,8 @@ export default {
180
237
  loading: false,
181
238
  /** The currently-selected value (mirrors the workspace key). */
182
239
  selected: undefined,
240
+ /** Counted totals of the options that ask (`countFrom`), by option position. */
241
+ optionCounts: {},
183
242
  }
184
243
  },
185
244
 
@@ -233,9 +292,73 @@ export default {
233
292
  return src && typeof src === 'object' && src.register && src.schema ? src : null
234
293
  },
235
294
 
236
- /** Choice style: 'select' or 'radio' (default). */
295
+ /** Choice style: 'chips', 'select' or 'radio' (default). */
237
296
  style() {
238
- 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 : ''
239
362
  },
240
363
 
241
364
  /** Whether to render per-option counts. */
@@ -316,17 +439,115 @@ export default {
316
439
  // Seed the selection: existing workspace value → content.default → the
317
440
  // "All" clear option (empty) when present, else the first option once
318
441
  // loaded (handled in loadOptions).
442
+ const fromAddress = this.readAddress()
319
443
  const existing = this.readWorkspace()
320
- if (existing !== undefined) {
444
+ if (fromAddress !== undefined) {
445
+ this.selected = fromAddress
446
+ this.writeWorkspace(fromAddress)
447
+ } else if (existing !== undefined) {
321
448
  this.selected = existing
322
449
  } else if (this.content.default !== undefined) {
323
450
  this.selected = this.content.default
324
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)
325
456
  }
326
457
  this.loadOptions()
327
458
  },
328
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
+
329
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
+
330
551
  /**
331
552
  * Normalise a raw option into `{ value, label, count? }`. Accepts
332
553
  * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR
@@ -503,6 +724,17 @@ export default {
503
724
  this.applySelection(option.value)
504
725
  },
505
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
+
506
738
  /**
507
739
  * NcSelect input handler.
508
740
  *
@@ -523,6 +755,7 @@ export default {
523
755
  applySelection(value) {
524
756
  this.selected = value
525
757
  this.writeWorkspace(value)
758
+ this.writeAddress(value)
526
759
  /**
527
760
  * @event change Emitted when the selection changes. Payload: `{ key, value }`.
528
761
  */
@@ -610,6 +843,46 @@ export default {
610
843
  gap: 2px;
611
844
  }
612
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
+
613
886
  /* The start card: text left, control (and link) right, as PqDashboard's "Contact starten". */
614
887
  .cn-workspace-filter-widget--start {
615
888
  flex-direction: row;
@@ -657,4 +930,29 @@ export default {
657
930
  color: var(--color-text-maxcontrast);
658
931
  font-size: 0.85em;
659
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
+ }
660
958
  </style>
@@ -219,7 +219,21 @@ export { CnTasksWidgetForm } from './CnTasksWidgetForm/index.js'
219
219
  export { CnSectionsWidget } from './CnSectionsWidget/index.js'
220
220
  export { CnFactsWidget } from './CnFactsWidget/index.js'
221
221
  export { CnFieldListWidget } from './CnFieldListWidget/index.js'
222
+ export { CnSettingsFormWidget } from './CnSettingsFormWidget/index.js'
223
+ export { CnSwitchRowsWidget } from './CnSwitchRowsWidget/index.js'
224
+ export { CnRadioCardsWidget } from './CnRadioCardsWidget/index.js'
225
+ export { CnChipsFieldWidget } from './CnChipsFieldWidget/index.js'
226
+ export { CnToggleTableWidget } from './CnToggleTableWidget/index.js'
227
+ export { CnChoicePickerWidget } from './CnChoicePickerWidget/index.js'
222
228
  export { CnRecordListWidget } from './CnRecordListWidget/index.js'
229
+ export { CnBannerWidget } from './CnBannerWidget/index.js'
230
+ export { default as CnConversationWidget } from './CnConversationThread/CnConversationWidget.vue'
231
+ export { default as CnDocumentReviewWidget } from './CnDocumentReviewList/CnDocumentReviewWidget.vue'
232
+ export { default as CnNextStepWidget } from './CnNextStepCard/CnNextStepWidget.vue'
233
+ export { default as CnAuditTrailWidget } from './CnAuditTrailWidget/CnAuditTrailWidget.vue'
234
+ export { CnKbSearchWidget } from './CnKbSearchWidget/index.js'
235
+ export { CnInteractionFormWidget } from './CnInteractionFormWidget/index.js'
236
+ export { CnWorkspaceFilterWidget } from './CnWorkspaceFilterWidget/index.js'
223
237
  export { CnFilePreview } from './CnFilePreview/index.js'
224
238
  export { CnTaskFormDialog } from './CnTaskFormDialog/index.js'
225
239
  export { CnChildRecordsField } from './CnChildRecordsField/index.js'
@@ -228,6 +242,7 @@ export { CnMarkdownWidget } from './CnMarkdownWidget/index.js'
228
242
  export { CnMarkdownWidgetForm } from './CnMarkdownWidgetForm/index.js'
229
243
  export { CnObjectListWidget } from './CnObjectListWidget/index.js'
230
244
  export { CnObjectListWidgetForm } from './CnObjectListWidgetForm/index.js'
245
+ export { CnSavedViewsWidget } from './CnSavedViewsWidget/index.js'
231
246
  export { CnSavedViewWidget } from './CnSavedViewWidget/index.js'
232
247
  export { CnSavedViewWidgetForm } from './CnSavedViewWidgetForm/index.js'
233
248
  export { CnChartWidgetForm } from './CnChartWidgetForm/index.js'
@@ -1,5 +1,6 @@
1
1
  import { computed, isRef, onBeforeUnmount, onMounted, ref, watch } from 'vue'
2
2
  import { useObjectStore } from '../store/index.js'
3
+ import { facetFilterParams } from '../utils/facets.js'
3
4
 
4
5
  /**
5
6
  * Composable for managing list view state with full objectStore integration.
@@ -163,10 +164,9 @@ export function useListView(objectTypeOrOptions, options) {
163
164
  }
164
165
 
165
166
  for (const [key, values] of Object.entries(activeFilters.value)) {
166
- if (values && values.length > 0) {
167
- // Single-value arrays are unwrapped to scalar params
168
- params[key] = values.length === 1 ? values[0] : values
169
- }
167
+ // Single-value arrays are unwrapped to scalar params; the
168
+ // missing-value option becomes `<key>_isnull=true`.
169
+ Object.assign(params, facetFilterParams(key, values))
170
170
  }
171
171
 
172
172
  // Fixed filters (e.g. a route-param-scoped `pages[].config.filter`) are
@@ -202,6 +202,15 @@
202
202
  gap: 4px;
203
203
  }
204
204
 
205
+ /* No inner scroller: tabs that do not fit the width wrap onto a second row
206
+ instead of scrolling sideways (the library's default strip), so the strip
207
+ has no scrollbar, no clipped tab and no fade or chevron to find the rest. */
208
+ .cn-look-board .cn-tabs--board .cn-tabs__nav {
209
+ flex-wrap: wrap;
210
+ overflow: visible;
211
+ row-gap: 4px;
212
+ }
213
+
205
214
  .cn-look-board .cn-tabs--board .cn-tabs__nav-item {
206
215
  background-color: var(--color-background-dark);
207
216
  border: 1px solid var(--color-border-dark);
@@ -347,12 +356,28 @@
347
356
  padding: 0 0 10px;
348
357
  }
349
358
 
350
- .cn-look-board .cn-object-data-widget__label {
351
- color: var(--color-text-maxcontrast);
359
+ /* Outranks the component's own `.cn-object-data-widget__label[data-v-...]`
360
+ (weight 500, 0.85em, which has the same specificity as the look's rule and
361
+ wins on source order wherever a bundle, such as a companion app's, loads
362
+ after this stylesheet), through the grid the labels sit in. Measured live:
363
+ the labels read bold and dark where the boards (DqContact, PqKlant, ShKlant)
364
+ draw them 13px, regular weight and light grey.
365
+
366
+ The colour carries `!important`: a theme (nldesign's element overrides) sets
367
+ the ink of every `div` outside the header with a selector that has an id in
368
+ its `:not()`, which no class rule outranks. */
369
+ .cn-look-board .cn-object-data-widget__grid .cn-object-data-widget__label {
370
+ color: var(--color-text-maxcontrast) !important;
352
371
  font-size: 13px;
353
372
  font-weight: 400;
354
373
  }
355
374
 
375
+ /* The facts card's labels: the same light grey, regular weight. */
376
+ .cn-look-board .cn-facts-widget .cn-facts-widget__label {
377
+ color: var(--color-text-maxcontrast);
378
+ font-weight: 400;
379
+ }
380
+
356
381
  .cn-look-board .cn-object-data-widget__value {
357
382
  font-weight: 500;
358
383
  }
@@ -610,3 +635,12 @@
610
635
  font-size: 13px;
611
636
  margin: 2px 0 0;
612
637
  }
638
+
639
+ /* The sidebar's own open toggle (NcAppSidebar's `.app-sidebar__toggle`, drawn
640
+ when the sidebar is closed) is positioned over the content's top-right
641
+ corner, which in this look is the header's last button: a stray square icon
642
+ on "More". The board draws none, so it is hidden on a detail page and the
643
+ header menu offers "Open sidebar" instead. */
644
+ .cn-look-board:has(.cn-detail-page) > .app-sidebar__toggle {
645
+ display: none;
646
+ }
@@ -249,7 +249,8 @@
249
249
  }
250
250
 
251
251
  /* Filter: a labelled secondary button, 36px, radius 8, with the active count. */
252
- .cn-look-board .cn-actions-bar__filter-button.button-vue {
252
+ .cn-look-board .cn-actions-bar__filter-button.button-vue,
253
+ .cn-look-board .cn-actions-bar__filter-menu .button-vue {
253
254
  min-height: 36px;
254
255
  height: 36px;
255
256
  border-radius: 8px;
@@ -499,11 +500,16 @@
499
500
  max-width: calc(100% - 26px);
500
501
  }
501
502
 
502
- /* The selection column: 28px, 18px checkboxes. */
503
+ /* The selection column: 18px checkboxes, 28px of content after 16px of padding.
504
+ The box model is set with `!important` and the widths include the padding:
505
+ Nextcloud's server.css sets `box-sizing: border-box` on everything under
506
+ `#content[class*="app-"]`, an id selector no class rule outranks, so a plain
507
+ `content-box` here was ignored and the cell left 12px for the checkbox (the
508
+ header's checkbox showed as a stray bracket). */
503
509
  .cn-look-board .cn-table-container--board .cn-data-table .cn-table-col--checkbox {
504
- box-sizing: content-box;
505
- width: 28px;
506
- min-width: 28px;
510
+ box-sizing: border-box !important;
511
+ width: 44px;
512
+ min-width: 44px;
507
513
  padding-inline: 16px 0;
508
514
  text-align: start;
509
515
  }
@@ -551,6 +557,29 @@
551
557
  font-size: 13px;
552
558
  }
553
559
 
560
+ /* An avatar in the title column (PtAccounts): a 32px chip circle, 10px before
561
+ the name, the e-mail under the name beside it. The name keeps the title's
562
+ weight and size, and its underline: an inline-flex box is atomic, so the
563
+ cell's own underline does not reach it. */
564
+ .cn-look-board .cn-table-container--board .cn-data-table .cn-cell-renderer__avatar {
565
+ gap: 10px;
566
+ }
567
+
568
+ .cn-look-board .cn-table-container--board .cn-data-table .cn-cell-renderer__avatar-initials {
569
+ background: var(--color-background-dark);
570
+ color: var(--color-main-text);
571
+ font-size: 12px;
572
+ }
573
+
574
+ .cn-look-board .cn-table-container--board .cn-data-table td.cn-table-col--title .cn-cell-renderer__avatar-name {
575
+ text-decoration: underline;
576
+ text-underline-offset: 2px;
577
+ }
578
+
579
+ .cn-look-board .cn-table-container--board.cn-table-container--title-plain .cn-data-table td.cn-table-col--title .cn-cell-renderer__avatar-name {
580
+ text-decoration: none;
581
+ }
582
+
554
583
  /* A status pill: 3px 10px, radius 12, 13px weight 600. The colours stay the
555
584
  status colour map's. */
556
585
  .cn-look-board .cn-table-container--board .cn-data-table .cn-status-badge {
@@ -561,10 +590,12 @@
561
590
  line-height: 1.4;
562
591
  }
563
592
 
564
- /* The row menu column holds one 34px button. */
593
+ /* The row menu column holds one 34px button between 16px of padding, so 66px
594
+ border to border (see the selection column for why the box model is forced). */
565
595
  .cn-look-board .cn-table-container--board .cn-data-table .cn-table-col--actions {
566
- width: 34px;
567
- min-width: 0;
596
+ box-sizing: border-box !important;
597
+ width: 66px;
598
+ min-width: 66px;
568
599
  padding-inline: 16px;
569
600
  text-align: end;
570
601
  }