@conduction/nextcloud-vue 2.59.0 → 2.61.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 (254) hide show
  1. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +14 -1
  2. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +80 -1
  5. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  6. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +46 -4
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  8. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +232 -10
  9. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  10. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +79 -25
  11. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  12. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js +42 -3
  13. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js.map +1 -1
  14. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js +39 -6
  15. package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js.map +1 -1
  16. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +46 -0
  17. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  18. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +11 -4
  19. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  20. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js +10 -0
  21. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js.map +1 -0
  22. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +39 -0
  23. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -0
  24. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +16 -0
  25. package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js.map +1 -0
  26. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -1
  27. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  28. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +147 -89
  29. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  30. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +10 -0
  31. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js.map +1 -0
  32. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +259 -0
  33. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -0
  34. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +131 -0
  35. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -0
  36. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +10 -0
  37. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js.map +1 -0
  38. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +116 -0
  39. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -0
  40. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +24 -0
  41. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -0
  42. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +10 -2
  43. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  44. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  45. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +503 -28
  46. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +303 -144
  48. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js +10 -0
  50. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js.map +1 -0
  51. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js +237 -0
  52. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js.map +1 -0
  53. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js +120 -0
  54. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js.map +1 -0
  55. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js +10 -0
  56. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js.map +1 -0
  57. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +77 -0
  58. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -0
  59. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js +27 -0
  60. package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -0
  61. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +171 -12
  62. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +15 -7
  64. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  65. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js +37 -3
  66. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js.map +1 -1
  67. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js +44 -16
  68. package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js.map +1 -1
  69. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +132 -3
  70. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  71. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -3
  72. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  73. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js +10 -0
  74. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js.map +1 -0
  75. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js +316 -0
  76. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js.map +1 -0
  77. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js +105 -0
  78. package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js.map +1 -0
  79. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js +10 -0
  80. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js.map +1 -0
  81. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js +150 -0
  82. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -0
  83. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js +106 -0
  84. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -0
  85. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js +9 -0
  86. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js.map +1 -0
  87. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +47 -0
  88. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -0
  89. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js +17 -0
  90. package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js.map +1 -0
  91. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +49 -0
  92. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  93. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  94. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js +6 -0
  95. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js.map +1 -1
  96. package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue3.js.map +1 -1
  97. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js +46 -0
  98. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js.map +1 -1
  99. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js +15 -3
  100. package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js.map +1 -1
  101. package/dist/esm/components/CnPageRenderer/pageTypes.js +1 -0
  102. package/dist/esm/components/CnPageRenderer/pageTypes.js.map +1 -1
  103. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +37 -1
  104. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  105. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +29 -13
  106. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  107. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +50 -3
  108. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
  109. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
  110. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +10 -0
  111. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js.map +1 -0
  112. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +186 -0
  113. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -0
  114. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +46 -0
  115. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -0
  116. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +11 -0
  117. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js.map +1 -0
  118. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +298 -0
  119. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -0
  120. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +77 -0
  121. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -0
  122. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js +10 -0
  123. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js.map +1 -0
  124. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js +169 -0
  125. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js.map +1 -0
  126. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js +48 -0
  127. package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js.map +1 -0
  128. package/dist/esm/components/CnTabs/CnTab.vue2.js +35 -0
  129. package/dist/esm/components/CnTabs/CnTab.vue2.js.map +1 -1
  130. package/dist/esm/components/CnTabs/CnTab.vue3.js.map +1 -1
  131. package/dist/esm/components/CnTabs/CnTabs.vue2.js +120 -7
  132. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  133. package/dist/esm/components/CnTabs/CnTabs.vue3.js +57 -5
  134. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  135. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +59 -4
  136. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  137. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +6 -2
  138. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  139. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +10 -0
  140. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js.map +1 -0
  141. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +484 -0
  142. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -0
  143. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +115 -0
  144. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -0
  145. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js +10 -0
  146. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js.map +1 -0
  147. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js +189 -0
  148. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js.map +1 -0
  149. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js +74 -0
  150. package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js.map +1 -0
  151. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +82 -8
  152. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  153. package/dist/esm/index.js +16 -0
  154. package/dist/esm/index.js.map +1 -1
  155. package/dist/esm/l10n/en.json.js +55 -1
  156. package/dist/esm/l10n/en.json.js.map +1 -1
  157. package/dist/esm/l10n/nl.json.js +55 -1
  158. package/dist/esm/l10n/nl.json.js.map +1 -1
  159. package/dist/esm/nextcloud-vue.css +1036 -19
  160. package/dist/esm/utils/dateVariant.js +124 -0
  161. package/dist/esm/utils/dateVariant.js.map +1 -0
  162. package/dist/esm/utils/detailActionModel.js +260 -0
  163. package/dist/esm/utils/detailActionModel.js.map +1 -0
  164. package/dist/esm/utils/dueRule.js +84 -0
  165. package/dist/esm/utils/dueRule.js.map +1 -0
  166. package/dist/esm/utils/fetchAggregate.js +37 -1
  167. package/dist/esm/utils/fetchAggregate.js.map +1 -1
  168. package/dist/esm/utils/fetchFilterCounts.js +186 -0
  169. package/dist/esm/utils/fetchFilterCounts.js.map +1 -0
  170. package/dist/esm/utils/headers.js +28 -2
  171. package/dist/esm/utils/headers.js.map +1 -1
  172. package/dist/esm/utils/libraryWidgetKeys.js +5 -0
  173. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  174. package/dist/esm/utils/readPath.js +30 -0
  175. package/dist/esm/utils/readPath.js.map +1 -0
  176. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  177. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  178. package/dist/nextcloud-vue.cjs.js +16019 -9528
  179. package/dist/nextcloud-vue.cjs.js.map +2 -2
  180. package/dist/nextcloud-vue.css +1036 -19
  181. package/l10n/en.json +55 -1
  182. package/l10n/nl.json +55 -1
  183. package/package.json +1 -1
  184. package/scripts/.jsdoc-baselines.json +4 -0
  185. package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -1
  186. package/src/components/CnAppNav/CnAppNav.md +26 -0
  187. package/src/components/CnAppNav/CnAppNav.vue +145 -2
  188. package/src/components/CnBannerWidget/CnBannerWidget.vue +373 -11
  189. package/src/components/CnBannerWidgetForm/CnBannerWidgetForm.vue +65 -3
  190. package/src/components/CnBoardView/CnBoardView.vue +77 -0
  191. package/src/components/CnBrandStripe/CnBrandStripe.md +22 -0
  192. package/src/components/CnBrandStripe/CnBrandStripe.vue +100 -0
  193. package/src/components/CnBrandStripe/index.js +4 -0
  194. package/src/components/CnCellRenderer/CnCellRenderer.vue +207 -1
  195. package/src/components/CnConversationThread/CnConversationThread.md +51 -0
  196. package/src/components/CnConversationThread/CnConversationThread.vue +457 -0
  197. package/src/components/CnConversationThread/CnConversationWidget.vue +144 -0
  198. package/src/components/CnConversationThread/index.js +4 -0
  199. package/src/components/CnDashboardPage/CnDashboardPage.vue +10 -2
  200. package/src/components/CnDetailPage/CnDetailPage.md +16 -0
  201. package/src/components/CnDetailPage/CnDetailPage.vue +687 -49
  202. package/src/components/CnDocumentReviewList/CnDocumentReviewList.md +55 -0
  203. package/src/components/CnDocumentReviewList/CnDocumentReviewList.vue +384 -0
  204. package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +108 -0
  205. package/src/components/CnDocumentReviewList/index.js +4 -0
  206. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +191 -14
  207. package/src/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue +53 -3
  208. package/src/components/CnIndexPage/CnIndexPage.vue +135 -3
  209. package/src/components/CnLinkCardsPage/CnLinkCardsPage.vue +484 -0
  210. package/src/components/CnLinkCardsPage/index.js +4 -0
  211. package/src/components/CnNextStepCard/CnNextStepCard.md +40 -0
  212. package/src/components/CnNextStepCard/CnNextStepCard.vue +319 -0
  213. package/src/components/CnNextStepCard/CnNextStepWidget.vue +59 -0
  214. package/src/components/CnNextStepCard/index.js +4 -0
  215. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +49 -0
  216. package/src/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue +6 -0
  217. package/src/components/CnObjectKanban/CnObjectKanban.vue +86 -2
  218. package/src/components/CnPageRenderer/pageTypes.js +1 -0
  219. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +3 -0
  220. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +60 -1
  221. package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +50 -3
  222. package/src/components/CnSegmentedControl/CnSegmentedControl.md +46 -0
  223. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +291 -0
  224. package/src/components/CnSegmentedControl/index.js +4 -0
  225. package/src/components/CnStackedBarWidget/CnStackedBarWidget.md +15 -0
  226. package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +414 -0
  227. package/src/components/CnStackedBarWidget/index.js +14 -0
  228. package/src/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue +224 -0
  229. package/src/components/CnStackedBarWidgetForm/index.js +4 -0
  230. package/src/components/CnTabs/CnTab.vue +35 -0
  231. package/src/components/CnTabs/CnTabs.vue +244 -10
  232. package/src/components/CnTabsWidget/CnTabsWidget.vue +63 -4
  233. package/src/components/CnWeekStripWidget/CnWeekStripWidget.md +31 -0
  234. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +668 -0
  235. package/src/components/CnWeekStripWidget/index.js +14 -0
  236. package/src/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue +265 -0
  237. package/src/components/CnWeekStripWidgetForm/index.js +4 -0
  238. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +74 -0
  239. package/src/components/index.js +12 -0
  240. package/src/css/detail-page.css +57 -2
  241. package/src/index.js +16 -0
  242. package/src/schemas/app-manifest-v2.schema.json +433 -3
  243. package/src/schemas/app-manifest.schema.json +2 -1
  244. package/src/types/manifest.d.ts +1 -1
  245. package/src/utils/dateVariant.js +120 -0
  246. package/src/utils/detailActionModel.js +256 -0
  247. package/src/utils/dueRule.js +94 -0
  248. package/src/utils/fetchAggregate.js +36 -0
  249. package/src/utils/fetchFilterCounts.js +182 -0
  250. package/src/utils/headers.js +28 -2
  251. package/src/utils/index.js +1 -0
  252. package/src/utils/libraryWidgetKeys.js +5 -0
  253. package/src/utils/readPath.js +27 -0
  254. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -1,6 +1,7 @@
1
+ import { getCurrentUser } from '@nextcloud/auth';
1
2
  import { subscribe, unsubscribe } from '@nextcloud/event-bus';
2
3
  import { translate } from '@nextcloud/l10n';
3
- import { NcActionButton, NcActionLink, NcActionSeparator, NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue';
4
+ import { NcActionButton, NcActionCaption, NcActionLink, NcActionSeparator, NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue';
4
5
  import { ref, provide, watch } from 'vue';
5
6
  import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue';
6
7
  import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue';
@@ -12,19 +13,20 @@ import InformationOutline from 'vue-material-design-icons/InformationOutline.vue
12
13
  import Pencil from 'vue-material-design-icons/Pencil.vue';
13
14
  import Plus from 'vue-material-design-icons/Plus.vue';
14
15
  import Refresh from 'vue-material-design-icons/Refresh.vue';
15
- import __sfc_main$e from '../../dialogs/CnRelationLinkModal.vue.js';
16
- import __sfc_main$d from '../../dialogs/CnWidgetStyleEditorModal.vue.js';
16
+ import __sfc_main$g from '../../dialogs/CnRelationLinkModal.vue.js';
17
+ import __sfc_main$f from '../../dialogs/CnWidgetStyleEditorModal.vue.js';
17
18
  import __sfc_main$1 from '../CnActionsMenu/CnActionsMenu.vue.js';
18
- import __sfc_main$b from '../CnBodySections/CnBodySections.vue.js';
19
+ import __sfc_main$d from '../CnBodySections/CnBodySections.vue.js';
19
20
  import __sfc_main$2 from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
20
- import __sfc_main$6 from '../CnDashboardGrid/CnDashboardGrid.vue.js';
21
- import __sfc_main$4 from '../CnDetailWidgetHost/CnDetailWidgetHost.vue.js';
22
- import __sfc_main$5 from '../CnFormDialog/CnFormDialog.vue.js';
23
- import __sfc_main$7 from '../CnLifecycleActions/CnLifecycleActions.vue.js';
21
+ import __sfc_main$7 from '../CnDashboardGrid/CnDashboardGrid.vue.js';
22
+ import __sfc_main$5 from '../CnDetailWidgetHost/CnDetailWidgetHost.vue.js';
23
+ import __sfc_main$6 from '../CnFormDialog/CnFormDialog.vue.js';
24
+ import __sfc_main$8 from '../CnLifecycleActions/CnLifecycleActions.vue.js';
24
25
  import __sfc_main$3 from '../CnLockedBanner/CnLockedBanner.vue.js';
25
- import __sfc_main$a from '../CnRelatedCollections/CnRelatedCollections.vue.js';
26
- import __sfc_main$9 from '../CnSummaryAggregates/CnSummaryAggregates.vue.js';
27
- import __sfc_main$c from '../CnTranslatedBadge/CnTranslatedBadge.vue.js';
26
+ import __sfc_main$4 from '../CnNextStepCard/CnNextStepCard.vue.js';
27
+ import __sfc_main$c from '../CnRelatedCollections/CnRelatedCollections.vue.js';
28
+ import __sfc_main$b from '../CnSummaryAggregates/CnSummaryAggregates.vue.js';
29
+ import __sfc_main$e from '../CnTranslatedBadge/CnTranslatedBadge.vue.js';
28
30
  import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js';
29
31
  import { useObjectLock } from '../../composables/useObjectLock.js';
30
32
  import { useObjectPresence } from '../../composables/useObjectPresence.js';
@@ -33,11 +35,13 @@ import { gridLayout } from '../../mixins/gridLayout.js';
33
35
  import { isAppInstalled } from '../../utils/appInstalled.js';
34
36
  import { compactLayoutRows } from '../../utils/dashboardPlacement.js';
35
37
  import { defaultDetailGrid } from '../../utils/defaultDetailGrid.js';
38
+ import { stageOf, normalisePinnedAction, stageEntry, MAX_QUICK_ACTIONS, groupMenuEntries, resolveNextStep, resolvePill } from '../../utils/detailActionModel.js';
36
39
  import { cnGridCellStyle, hasGridRow } from '../../utils/grid.js';
37
40
  import { slotRenders } from '../../utils/slotContent.js';
38
41
  import { isDataWidgetDef, isRelatedWidgetDef, isGeoWidgetDef, isContentOnlyWidgetDef, isCardWidgetDef, widgetContentOf, resolveRegistryRenderer, widgetTitleOf } from '../../utils/widgetDispatch.js';
39
- import __sfc_main$8 from '../CnActionButtons/CnActionButtons.vue.js';
42
+ import __sfc_main$9 from '../CnActionButtons/CnActionButtons.vue.js';
40
43
  import __sfc_main from '../CnIcon/CnIcon.vue.js';
44
+ import __sfc_main$a from '../CnStatusBadge/CnStatusBadge.vue.js';
41
45
  import { getWidgetTypeEntry } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
42
46
  import '../CnWidgetGrid/registerDashboardWidgets.js';
43
47
  import { useObjectStore } from '../../store/useObjectStore.js';
@@ -162,6 +166,7 @@ var script = {
162
166
  ChevronLeft,
163
167
  ChevronRight,
164
168
  NcActionButton,
169
+ NcActionCaption,
165
170
  NcActionLink,
166
171
  NcActionSeparator,
167
172
  NcButton,
@@ -176,17 +181,19 @@ var script = {
176
181
  CnActionsMenu: __sfc_main$1,
177
182
  CnBuildiqEditButton: __sfc_main$2,
178
183
  CnLockedBanner: __sfc_main$3,
179
- CnDetailWidgetHost: __sfc_main$4,
180
- CnFormDialog: __sfc_main$5,
181
- CnDashboardGrid: __sfc_main$6,
182
- CnLifecycleActions: __sfc_main$7,
183
- CnActionButtons: __sfc_main$8,
184
- CnSummaryAggregates: __sfc_main$9,
185
- CnRelatedCollections: __sfc_main$a,
186
- CnBodySections: __sfc_main$b,
187
- CnTranslatedBadge: __sfc_main$c,
188
- CnWidgetStyleEditorModal: __sfc_main$d,
189
- CnRelationLinkModal: __sfc_main$e,
184
+ CnNextStepCard: __sfc_main$4,
185
+ CnDetailWidgetHost: __sfc_main$5,
186
+ CnFormDialog: __sfc_main$6,
187
+ CnDashboardGrid: __sfc_main$7,
188
+ CnLifecycleActions: __sfc_main$8,
189
+ CnActionButtons: __sfc_main$9,
190
+ CnStatusBadge: __sfc_main$a,
191
+ CnSummaryAggregates: __sfc_main$b,
192
+ CnRelatedCollections: __sfc_main$c,
193
+ CnBodySections: __sfc_main$d,
194
+ CnTranslatedBadge: __sfc_main$e,
195
+ CnWidgetStyleEditorModal: __sfc_main$f,
196
+ CnRelationLinkModal: __sfc_main$g,
190
197
  Cog,
191
198
  Plus,
192
199
  Pencil,
@@ -989,6 +996,130 @@ var script = {
989
996
  type: Boolean,
990
997
  default: false,
991
998
  },
999
+
1000
+ // ── The action model (detail-action-model-and-case-surfaces) ────
1001
+
1002
+ /**
1003
+ * The primary action per stage (manifest `config.primaryActionByStage`):
1004
+ * a map from a stage value to an action. When the record's stage has
1005
+ * an entry, that action is the page's primary button, so the button
1006
+ * names the next step: "Take on" on a new case, "Publish" on a
1007
+ * decided one. An entry is an action object in the `headerActions`
1008
+ * shape, or the id of a declared header action. A stage without an
1009
+ * entry falls back to `primaryAction`.
1010
+ *
1011
+ * @type {Record<string, string|object>|null}
1012
+ */
1013
+ primaryActionByStage: {
1014
+ type: Object,
1015
+ default: null,
1016
+ },
1017
+
1018
+ /**
1019
+ * Dot-path to the field that holds the record's stage. Read by
1020
+ * `primaryActionByStage` and `nextStep`.
1021
+ *
1022
+ * @type {string}
1023
+ */
1024
+ stageField: {
1025
+ type: String,
1026
+ default: 'status',
1027
+ },
1028
+
1029
+ /**
1030
+ * Always visible buttons in the header (manifest `config.quickActions`)
1031
+ * for the few actions a handler uses on every record. At most three
1032
+ * render; later entries are dropped. An entry is an action object in
1033
+ * the `headerActions` shape, or the id of a declared header action,
1034
+ * which then leaves the Actions menu.
1035
+ *
1036
+ * @type {Array<string|object>}
1037
+ */
1038
+ quickActions: {
1039
+ type: Array,
1040
+ default: () => [],
1041
+ },
1042
+
1043
+ /**
1044
+ * What the Actions menu itself shows (manifest `config.actionsMenu`):
1045
+ * `{ showRefresh?, showHelpLinks?, label? }`. `showRefresh: false`
1046
+ * removes Refresh. `showHelpLinks: false` removes Request a feature,
1047
+ * Report a bug and Documentation, for an app that offers them in its
1048
+ * own help menu. `label` names the menu, for example "More". `null`
1049
+ * (the default) changes nothing.
1050
+ *
1051
+ * @type {{showRefresh?: boolean, showHelpLinks?: boolean, label?: string}|null}
1052
+ */
1053
+ actionsMenu: {
1054
+ type: Object,
1055
+ default: null,
1056
+ },
1057
+
1058
+ /**
1059
+ * The "what now" card (manifest `config.nextStep`):
1060
+ * `{ field?, stages: { <stage>: { title?, checklist, after? } } }`.
1061
+ * Each checklist item is `{ label, doneField?, doneWhen?, hint? }`.
1062
+ * Rendered above the body for a stage that declares a checklist, with
1063
+ * the primary button inside it. See `CnNextStepCard`.
1064
+ *
1065
+ * @type {object|null}
1066
+ */
1067
+ nextStep: {
1068
+ type: Object,
1069
+ default: null,
1070
+ },
1071
+
1072
+ /**
1073
+ * A pill above the title saying what kind of record this is
1074
+ * (manifest `config.typePill`): `{ field, colorMap?, labels?, variant? }`.
1075
+ * Rendered through `CnStatusBadge`; `colorMap` is keyed on the field's
1076
+ * raw value, `labels` maps a raw value to the text to show.
1077
+ *
1078
+ * @type {{field: string, colorMap?: object, labels?: object, variant?: string}|null}
1079
+ */
1080
+ typePill: {
1081
+ type: Object,
1082
+ default: null,
1083
+ },
1084
+
1085
+ /**
1086
+ * A pill above the title saying where the record stands (manifest
1087
+ * `config.statusPill`). Same shape as `typePill`.
1088
+ *
1089
+ * @type {{field: string, colorMap?: object, labels?: object, variant?: string}|null}
1090
+ */
1091
+ statusPill: {
1092
+ type: Object,
1093
+ default: null,
1094
+ },
1095
+
1096
+ /**
1097
+ * A column of cards beside the body (manifest `config.sideColumn`),
1098
+ * for the record's facts: deadline, requester, handler, links. Each
1099
+ * entry is a widget definition (`{ id?, type, title?, content? }`) or
1100
+ * the id of a widget declared in `widgets`. The column stacks under
1101
+ * the body on a narrow page. Empty (the default) leaves the layout as
1102
+ * it is.
1103
+ *
1104
+ * @type {Array<string|object>}
1105
+ */
1106
+ sideColumn: {
1107
+ type: Array,
1108
+ default: () => [],
1109
+ },
1110
+
1111
+ /**
1112
+ * Whether the current user administers this instance. Shows the
1113
+ * `adminOnly` header actions. `null` (the default) reads it from
1114
+ * `getCurrentUser()`. Visibility only, never an authorization
1115
+ * decision: the endpoint behind an action decides who may call it.
1116
+ *
1117
+ * @type {boolean|null}
1118
+ */
1119
+ isAdmin: {
1120
+ type: Boolean,
1121
+ default: null,
1122
+ },
992
1123
  },
993
1124
 
994
1125
  emits: [
@@ -1256,7 +1387,7 @@ var script = {
1256
1387
  * @spec openspec/changes/case-page-and-list-as-a-place/specs/index-page/spec.md
1257
1388
  */
1258
1389
  primaryActionAnchorId() {
1259
- const scope = this.primaryAction?.id || this.pageId || this.objectId || 'record';
1390
+ const scope = this.stagePrimaryEntry?.id || this.primaryAction?.id || this.pageId || this.objectId || 'record';
1260
1391
  return `cn-primary-action-${String(scope).replace(/[^A-Za-z0-9_-]/g, '-')}`
1261
1392
  },
1262
1393
 
@@ -1271,7 +1402,291 @@ var script = {
1271
1402
  * @spec openspec/changes/case-page-and-list-as-a-place/specs/index-page/spec.md
1272
1403
  */
1273
1404
  skipLinkLabel() {
1274
- return `${this.effectiveTranslate('Skip to')} ${this.primaryActionLabel}`
1405
+ return `${this.effectiveTranslate('Skip to')} ${this.effectivePrimaryLabel}`
1406
+ },
1407
+
1408
+ // ── The action model (detail-action-model-and-case-surfaces) ────
1409
+
1410
+ /**
1411
+ * The record's stage, as `primaryActionByStage` and `nextStep` key it.
1412
+ *
1413
+ * @return {string} The stage, or '' while the record has none.
1414
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1415
+ */
1416
+ recordStage() {
1417
+ return stageOf(this.currentObject, this.stageField)
1418
+ },
1419
+
1420
+ /**
1421
+ * The stage's primary action as an id, plus its definition when the
1422
+ * map carries one inline.
1423
+ *
1424
+ * @return {{id: string, inline: object|null}|null} The pinned action, or null when this stage declares none.
1425
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1426
+ */
1427
+ stagePrimary() {
1428
+ return normalisePinnedAction(stageEntry(this.primaryActionByStage, this.recordStage), 'cn-stage-primary')
1429
+ },
1430
+
1431
+ /**
1432
+ * The quick actions as ids, plus definitions for the inline ones.
1433
+ * Capped at three, and never the action that is already the primary
1434
+ * button.
1435
+ *
1436
+ * @return {Array<{id: string, inline: object|null}>} The pinned actions.
1437
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-quick-actions
1438
+ */
1439
+ pinnedQuickActions() {
1440
+ const primaryId = this.stagePrimary?.id;
1441
+ return (Array.isArray(this.quickActions) ? this.quickActions : [])
1442
+ .map((entry, index) => normalisePinnedAction(entry, `cn-quick-${index}`))
1443
+ .filter((pinned) => pinned && pinned.id !== primaryId)
1444
+ .slice(0, MAX_QUICK_ACTIONS)
1445
+ },
1446
+
1447
+ /**
1448
+ * The stage's primary action in dispatchable form: the menu entry
1449
+ * CnActionButtons built for it, with its `run()`. Null while the
1450
+ * action is hidden by its own `visibleWhen`, in which case the page
1451
+ * falls back to `primaryAction`.
1452
+ *
1453
+ * @return {object|null} The entry, or null.
1454
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1455
+ */
1456
+ stagePrimaryEntry() {
1457
+ const id = this.stagePrimary?.id;
1458
+ return (id && this.menuHeaderActions.find((entry) => entry.id === id)) || null
1459
+ },
1460
+
1461
+ /**
1462
+ * The quick actions in dispatchable form, in declaration order.
1463
+ *
1464
+ * @return {Array<object>} The entries that are visible.
1465
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-quick-actions
1466
+ */
1467
+ quickActionEntries() {
1468
+ return this.pinnedQuickActions
1469
+ .map((pinned) => this.menuHeaderActions.find((entry) => entry.id === pinned.id))
1470
+ .filter(Boolean)
1471
+ },
1472
+
1473
+ /**
1474
+ * What the primary button says: the stage's action when the stage
1475
+ * declares one, the page's `primaryAction` otherwise. Empty gates
1476
+ * both the button and the skip link.
1477
+ *
1478
+ * @return {string} The label, or an empty string.
1479
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1480
+ */
1481
+ effectivePrimaryLabel() {
1482
+ return this.stagePrimaryEntry ? this.stagePrimaryEntry.label : this.primaryActionLabel
1483
+ },
1484
+
1485
+ /**
1486
+ * The URL the primary button links to, when its action is a link.
1487
+ *
1488
+ * @return {string} The href, or '' for an action that is dispatched.
1489
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1490
+ */
1491
+ primaryActionHref() {
1492
+ return this.stagePrimaryEntry?.href || ''
1493
+ },
1494
+
1495
+ /**
1496
+ * The link target that goes with `primaryActionHref`.
1497
+ *
1498
+ * @return {string|undefined} The target, or undefined.
1499
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1500
+ */
1501
+ primaryActionTarget() {
1502
+ return this.stagePrimaryEntry?.linkTarget || undefined
1503
+ },
1504
+
1505
+ /**
1506
+ * Whether the primary button waits for its own request.
1507
+ *
1508
+ * @return {boolean} True while the stage's action is in flight.
1509
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
1510
+ */
1511
+ primaryActionDisabled() {
1512
+ return Boolean(this.stagePrimaryEntry?.disabled)
1513
+ },
1514
+
1515
+ /**
1516
+ * Whether the viewer administers this instance, for `adminOnly`
1517
+ * actions. The prop wins; otherwise Nextcloud says.
1518
+ *
1519
+ * @return {boolean} True for an instance admin.
1520
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-grouped-and-admin-only-menu-actions
1521
+ */
1522
+ viewerIsAdmin() {
1523
+ if (this.isAdmin !== null) {
1524
+ return this.isAdmin
1525
+ }
1526
+ try {
1527
+ return getCurrentUser()?.isAdmin === true
1528
+ } catch {
1529
+ return false
1530
+ }
1531
+ },
1532
+
1533
+ /**
1534
+ * The declared actions by id, for the `group` and `adminOnly` a menu
1535
+ * entry does not carry itself.
1536
+ *
1537
+ * @return {Record<string, object>} The lookup.
1538
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-grouped-and-admin-only-menu-actions
1539
+ */
1540
+ headerActionsById() {
1541
+ return Object.fromEntries(this.effectiveHeaderActions
1542
+ .filter((action) => action && action.id)
1543
+ .map((action) => [action.id, action]))
1544
+ },
1545
+
1546
+ /**
1547
+ * The menu entries in the groups the menu draws: ungrouped first,
1548
+ * named groups in first appearance order, admin actions last and for
1549
+ * admins only. A page that groups nothing gets one captionless group.
1550
+ *
1551
+ * @return {Array<{key: string, label: string, entries: Array<object>}>} The groups.
1552
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-grouped-and-admin-only-menu-actions
1553
+ */
1554
+ headerMenuGroups() {
1555
+ const groups = groupMenuEntries(this.headerMenuEntries, this.headerActionsById, {
1556
+ isAdmin: this.viewerIsAdmin,
1557
+ adminLabel: translate('nextcloud-vue', 'Administration'),
1558
+ });
1559
+ return groups.map((group) => ({ ...group, label: group.label ? this.effectiveTranslate(group.label) : '' }))
1560
+ },
1561
+
1562
+ /**
1563
+ * Whether Refresh renders in the Actions menu.
1564
+ *
1565
+ * @return {boolean} The existing rule, unless `actionsMenu.showRefresh` is false.
1566
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-actions-menu-built-ins-are-optional
1567
+ */
1568
+ menuShowsRefresh() {
1569
+ return this.actionsMenu?.showRefresh === false ? false : this.effectiveHeaderShowRefresh
1570
+ },
1571
+
1572
+ /**
1573
+ * Whether the help links render in the Actions menu.
1574
+ *
1575
+ * @return {boolean} True unless `actionsMenu.showHelpLinks` is false.
1576
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-actions-menu-built-ins-are-optional
1577
+ */
1578
+ menuShowsHelpLinks() {
1579
+ return this.actionsMenu?.showHelpLinks !== false
1580
+ },
1581
+
1582
+ /**
1583
+ * The Actions menu's name.
1584
+ *
1585
+ * @return {string|undefined} `actionsMenu.label` translated, or undefined for the default "Actions".
1586
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-actions-menu-built-ins-are-optional
1587
+ */
1588
+ actionsMenuName() {
1589
+ const label = this.actionsMenu?.label;
1590
+ return typeof label === 'string' && label !== '' ? this.effectiveTranslate(label) : undefined
1591
+ },
1592
+
1593
+ /**
1594
+ * Whether the page is showing its body: not the not-found, loading,
1595
+ * error or empty state. The "what now" card and the side column are
1596
+ * siblings of the body and follow it.
1597
+ *
1598
+ * @return {boolean} True when the body renders.
1599
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-next-step-card
1600
+ */
1601
+ showsBody() {
1602
+ return !this.objectNotFound && !this.showLoadingState && !this.error && !this.empty
1603
+ },
1604
+
1605
+ /**
1606
+ * The "what now" card for the record's stage, labels translated.
1607
+ *
1608
+ * @return {{stage: string, title: string, items: Array<object>, after: string}|null} The card, or null when the stage declares no checklist.
1609
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-next-step-card
1610
+ */
1611
+ nextStepCard() {
1612
+ const card = resolveNextStep(this.nextStep, this.currentObject, this.stageField);
1613
+ if (!card) {
1614
+ return null
1615
+ }
1616
+ const tr = (text) => (text ? this.effectiveTranslate(text) : '');
1617
+ return {
1618
+ ...card,
1619
+ title: tr(card.title),
1620
+ after: tr(card.after),
1621
+ items: card.items.map((item) => ({ ...item, label: tr(item.label), hint: tr(item.hint) })),
1622
+ }
1623
+ },
1624
+
1625
+ /**
1626
+ * Whether the "what now" card renders.
1627
+ *
1628
+ * @return {boolean} True when the stage has a checklist and the body is showing.
1629
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-next-step-card
1630
+ */
1631
+ showsNextStepCard() {
1632
+ return Boolean(this.nextStepCard) && this.showsBody
1633
+ },
1634
+
1635
+ /**
1636
+ * The pills above the title: type first, then status.
1637
+ *
1638
+ * @return {Array<{key: string, label: string, colorKey: string, colorMap: object|null, variant: string}>} The pills whose field has a value.
1639
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-header-pills
1640
+ */
1641
+ headerPills() {
1642
+ return [['type', this.typePill], ['status', this.statusPill]]
1643
+ .map(([key, config]) => {
1644
+ const pill = resolvePill(config, this.resolvedObject);
1645
+ return pill ? { ...pill, key, label: this.effectiveTranslate(pill.label) } : null
1646
+ })
1647
+ .filter(Boolean)
1648
+ },
1649
+
1650
+ /**
1651
+ * The side column's widget definitions. A string names a widget
1652
+ * declared in `widgets`; an object is a definition of its own.
1653
+ *
1654
+ * @return {Array<object>} The definitions that resolve, each with an `id`.
1655
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-side-column
1656
+ */
1657
+ sideColumnWidgets() {
1658
+ const declared = Array.isArray(this.widgets) ? this.widgets : [];
1659
+ return (Array.isArray(this.sideColumn) ? this.sideColumn : [])
1660
+ .map((entry, index) => {
1661
+ if (typeof entry === 'string') {
1662
+ return declared.find((widget) => widget && widget.id === entry) || null
1663
+ }
1664
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
1665
+ return null
1666
+ }
1667
+ return entry.id ? entry : { ...entry, id: `cn-side-${index}` }
1668
+ })
1669
+ .filter(Boolean)
1670
+ },
1671
+
1672
+ /**
1673
+ * Whether the side column renders.
1674
+ *
1675
+ * @return {boolean} True when it has widgets and the body is showing.
1676
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-side-column
1677
+ */
1678
+ showsSideColumn() {
1679
+ return this.sideColumnWidgets.length > 0 && this.showsBody
1680
+ },
1681
+
1682
+ /**
1683
+ * Accessible name of the side column.
1684
+ *
1685
+ * @return {string} The label.
1686
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-side-column
1687
+ */
1688
+ sideColumnLabel() {
1689
+ return translate('nextcloud-vue', 'Details')
1275
1690
  },
1276
1691
 
1277
1692
  /**
@@ -1475,7 +1890,16 @@ var script = {
1475
1890
  */
1476
1891
  headerMenuEntries() {
1477
1892
  const lifecycle = this.showsLifecycleActions ? this.lifecycleMenuEntries : [];
1478
- return [...lifecycle, ...this.menuHeaderActions]
1893
+ // An action drawn as a button, the stage's primary one or a quick
1894
+ // action, is not listed a second time in the menu.
1895
+ const pinned = new Set([
1896
+ ...(this.stagePrimaryEntry ? [this.stagePrimaryEntry.id] : []),
1897
+ ...this.quickActionEntries.map((entry) => entry.id),
1898
+ ]);
1899
+ const inMenu = pinned.size > 0
1900
+ ? this.menuHeaderActions.filter((entry) => !pinned.has(entry.id))
1901
+ : this.menuHeaderActions;
1902
+ return [...lifecycle, ...inMenu]
1479
1903
  },
1480
1904
 
1481
1905
  /**
@@ -1497,7 +1921,17 @@ var script = {
1497
1921
  * @return {Array<object>} The action descriptors.
1498
1922
  */
1499
1923
  effectiveHeaderActions() {
1500
- const declared = Array.isArray(this.headerActions) ? this.headerActions : [];
1924
+ const authored = Array.isArray(this.headerActions) ? this.headerActions : [];
1925
+ // Inline pinned actions (a stage's primary action, a quick action
1926
+ // written out in place) join the list CnActionButtons dispatches,
1927
+ // so they get the same dialogs, toasts and `visibleWhen` gating as
1928
+ // any header action. An id that is already declared is not added
1929
+ // twice. With nothing pinned inline this is `headerActions` itself.
1930
+ const known = new Set(authored.map((action) => action && action.id));
1931
+ const inline = [this.stagePrimary, ...this.pinnedQuickActions]
1932
+ .filter((pinned) => pinned && pinned.inline && !known.has(pinned.id))
1933
+ .map((pinned) => pinned.inline);
1934
+ const declared = inline.length > 0 ? [...authored, ...inline] : authored;
1501
1935
  if (!(this.foldsEditIntoActions && this.canEditRecord)) {
1502
1936
  return declared
1503
1937
  }
@@ -2310,7 +2744,11 @@ var script = {
2310
2744
  * @spec openspec/changes/case-page-and-list-as-a-place/specs/index-page/spec.md
2311
2745
  */
2312
2746
  onSkipToPrimaryAction(event) {
2313
- const target = this.$refs.primaryActionButton?.$el ?? this.$refs.primaryActionButton;
2747
+ // The ref covers the header button; the id also finds the button
2748
+ // when it sits inside the "what now" card.
2749
+ const target = this.$refs.primaryActionButton?.$el
2750
+ ?? this.$refs.primaryActionButton
2751
+ ?? this.$el?.querySelector?.(`[id="${this.primaryActionAnchorId}"]`);
2314
2752
  const focusable = target?.matches?.('button, a') ? target : target?.querySelector?.('button, a');
2315
2753
  if (focusable?.focus) {
2316
2754
  event.preventDefault();
@@ -2318,6 +2756,43 @@ var script = {
2318
2756
  }
2319
2757
  },
2320
2758
 
2759
+ /**
2760
+ * The primary button was pressed.
2761
+ *
2762
+ * A stage's action is dispatched the way a header action is, through
2763
+ * the `run()` CnActionButtons bound for it, and announced to the host
2764
+ * with its declaration. A link action is left to the browser. Without
2765
+ * a stage action this is the page's `primaryAction`, announced as
2766
+ * before.
2767
+ *
2768
+ * @return {void}
2769
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
2770
+ */
2771
+ onPrimaryActionClick() {
2772
+ const entry = this.stagePrimaryEntry;
2773
+ if (!entry) {
2774
+ this.$emit('primary-action', this.primaryAction);
2775
+ return
2776
+ }
2777
+ this.$emit('primary-action', this.headerActionsById[entry.id] || { id: entry.id, label: entry.label });
2778
+ this.onPinnedActionClick(entry);
2779
+ },
2780
+
2781
+ /**
2782
+ * A pinned action's button was pressed: run it, unless it is a link
2783
+ * the browser is already following.
2784
+ *
2785
+ * @param {object} entry The action's menu entry.
2786
+ * @return {void}
2787
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-quick-actions
2788
+ */
2789
+ onPinnedActionClick(entry) {
2790
+ if (!entry || entry.href || typeof entry.run !== 'function') {
2791
+ return
2792
+ }
2793
+ entry.run();
2794
+ },
2795
+
2321
2796
  /**
2322
2797
  * The active tab changed: tell the host, and put it in the address
2323
2798
  * when the page declares that its tab is part of its address.