@conduction/nextcloud-vue 2.58.0 → 2.60.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 (507) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +14 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  8. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  11. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +39 -0
  13. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +46 -4
  15. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  16. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +224 -9
  17. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +79 -25
  19. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  20. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js +42 -3
  21. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js.map +1 -1
  22. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js +39 -6
  23. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js.map +1 -1
  24. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +58 -5
  25. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  26. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +13 -5
  27. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  28. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js +10 -0
  29. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js.map +1 -0
  30. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +39 -0
  31. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -0
  32. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +16 -0
  33. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js.map +1 -0
  34. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  35. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  36. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  37. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -1
  38. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  39. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +147 -89
  40. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  41. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  42. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  43. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  44. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +10 -0
  45. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js.map +1 -0
  46. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +259 -0
  47. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -0
  48. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +131 -0
  49. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -0
  50. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +10 -0
  51. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js.map +1 -0
  52. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +116 -0
  53. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -0
  54. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +24 -0
  55. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -0
  56. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  57. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  58. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  59. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  60. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  61. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  62. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  63. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  64. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +532 -29
  65. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +300 -142
  67. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js +10 -0
  69. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js.map +1 -0
  70. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js +237 -0
  71. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js.map +1 -0
  72. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js +120 -0
  73. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js.map +1 -0
  74. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js +10 -0
  75. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js.map +1 -0
  76. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +77 -0
  77. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -0
  78. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js +27 -0
  79. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -0
  80. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  81. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  82. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  83. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  84. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  85. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  86. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  87. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  88. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  89. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  90. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  91. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  92. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  93. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  94. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  95. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  96. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  97. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +169 -12
  98. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +15 -7
  100. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  101. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js +37 -3
  102. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js.map +1 -1
  103. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js +44 -16
  104. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js.map +1 -1
  105. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +199 -16
  106. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  107. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +20 -10
  108. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  109. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  110. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  111. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  112. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  113. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  114. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  115. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  116. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  117. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  118. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  119. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  120. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  121. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  122. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  123. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  124. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js +10 -0
  125. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js.map +1 -0
  126. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js +150 -0
  127. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -0
  128. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js +106 -0
  129. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -0
  130. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js +9 -0
  131. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js.map +1 -0
  132. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +47 -0
  133. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -0
  134. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js +17 -0
  135. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js.map +1 -0
  136. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  137. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  138. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  139. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  140. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +49 -0
  141. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  142. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  143. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js +6 -0
  144. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js.map +1 -1
  145. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue3.js.map +1 -1
  146. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js +46 -0
  147. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js.map +1 -1
  148. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js +15 -3
  149. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js.map +1 -1
  150. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  151. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  152. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  153. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  154. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  155. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  156. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  157. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  158. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  159. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  160. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  161. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  162. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  163. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  164. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  165. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  166. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  167. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +37 -1
  168. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  169. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +29 -13
  170. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  171. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +100 -3
  172. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  173. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  174. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  175. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  176. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  177. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +50 -3
  178. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
  179. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
  180. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +10 -0
  181. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js.map +1 -0
  182. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +186 -0
  183. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -0
  184. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +46 -0
  185. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -0
  186. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  187. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  188. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  189. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +11 -0
  190. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js.map +1 -0
  191. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +298 -0
  192. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -0
  193. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +77 -0
  194. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -0
  195. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js +10 -0
  196. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js.map +1 -0
  197. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js +169 -0
  198. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js.map +1 -0
  199. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js +48 -0
  200. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js.map +1 -0
  201. package/dist/esm/components/CnTabs/CnTab.vue2.js +35 -0
  202. package/dist/esm/components/CnTabs/CnTab.vue2.js.map +1 -1
  203. package/dist/esm/components/CnTabs/CnTab.vue3.js.map +1 -1
  204. package/dist/esm/components/CnTabs/CnTabs.vue2.js +120 -7
  205. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  206. package/dist/esm/components/CnTabs/CnTabs.vue3.js +57 -5
  207. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  208. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +59 -4
  209. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  210. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +6 -2
  211. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  212. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  213. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  214. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  215. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  216. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +10 -0
  217. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js.map +1 -0
  218. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +484 -0
  219. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -0
  220. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +115 -0
  221. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -0
  222. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js +10 -0
  223. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js.map +1 -0
  224. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js +189 -0
  225. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js.map +1 -0
  226. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js +74 -0
  227. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js.map +1 -0
  228. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +82 -8
  229. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  230. package/dist/esm/index.js +10 -0
  231. package/dist/esm/index.js.map +1 -1
  232. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  233. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  234. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  235. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  236. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  237. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  238. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  239. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  240. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  241. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  242. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  243. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  244. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  245. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  246. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  247. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  248. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  249. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  250. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  251. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  252. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  253. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  254. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  255. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  256. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  257. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  258. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  259. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  260. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  261. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  262. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  263. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  264. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  265. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  266. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  267. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  268. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  269. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  270. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  271. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  272. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  273. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  274. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  275. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  276. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  277. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  278. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  279. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  280. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  281. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  282. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  283. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  284. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  285. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  286. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  287. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  288. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  289. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  290. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  291. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  292. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  293. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  294. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  295. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  296. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  297. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  298. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  299. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  300. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  301. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  302. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  303. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  304. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  305. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  306. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  307. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  308. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  309. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  310. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  311. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  312. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  313. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  314. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  315. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  316. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  317. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  318. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  319. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  320. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  321. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  322. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  323. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  324. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  325. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  326. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  327. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  328. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  329. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  330. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  331. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  332. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  333. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  334. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  335. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  336. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  337. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  338. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  339. package/dist/esm/l10n/en.json.js +55 -1
  340. package/dist/esm/l10n/en.json.js.map +1 -1
  341. package/dist/esm/l10n/nl.json.js +55 -1
  342. package/dist/esm/l10n/nl.json.js.map +1 -1
  343. package/dist/esm/nextcloud-vue.css +998 -7
  344. package/dist/esm/utils/actionLink.js +5 -0
  345. package/dist/esm/utils/actionLink.js.map +1 -1
  346. package/dist/esm/utils/actionsDispatcher.js +16 -1
  347. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  348. package/dist/esm/utils/dateVariant.js +124 -0
  349. package/dist/esm/utils/dateVariant.js.map +1 -0
  350. package/dist/esm/utils/detailActionModel.js +260 -0
  351. package/dist/esm/utils/detailActionModel.js.map +1 -0
  352. package/dist/esm/utils/dueRule.js +84 -0
  353. package/dist/esm/utils/dueRule.js.map +1 -0
  354. package/dist/esm/utils/fetchAggregate.js +37 -1
  355. package/dist/esm/utils/fetchAggregate.js.map +1 -1
  356. package/dist/esm/utils/fetchFilterCounts.js +186 -0
  357. package/dist/esm/utils/fetchFilterCounts.js.map +1 -0
  358. package/dist/esm/utils/libraryWidgetKeys.js +5 -0
  359. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  360. package/dist/esm/utils/linkNavigation.js +6 -3
  361. package/dist/esm/utils/linkNavigation.js.map +1 -1
  362. package/dist/esm/utils/readPath.js +30 -0
  363. package/dist/esm/utils/readPath.js.map +1 -0
  364. package/dist/esm/utils/rowAuxClick.js +30 -5
  365. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  366. package/dist/esm/utils/safeHref.js +18 -3
  367. package/dist/esm/utils/safeHref.js.map +1 -1
  368. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  369. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  370. package/dist/nextcloud-vue.cjs.js +15855 -9353
  371. package/dist/nextcloud-vue.cjs.js.map +2 -2
  372. package/dist/nextcloud-vue.css +998 -7
  373. package/l10n/en.json +55 -1
  374. package/l10n/nl.json +55 -1
  375. package/package.json +1 -1
  376. package/scripts/.jsdoc-baselines.json +3 -0
  377. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  378. package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -4
  379. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  380. package/src/components/CnAppNav/CnAppNav.md +26 -0
  381. package/src/components/CnAppNav/CnAppNav.vue +104 -1
  382. package/src/components/CnBannerWidget/CnBannerWidget.vue +365 -10
  383. package/src/components/CnBannerWidgetForm/CnBannerWidgetForm.vue +65 -3
  384. package/src/components/CnBoardView/CnBoardView.vue +90 -5
  385. package/src/components/CnBrandStripe/CnBrandStripe.md +22 -0
  386. package/src/components/CnBrandStripe/CnBrandStripe.vue +100 -0
  387. package/src/components/CnBrandStripe/index.js +4 -0
  388. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  389. package/src/components/CnCellRenderer/CnCellRenderer.vue +207 -1
  390. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  391. package/src/components/CnConversationThread/CnConversationThread.md +51 -0
  392. package/src/components/CnConversationThread/CnConversationThread.vue +457 -0
  393. package/src/components/CnConversationThread/CnConversationWidget.vue +144 -0
  394. package/src/components/CnConversationThread/index.js +4 -0
  395. package/src/components/CnDataTable/CnDataTable.md +1 -1
  396. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  397. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  398. package/src/components/CnDetailPage/CnDetailPage.md +17 -1
  399. package/src/components/CnDetailPage/CnDetailPage.vue +712 -49
  400. package/src/components/CnDocumentReviewList/CnDocumentReviewList.md +55 -0
  401. package/src/components/CnDocumentReviewList/CnDocumentReviewList.vue +384 -0
  402. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +108 -0
  403. package/src/components/CnDocumentReviewList/index.js +4 -0
  404. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  405. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  406. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  407. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  408. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  409. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +189 -14
  410. package/src/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue +53 -3
  411. package/src/components/CnIndexPage/CnIndexPage.vue +210 -17
  412. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  413. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  414. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  415. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  416. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  417. package/src/components/CnNextStepCard/CnNextStepCard.md +40 -0
  418. package/src/components/CnNextStepCard/CnNextStepCard.vue +319 -0
  419. package/src/components/CnNextStepCard/CnNextStepWidget.vue +59 -0
  420. package/src/components/CnNextStepCard/index.js +4 -0
  421. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  422. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +49 -0
  423. package/src/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue +6 -0
  424. package/src/components/CnObjectKanban/CnObjectKanban.vue +86 -2
  425. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  426. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  427. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  428. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  429. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  430. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +3 -0
  431. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +60 -1
  432. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +100 -3
  433. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  434. package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +50 -3
  435. package/src/components/CnSegmentedControl/CnSegmentedControl.md +46 -0
  436. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +291 -0
  437. package/src/components/CnSegmentedControl/index.js +4 -0
  438. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  439. package/src/components/CnStackedBarWidget/CnStackedBarWidget.md +15 -0
  440. package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +414 -0
  441. package/src/components/CnStackedBarWidget/index.js +14 -0
  442. package/src/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue +224 -0
  443. package/src/components/CnStackedBarWidgetForm/index.js +4 -0
  444. package/src/components/CnTabs/CnTab.vue +35 -0
  445. package/src/components/CnTabs/CnTabs.vue +251 -13
  446. package/src/components/CnTabsWidget/CnTabsWidget.vue +63 -4
  447. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  448. package/src/components/CnWeekStripWidget/CnWeekStripWidget.md +31 -0
  449. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +668 -0
  450. package/src/components/CnWeekStripWidget/index.js +14 -0
  451. package/src/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue +265 -0
  452. package/src/components/CnWeekStripWidgetForm/index.js +4 -0
  453. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +74 -0
  454. package/src/components/index.js +11 -0
  455. package/src/css/detail-page.css +47 -0
  456. package/src/css/table.css +26 -0
  457. package/src/index.js +9 -0
  458. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  459. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  460. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  461. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  462. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  463. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  464. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  465. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  466. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  467. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  468. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  469. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  470. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  471. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  472. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  473. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  474. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  475. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  476. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  477. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  478. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  479. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  480. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  481. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  482. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  483. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  484. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  485. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  486. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  487. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  488. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  489. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  490. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  491. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  492. package/src/schemas/app-manifest-v2.schema.json +389 -1
  493. package/src/schemas/app-manifest.schema.json +2 -1
  494. package/src/utils/actionLink.js +5 -0
  495. package/src/utils/actionsDispatcher.js +15 -0
  496. package/src/utils/dateVariant.js +120 -0
  497. package/src/utils/detailActionModel.js +256 -0
  498. package/src/utils/dueRule.js +94 -0
  499. package/src/utils/fetchAggregate.js +36 -0
  500. package/src/utils/fetchFilterCounts.js +182 -0
  501. package/src/utils/index.js +1 -0
  502. package/src/utils/libraryWidgetKeys.js +5 -0
  503. package/src/utils/linkNavigation.js +6 -3
  504. package/src/utils/readPath.js +27 -0
  505. package/src/utils/rowAuxClick.js +29 -4
  506. package/src/utils/safeHref.js +18 -3
  507. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -125,6 +125,19 @@ var script = {
125
125
  default: 0,
126
126
  validator: (v) => Number.isFinite(v) && v >= 0,
127
127
  },
128
+
129
+ /**
130
+ * How many records each tab matches, keyed by tab index (an array in
131
+ * tab order works too). A tab with a number here shows it after its
132
+ * label; a tab without one shows no count. A tab can also carry its
133
+ * own `count`. `null` (the default) shows no counts at all.
134
+ *
135
+ * @type {{[index: number]: number}|Array<number|null>|null}
136
+ */
137
+ counts: {
138
+ type: [Object, Array],
139
+ default: null,
140
+ },
128
141
  },
129
142
 
130
143
  emits: ['update:active-index', 'update:selected-indices'],
@@ -218,10 +231,19 @@ var script = {
218
231
  * omitted — an empty selection already means "all".
219
232
  *
220
233
  * @return {Array<{label: string, index: number, icon: string}>}
234
+ * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views
221
235
  */
222
236
  dropdownOptions() {
223
237
  return this.tabs
224
- .map((tab, index) => ({ label: tab.label, icon: tab.icon, index, _empty: this.isEmptyFilter(tab) }))
238
+ .map((tab, index) => {
239
+ const count = this.countOf({ tab, index });
240
+ return {
241
+ label: count === null ? tab.label : `${tab.label} (${count})`,
242
+ icon: tab.icon,
243
+ index,
244
+ _empty: this.isEmptyFilter(tab),
245
+ }
246
+ })
225
247
  .filter((o) => !o._empty)
226
248
  },
227
249
 
@@ -240,6 +262,20 @@ var script = {
240
262
  },
241
263
 
242
264
  methods: {
265
+ /**
266
+ * The count to show on a tab, or null for none: `counts[index]`
267
+ * first, else the tab's own `count`.
268
+ *
269
+ * @param {{tab: object, index: number}} entry The tab and its index.
270
+ * @return {number|null}
271
+ * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views
272
+ */
273
+ countOf(entry) {
274
+ const fromProp = this.counts ? this.counts[entry.index] : undefined;
275
+ const value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count;
276
+ return (typeof value === 'number' && Number.isFinite(value)) ? value : null
277
+ },
278
+
243
279
  /**
244
280
  * Is tab `i` rendered active in chips mode (handles both single
245
281
  * `activeIndex` and `multiple` `selectedIndices`).
@@ -1 +1 @@
1
- {"version":3,"file":"CnQuickFilterBar.vue2.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"tab\"\n\t\t\t\t:aria-selected=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn active[0].tab.label\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{count} more filters', { count: this.overflowEntries.length })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => ({ label: tab.label, icon: tab.icon, index, _empty: this.isEmptyFilter(tab) }))\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnIcon","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnQuickFilterBar.vue2.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"tab\"\n\t\t\t\t:aria-selected=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn active[0].tab.label\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{count} more filters', { count: this.overflowEntries.length })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? tab.label : `${tab.label} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnIcon","t"],"mappings":"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"}
@@ -6,15 +6,25 @@ const _hoisted_1 = {
6
6
  };
7
7
  const _hoisted_2 = ["aria-selected", "onClick"];
8
8
  const _hoisted_3 = { class: "cn-quick-filter-bar__label" };
9
- const _hoisted_4 = ["aria-expanded", "aria-label", "title"];
10
- const _hoisted_5 = {
9
+ const _hoisted_4 = {
10
+ key: 1,
11
+ class: "cn-quick-filter-bar__count",
12
+ "data-testid": "cn-quick-filter-count"
13
+ };
14
+ const _hoisted_5 = ["aria-expanded", "aria-label", "title"];
15
+ const _hoisted_6 = {
11
16
  key: 0,
12
17
  class: "cn-quick-filter-bar__label"
13
18
  };
14
- const _hoisted_6 = { class: "cn-quick-filter-bar__more-heading" };
15
- const _hoisted_7 = { class: "cn-quick-filter-bar__more-list" };
16
- const _hoisted_8 = ["aria-pressed", "onClick"];
17
- const _hoisted_9 = { class: "cn-quick-filter-bar__label" };
19
+ const _hoisted_7 = { class: "cn-quick-filter-bar__more-heading" };
20
+ const _hoisted_8 = { class: "cn-quick-filter-bar__more-list" };
21
+ const _hoisted_9 = ["aria-pressed", "onClick"];
22
+ const _hoisted_10 = { class: "cn-quick-filter-bar__label" };
23
+ const _hoisted_11 = {
24
+ key: 1,
25
+ class: "cn-quick-filter-bar__count",
26
+ "data-testid": "cn-quick-filter-count"
27
+ };
18
28
 
19
29
  function render(_ctx, _cache, $props, $setup, $data, $options) {
20
30
  const _component_NcSelect = resolveComponent("NcSelect");
@@ -63,7 +73,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
63
73
  class: "cn-quick-filter-bar__icon"
64
74
  }, null, 8 /* PROPS */, ["name"]))
65
75
  : createCommentVNode("v-if", true),
66
- createElementVNode("span", _hoisted_3, toDisplayString(entry.tab.label), 1 /* TEXT */)
76
+ createElementVNode("span", _hoisted_3, toDisplayString(entry.tab.label), 1 /* TEXT */),
77
+ ($options.countOf(entry) !== null)
78
+ ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
79
+ : createCommentVNode("v-if", true)
67
80
  ], 10 /* CLASS, PROPS */, _hoisted_2))
68
81
  }), 128 /* KEYED_FRAGMENT */))
69
82
  ]),
@@ -92,21 +105,21 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
92
105
  onClick: _cache[0] || (_cache[0] = $event => ($data.moreOpen = !$data.moreOpen))
93
106
  }, [
94
107
  ($options.overflowLabel)
95
- ? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString($options.overflowLabel), 1 /* TEXT */))
108
+ ? (openBlock(), createElementBlock("span", _hoisted_6, toDisplayString($options.overflowLabel), 1 /* TEXT */))
96
109
  : createCommentVNode("v-if", true),
97
110
  createVNode(_component_DotsHorizontal, {
98
111
  size: 16,
99
112
  class: "cn-quick-filter-bar__icon"
100
113
  })
101
- ], 10 /* CLASS, PROPS */, _hoisted_4)
114
+ ], 10 /* CLASS, PROPS */, _hoisted_5)
102
115
  ]),
103
116
  default: withCtx(() => [
104
117
  createElementVNode("div", {
105
118
  class: "cn-quick-filter-bar__more-panel",
106
119
  onKeydown: _cache[1] || (_cache[1] = withKeys(withModifiers($event => ($data.moreOpen = false), ["stop"]), ["escape"]))
107
120
  }, [
108
- createElementVNode("p", _hoisted_6, toDisplayString($options.moreHeading), 1 /* TEXT */),
109
- createElementVNode("div", _hoisted_7, [
121
+ createElementVNode("p", _hoisted_7, toDisplayString($options.moreHeading), 1 /* TEXT */),
122
+ createElementVNode("div", _hoisted_8, [
110
123
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.overflowEntries, (entry) => {
111
124
  return (openBlock(), createElementBlock("button", {
112
125
  key: entry.tab.label + ':' + entry.index,
@@ -124,8 +137,11 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
124
137
  class: "cn-quick-filter-bar__icon"
125
138
  }, null, 8 /* PROPS */, ["name"]))
126
139
  : createCommentVNode("v-if", true),
127
- createElementVNode("span", _hoisted_9, toDisplayString(entry.tab.label), 1 /* TEXT */)
128
- ], 10 /* CLASS, PROPS */, _hoisted_8))
140
+ createElementVNode("span", _hoisted_10, toDisplayString(entry.tab.label), 1 /* TEXT */),
141
+ ($options.countOf(entry) !== null)
142
+ ? (openBlock(), createElementBlock("span", _hoisted_11, toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
143
+ : createCommentVNode("v-if", true)
144
+ ], 10 /* CLASS, PROPS */, _hoisted_9))
129
145
  }), 128 /* KEYED_FRAGMENT */))
130
146
  ])
131
147
  ], 32 /* NEED_HYDRATION */)
@@ -1 +1 @@
1
- {"version":3,"file":"CnQuickFilterBar.vue3.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue?vue&type=template&id=8e121822&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"tab\"\n\t\t\t\t:aria-selected=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn active[0].tab.label\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{count} more filters', { count: this.overflowEntries.length })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => ({ label: tab.label, icon: tab.icon, index, _empty: this.isEmptyFilter(tab) }))\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createElementVNode","_Fragment","_renderList","_createBlock","_toDisplayString","_createElementBlock"],"mappings":"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"}
1
+ {"version":3,"file":"CnQuickFilterBar.vue3.js","sources":["../../../../src/components/CnQuickFilterBar/CnQuickFilterBar.vue?vue&type=template&id=8e121822&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: AGPL-3.0-or-later\n -->\n\n<template>\n\t<!-- Dropdown mode: a single NcSelect (multi or single) instead of the chip strip. -->\n\t<div\n\t\tv-if=\"mode === 'dropdown'\"\n\t\tclass=\"cn-quick-filter-bar cn-quick-filter-bar--dropdown\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<NcSelect\n\t\t\t:modelValue=\"dropdownValue\"\n\t\t\t:options=\"dropdownOptions\"\n\t\t\t:multiple=\"multiple\"\n\t\t\t:keepOpen=\"multiple\"\n\t\t\t:clearable=\"true\"\n\t\t\tlabel=\"label\"\n\t\t\tclass=\"cn-quick-filter-bar__select\"\n\t\t\t:inputLabel=\"selectLabel\"\n\t\t\t:aria-label-combobox=\"selectLabel\"\n\t\t\t:placeholder=\"placeholder || selectLabel\"\n\t\t\t@update:modelValue=\"onSelectInput\" />\n\t</div>\n\t<!-- Chips mode (default): the clickable tab strip. -->\n\t<div v-else\n\t\tclass=\"cn-quick-filter-bar\"\n\t\t:class=\"{ 'cn-quick-filter-bar--inline': inline }\">\n\t\t<!-- The tablist holds ONLY tabs: the overflow chip is a sibling, not a\n\t\t child, because a role=\"tablist\" may not contain a menu button. -->\n\t\t<div class=\"cn-quick-filter-bar__tabs\" role=\"tablist\">\n\t\t\t<button\n\t\t\t\tv-for=\"entry in visibleEntries\"\n\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"tab\"\n\t\t\t\t:aria-selected=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\tclass=\"cn-quick-filter-bar__tab\"\n\t\t\t\t:class=\"[{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }]\"\n\t\t\t\t@click=\"onClick(entry.index)\">\n\t\t\t\t<CnIcon\n\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t:size=\"16\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t</button>\n\t\t</div>\n\t\t<!-- The overflow is a CHIP and not a toolbar button: it is one of the\n\t\t lenses, so it carries the same pill, the same active fill and the\n\t\t label of whichever hidden lens is on. -->\n\t\t<NcPopover\n\t\t\tv-if=\"overflowEntries.length > 0\"\n\t\t\tv-model:shown=\"moreOpen\"\n\t\t\t:triggers=\"[]\"\n\t\t\tpopupRole=\"dialog\"\n\t\t\tplacement=\"bottom-end\"\n\t\t\tpopoverBaseClass=\"cn-quick-filter-bar__popper\">\n\t\t\t<template #trigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdata-testid=\"cn-quick-filter-more\"\n\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more\"\n\t\t\t\t\t:class=\"{\n\t\t\t\t\t\t'cn-quick-filter-bar__tab--active': activeOverflowEntries.length > 0,\n\t\t\t\t\t\t'cn-quick-filter-bar__more--icon-only': !overflowLabel,\n\t\t\t\t\t}\"\n\t\t\t\t\t:aria-expanded=\"moreOpen ? 'true' : 'false'\"\n\t\t\t\t\taria-haspopup=\"dialog\"\n\t\t\t\t\t:aria-label=\"overflowAriaLabel\"\n\t\t\t\t\t:title=\"overflowAriaLabel\"\n\t\t\t\t\t@click=\"moreOpen = !moreOpen\">\n\t\t\t\t\t<span v-if=\"overflowLabel\" class=\"cn-quick-filter-bar__label\">{{ overflowLabel }}</span>\n\t\t\t\t\t<DotsHorizontal :size=\"16\" class=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t</button>\n\t\t\t</template>\n\t\t\t<div\n\t\t\t\tclass=\"cn-quick-filter-bar__more-panel\"\n\t\t\t\t@keydown.escape.stop=\"moreOpen = false\">\n\t\t\t\t<p class=\"cn-quick-filter-bar__more-heading\">\n\t\t\t\t\t{{ moreHeading }}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"cn-quick-filter-bar__more-list\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"entry in overflowEntries\"\n\t\t\t\t\t\t:key=\"entry.tab.label + ':' + entry.index\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tdata-testid=\"cn-quick-filter-more-item\"\n\t\t\t\t\t\tclass=\"cn-quick-filter-bar__tab cn-quick-filter-bar__more-item\"\n\t\t\t\t\t\t:class=\"{ 'cn-quick-filter-bar__tab--active': isChipActive(entry.index) }\"\n\t\t\t\t\t\t:aria-pressed=\"isChipActive(entry.index) ? 'true' : 'false'\"\n\t\t\t\t\t\t@click=\"onOverflowClick(entry.index)\">\n\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\tv-if=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:name=\"entry.tab.icon\"\n\t\t\t\t\t\t\t:size=\"16\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__icon\" />\n\t\t\t\t\t\t<span class=\"cn-quick-filter-bar__label\">{{ entry.tab.label }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"countOf(entry) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-quick-filter-bar__count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-quick-filter-count\">{{ ' ' + countOf(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcPopover, NcSelect } from '@nextcloud/vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\n\n/**\n * CnQuickFilterBar — quick-filter control rendered above a `type:\"index\"`\n * page's table. Each tab carries a manifest `filter` map that `CnIndexPage`\n * merges into the `useListView` fetch when the tab is active.\n *\n * Two presentations, chosen by `mode`:\n * - `'chips'` (default) — a horizontal row of pill-shaped buttons; the\n * active one is filled, the rest outlined. `maxVisible` caps how many\n * pills render and moves the rest into an overflow menu.\n * - `'dropdown'` — a single `NcSelect`. The \"All\" / empty-filter tab is\n * dropped from the options (an empty selection means \"all\").\n *\n * Two selection cardinalities, chosen by `multiple`:\n * - single (default) — one active tab; uses the `activeIndex` v-model\n * (`update:active-index`).\n * - `multiple` — several tabs at once; uses the `selectedIndices` array\n * prop + `update:selected-indices` event. `CnIndexPage` ORs the selected\n * tabs' filters together.\n *\n * Implementation is deliberately a thin styled `<button>` list (chips) /\n * `NcSelect` (dropdown) rather than `NcAppNavigation*` — this lives INSIDE\n * the index page, not as the app's main nav.\n */\nexport default {\n\tname: 'CnQuickFilterBar',\n\n\tcomponents: { CnIcon, DotsHorizontal, NcPopover, NcSelect },\n\n\t// NO `model: { prop, event }` OPTION.\n\t//\n\t// The Vue-2 `model` option is REMOVED in Vue 3 — read by nothing, warned\n\t// about by nothing — so it survived the migration as a declaration that\n\t// looked authoritative while doing exactly zero. The component's real\n\t// contract is the explicit `:active-index` / `@update:active-index` pair\n\t// (and `:selected-indices` / `@update:selected-indices` in `multiple`\n\t// mode), which is what `CnIndexPage` binds. Surfaced by\n\t// `vue/no-deprecated-model-definition`, which this repo now arms through\n\t// its own published preset.\n\n\tprops: {\n\t\t/**\n\t\t * Tab definitions — same shape `pages[].config.quickFilters[]` uses.\n\t\t * `filter` is consumed by the parent (CnIndexPage), not this component.\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\trequired: true,\n\t\t\tvalidator: (arr) => Array.isArray(arr) && arr.every((t) => t && typeof t.label === 'string'),\n\t\t},\n\n\t\t/**\n\t\t * Render bare (no padding / bottom border / background) for embedding\n\t\t * inline inside another bar — e.g. the `#filters` slot of `CnActionsBar`,\n\t\t * so the tabs sit beside the view toggle instead of as a separate row.\n\t\t */\n\t\tinline: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Index of the currently active tab, or `null` for none active. Single-select only. */\n\t\tactiveIndex: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Presentation: `'chips'` (pill button strip, default) or\n\t\t * `'dropdown'` (a single `NcSelect`).\n\t\t *\n\t\t * @type {'chips'|'dropdown'}\n\t\t */\n\t\tmode: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (v) => ['chips', 'dropdown'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Allow more than one tab active at once. Selection is exposed via\n\t\t * `selectedIndices` + `update:selected-indices`; the parent ORs the\n\t\t * selected tabs' filters together.\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Active tab indices when `multiple` is set (the array v-model).\n\t\t *\n\t\t * @type {number[]}\n\t\t */\n\t\tselectedIndices: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Accessible label / placeholder for the dropdown control. */\n\t\tselectLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'Filter',\n\t\t},\n\n\t\t/** Placeholder text for the dropdown (falls back to `selectLabel`). */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Chips mode only: how many pills render inline before the rest move\n\t\t * into an overflow menu. `0` (the default) renders every tab, which is\n\t\t * the behaviour this component has always had. The visible set is the\n\t\t * FIRST `maxVisible` tabs in declared order — reorder `tabs` to change\n\t\t * which ones stay out. Ignored in `dropdown` mode.\n\t\t */\n\t\tmaxVisible: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t\tvalidator: (v) => Number.isFinite(v) && v >= 0,\n\t\t},\n\n\t\t/**\n\t\t * How many records each tab matches, keyed by tab index (an array in\n\t\t * tab order works too). A tab with a number here shows it after its\n\t\t * label; a tab without one shows no count. A tab can also carry its\n\t\t * own `count`. `null` (the default) shows no counts at all.\n\t\t *\n\t\t * @type {{[index: number]: number}|Array<number|null>|null}\n\t\t */\n\t\tcounts: {\n\t\t\ttype: [Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['update:active-index', 'update:selected-indices'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow chip's panel is open. */\n\t\t\tmoreOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Every tab paired with its own index, so the overflow split can slice\n\t\t * the list without losing the index the parent's filters are keyed on.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tentries() {\n\t\t\treturn this.tabs.map((tab, index) => ({ tab, index }))\n\t\t},\n\n\t\t/**\n\t\t * The tabs rendered as pills — all of them unless `maxVisible` caps it.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tvisibleEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.slice(0, this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The tabs moved into the overflow menu (empty when `maxVisible` is 0\n\t\t * or there is nothing to hide).\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\toverflowEntries() {\n\t\t\tif (!this.maxVisible || this.tabs.length <= this.maxVisible) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.entries.slice(this.maxVisible)\n\t\t},\n\n\t\t/**\n\t\t * The active tabs that live in the overflow menu.\n\t\t *\n\t\t * @return {Array<{tab: object, index: number}>}\n\t\t */\n\t\tactiveOverflowEntries() {\n\t\t\treturn this.overflowEntries.filter((e) => this.isChipActive(e.index))\n\t\t},\n\n\t\t/**\n\t\t * Text on the overflow chip — an active hidden tab names itself there,\n\t\t * so the strip never reads \"All\" while the list is narrowed. Nothing\n\t\t * active leaves the chip as the bare `⋯` glyph.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\toverflowLabel() {\n\t\t\tconst active = this.activeOverflowEntries\n\t\t\tif (active.length === 1) {\n\t\t\t\treturn active[0].tab.label\n\t\t\t}\n\t\t\tif (active.length > 1) {\n\t\t\t\treturn t('nextcloud-vue', '{count} filters', { count: active.length })\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\t/** @return {string} Accessible name for the overflow chip. */\n\t\toverflowAriaLabel() {\n\t\t\tif (this.overflowLabel) {\n\t\t\t\treturn t('nextcloud-vue', '{label} — show the other filters', { label: this.overflowLabel })\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{count} more filters', { count: this.overflowEntries.length })\n\t\t},\n\n\t\t/** @return {string} Heading above the hidden chips in the panel. */\n\t\tmoreHeading() {\n\t\t\treturn t('nextcloud-vue', 'More filters')\n\t\t},\n\n\t\t/**\n\t\t * Dropdown options: every tab that carries a non-empty `filter`,\n\t\t * tagged with its original index. The \"All\" / empty-filter tab is\n\t\t * omitted — an empty selection already means \"all\".\n\t\t *\n\t\t * @return {Array<{label: string, index: number, icon: string}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tdropdownOptions() {\n\t\t\treturn this.tabs\n\t\t\t\t.map((tab, index) => {\n\t\t\t\t\tconst count = this.countOf({ tab, index })\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlabel: count === null ? tab.label : `${tab.label} (${count})`,\n\t\t\t\t\t\ticon: tab.icon,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\t_empty: this.isEmptyFilter(tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((o) => !o._empty)\n\t\t},\n\n\t\t/**\n\t\t * Current NcSelect value — an array of option objects when\n\t\t * `multiple`, a single option object (or null) otherwise.\n\t\t *\n\t\t * @return {object|object[]|null}\n\t\t */\n\t\tdropdownValue() {\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.dropdownOptions.filter((o) => this.selectedIndices.includes(o.index))\n\t\t\t}\n\t\t\treturn this.dropdownOptions.find((o) => o.index === this.activeIndex) || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The count to show on a tab, or null for none: `counts[index]`\n\t\t * first, else the tab's own `count`.\n\t\t *\n\t\t * @param {{tab: object, index: number}} entry The tab and its index.\n\t\t * @return {number|null}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-counts-on-filters-and-views\n\t\t */\n\t\tcountOf(entry) {\n\t\t\tconst fromProp = this.counts ? this.counts[entry.index] : undefined\n\t\t\tconst value = (fromProp !== undefined && fromProp !== null) ? fromProp : entry.tab.count\n\t\t\treturn (typeof value === 'number' && Number.isFinite(value)) ? value : null\n\t\t},\n\n\t\t/**\n\t\t * Is tab `i` rendered active in chips mode (handles both single\n\t\t * `activeIndex` and `multiple` `selectedIndices`).\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t * @return {boolean}\n\t\t */\n\t\tisChipActive(i) {\n\t\t\treturn this.multiple ? this.selectedIndices.includes(i) : i === this.activeIndex\n\t\t},\n\n\t\t/**\n\t\t * Whether a tab's `filter` map is absent/empty (the \"All\" tab).\n\t\t *\n\t\t * @param {{label: string, filter?: object}} tab An entry from the `tabs` prop.\n\t\t * @return {boolean} True when the tab applies no filter, so selecting it\n\t\t * clears the multi-selection rather than adding to it.\n\t\t */\n\t\tisEmptyFilter(tab) {\n\t\t\treturn !tab || !tab.filter || Object.keys(tab.filter).length === 0\n\t\t},\n\n\t\t/**\n\t\t * Chip-click handler. In single mode emits the new active index; in\n\t\t * multiple mode toggles the index in/out of the selection. Clicking\n\t\t * an empty-filter (\"All\") chip clears the multi-selection.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonClick(i) {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (this.isEmptyFilter(this.tabs[i])) {\n\t\t\t\t\t/**\n\t\t\t\t\t * @event update:selected-indices Active tab indices changed (multiple mode).\n\t\t\t\t\t * @type {number[]}\n\t\t\t\t\t */\n\t\t\t\t\tthis.$emit('update:selected-indices', [])\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst next = this.selectedIndices.includes(i)\n\t\t\t\t\t? this.selectedIndices.filter((x) => x !== i)\n\t\t\t\t\t: [...this.selectedIndices, i]\n\t\t\t\tthis.$emit('update:selected-indices', next)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (i === this.activeIndex) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', i)\n\t\t},\n\n\t\t/**\n\t\t * A chip clicked inside the overflow panel. Single-select closes the\n\t\t * panel on the way out; multi-select keeps it open so several lenses\n\t\t * can be toggled in one visit.\n\t\t *\n\t\t * @param {number} i Zero-based tab index.\n\t\t */\n\t\tonOverflowClick(i) {\n\t\t\tthis.onClick(i)\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.moreOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler — normalises the option object(s) back to\n\t\t * indices and emits the matching model event.\n\t\t *\n\t\t * @param {object|object[]|null} val Selected option object(s).\n\t\t */\n\t\tonSelectInput(val) {\n\t\t\tif (this.multiple) {\n\t\t\t\tconst arr = Array.isArray(val) ? val : []\n\t\t\t\tthis.$emit('update:selected-indices', arr.map((o) => o.index))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('update:active-index', val ? val.index : null)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-quick-filter-bar {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tbackground: var(--color-main-background);\n}\n\n.cn-quick-filter-bar__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n/* Inline variant — bare strip for embedding inside another bar (e.g. the\n CnActionsBar #filters slot), so it reads as a control beside the view toggle\n rather than a separate bordered row. */\n.cn-quick-filter-bar--inline {\n\tpadding: 0;\n\tborder-bottom: none;\n\tbackground: transparent;\n}\n\n/* Dropdown variant — give the NcSelect a sensible minimum so multi-select\n chips have room without stretching the whole bar. */\n.cn-quick-filter-bar--dropdown {\n\talign-items: center;\n}\n\n.cn-quick-filter-bar__select {\n\tmin-width: 220px;\n}\n\n.cn-quick-filter-bar__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\ttransition: background-color 120ms, color 120ms, border-color 120ms;\n}\n\n.cn-quick-filter-bar__tab:hover,\n.cn-quick-filter-bar__tab:focus-visible {\n\tbackground: var(--color-background-hover);\n\toutline: none;\n}\n\n.cn-quick-filter-bar__tab--active {\n\tbackground: var(--color-primary-element, var(--color-primary, #4376fc));\n\tcolor: var(--color-primary-element-text, #fff);\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__icon {\n\tdisplay: inline-flex;\n}\n\n.cn-quick-filter-bar__label {\n\tline-height: 1;\n}\n\n/* Inherits the chip's own text colour, so it stays readable on the active\n (primary) fill as well as on the resting one. The count's text starts with\n a space: the chip is a flex row, so the space is not drawn, but it keeps a\n screen reader from reading label and count as one word. */\n.cn-quick-filter-bar__count {\n\tmin-width: 1.5em;\n\tpadding: 2px 6px;\n\tborder: 1px solid currentColor;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tline-height: 1;\n\ttext-align: center;\n}\n\n/* NcPopover wraps its trigger in a plain `<div class=\"v-popper\">`, which as a\n block would drop the chip onto its own line under the strip. */\n.cn-quick-filter-bar > :deep(.v-popper) {\n\tdisplay: inline-flex;\n}\n\n/* The `⋯` glyph is the chip's whole content while no hidden lens is on, so the\n pill tightens to a circle rather than sitting as a wide empty capsule. */\n.cn-quick-filter-bar__more {\n\tgap: 4px;\n}\n\n.cn-quick-filter-bar__more--icon-only {\n\tpadding: 4px 8px;\n}\n\n.cn-quick-filter-bar__more[aria-expanded='true'] {\n\tborder-color: var(--color-primary-element, var(--color-primary, #4376fc));\n}\n\n.cn-quick-filter-bar__more-panel {\n\tpadding: 10px 12px 12px;\n\tmax-width: 280px;\n}\n\n.cn-quick-filter-bar__more-heading {\n\tmargin: 0 0 8px;\n\tfont-size: 12px;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The hidden lenses stay chips — the panel is more of the strip, not a\n different control that happens to hold the same filters. */\n.cn-quick-filter-bar__more-list {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmax-height: 320px;\n\toverflow-y: auto;\n}\n\n.cn-quick-filter-bar__more-item {\n\tmax-width: 100%;\n}\n\n.cn-quick-filter-bar__more-item .cn-quick-filter-bar__label {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createElementVNode","_Fragment","_renderList","_createBlock","_toDisplayString","_openBlock","_createElementBlock"],"mappings":"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"}
@@ -43,6 +43,26 @@ const CORE_TABS = ['files', 'notes', 'tags', 'tasks', 'auditTrail', 'shares'];
43
43
  /** One-time guard so the legacy-path deprecation warning logs only once. */
44
44
  let legacyWarned = false;
45
45
 
46
+ /**
47
+ * Schema titles by numeric schema id, shared by every widget on the page so a
48
+ * schema is asked for once. OpenRegister's `/uses` and `/used` answer
49
+ * `@self.schema` as that id ("120"), which is not a word anyone can read.
50
+ *
51
+ * @type {Map<string, Promise<string>>}
52
+ */
53
+ const schemaTitleCache = new Map();
54
+
55
+ /**
56
+ * Whether a value is a bare number, the way OpenRegister names a schema by id.
57
+ *
58
+ * @param {string|number|undefined|null} value The value.
59
+ * @return {boolean}
60
+ */
61
+ function isNumericId(value) {
62
+ return (typeof value === 'number' && Number.isFinite(value))
63
+ || (typeof value === 'string' && /^\d+$/.test(value.trim()))
64
+ }
65
+
46
66
  /**
47
67
  * Leaf groups surfaced by the aggregated `/relations` endpoint, in tab order.
48
68
  * `responseKey` is the key in the `/relations` payload; `integrationId` is the
@@ -125,6 +145,14 @@ var script = {
125
145
  NcEmptyContent,
126
146
  },
127
147
 
148
+ inject: {
149
+ /**
150
+ * The host app's translator (CnAppRoot provides it), so a schema title
151
+ * reads in the app's language. Without it a title reads as stored.
152
+ */
153
+ cnTranslate: { default: () => (key) => key },
154
+ },
155
+
128
156
  props: {
129
157
  /** Widget title shown in the header. */
130
158
  title: {
@@ -388,6 +416,8 @@ var script = {
388
416
  * @type {HTMLInputElement|null}
389
417
  */
390
418
  fileInputEl: null,
419
+ /** Schema titles by numeric schema id, for object rows. */
420
+ schemaTitles: {},
391
421
  /** Whether any section/tab is currently fetching. */
392
422
  loading: false,
393
423
  /** True once the first fetch has completed (gates the empty state). */
@@ -1080,9 +1110,74 @@ var script = {
1080
1110
  self.name,
1081
1111
  raw.summary,
1082
1112
  raw.description,
1083
- ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v)) || self.schema || String(id);
1084
- const meta = self.schema || raw.schema || '';
1085
- return { id, label, meta: typeof meta === 'string' ? meta : '', raw }
1113
+ ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v))
1114
+ || [raw.givenName, raw.familyName].filter((v) => typeof v === 'string' && v.trim()).join(' ');
1115
+ // OpenRegister names the schema by numeric id: show its title, never the number.
1116
+ const schema = this.schemaName(self.schema || raw.schema);
1117
+ const finalLabel = label || schema || String(id);
1118
+ return { id, label: finalLabel, meta: schema === finalLabel ? '' : schema, raw }
1119
+ },
1120
+
1121
+ /**
1122
+ * How a row names its schema: the translated title for a numeric id
1123
+ * (empty until it is read, or when it cannot be), a slug as it is.
1124
+ *
1125
+ * @param {string|number|undefined|null} schema - `@self.schema` of the related object.
1126
+ * @return {string}
1127
+ */
1128
+ schemaName(schema) {
1129
+ if (isNumericId(schema)) {
1130
+ const title = this.schemaTitles[String(schema).trim()];
1131
+ return title ? this.cnTranslate(title) : ''
1132
+ }
1133
+ return typeof schema === 'string' ? schema : ''
1134
+ },
1135
+
1136
+ /**
1137
+ * Read the titles of the numeric schema ids in these envelopes once,
1138
+ * before the rows are built, so no row shows a number first.
1139
+ *
1140
+ * @param {Array<object|null>} envelopes - The `{ results }` payloads.
1141
+ * @return {Promise<void>}
1142
+ */
1143
+ async resolveSchemaTitles(envelopes) {
1144
+ const ids = new Set();
1145
+ for (const envelope of envelopes) {
1146
+ for (const raw of ((envelope && envelope.results) || [])) {
1147
+ const schema = (raw && (raw['@self'] || {}).schema) ?? (raw && raw.schema);
1148
+ if (isNumericId(schema)) {
1149
+ ids.add(String(schema).trim());
1150
+ }
1151
+ }
1152
+ }
1153
+ const titles = { ...this.schemaTitles };
1154
+ await Promise.all([...ids].filter((id) => !(id in titles)).map(async (id) => {
1155
+ if (!schemaTitleCache.has(id)) {
1156
+ schemaTitleCache.set(id, this.fetchSchemaTitle(id));
1157
+ }
1158
+ titles[id] = await schemaTitleCache.get(id);
1159
+ }));
1160
+ this.schemaTitles = titles;
1161
+ },
1162
+
1163
+ /**
1164
+ * GET one schema's title; '' when it cannot be read.
1165
+ *
1166
+ * @param {string} id - The numeric schema id.
1167
+ * @return {Promise<string>}
1168
+ */
1169
+ async fetchSchemaTitle(id) {
1170
+ try {
1171
+ const response = await fetch(generateUrl('/apps/openregister/api/schemas/{id}', { id }), { method: 'GET', headers: buildHeaders() });
1172
+ if (!response.ok) {
1173
+ return ''
1174
+ }
1175
+ const schema = await response.json();
1176
+ const title = schema && (schema.title || schema.slug);
1177
+ return typeof title === 'string' ? title : ''
1178
+ } catch {
1179
+ return ''
1180
+ }
1086
1181
  },
1087
1182
 
1088
1183
  /**
@@ -1186,6 +1281,7 @@ var script = {
1186
1281
  const groups = [];
1187
1282
 
1188
1283
  if (this.showObjects) {
1284
+ await this.resolveSchemaTitles([uses, used, contracts]);
1189
1285
  const objectItems = this.mergeObjectResults([uses, used, contracts]);
1190
1286
  groups.push({ key: 'objects', label: this.objectsLabel, icon: 'FileTreeOutline', integrationId: '', items: objectItems, total: objectItems.length });
1191
1287
  }
@@ -1311,6 +1407,7 @@ var script = {
1311
1407
  calls.push(store.fetchContracts(type, id));
1312
1408
  }
1313
1409
  const groups = await Promise.all(calls);
1410
+ await this.resolveSchemaTitles(groups.map((results) => ({ results: results || [] })));
1314
1411
  const seen = new Set();
1315
1412
  const merged = [];
1316
1413
  for (const group of groups) {