@conduction/nextcloud-vue 2.56.0-beta.4 → 2.56.0-beta.5

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 (300) 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.map +1 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  12. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  13. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  15. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  16. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  17. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  18. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  19. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  20. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  26. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  28. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  34. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  38. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  40. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  48. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  52. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  54. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  55. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  56. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  57. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  58. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  60. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  62. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  65. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  67. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  69. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  70. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  71. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  73. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  75. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  76. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  78. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  80. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  82. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  85. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  86. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  87. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  88. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  89. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  90. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  92. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  93. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  94. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  96. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  102. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  103. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  108. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  109. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  110. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  117. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  123. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  124. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  125. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  130. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  131. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  132. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  137. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  139. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  141. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  143. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  144. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  149. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  150. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  151. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  156. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  157. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  158. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  163. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  164. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  165. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  171. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  172. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  177. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  178. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  179. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  184. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  186. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  188. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  195. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  196. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  201. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  202. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  203. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  208. package/dist/esm/l10n/en.json.js +1 -0
  209. package/dist/esm/l10n/en.json.js.map +1 -1
  210. package/dist/esm/l10n/nl.json.js +1 -0
  211. package/dist/esm/l10n/nl.json.js.map +1 -1
  212. package/dist/esm/nextcloud-vue.css +71 -7
  213. package/dist/esm/utils/actionLink.js +5 -0
  214. package/dist/esm/utils/actionLink.js.map +1 -1
  215. package/dist/esm/utils/actionsDispatcher.js +16 -1
  216. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  217. package/dist/esm/utils/linkNavigation.js +6 -3
  218. package/dist/esm/utils/linkNavigation.js.map +1 -1
  219. package/dist/esm/utils/rowAuxClick.js +30 -5
  220. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  221. package/dist/esm/utils/safeHref.js +18 -3
  222. package/dist/esm/utils/safeHref.js.map +1 -1
  223. package/dist/nextcloud-vue.cjs.js +809 -383
  224. package/dist/nextcloud-vue.cjs.js.map +2 -2
  225. package/dist/nextcloud-vue.css +71 -7
  226. package/l10n/en.json +1 -0
  227. package/l10n/nl.json +1 -0
  228. package/package.json +1 -1
  229. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  230. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  231. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  232. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  233. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  234. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  235. package/src/components/CnDataTable/CnDataTable.md +1 -1
  236. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  237. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  238. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  239. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  240. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  241. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  242. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  243. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  244. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  245. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  246. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  247. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  248. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  249. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  250. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  251. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  252. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  253. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  254. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  255. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  256. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  257. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  258. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  259. package/src/components/CnTabs/CnTabs.vue +7 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  261. package/src/css/table.css +26 -0
  262. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  263. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  264. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  265. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  266. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  267. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  268. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  269. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  270. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  271. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  272. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  273. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  274. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  275. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  276. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  277. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  278. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  279. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  280. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  281. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  282. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  283. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  284. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  285. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  286. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  287. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  288. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  289. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  290. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  291. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  292. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  293. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  294. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  295. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  296. package/src/utils/actionLink.js +5 -0
  297. package/src/utils/actionsDispatcher.js +15 -0
  298. package/src/utils/linkNavigation.js +6 -3
  299. package/src/utils/rowAuxClick.js +29 -4
  300. package/src/utils/safeHref.js +18 -3
@@ -1 +1 @@
1
- {"version":3,"file":"CnActionsMenu.vue2.js","sources":["../../../../src/components/CnActionsMenu/CnActionsMenu.vue"],"sourcesContent":["<!--\n CnActionsMenu — Shared \"…\" overflow Actions menu.\n\n Renders the canonical action set that appears on every Conduction\n surface — Refresh, then the mandatory trio Request a feature / Report a\n bug / Documentation — inside a single NcActions overflow. Request a\n feature opens the forge's feature-request issue form directly, exactly\n like Report a bug (team decision 2026-09-04: the in-product suggestion\n modal is gone — the forge is where the conversation happens, in English).\n Used by CnWidgetWrapper (widgets) and the page-level headers of\n CnDetailPage / CnDashboardPage so the three surfaces stay in lockstep.\n\n The trio is not optional and not conditional on configuration: each item\n resolves its own target (a forge new-issue deep-link for the bug report,\n `cnDocumentationBaseUrl` + the surface's `docsAnchor` for the docs link),\n so a host that passes no URLs still renders all three. That is the point\n — the items used to be per-host markup, and OpenRegister's widgets shipped\n without the Documentation entry while OpenCatalogi's were inconsistent.\n-->\n<template>\n\t<!-- Root <template v-if> (Vue 3 native fragment, renders no DOM node — was\n\t vue-frag <Fragment>) so NcActions stays in its host's flex/grid flow. -->\n\t<template v-if=\"hasOverflowMenu\">\n\t\t<NcActions\n\t\t\t:forceMenu=\"true\"\n\t\t\t:forceName=\"true\"\n\t\t\t:menuName=\"actionsMenuLabel\"\n\t\t\t:open=\"menuOpen\"\n\t\t\t:data-testid=\"`${testidBase}-actions`\"\n\t\t\t@update:open=\"menuOpen = $event\">\n\t\t\t<template #icon>\n\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t</template>\n\t\t\t<!-- Stays open while refreshing; onRefreshClick closes the menu once the refresh settles. -->\n\t\t\t<NcActionButton\n\t\t\t\tv-if=\"showRefresh\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-refresh`\"\n\t\t\t\t:disabled=\"refreshBusy\"\n\t\t\t\t:closeAfterClick=\"false\"\n\t\t\t\t@click=\"onRefreshClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"refreshBusy\" :size=\"20\" />\n\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ refreshLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<!-- @slot primary-items The surface's OWN actions — a page's\n\t\t\t manifest `headerActions`, say — rendered above the canonical\n\t\t\t trio. They sit here rather than in `#action-items` because a\n\t\t\t case's Add party belongs above Report a bug, not under it.\n\t\t\t The caller owns the trailing NcActionSeparator: only the\n\t\t\t caller knows whether its v-for produced any items, and a\n\t\t\t separator rendered here would strand itself when it did\n\t\t\t not. -->\n\t\t\t<slot name=\"primary-items\" />\n\t\t\t<!-- The canonical trio — Request a feature / Report a bug /\n\t\t\t Documentation — renders on EVERY surface. None of the three\n\t\t\t is conditional on a URL being configured any more: each\n\t\t\t resolves its own target (see resolvedDocumentationUrl /\n\t\t\t resolvedReportBugUrl), so a host that forgets to pass one\n\t\t\t still gets a working item instead of a silently missing one.\n\t\t\t `showRequestFeature` / `showReportBug` / `showDocumentation`\n\t\t\t exist only for the rare surface that must suppress one\n\t\t\t deliberately; they all default to true. -->\n\t\t\t<!-- A real link whenever the form's URL is known, so it can be\n\t\t\t middle-clicked or copied; a button only for a host with no\n\t\t\t URL that handles @request-feature itself. -->\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showRequestFeature && resolvedRequestFeatureUrl\"\n\t\t\t\t:href=\"resolvedRequestFeatureUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionButton\n\t\t\t\tv-else-if=\"showRequestFeature\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showReportBug && resolvedReportBugUrl\"\n\t\t\t\t:href=\"resolvedReportBugUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-report-bug`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BugOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ reportBugLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showDocumentation && resolvedDocumentationUrl\"\n\t\t\t\t:href=\"resolvedDocumentationUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-documentation`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ documentationLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<!-- @slot action-items Additional NcActionButton-family items\n\t\t\t rendered inside the overflow menu, after the built-in\n\t\t\t Refresh + Request-a-feature / Report-a-bug / Documentation\n\t\t\t group. -->\n\t\t\t<slot name=\"action-items\" />\n\t\t</NcActions>\n\t</template>\n</template>\n\n<script>\nimport { emit as emitOnBus } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport BugOutline from 'vue-material-design-icons/BugOutline.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport LightbulbOutline from 'vue-material-design-icons/LightbulbOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport { buildBugReportUrl, buildFeatureRequestUrl, DEFAULT_FORGE } from '../../utils/forge.js'\n\n/**\n * The fleet's per-app documentation site, derived from the app id. Used only\n * when no `documentationUrl` prop and no `cnDocumentationBaseUrl` inject are\n * available, so that the Documentation item is never absent — an app that\n * hosts its docs anywhere else provides the base instead.\n *\n * @param {string} appId Consuming app's slug.\n * @return {string} Documentation base URL, or '' when the app id is unknown.\n */\nfunction defaultDocsBase(appId) {\n\tconst id = String(appId || '').trim()\n\tif (!id) {\n\t\treturn ''\n\t}\n\treturn `https://${id}.conduction.nl/docs/`\n}\n\n/**\n * Resolve a documentation deep-link from a base URL and a per-widget\n * anchor. An anchor already starting with `#`, `/` or a `scheme://` is\n * used as written (respectively appended, resolved against the base's\n * origin, or taken whole); a bare slug becomes a `#fragment`, which is\n * how a docs page addresses one section of itself.\n *\n * @param {string} base Documentation base URL.\n * @param {string} anchor Per-widget anchor / path fragment.\n * @return {string} The resolved URL, or '' when there is no base to build on.\n */\nexport function resolveDocsUrl(base, anchor) {\n\tconst a = String(anchor || '').trim()\n\tif (a.includes('://')) {\n\t\treturn a\n\t}\n\tconst b = String(base || '').trim()\n\tif (!b) {\n\t\treturn ''\n\t}\n\tif (!a) {\n\t\treturn b\n\t}\n\tif (a.startsWith('#')) {\n\t\treturn `${b.replace(/#.*$/, '')}${a}`\n\t}\n\tif (a.startsWith('/')) {\n\t\ttry {\n\t\t\treturn new URL(a, b).toString()\n\t\t} catch {\n\t\t\treturn `${b.replace(/\\/+$/, '')}${a}`\n\t\t}\n\t}\n\treturn `${b.replace(/#.*$/, '').replace(/\\/+$/, '')}#${a}`\n}\n\n/**\n * Build a synthetic event object handed to host listeners alongside the\n * action payload. Mirrors the Vue 3 / DOM Event API enough to let a host\n * call `event.preventDefault()` to suppress the menu's built-in default\n * handler. Because Vue's `$emit` is synchronous, the same object also\n * propagates up through wrapping components (e.g. CnWidgetWrapper\n * re-emitting `@refresh`), so a host listener on the outer component can\n * still suppress the default.\n *\n * `waitUntil(promise)` lets a listener keep the Refresh item spinning, and the\n * menu open, until that promise settles.\n *\n * @param {(promise: Promise<unknown>) => void} [waitUntil] Collector for refresh work.\n * @return {{defaultPrevented: boolean, preventDefault: () => void, waitUntil: (promise: Promise<unknown>) => void}}\n */\nfunction createSyntheticEvent(waitUntil = () => {}) {\n\tconst ev = {\n\t\tdefaultPrevented: false,\n\t\tpreventDefault() {\n\t\t\tthis.defaultPrevented = true\n\t\t},\n\t\twaitUntil,\n\t}\n\treturn ev\n}\n\n/** Shortest time the Refresh spinner shows, so a fast refresh is still visible. */\nconst MIN_REFRESH_SPIN_MS = 400\n\n/** Longest the Refresh item waits on `waitUntil` work; axios has no default timeout. */\nconst MAX_REFRESH_WAIT_MS = 15000\n\n/**\n * CnActionsMenu — the shared built-in overflow Actions menu.\n *\n * Renders Refresh plus the mandatory trio Request a feature / Report a bug /\n * Documentation. The trio is unconditional: the bug link is built from the\n * app's forge repo and the docs link from the app-wide documentation base\n * plus this surface's `docsAnchor`, so no host can ship a menu missing one.\n * Pass `docsAnchor` per widget type — that is what makes Documentation open\n * that widget's own section instead of the docs homepage.\n *\n * ```vue\n * <CnActionsMenu\n * :widget-id=\"resolvedWidgetId\"\n * :title=\"displayTitle\"\n * :surface=\"`widget:${resolvedWidgetId}`\"\n * docs-anchor=\"open-cases\"\n * testid-base=\"cn-widget-wrapper\"\n * @refresh=\"(p, e) => $emit('refresh', p, e)\"\n * @request-feature=\"(p, e) => $emit('request-feature', p, e)\">\n * <template #action-items><slot name=\"action-items\" /></template>\n * </CnActionsMenu>\n * ```\n */\nexport default {\n\tname: 'CnActionsMenu',\n\n\tcomponents: {\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcLoadingIcon,\n\t\tDotsHorizontal,\n\t\tRefresh,\n\t\tLightbulbOutline,\n\t\tBookOpenVariant,\n\t\tBugOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consuming app's slug (e.g. \"pipelinq\"). Provided by CnAppRoot.\n\t\t * Defaults to empty string when no CnAppRoot ancestor exists.\n\t\t */\n\t\tcnAppId: { default: () => '' },\n\t\t/**\n\t\t * Repo slug both forge deep-links target (e.g.\n\t\t * `ConductionNL/pipelinq`) — the Request-a-feature and Report-a-bug\n\t\t * new-issue forms. Provided by CnAppRoot from the manifest's\n\t\t * `nav.featureRequestRepo` field (with fallback to\n\t\t * `ConductionNL/<appId>`). Empty when no ancestor — the default\n\t\t * handler warns and skips opening rather than open a broken link.\n\t\t */\n\t\tcnFeatureRequestRepo: { default: () => '' },\n\t\t/**\n\t\t * Forge config (`{type, baseUrl}`) both new-issue deep-links are\n\t\t * built against. Provided by CnAppRoot from `manifest.nav.forge`.\n\t\t * Defaults to DEFAULT_FORGE when no CnAppRoot ancestor exists —\n\t\t * a third hardcoded Codeberg default lived here, so a menu mounted\n\t\t * standalone contradicted both the fleet default and the app it was\n\t\t * reporting for.\n\t\t */\n\t\tcnFeatureRequestForge: { default: () => ({ ...DEFAULT_FORGE }) },\n\t\t/**\n\t\t * Resolver for a widget's manifest title — the AUTHORED English\n\t\t * source string — provided by CnDashboardPage as\n\t\t * `(widgetId) => string`. The `title` prop this component receives\n\t\t * has already been through the host translate function\n\t\t * — CnDashboardPage's getWidgetTitle is the display chokepoint — and\n\t\t * may also be a user-typed customTitle in the user's own language, so\n\t\t * it is the wrong thing to put in a bug-report title. Returns '' when\n\t\t * no dashboard ancestor provides it (a standalone widget, a detail\n\t\t * page) or the widget def carries no title, and the link falls back\n\t\t * to the surface slug.\n\t\t */\n\t\tcnWidgetTitleSource: { default: () => () => '' },\n\t\t/**\n\t\t * App-wide documentation base URL (e.g.\n\t\t * `https://pipelinq.conduction.nl/docs`), provided by CnAppRoot from\n\t\t * `manifest.nav.documentationUrl`. Every widget's Documentation item\n\t\t * is built from this base plus the widget's own `docsAnchor`, so the\n\t\t * link lands on that widget's section rather than the docs homepage.\n\t\t * Empty when no ancestor provides one — the host's explicit\n\t\t * `documentationUrl` prop then has to carry the whole URL.\n\t\t */\n\t\tcnDocumentationBaseUrl: { default: () => '' },\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * Whether the Refresh item renders. The parent surface is\n\t\t * responsible for any opt-out aliasing (e.g. CnWidgetWrapper's\n\t\t * `hideRefresh`) and passes the resolved boolean here.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the Request-a-feature item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link target, opened in a new tab. Wins over\n\t\t * the `cnDocumentationBaseUrl` + `docsAnchor` pair. Leave empty (the\n\t\t * default) to let the menu build the per-widget deep-link itself.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * This surface's own section in the app's documentation, appended to\n\t\t * the app-wide `cnDocumentationBaseUrl`. A bare slug (`open-cases`)\n\t\t * becomes a `#fragment`; a value starting with `/` is resolved as a\n\t\t * path; a full `scheme://` URL is used as written. Supplying it is\n\t\t * what makes the Documentation item land on THIS widget's section\n\t\t * rather than the docs homepage.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocsAnchor: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the Documentation item renders. Defaults to true — the\n\t\t * canonical trio is meant to be present on every surface; set false\n\t\t * only where a docs link genuinely cannot exist.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the \"Report a bug\" item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit \"Report a bug\" target. Empty (the default) builds a\n\t\t * new-issue deep-link on the app's forge from the injected\n\t\t * `cnFeatureRequestRepo` + `cnFeatureRequestForge`, pre-filled with\n\t\t * the surface's title.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\treportBugUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Report-a-bug action. */\n\t\treportBugLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Report a bug'),\n\t\t},\n\n\t\t/**\n\t\t * Pre-translated label for the Documentation item. Defaults to the\n\t\t * lib's translation of \"Documentation\".\n\t\t */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded on the `@refresh` / `@request-feature`\n\t\t * payloads (as `widgetId`) and on the `cn:widget:refresh`\n\t\t * event-bus payload. The parent resolves it (explicit id or\n\t\t * slugified title).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Human-readable title carried on action payloads.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable `surface` slug naming where the menu sits (e.g.\n\t\t * `widget:<id>`, `detail:<id>`, `dashboard:<id>`). Used as the\n\t\t * English headline fallback for both new-issue deep-links when no\n\t\t * authored title can be recovered.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: { // eslint-disable-line vue/no-unused-properties -- published prop kept so hosts that still bind it do not leak it into $attrs\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether a refresh is currently in flight. While true, the Refresh\n\t\t * item is disabled and shows a loading spinner for exactly as long as\n\t\t * this stays true — so the spinner reflects the real refresh time.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Event-bus channel the default Refresh handler emits on when no\n\t\t * host listener suppresses it. Widgets use `cn:widget:refresh`;\n\t\t * page surfaces pass `cn:page:refresh`.\n\t\t */\n\t\trefreshChannel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn:widget:refresh',\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\n\t\t/**\n\t\t * Prefix for the `data-testid`s emitted on the menu container and\n\t\t * its items: `<base>-actions` (container), `<base>-action-refresh`,\n\t\t * `<base>-action-request-feature`, `<base>-action-report-bug`,\n\t\t * `<base>-action-documentation`.\n\t\t * Lets each host keep its own stable testids.\n\t\t */\n\t\ttestidBase: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn-actions-menu',\n\t\t},\n\t},\n\n\temits: ['refresh', 'request-feature'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow menu is open. */\n\t\t\tmenuOpen: false,\n\t\t\t/** Whether a refresh this menu started is still settling. */\n\t\t\trefreshPending: false,\n\t\t\t/** Close the menu once the host's `refreshing` falls back to false. */\n\t\t\tcloseWhenIdle: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Whether the Refresh item spins: the host's flag or our own pending refresh. */\n\t\trefreshBusy() {\n\t\t\treturn this.refreshing || this.refreshPending\n\t\t},\n\n\t\t/**\n\t\t * Whether the overflow `…` menu renders at all. True when at least\n\t\t * one built-in item is visible OR the caller provided an\n\t\t * `action-items` slot.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasOverflowMenu() {\n\t\t\tif (this.showRefresh) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showDocumentation && this.resolvedDocumentationUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showReportBug && this.resolvedReportBugUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showRequestFeature) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.$slots['primary-items']) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * The Documentation item's target: the explicit `documentationUrl`\n\t\t * when given, otherwise the app-wide base deep-linked with this\n\t\t * surface's `docsAnchor`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDocumentationUrl() {\n\t\t\tif (this.documentationUrl) {\n\t\t\t\treturn this.docsAnchor\n\t\t\t\t\t? resolveDocsUrl(this.documentationUrl, this.docsAnchor)\n\t\t\t\t\t: this.documentationUrl\n\t\t\t}\n\t\t\tif (this.cnDocumentationBaseUrl) {\n\t\t\t\treturn resolveDocsUrl(this.cnDocumentationBaseUrl, this.docsAnchor)\n\t\t\t}\n\t\t\t// Last resort so the item is never simply MISSING — an absent\n\t\t\t// Documentation entry is the defect this menu exists to prevent.\n\t\t\t// The fleet's convention is one docs site per app id; an app that\n\t\t\t// hosts its docs elsewhere sets `cnDocumentationBaseUrl` on\n\t\t\t// CnAppRoot, and the warning below says so.\n\t\t\treturn resolveDocsUrl(defaultDocsBase(this.cnAppId), this.docsAnchor)\n\t\t},\n\n\t\t/**\n\t\t * This surface's title AS AUTHORED, for anything that must not be\n\t\t * localized. Asks the injected dashboard resolver for the widget's\n\t\t * manifest source string; '' when nothing can supply one.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceTitle() {\n\t\t\tconst resolve = this.cnWidgetTitleSource\n\t\t\tif (typeof resolve !== 'function' || !this.widgetId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn String(resolve(this.widgetId) || '').trim()\n\t\t\t} catch {\n\t\t\t\t// A host resolver that throws must not take the menu with it —\n\t\t\t\t// the link degrades to the surface slug.\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The Report-a-bug target: the explicit `reportBugUrl` when given,\n\t\t * otherwise a new-issue deep-link on the app's forge, pre-filled with\n\t\t * a title naming the surface the report came from.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedReportBugUrl() {\n\t\t\tif (this.reportBugUrl) {\n\t\t\t\treturn this.reportBugUrl\n\t\t\t}\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// buildBugReportUrl owns both the host (one resolveForge for the\n\t\t\t// whole suggestion flow) and the bug-report issue FORM. This was\n\t\t\t// hand-rolled here against a local copy of the forge host map that\n\t\t\t// defaulted to Codeberg, so a menu mounted without a CnAppRoot sent\n\t\t\t// bug reports to a different host than the Request-a-feature item\n\t\t\t// directly above it — and it linked the BLANK issue form, so every\n\t\t\t// in-product report arrived with no steps, no expected/actual and\n\t\t\t// no severity.\n\t\t\t//\n\t\t\t// The headline must be ENGLISH: the `title` prop is already\n\t\t\t// translated (CnDashboardPage's getWidgetTitle is the display\n\t\t\t// chokepoint), so a report from a French UI read \"[BUG] Activité\n\t\t\t// récente\" and one from a Russian UI was in Cyrillic — unreadable\n\t\t\t// to a maintainer, even though the English msgid was sitting in the\n\t\t\t// manifest. `cnWidgetTitleSource` hands back that manifest string,\n\t\t\t// skipping any user-typed customTitle for the same reason.\n\t\t\t//\n\t\t\t// With no dashboard ancestor to ask, fall back to the surface slug\n\t\t\t// rather than the translated prop: a slug is English by\n\t\t\t// construction, and \"always English\" is the point. The localized\n\t\t\t// title is deliberately not carried in the URL at all — see\n\t\t\t// buildBugReportUrl for why it was dropped.\n\t\t\treturn buildBugReportUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The Request-a-feature target: the forge's feature-request issue\n\t\t * FORM, built exactly like resolvedReportBugUrl — same repo, same\n\t\t * forge, same English-headline rules (see that computed for why the\n\t\t * headline is never the translated title). Empty when no repo can\n\t\t * be resolved, in which case the click handler warns and does\n\t\t * nothing rather than open a broken link.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRequestFeatureUrl() {\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trefreshing(busy) {\n\t\t\tif (!busy && this.closeWhenIdle) {\n\t\t\t\tthis.closeWhenIdle = false\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Refresh click — emits `@refresh`, then runs the built-in default\n\t\t * (emit on `refreshChannel`) unless a host called\n\t\t * `event.preventDefault()` on the second handler arg. The item spins\n\t\t * and the menu stays open until every promise handed to `waitUntil`\n\t\t * (on the event or the bus payload) settles, or 15 s pass, and the\n\t\t * host's `refreshing` is false; then the menu closes.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRefreshClick() {\n\t\t\tif (this.refreshBusy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst work = []\n\t\t\tconst waitUntil = (promise) => {\n\t\t\t\twork.push(Promise.resolve(promise))\n\t\t\t}\n\t\t\tconst ev = createSyntheticEvent(waitUntil)\n\t\t\tthis.refreshPending = true\n\t\t\tconst startedAt = Date.now()\n\t\t\t/**\n\t\t\t * @event refresh User clicked the Refresh item. Payload:\n\t\t\t * `{ widgetId, title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default (event-bus\n\t\t\t * emit on `refreshChannel`), and its `waitUntil(promise)` to keep\n\t\t\t * the item spinning until that work settles.\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (!ev.defaultPrevented) {\n\t\t\t\temitOnBus(this.refreshChannel, {\n\t\t\t\t\twidgetId: this.widgetId,\n\t\t\t\t\ttitle: this.title,\n\t\t\t\t\twaitUntil,\n\t\t\t\t})\n\t\t\t}\n\t\t\tlet ceiling\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.allSettled(work),\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tceiling = setTimeout(resolve, MAX_REFRESH_WAIT_MS)\n\t\t\t\t}),\n\t\t\t])\n\t\t\tclearTimeout(ceiling)\n\t\t\tconst hold = MIN_REFRESH_SPIN_MS - (Date.now() - startedAt)\n\t\t\tif (hold > 0) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, hold))\n\t\t\t}\n\t\t\tthis.refreshPending = false\n\t\t\tif (this.refreshing) {\n\t\t\t\tthis.closeWhenIdle = true\n\t\t\t} else {\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Request-a-feature click — emits `@request-feature`. The item is a\n\t\t * link to the forge's feature-request form, so the browser opens it\n\t\t * unless a host called `event.preventDefault()`, which then cancels\n\t\t * the link. With no `cnFeatureRequestRepo` the item is a button and\n\t\t * this only warns.\n\t\t *\n\t\t * @param {Event} [nativeEvent] The link's click event.\n\t\t * @return {void}\n\t\t */\n\t\tonRequestFeatureClick(nativeEvent) {\n\t\t\tconst ev = createSyntheticEvent()\n\t\t\t/**\n\t\t\t * @event request-feature User clicked the Request a feature\n\t\t\t * item. Payload: `{ widgetId, title }`. Handlers may call the\n\t\t\t * second arg's `preventDefault()` to suppress the built-in\n\t\t\t * default (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (ev.defaultPrevented) {\n\t\t\t\tif (nativeEvent && typeof nativeEvent.preventDefault === 'function') {\n\t\t\t\t\tnativeEvent.preventDefault()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.resolvedRequestFeatureUrl) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnActionsMenu] Cannot open the feature-request form: missing cnFeatureRequestRepo inject (mount under CnAppRoot or bind a custom @request-feature listener).')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["t","emitOnBus"],"mappings":"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"}
1
+ {"version":3,"file":"CnActionsMenu.vue2.js","sources":["../../../../src/components/CnActionsMenu/CnActionsMenu.vue"],"sourcesContent":["<!--\n CnActionsMenu — Shared \"…\" overflow Actions menu.\n\n Renders the canonical action set that appears on every Conduction\n surface — Refresh, then the mandatory trio Request a feature / Report a\n bug / Documentation — inside a single NcActions overflow. Request a\n feature opens the forge's feature-request issue form directly, exactly\n like Report a bug (team decision 2026-09-04: the in-product suggestion\n modal is gone — the forge is where the conversation happens, in English).\n Used by CnWidgetWrapper (widgets) and the page-level headers of\n CnDetailPage / CnDashboardPage so the three surfaces stay in lockstep.\n\n The trio is not optional and not conditional on configuration: each item\n resolves its own target (a forge new-issue deep-link for the bug report,\n `cnDocumentationBaseUrl` + the surface's `docsAnchor` for the docs link),\n so a host that passes no URLs still renders all three. That is the point\n — the items used to be per-host markup, and OpenRegister's widgets shipped\n without the Documentation entry while OpenCatalogi's were inconsistent.\n-->\n<template>\n\t<!-- Root <template v-if> (Vue 3 native fragment, renders no DOM node — was\n\t vue-frag <Fragment>) so NcActions stays in its host's flex/grid flow. -->\n\t<template v-if=\"hasOverflowMenu\">\n\t\t<NcActions\n\t\t\t:forceMenu=\"true\"\n\t\t\t:forceName=\"true\"\n\t\t\t:menuName=\"actionsMenuLabel\"\n\t\t\t:open=\"menuOpen\"\n\t\t\t:data-testid=\"`${testidBase}-actions`\"\n\t\t\t@update:open=\"menuOpen = $event\">\n\t\t\t<template #icon>\n\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t</template>\n\t\t\t<!-- Stays open while refreshing; onRefreshClick closes the menu once the refresh settles. -->\n\t\t\t<NcActionButton\n\t\t\t\tv-if=\"showRefresh\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-refresh`\"\n\t\t\t\t:disabled=\"refreshBusy\"\n\t\t\t\t:closeAfterClick=\"false\"\n\t\t\t\t@click=\"onRefreshClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"refreshBusy\" :size=\"20\" />\n\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ refreshLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<!-- @slot primary-items The surface's OWN actions — a page's\n\t\t\t manifest `headerActions`, say — rendered above the canonical\n\t\t\t trio. They sit here rather than in `#action-items` because a\n\t\t\t case's Add party belongs above Report a bug, not under it.\n\t\t\t The caller owns the trailing NcActionSeparator: only the\n\t\t\t caller knows whether its v-for produced any items, and a\n\t\t\t separator rendered here would strand itself when it did\n\t\t\t not. -->\n\t\t\t<slot name=\"primary-items\" />\n\t\t\t<!-- The canonical trio — Request a feature / Report a bug /\n\t\t\t Documentation — renders on EVERY surface. None of the three\n\t\t\t is conditional on a URL being configured any more: each\n\t\t\t resolves its own target (see resolvedDocumentationUrl /\n\t\t\t resolvedReportBugUrl), so a host that forgets to pass one\n\t\t\t still gets a working item instead of a silently missing one.\n\t\t\t `showRequestFeature` / `showReportBug` / `showDocumentation`\n\t\t\t exist only for the rare surface that must suppress one\n\t\t\t deliberately; they all default to true. -->\n\t\t\t<!-- A real link whenever the form's URL is known, so it can be\n\t\t\t middle-clicked or copied; a button only for a host with no\n\t\t\t URL that handles @request-feature itself. -->\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showRequestFeature && resolvedRequestFeatureUrl\"\n\t\t\t\t:href=\"resolvedRequestFeatureUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionButton\n\t\t\t\tv-else-if=\"showRequestFeature\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showReportBug && resolvedReportBugUrl\"\n\t\t\t\t:href=\"resolvedReportBugUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-report-bug`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BugOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ reportBugLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showDocumentation && resolvedDocumentationUrl\"\n\t\t\t\t:href=\"resolvedDocumentationUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-documentation`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ documentationLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<!-- @slot action-items Additional NcActionButton-family items\n\t\t\t rendered inside the overflow menu, after the built-in\n\t\t\t Refresh + Request-a-feature / Report-a-bug / Documentation\n\t\t\t group. -->\n\t\t\t<slot name=\"action-items\" />\n\t\t</NcActions>\n\t</template>\n</template>\n\n<script>\nimport { emit as emitOnBus } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport BugOutline from 'vue-material-design-icons/BugOutline.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport LightbulbOutline from 'vue-material-design-icons/LightbulbOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport { buildBugReportUrl, buildFeatureRequestUrl, DEFAULT_FORGE } from '../../utils/forge.js'\n\n/**\n * The fleet's per-app documentation site, derived from the app id. Used only\n * when no `documentationUrl` prop and no `cnDocumentationBaseUrl` inject are\n * available, so that the Documentation item is never absent — an app that\n * hosts its docs anywhere else provides the base instead.\n *\n * @param {string} appId Consuming app's slug.\n * @return {string} Documentation base URL, or '' when the app id is unknown.\n */\nfunction defaultDocsBase(appId) {\n\tconst id = String(appId || '').trim()\n\tif (!id) {\n\t\treturn ''\n\t}\n\treturn `https://${id}.conduction.nl/docs/`\n}\n\n/**\n * Resolve a documentation deep-link from a base URL and a per-widget\n * anchor. An anchor already starting with `#`, `/` or a `scheme://` is\n * used as written (respectively appended, resolved against the base's\n * origin, or taken whole); a bare slug becomes a `#fragment`, which is\n * how a docs page addresses one section of itself.\n *\n * @param {string} base Documentation base URL.\n * @param {string} anchor Per-widget anchor / path fragment.\n * @return {string} The resolved URL, or '' when there is no base to build on.\n */\nexport function resolveDocsUrl(base, anchor) {\n\tconst a = String(anchor || '').trim()\n\tif (a.includes('://')) {\n\t\treturn a\n\t}\n\tconst b = String(base || '').trim()\n\tif (!b) {\n\t\treturn ''\n\t}\n\tif (!a) {\n\t\treturn b\n\t}\n\tif (a.startsWith('#')) {\n\t\treturn `${b.replace(/#.*$/, '')}${a}`\n\t}\n\tif (a.startsWith('/')) {\n\t\ttry {\n\t\t\treturn new URL(a, b).toString()\n\t\t} catch {\n\t\t\treturn `${b.replace(/\\/+$/, '')}${a}`\n\t\t}\n\t}\n\treturn `${b.replace(/#.*$/, '').replace(/\\/+$/, '')}#${a}`\n}\n\n/**\n * Build a synthetic event object handed to host listeners alongside the\n * action payload. Mirrors the Vue 3 / DOM Event API enough to let a host\n * call `event.preventDefault()` to suppress the menu's built-in default\n * handler. Because Vue's `$emit` is synchronous, the same object also\n * propagates up through wrapping components (e.g. CnWidgetWrapper\n * re-emitting `@refresh`), so a host listener on the outer component can\n * still suppress the default.\n *\n * `waitUntil(promise)` lets a listener keep the Refresh item spinning, and the\n * menu open, until that promise settles.\n *\n * @param {(promise: Promise<unknown>) => void} [waitUntil] Collector for refresh work.\n * @return {{defaultPrevented: boolean, preventDefault: () => void, waitUntil: (promise: Promise<unknown>) => void}}\n */\nfunction createSyntheticEvent(waitUntil = () => {}) {\n\tconst ev = {\n\t\tdefaultPrevented: false,\n\t\tpreventDefault() {\n\t\t\tthis.defaultPrevented = true\n\t\t},\n\t\twaitUntil,\n\t}\n\treturn ev\n}\n\n/** Shortest time the Refresh spinner shows, so a fast refresh is still visible. */\nconst MIN_REFRESH_SPIN_MS = 400\n\n/** Longest the Refresh item waits on `waitUntil` work; axios has no default timeout. */\nconst MAX_REFRESH_WAIT_MS = 15000\n\n/**\n * CnActionsMenu — the shared built-in overflow Actions menu.\n *\n * Renders Refresh plus the mandatory trio Request a feature / Report a bug /\n * Documentation. The trio is unconditional: the bug link is built from the\n * app's forge repo and the docs link from the app-wide documentation base\n * plus this surface's `docsAnchor`, so no host can ship a menu missing one.\n * Pass `docsAnchor` per widget type — that is what makes Documentation open\n * that widget's own section instead of the docs homepage.\n *\n * ```vue\n * <CnActionsMenu\n * :widget-id=\"resolvedWidgetId\"\n * :title=\"displayTitle\"\n * :surface=\"`widget:${resolvedWidgetId}`\"\n * docs-anchor=\"open-cases\"\n * testid-base=\"cn-widget-wrapper\"\n * @refresh=\"(p, e) => $emit('refresh', p, e)\"\n * @request-feature=\"(p, e) => $emit('request-feature', p, e)\">\n * <template #action-items><slot name=\"action-items\" /></template>\n * </CnActionsMenu>\n * ```\n */\nexport default {\n\tname: 'CnActionsMenu',\n\n\tcomponents: {\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcLoadingIcon,\n\t\tDotsHorizontal,\n\t\tRefresh,\n\t\tLightbulbOutline,\n\t\tBookOpenVariant,\n\t\tBugOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consuming app's slug (e.g. \"pipelinq\"). Provided by CnAppRoot.\n\t\t * Defaults to empty string when no CnAppRoot ancestor exists.\n\t\t */\n\t\tcnAppId: { default: () => '' },\n\t\t/**\n\t\t * Repo slug both forge deep-links target (e.g.\n\t\t * `ConductionNL/pipelinq`) — the Request-a-feature and Report-a-bug\n\t\t * new-issue forms. Provided by CnAppRoot from the manifest's\n\t\t * `nav.featureRequestRepo` field (with fallback to\n\t\t * `ConductionNL/<appId>`). Empty when no ancestor — the default\n\t\t * handler warns and skips opening rather than open a broken link.\n\t\t */\n\t\tcnFeatureRequestRepo: { default: () => '' },\n\t\t/**\n\t\t * Forge config (`{type, baseUrl}`) both new-issue deep-links are\n\t\t * built against. Provided by CnAppRoot from `manifest.nav.forge`.\n\t\t * Defaults to DEFAULT_FORGE when no CnAppRoot ancestor exists —\n\t\t * a third hardcoded Codeberg default lived here, so a menu mounted\n\t\t * standalone contradicted both the fleet default and the app it was\n\t\t * reporting for.\n\t\t */\n\t\tcnFeatureRequestForge: { default: () => ({ ...DEFAULT_FORGE }) },\n\t\t/**\n\t\t * Resolver for a widget's manifest title — the AUTHORED English\n\t\t * source string — provided by CnDashboardPage as\n\t\t * `(widgetId) => string`. The `title` prop this component receives\n\t\t * has already been through the host translate function\n\t\t * — CnDashboardPage's getWidgetTitle is the display chokepoint — and\n\t\t * may also be a user-typed customTitle in the user's own language, so\n\t\t * it is the wrong thing to put in a bug-report title. Returns '' when\n\t\t * no dashboard ancestor provides it (a standalone widget, a detail\n\t\t * page) or the widget def carries no title, and the link falls back\n\t\t * to the surface slug.\n\t\t */\n\t\tcnWidgetTitleSource: { default: () => () => '' },\n\t\t/**\n\t\t * App-wide documentation base URL (e.g.\n\t\t * `https://pipelinq.conduction.nl/docs`), provided by CnAppRoot from\n\t\t * `manifest.nav.documentationUrl`. Every widget's Documentation item\n\t\t * is built from this base plus the widget's own `docsAnchor`, so the\n\t\t * link lands on that widget's section rather than the docs homepage.\n\t\t * Empty when no ancestor provides one — the host's explicit\n\t\t * `documentationUrl` prop then has to carry the whole URL.\n\t\t */\n\t\tcnDocumentationBaseUrl: { default: () => '' },\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * Whether the Refresh item renders. The parent surface is\n\t\t * responsible for any opt-out aliasing (e.g. CnWidgetWrapper's\n\t\t * `hideRefresh`) and passes the resolved boolean here.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the Request-a-feature item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link target, opened in a new tab. Wins over\n\t\t * the `cnDocumentationBaseUrl` + `docsAnchor` pair. Leave empty (the\n\t\t * default) to let the menu build the per-widget deep-link itself.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * This surface's own section in the app's documentation, appended to\n\t\t * the app-wide `cnDocumentationBaseUrl`. A bare slug (`open-cases`)\n\t\t * becomes a `#fragment`; a value starting with `/` is resolved as a\n\t\t * path; a full `scheme://` URL is used as written. Supplying it is\n\t\t * what makes the Documentation item land on THIS widget's section\n\t\t * rather than the docs homepage.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocsAnchor: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the Documentation item renders. Defaults to true — the\n\t\t * canonical trio is meant to be present on every surface; set false\n\t\t * only where a docs link genuinely cannot exist.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the \"Report a bug\" item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit \"Report a bug\" target. Empty (the default) builds a\n\t\t * new-issue deep-link on the app's forge from the injected\n\t\t * `cnFeatureRequestRepo` + `cnFeatureRequestForge`, pre-filled with\n\t\t * the surface's title.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\treportBugUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Report-a-bug action. */\n\t\treportBugLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Report a bug'),\n\t\t},\n\n\t\t/**\n\t\t * Pre-translated label for the Documentation item. Defaults to the\n\t\t * lib's translation of \"Documentation\".\n\t\t */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded on the `@refresh` / `@request-feature`\n\t\t * payloads (as `widgetId`) and on the `cn:widget:refresh`\n\t\t * event-bus payload. The parent resolves it (explicit id or\n\t\t * slugified title).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Human-readable title carried on action payloads.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable `surface` slug naming where the menu sits (e.g.\n\t\t * `widget:<id>`, `detail:<id>`, `dashboard:<id>`). Used as the\n\t\t * English headline fallback for both new-issue deep-links when no\n\t\t * authored title can be recovered.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: { // eslint-disable-line vue/no-unused-properties -- published prop kept so hosts that still bind it do not leak it into $attrs\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether a refresh is currently in flight. While true, the Refresh\n\t\t * item is disabled and shows a loading spinner for exactly as long as\n\t\t * this stays true — so the spinner reflects the real refresh time.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Event-bus channel the default Refresh handler emits on when no\n\t\t * host listener suppresses it. Widgets use `cn:widget:refresh`;\n\t\t * page surfaces pass `cn:page:refresh`.\n\t\t */\n\t\trefreshChannel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn:widget:refresh',\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\n\t\t/**\n\t\t * Prefix for the `data-testid`s emitted on the menu container and\n\t\t * its items: `<base>-actions` (container), `<base>-action-refresh`,\n\t\t * `<base>-action-request-feature`, `<base>-action-report-bug`,\n\t\t * `<base>-action-documentation`.\n\t\t * Lets each host keep its own stable testids.\n\t\t */\n\t\ttestidBase: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn-actions-menu',\n\t\t},\n\t},\n\n\temits: ['refresh', 'request-feature'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow menu is open. */\n\t\t\tmenuOpen: false,\n\t\t\t/** Whether a refresh this menu started is still settling. */\n\t\t\trefreshPending: false,\n\t\t\t/** Close the menu once the host's `refreshing` falls back to false. */\n\t\t\tcloseWhenIdle: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Whether the Refresh item spins: the host's flag or our own pending refresh. */\n\t\trefreshBusy() {\n\t\t\treturn this.refreshing || this.refreshPending\n\t\t},\n\n\t\t/**\n\t\t * Whether the overflow `…` menu renders at all. True when at least\n\t\t * one built-in item is visible OR the caller provided an\n\t\t * `action-items` slot.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasOverflowMenu() {\n\t\t\tif (this.showRefresh) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showDocumentation && this.resolvedDocumentationUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showReportBug && this.resolvedReportBugUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showRequestFeature) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.$slots['primary-items']) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * The Documentation item's target: the explicit `documentationUrl`\n\t\t * when given, otherwise the app-wide base deep-linked with this\n\t\t * surface's `docsAnchor`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDocumentationUrl() {\n\t\t\tif (this.documentationUrl) {\n\t\t\t\treturn this.docsAnchor\n\t\t\t\t\t? resolveDocsUrl(this.documentationUrl, this.docsAnchor)\n\t\t\t\t\t: this.documentationUrl\n\t\t\t}\n\t\t\tif (this.cnDocumentationBaseUrl) {\n\t\t\t\treturn resolveDocsUrl(this.cnDocumentationBaseUrl, this.docsAnchor)\n\t\t\t}\n\t\t\t// Last resort so the item is never simply MISSING — an absent\n\t\t\t// Documentation entry is the defect this menu exists to prevent.\n\t\t\t// The fleet's convention is one docs site per app id; an app that\n\t\t\t// hosts its docs elsewhere sets `cnDocumentationBaseUrl` on\n\t\t\t// CnAppRoot, and the warning below says so.\n\t\t\treturn resolveDocsUrl(defaultDocsBase(this.cnAppId), this.docsAnchor)\n\t\t},\n\n\t\t/**\n\t\t * This surface's title AS AUTHORED, for anything that must not be\n\t\t * localized. Asks the injected dashboard resolver for the widget's\n\t\t * manifest source string; '' when nothing can supply one.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceTitle() {\n\t\t\tconst resolve = this.cnWidgetTitleSource\n\t\t\tif (typeof resolve !== 'function' || !this.widgetId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn String(resolve(this.widgetId) || '').trim()\n\t\t\t} catch {\n\t\t\t\t// A host resolver that throws must not take the menu with it —\n\t\t\t\t// the link degrades to the surface slug.\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The Report-a-bug target: the explicit `reportBugUrl` when given,\n\t\t * otherwise a new-issue deep-link on the app's forge, pre-filled with\n\t\t * a title naming the surface the report came from.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedReportBugUrl() {\n\t\t\tif (this.reportBugUrl) {\n\t\t\t\treturn this.reportBugUrl\n\t\t\t}\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// buildBugReportUrl owns both the host (one resolveForge for the\n\t\t\t// whole suggestion flow) and the bug-report issue FORM. This was\n\t\t\t// hand-rolled here against a local copy of the forge host map that\n\t\t\t// defaulted to Codeberg, so a menu mounted without a CnAppRoot sent\n\t\t\t// bug reports to a different host than the Request-a-feature item\n\t\t\t// directly above it — and it linked the BLANK issue form, so every\n\t\t\t// in-product report arrived with no steps, no expected/actual and\n\t\t\t// no severity.\n\t\t\t//\n\t\t\t// The headline must be ENGLISH: the `title` prop is already\n\t\t\t// translated (CnDashboardPage's getWidgetTitle is the display\n\t\t\t// chokepoint), so a report from a French UI read \"[BUG] Activité\n\t\t\t// récente\" and one from a Russian UI was in Cyrillic — unreadable\n\t\t\t// to a maintainer, even though the English msgid was sitting in the\n\t\t\t// manifest. `cnWidgetTitleSource` hands back that manifest string,\n\t\t\t// skipping any user-typed customTitle for the same reason.\n\t\t\t//\n\t\t\t// With no dashboard ancestor to ask, fall back to the surface slug\n\t\t\t// rather than the translated prop: a slug is English by\n\t\t\t// construction, and \"always English\" is the point. The localized\n\t\t\t// title is deliberately not carried in the URL at all — see\n\t\t\t// buildBugReportUrl for why it was dropped.\n\t\t\treturn buildBugReportUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The Request-a-feature target: the forge's feature-request issue\n\t\t * FORM, built exactly like resolvedReportBugUrl — same repo, same\n\t\t * forge, same English-headline rules (see that computed for why the\n\t\t * headline is never the translated title). Empty when no repo can\n\t\t * be resolved, in which case the click handler warns and does\n\t\t * nothing rather than open a broken link.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRequestFeatureUrl() {\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trefreshing(busy) {\n\t\t\tif (!busy && this.closeWhenIdle) {\n\t\t\t\tthis.closeWhenIdle = false\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Refresh click — emits `@refresh`, then runs the built-in default\n\t\t * (emit on `refreshChannel`) unless a host called\n\t\t * `event.preventDefault()` on the second handler arg. The item spins\n\t\t * and the menu stays open until every promise handed to `waitUntil`\n\t\t * (on the event or the bus payload) settles, or 15 s pass, and the\n\t\t * host's `refreshing` is false; then the menu closes.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRefreshClick() {\n\t\t\tif (this.refreshBusy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst work = []\n\t\t\tconst waitUntil = (promise) => {\n\t\t\t\twork.push(Promise.resolve(promise))\n\t\t\t}\n\t\t\tconst ev = createSyntheticEvent(waitUntil)\n\t\t\tthis.refreshPending = true\n\t\t\tconst startedAt = Date.now()\n\t\t\t/**\n\t\t\t * @event refresh User clicked the Refresh item. Payload:\n\t\t\t * `{ widgetId, title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default (event-bus\n\t\t\t * emit on `refreshChannel`), and its `waitUntil(promise)` to keep\n\t\t\t * the item spinning until that work settles.\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (!ev.defaultPrevented) {\n\t\t\t\temitOnBus(this.refreshChannel, {\n\t\t\t\t\twidgetId: this.widgetId,\n\t\t\t\t\ttitle: this.title,\n\t\t\t\t\twaitUntil,\n\t\t\t\t})\n\t\t\t}\n\t\t\tlet ceiling\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.allSettled(work),\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tceiling = setTimeout(resolve, MAX_REFRESH_WAIT_MS)\n\t\t\t\t}),\n\t\t\t])\n\t\t\tclearTimeout(ceiling)\n\t\t\tconst hold = MIN_REFRESH_SPIN_MS - (Date.now() - startedAt)\n\t\t\tif (hold > 0) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, hold))\n\t\t\t}\n\t\t\tthis.refreshPending = false\n\t\t\tif (this.refreshing) {\n\t\t\t\tthis.closeWhenIdle = true\n\t\t\t} else {\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Request-a-feature click — emits `@request-feature`. The item is a\n\t\t * link to the forge's feature-request form, so the browser opens it\n\t\t * unless a host called `event.preventDefault()`, which then cancels\n\t\t * the link. With no `cnFeatureRequestRepo` the item is a button and\n\t\t * this only warns.\n\t\t *\n\t\t * @param {Event} [nativeEvent] The link's click event.\n\t\t * @return {void}\n\t\t */\n\t\tonRequestFeatureClick(nativeEvent) {\n\t\t\tconst ev = createSyntheticEvent()\n\t\t\t/**\n\t\t\t * @event request-feature User clicked the Request a feature\n\t\t\t * item. Payload: `{ widgetId, title }`. Handlers may call the\n\t\t\t * second arg's `preventDefault()` to suppress the built-in\n\t\t\t * default (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (ev.defaultPrevented) {\n\t\t\t\tif (nativeEvent && typeof nativeEvent.preventDefault === 'function') {\n\t\t\t\t\tnativeEvent.preventDefault()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.resolvedRequestFeatureUrl) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnActionsMenu] Cannot open the feature-request form: missing cnFeatureRequestRepo inject (mount under CnAppRoot or bind a custom @request-feature listener).')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["t","emitOnBus"],"mappings":";;;;;;;;;;AAmIA;AACC;AACA;;;AAGA;AACA;AACA;;AAED,SAAS,eAAe,CAAC,KAAK,EAAE;AAC/B,CAAA,MAAM,EAAC,GAAI,MAAM,CAAC,KAAM,IAAG,EAAE,CAAC,CAAC,IAAI,GAAC;AACpC,CAAA,IAAI,CAAC,EAAE,EAAE;AACR,EAAA,OAAO,EAAC;AACT,EAAA;AACA,CAAA,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,oBAAoB,CAAA;AAC1C,CAAA;;AAEA;;;;;AAKC;AACA;AACA;;;;AAIM,SAAS,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE;AAC5C,CAAA,MAAM,CAAE,GAAE,MAAM,CAAC,MAAO,IAAG,EAAE,CAAC,CAAC,IAAI,GAAC;AACpC,CAAA,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACtB,EAAA,OAAO,CAAA;AACR,EAAA;CACA,MAAM,CAAA,GAAI,MAAM,CAAC,IAAG,IAAK,EAAE,CAAC,CAAC,IAAI,GAAC;AAClC,CAAA,IAAI,CAAC,CAAC,EAAE;AACP,EAAA,OAAO,EAAC;AACT,EAAA;AACA,CAAA,IAAI,CAAC,CAAC,EAAE;AACP,EAAA,OAAO,CAAA;AACR,EAAA;AACA,CAAA,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AACtB,EAAA,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACrC,EAAA;AACA,CAAA,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AACtB,EAAA,IAAI;GACH,OAAO,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAC;AAC/B,GAAA,CAAE,MAAM;AACP,GAAA,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACrC,GAAA;AACD,EAAA;CACA,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC1D,CAAA;;AAEA;;;AAGC;;;;;AAKA;AACA;AACA;AACA;AACA;;;AAGD,SAAS,oBAAoB,CAAC,SAAQ,GAAI,MAAM,EAAE,EAAE;AACnD,CAAA,MAAM,KAAK;EACV,gBAAgB,EAAE,KAAK;AACvB,EAAA,cAAc,GAAG;GAChB,IAAI,CAAC,gBAAiB,GAAE,KAAG;GAC3B;AACD,EAAA,SAAS;AACV,GAAA;AACA,CAAA,OAAO,EAAC;AACT,CAAA;;AAEA;AACA,MAAM,mBAAkB,GAAI,IAAE;;AAE9B;AACA,MAAM,mBAAkB,GAAI,MAAI;;AAEhC;;AAEC;;;;;AAKA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;;AAGA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,eAAe;;CAErB,UAAU,EAAE;AACX,EAAA,SAAS;AACT,EAAA,cAAc;EACd,YAAY;EACZ,aAAa;AACb,EAAA,cAAc;AACd,EAAA,OAAO;AACP,EAAA,gBAAgB;AAChB,EAAA,eAAe;EACf,UAAU;EACV;;AAED,CAAA,MAAM,EAAE;AACP;;;;EAIA,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAC,EAAG;AAC9B;AACC;;;AAGA;;;;AAID,EAAA,oBAAoB,EAAE,EAAE,OAAO,EAAE,MAAM,IAAI;AAC3C;;;;;;;;EAQA,qBAAqB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,aAAY,EAAG,CAAA,EAAG;AAChE;;AAEC;;AAEA;;;;;;AAMA;;AAED,EAAA,mBAAmB,EAAE,EAAE,OAAO,EAAE,MAAM,MAAM,IAAI;AAChD;AACC;AACA;AACA;;;;;;AAMD,EAAA,sBAAsB,EAAE,EAAE,OAAO,EAAE,MAAM,IAAI;EAC7C;;AAED,CAAA,YAAY,EAAE,KAAK;;AAEnB,CAAA,KAAK,EAAE;AACN;;;;AAIC;AACA;;EAED,WAAW,EAAE;GACZ,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;AAED;AACC;AACA;AACA;;AAED,EAAA,kBAAkB,EAAE;GACnB,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;AAED;;;;AAIC;;;AAGD,EAAA,gBAAgB,EAAE;GACjB,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;;;;AAOC;;;EAGD,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;AAGC;AACA;AACA;;AAED,EAAA,iBAAiB,EAAE;GAClB,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;AAED;AACC;AACA;AACA;;AAED,EAAA,aAAa,EAAE;GACd,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;AAED;;;;AAIC;AACA;;;EAGD,YAAY,EAAE;GACb,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;AAGD,EAAA,cAAc,EAAE;GACf,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,cAAc,CAAC;GACjD;;AAED;;AAEC;;AAED,EAAA,kBAAkB,EAAE;GACnB,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,eAAe,CAAC;GAClD;;AAED;;;;AAIC;AACA;;;AAGD,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;AACC;;AAED,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;;AAKC;;;AAGD,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;;AAKC;;;EAGD,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;AAIC;AACA;;EAED,UAAU,EAAE;GACX,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;;;AAGC;;AAED,EAAA,cAAc,EAAE;GACf,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,mBAAmB;GAC5B;;AAED;EACA,YAAY,EAAE;GACb,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;GAC5C;;;AAGD,EAAA,mBAAmB,EAAE;GACpB,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,mBAAmB,CAAC;GACtD;;;AAGD,EAAA,gBAAgB,EAAE;GACjB,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;GAC5C;;AAED;;;;AAIC;AACA;;EAED,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,iBAAiB;GAC1B;EACD;;AAED,CAAA,KAAK,EAAE,CAAC,SAAS,EAAE,iBAAiB,CAAC;;AAErC,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN;AACA,GAAA,QAAQ,EAAE,KAAK;;AAEf,GAAA,cAAc,EAAE,KAAK;;AAErB,GAAA,aAAa,EAAE,KAAK;AACrB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;EACA,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,UAAW,IAAG,IAAI,CAAC,cAAa;GAC5C;;AAED;;AAEC;AACA;AACA;AACA;;AAED,EAAA,eAAe,GAAG;AACjB,GAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACrB,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,IAAI,CAAC,iBAAkB,IAAG,IAAI,CAAC,wBAAwB,EAAE;AAC5D,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,IAAI,CAAC,aAAc,IAAG,IAAI,CAAC,oBAAoB,EAAE;AACpD,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,IAAI,CAAC,kBAAkB,EAAE;AAC5B,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE;AACjC,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAE,IAAG,OAAO,CAAC,IAAI,CAAC,MAAK,IAAK,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;GACjG;;AAED;;;;AAIC;AACA;;EAED,wBAAwB,GAAG;GAC1B,IAAI,IAAI,CAAC,gBAAgB,EAAE;AAC1B,IAAA,OAAO,IAAI,CAAC,UAAS;OAClB,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,UAAU,CAAA;AACvD,OAAE,IAAI,CAAC,gBAAe;AACxB,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,sBAAsB,EAAE;AAChC,IAAA,OAAO,cAAc,CAAC,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,UAAU,CAAA;AACnE,IAAA;;;;;AAKA;AACA,GAAA,OAAO,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU,CAAA;GACpE;;AAED;;;;AAIC;AACA;;EAED,WAAW,GAAG;AACb,GAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,oBAAkB;GACvC,IAAI,OAAO,OAAQ,KAAI,UAAS,IAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;AACpD,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI;IACH,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAA,IAAK,EAAE,CAAC,CAAC,IAAI,EAAC;AAClD,IAAA,CAAE,MAAM;;AAEP;AACA,IAAA,OAAO,EAAC;AACT,IAAA;GACA;;AAED;;;AAGC;AACA;AACA;;EAED,oBAAoB,GAAG;AACtB,GAAA,IAAI,IAAI,CAAC,YAAY,EAAE;IACtB,OAAO,IAAI,CAAC,YAAW;AACxB,IAAA;GACA,MAAM,IAAK,GAAE,MAAM,CAAC,IAAI,CAAC,oBAAqB,IAAG,EAAE,CAAC,CAAC,IAAI,GAAC;AAC1D,GAAA,IAAI,CAAC,IAAI,EAAE;AACV,IAAA,OAAO,EAAC;AACT,IAAA;;;;;;;;;;;;;;;;;;;AAmBA;;;AAGA;GACA,OAAO,iBAAiB,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,EAAE;IAC1D,KAAK,EAAE,IAAI,CAAC,WAAW;AACvB,IAAA,OAAO,EAAE,IAAI,CAAC,OAAQ,IAAG,IAAI,CAAC,QAAQ;IACtC,CAAA;GACD;;AAED;;;;;;AAMC;AACA;AACA;;EAED,yBAAyB,GAAG;GAC3B,MAAM,IAAK,GAAE,MAAM,CAAC,IAAI,CAAC,oBAAqB,IAAG,EAAE,CAAC,CAAC,IAAI,GAAC;AAC1D,GAAA,IAAI,CAAC,IAAI,EAAE;AACV,IAAA,OAAO,EAAC;AACT,IAAA;GACA,OAAO,sBAAsB,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,EAAE;IAC/D,KAAK,EAAE,IAAI,CAAC,WAAW;AACvB,IAAA,OAAO,EAAE,IAAI,CAAC,OAAQ,IAAG,IAAI,CAAC,QAAQ;IACtC,CAAA;GACD;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,UAAU,CAAC,IAAI,EAAE;GAChB,IAAI,CAAC,IAAG,IAAK,IAAI,CAAC,aAAa,EAAE;IAChC,IAAI,CAAC,gBAAgB,MAAI;AACzB,IAAA,IAAI,CAAC,QAAS,GAAE,MAAI;AACrB,IAAA;GACA;EACD;;AAED,CAAA,OAAO,EAAE;AACR;;AAEC;;;;AAIA;AACA;;;AAGD,EAAA,MAAM,cAAc,GAAG;AACtB,GAAA,IAAI,IAAI,CAAC,WAAW,EAAE;IACrB,MAAK;AACN,IAAA;GACA,MAAM,IAAK,GAAE,GAAC;GACd,MAAM,YAAY,CAAC,OAAO,KAAK;AAC9B,IAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAA;AACnC,KAAA;AACA,GAAA,MAAM,KAAK,oBAAoB,CAAC,SAAS,EAAA;GACzC,IAAI,CAAC,cAAe,GAAE,KAAG;GACzB,MAAM,SAAU,GAAE,IAAI,CAAC,GAAG,GAAC;AAC3B;;;;;AAKC;AACA;;AAED,GAAA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAI,EAAG,EAAE,EAAE,EAAA;GACxE,IAAI,CAAC,EAAE,CAAC,gBAAgB,EAAE;AACzB,IAAAC,IAAS,CAAC,IAAI,CAAC,cAAc,EAAE;KAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACvB,KAAA,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,KAAA,SAAS;KACT,EAAA;AACF,IAAA;AACA,GAAA,IAAI,QAAM;AACV,GAAA,MAAM,OAAO,CAAC,IAAI,CAAC;IAClB,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;IACxB,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK;KACxB,OAAQ,GAAE,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAA;AAClD,KAAC,CAAC;IACF,EAAA;AACD,GAAA,YAAY,CAAC,OAAO,EAAA;GACpB,MAAM,IAAK,GAAE,uBAAuB,IAAI,CAAC,GAAG,EAAC,GAAI,SAAS,EAAA;GAC1D,IAAI,IAAK,GAAE,CAAC,EAAE;IACb,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,EAAA;AACzD,IAAA;GACA,IAAI,CAAC,iBAAiB,MAAI;AAC1B,GAAA,IAAI,IAAI,CAAC,UAAU,EAAE;IACpB,IAAI,CAAC,gBAAgB,KAAG;IACvB,MAAK;AACN,IAAA,IAAI,CAAC,QAAS,GAAE,MAAI;AACrB,IAAA;GACA;;AAED;;;;;AAKC;AACA;;;;AAID,EAAA,qBAAqB,CAAC,WAAW,EAAE;GAClC,MAAM,EAAG,GAAE,oBAAoB,GAAC;AAChC;;;;;AAKC;;AAED,GAAA,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAI,EAAG,EAAE,EAAE,EAAA;GAChF,IAAI,EAAE,CAAC,gBAAgB,EAAE;AACxB,IAAA,IAAI,WAAY,IAAG,OAAO,WAAW,CAAC,cAAe,KAAI,UAAU,EAAE;KACpE,WAAW,CAAC,cAAc,GAAC;AAC5B,KAAA;IACA,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE;AACpC;AACA,IAAA,OAAO,CAAC,IAAI,CAAC,+JAA+J,EAAA;AAC7K,IAAA;GACA;EACD;AACF;;;;"}
@@ -56,7 +56,6 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
56
56
  key: 1,
57
57
  href: $options.resolvedRequestFeatureUrl,
58
58
  target: "_blank",
59
- rel: "noopener noreferrer",
60
59
  "data-testid": `${$props.testidBase}-action-request-feature`,
61
60
  closeAfterClick: true,
62
61
  onClick: $options.onRequestFeatureClick
@@ -90,7 +89,6 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
90
89
  key: 3,
91
90
  href: $options.resolvedReportBugUrl,
92
91
  target: "_blank",
93
- rel: "noopener noreferrer",
94
92
  "data-testid": `${$props.testidBase}-action-report-bug`,
95
93
  closeAfterClick: true
96
94
  }, {
@@ -108,7 +106,6 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
108
106
  key: 4,
109
107
  href: $options.resolvedDocumentationUrl,
110
108
  target: "_blank",
111
- rel: "noopener noreferrer",
112
109
  "data-testid": `${$props.testidBase}-action-documentation`,
113
110
  closeAfterClick: true
114
111
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"CnActionsMenu.vue3.js","sources":["../../../../src/components/CnActionsMenu/CnActionsMenu.vue?vue&type=template&id=74d4ebf3&lang.js"],"sourcesContent":["<!--\n CnActionsMenu — Shared \"…\" overflow Actions menu.\n\n Renders the canonical action set that appears on every Conduction\n surface — Refresh, then the mandatory trio Request a feature / Report a\n bug / Documentation — inside a single NcActions overflow. Request a\n feature opens the forge's feature-request issue form directly, exactly\n like Report a bug (team decision 2026-09-04: the in-product suggestion\n modal is gone — the forge is where the conversation happens, in English).\n Used by CnWidgetWrapper (widgets) and the page-level headers of\n CnDetailPage / CnDashboardPage so the three surfaces stay in lockstep.\n\n The trio is not optional and not conditional on configuration: each item\n resolves its own target (a forge new-issue deep-link for the bug report,\n `cnDocumentationBaseUrl` + the surface's `docsAnchor` for the docs link),\n so a host that passes no URLs still renders all three. That is the point\n — the items used to be per-host markup, and OpenRegister's widgets shipped\n without the Documentation entry while OpenCatalogi's were inconsistent.\n-->\n<template>\n\t<!-- Root <template v-if> (Vue 3 native fragment, renders no DOM node — was\n\t vue-frag <Fragment>) so NcActions stays in its host's flex/grid flow. -->\n\t<template v-if=\"hasOverflowMenu\">\n\t\t<NcActions\n\t\t\t:forceMenu=\"true\"\n\t\t\t:forceName=\"true\"\n\t\t\t:menuName=\"actionsMenuLabel\"\n\t\t\t:open=\"menuOpen\"\n\t\t\t:data-testid=\"`${testidBase}-actions`\"\n\t\t\t@update:open=\"menuOpen = $event\">\n\t\t\t<template #icon>\n\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t</template>\n\t\t\t<!-- Stays open while refreshing; onRefreshClick closes the menu once the refresh settles. -->\n\t\t\t<NcActionButton\n\t\t\t\tv-if=\"showRefresh\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-refresh`\"\n\t\t\t\t:disabled=\"refreshBusy\"\n\t\t\t\t:closeAfterClick=\"false\"\n\t\t\t\t@click=\"onRefreshClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"refreshBusy\" :size=\"20\" />\n\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ refreshLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<!-- @slot primary-items The surface's OWN actions — a page's\n\t\t\t manifest `headerActions`, say — rendered above the canonical\n\t\t\t trio. They sit here rather than in `#action-items` because a\n\t\t\t case's Add party belongs above Report a bug, not under it.\n\t\t\t The caller owns the trailing NcActionSeparator: only the\n\t\t\t caller knows whether its v-for produced any items, and a\n\t\t\t separator rendered here would strand itself when it did\n\t\t\t not. -->\n\t\t\t<slot name=\"primary-items\" />\n\t\t\t<!-- The canonical trio — Request a feature / Report a bug /\n\t\t\t Documentation — renders on EVERY surface. None of the three\n\t\t\t is conditional on a URL being configured any more: each\n\t\t\t resolves its own target (see resolvedDocumentationUrl /\n\t\t\t resolvedReportBugUrl), so a host that forgets to pass one\n\t\t\t still gets a working item instead of a silently missing one.\n\t\t\t `showRequestFeature` / `showReportBug` / `showDocumentation`\n\t\t\t exist only for the rare surface that must suppress one\n\t\t\t deliberately; they all default to true. -->\n\t\t\t<!-- A real link whenever the form's URL is known, so it can be\n\t\t\t middle-clicked or copied; a button only for a host with no\n\t\t\t URL that handles @request-feature itself. -->\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showRequestFeature && resolvedRequestFeatureUrl\"\n\t\t\t\t:href=\"resolvedRequestFeatureUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionButton\n\t\t\t\tv-else-if=\"showRequestFeature\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showReportBug && resolvedReportBugUrl\"\n\t\t\t\t:href=\"resolvedReportBugUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-report-bug`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BugOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ reportBugLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showDocumentation && resolvedDocumentationUrl\"\n\t\t\t\t:href=\"resolvedDocumentationUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-documentation`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ documentationLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<!-- @slot action-items Additional NcActionButton-family items\n\t\t\t rendered inside the overflow menu, after the built-in\n\t\t\t Refresh + Request-a-feature / Report-a-bug / Documentation\n\t\t\t group. -->\n\t\t\t<slot name=\"action-items\" />\n\t\t</NcActions>\n\t</template>\n</template>\n\n<script>\nimport { emit as emitOnBus } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport BugOutline from 'vue-material-design-icons/BugOutline.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport LightbulbOutline from 'vue-material-design-icons/LightbulbOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport { buildBugReportUrl, buildFeatureRequestUrl, DEFAULT_FORGE } from '../../utils/forge.js'\n\n/**\n * The fleet's per-app documentation site, derived from the app id. Used only\n * when no `documentationUrl` prop and no `cnDocumentationBaseUrl` inject are\n * available, so that the Documentation item is never absent — an app that\n * hosts its docs anywhere else provides the base instead.\n *\n * @param {string} appId Consuming app's slug.\n * @return {string} Documentation base URL, or '' when the app id is unknown.\n */\nfunction defaultDocsBase(appId) {\n\tconst id = String(appId || '').trim()\n\tif (!id) {\n\t\treturn ''\n\t}\n\treturn `https://${id}.conduction.nl/docs/`\n}\n\n/**\n * Resolve a documentation deep-link from a base URL and a per-widget\n * anchor. An anchor already starting with `#`, `/` or a `scheme://` is\n * used as written (respectively appended, resolved against the base's\n * origin, or taken whole); a bare slug becomes a `#fragment`, which is\n * how a docs page addresses one section of itself.\n *\n * @param {string} base Documentation base URL.\n * @param {string} anchor Per-widget anchor / path fragment.\n * @return {string} The resolved URL, or '' when there is no base to build on.\n */\nexport function resolveDocsUrl(base, anchor) {\n\tconst a = String(anchor || '').trim()\n\tif (a.includes('://')) {\n\t\treturn a\n\t}\n\tconst b = String(base || '').trim()\n\tif (!b) {\n\t\treturn ''\n\t}\n\tif (!a) {\n\t\treturn b\n\t}\n\tif (a.startsWith('#')) {\n\t\treturn `${b.replace(/#.*$/, '')}${a}`\n\t}\n\tif (a.startsWith('/')) {\n\t\ttry {\n\t\t\treturn new URL(a, b).toString()\n\t\t} catch {\n\t\t\treturn `${b.replace(/\\/+$/, '')}${a}`\n\t\t}\n\t}\n\treturn `${b.replace(/#.*$/, '').replace(/\\/+$/, '')}#${a}`\n}\n\n/**\n * Build a synthetic event object handed to host listeners alongside the\n * action payload. Mirrors the Vue 3 / DOM Event API enough to let a host\n * call `event.preventDefault()` to suppress the menu's built-in default\n * handler. Because Vue's `$emit` is synchronous, the same object also\n * propagates up through wrapping components (e.g. CnWidgetWrapper\n * re-emitting `@refresh`), so a host listener on the outer component can\n * still suppress the default.\n *\n * `waitUntil(promise)` lets a listener keep the Refresh item spinning, and the\n * menu open, until that promise settles.\n *\n * @param {(promise: Promise<unknown>) => void} [waitUntil] Collector for refresh work.\n * @return {{defaultPrevented: boolean, preventDefault: () => void, waitUntil: (promise: Promise<unknown>) => void}}\n */\nfunction createSyntheticEvent(waitUntil = () => {}) {\n\tconst ev = {\n\t\tdefaultPrevented: false,\n\t\tpreventDefault() {\n\t\t\tthis.defaultPrevented = true\n\t\t},\n\t\twaitUntil,\n\t}\n\treturn ev\n}\n\n/** Shortest time the Refresh spinner shows, so a fast refresh is still visible. */\nconst MIN_REFRESH_SPIN_MS = 400\n\n/** Longest the Refresh item waits on `waitUntil` work; axios has no default timeout. */\nconst MAX_REFRESH_WAIT_MS = 15000\n\n/**\n * CnActionsMenu — the shared built-in overflow Actions menu.\n *\n * Renders Refresh plus the mandatory trio Request a feature / Report a bug /\n * Documentation. The trio is unconditional: the bug link is built from the\n * app's forge repo and the docs link from the app-wide documentation base\n * plus this surface's `docsAnchor`, so no host can ship a menu missing one.\n * Pass `docsAnchor` per widget type — that is what makes Documentation open\n * that widget's own section instead of the docs homepage.\n *\n * ```vue\n * <CnActionsMenu\n * :widget-id=\"resolvedWidgetId\"\n * :title=\"displayTitle\"\n * :surface=\"`widget:${resolvedWidgetId}`\"\n * docs-anchor=\"open-cases\"\n * testid-base=\"cn-widget-wrapper\"\n * @refresh=\"(p, e) => $emit('refresh', p, e)\"\n * @request-feature=\"(p, e) => $emit('request-feature', p, e)\">\n * <template #action-items><slot name=\"action-items\" /></template>\n * </CnActionsMenu>\n * ```\n */\nexport default {\n\tname: 'CnActionsMenu',\n\n\tcomponents: {\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcLoadingIcon,\n\t\tDotsHorizontal,\n\t\tRefresh,\n\t\tLightbulbOutline,\n\t\tBookOpenVariant,\n\t\tBugOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consuming app's slug (e.g. \"pipelinq\"). Provided by CnAppRoot.\n\t\t * Defaults to empty string when no CnAppRoot ancestor exists.\n\t\t */\n\t\tcnAppId: { default: () => '' },\n\t\t/**\n\t\t * Repo slug both forge deep-links target (e.g.\n\t\t * `ConductionNL/pipelinq`) — the Request-a-feature and Report-a-bug\n\t\t * new-issue forms. Provided by CnAppRoot from the manifest's\n\t\t * `nav.featureRequestRepo` field (with fallback to\n\t\t * `ConductionNL/<appId>`). Empty when no ancestor — the default\n\t\t * handler warns and skips opening rather than open a broken link.\n\t\t */\n\t\tcnFeatureRequestRepo: { default: () => '' },\n\t\t/**\n\t\t * Forge config (`{type, baseUrl}`) both new-issue deep-links are\n\t\t * built against. Provided by CnAppRoot from `manifest.nav.forge`.\n\t\t * Defaults to DEFAULT_FORGE when no CnAppRoot ancestor exists —\n\t\t * a third hardcoded Codeberg default lived here, so a menu mounted\n\t\t * standalone contradicted both the fleet default and the app it was\n\t\t * reporting for.\n\t\t */\n\t\tcnFeatureRequestForge: { default: () => ({ ...DEFAULT_FORGE }) },\n\t\t/**\n\t\t * Resolver for a widget's manifest title — the AUTHORED English\n\t\t * source string — provided by CnDashboardPage as\n\t\t * `(widgetId) => string`. The `title` prop this component receives\n\t\t * has already been through the host translate function\n\t\t * — CnDashboardPage's getWidgetTitle is the display chokepoint — and\n\t\t * may also be a user-typed customTitle in the user's own language, so\n\t\t * it is the wrong thing to put in a bug-report title. Returns '' when\n\t\t * no dashboard ancestor provides it (a standalone widget, a detail\n\t\t * page) or the widget def carries no title, and the link falls back\n\t\t * to the surface slug.\n\t\t */\n\t\tcnWidgetTitleSource: { default: () => () => '' },\n\t\t/**\n\t\t * App-wide documentation base URL (e.g.\n\t\t * `https://pipelinq.conduction.nl/docs`), provided by CnAppRoot from\n\t\t * `manifest.nav.documentationUrl`. Every widget's Documentation item\n\t\t * is built from this base plus the widget's own `docsAnchor`, so the\n\t\t * link lands on that widget's section rather than the docs homepage.\n\t\t * Empty when no ancestor provides one — the host's explicit\n\t\t * `documentationUrl` prop then has to carry the whole URL.\n\t\t */\n\t\tcnDocumentationBaseUrl: { default: () => '' },\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * Whether the Refresh item renders. The parent surface is\n\t\t * responsible for any opt-out aliasing (e.g. CnWidgetWrapper's\n\t\t * `hideRefresh`) and passes the resolved boolean here.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the Request-a-feature item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link target, opened in a new tab. Wins over\n\t\t * the `cnDocumentationBaseUrl` + `docsAnchor` pair. Leave empty (the\n\t\t * default) to let the menu build the per-widget deep-link itself.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * This surface's own section in the app's documentation, appended to\n\t\t * the app-wide `cnDocumentationBaseUrl`. A bare slug (`open-cases`)\n\t\t * becomes a `#fragment`; a value starting with `/` is resolved as a\n\t\t * path; a full `scheme://` URL is used as written. Supplying it is\n\t\t * what makes the Documentation item land on THIS widget's section\n\t\t * rather than the docs homepage.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocsAnchor: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the Documentation item renders. Defaults to true — the\n\t\t * canonical trio is meant to be present on every surface; set false\n\t\t * only where a docs link genuinely cannot exist.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the \"Report a bug\" item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit \"Report a bug\" target. Empty (the default) builds a\n\t\t * new-issue deep-link on the app's forge from the injected\n\t\t * `cnFeatureRequestRepo` + `cnFeatureRequestForge`, pre-filled with\n\t\t * the surface's title.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\treportBugUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Report-a-bug action. */\n\t\treportBugLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Report a bug'),\n\t\t},\n\n\t\t/**\n\t\t * Pre-translated label for the Documentation item. Defaults to the\n\t\t * lib's translation of \"Documentation\".\n\t\t */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded on the `@refresh` / `@request-feature`\n\t\t * payloads (as `widgetId`) and on the `cn:widget:refresh`\n\t\t * event-bus payload. The parent resolves it (explicit id or\n\t\t * slugified title).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Human-readable title carried on action payloads.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable `surface` slug naming where the menu sits (e.g.\n\t\t * `widget:<id>`, `detail:<id>`, `dashboard:<id>`). Used as the\n\t\t * English headline fallback for both new-issue deep-links when no\n\t\t * authored title can be recovered.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: { // eslint-disable-line vue/no-unused-properties -- published prop kept so hosts that still bind it do not leak it into $attrs\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether a refresh is currently in flight. While true, the Refresh\n\t\t * item is disabled and shows a loading spinner for exactly as long as\n\t\t * this stays true — so the spinner reflects the real refresh time.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Event-bus channel the default Refresh handler emits on when no\n\t\t * host listener suppresses it. Widgets use `cn:widget:refresh`;\n\t\t * page surfaces pass `cn:page:refresh`.\n\t\t */\n\t\trefreshChannel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn:widget:refresh',\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\n\t\t/**\n\t\t * Prefix for the `data-testid`s emitted on the menu container and\n\t\t * its items: `<base>-actions` (container), `<base>-action-refresh`,\n\t\t * `<base>-action-request-feature`, `<base>-action-report-bug`,\n\t\t * `<base>-action-documentation`.\n\t\t * Lets each host keep its own stable testids.\n\t\t */\n\t\ttestidBase: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn-actions-menu',\n\t\t},\n\t},\n\n\temits: ['refresh', 'request-feature'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow menu is open. */\n\t\t\tmenuOpen: false,\n\t\t\t/** Whether a refresh this menu started is still settling. */\n\t\t\trefreshPending: false,\n\t\t\t/** Close the menu once the host's `refreshing` falls back to false. */\n\t\t\tcloseWhenIdle: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Whether the Refresh item spins: the host's flag or our own pending refresh. */\n\t\trefreshBusy() {\n\t\t\treturn this.refreshing || this.refreshPending\n\t\t},\n\n\t\t/**\n\t\t * Whether the overflow `…` menu renders at all. True when at least\n\t\t * one built-in item is visible OR the caller provided an\n\t\t * `action-items` slot.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasOverflowMenu() {\n\t\t\tif (this.showRefresh) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showDocumentation && this.resolvedDocumentationUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showReportBug && this.resolvedReportBugUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showRequestFeature) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.$slots['primary-items']) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * The Documentation item's target: the explicit `documentationUrl`\n\t\t * when given, otherwise the app-wide base deep-linked with this\n\t\t * surface's `docsAnchor`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDocumentationUrl() {\n\t\t\tif (this.documentationUrl) {\n\t\t\t\treturn this.docsAnchor\n\t\t\t\t\t? resolveDocsUrl(this.documentationUrl, this.docsAnchor)\n\t\t\t\t\t: this.documentationUrl\n\t\t\t}\n\t\t\tif (this.cnDocumentationBaseUrl) {\n\t\t\t\treturn resolveDocsUrl(this.cnDocumentationBaseUrl, this.docsAnchor)\n\t\t\t}\n\t\t\t// Last resort so the item is never simply MISSING — an absent\n\t\t\t// Documentation entry is the defect this menu exists to prevent.\n\t\t\t// The fleet's convention is one docs site per app id; an app that\n\t\t\t// hosts its docs elsewhere sets `cnDocumentationBaseUrl` on\n\t\t\t// CnAppRoot, and the warning below says so.\n\t\t\treturn resolveDocsUrl(defaultDocsBase(this.cnAppId), this.docsAnchor)\n\t\t},\n\n\t\t/**\n\t\t * This surface's title AS AUTHORED, for anything that must not be\n\t\t * localized. Asks the injected dashboard resolver for the widget's\n\t\t * manifest source string; '' when nothing can supply one.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceTitle() {\n\t\t\tconst resolve = this.cnWidgetTitleSource\n\t\t\tif (typeof resolve !== 'function' || !this.widgetId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn String(resolve(this.widgetId) || '').trim()\n\t\t\t} catch {\n\t\t\t\t// A host resolver that throws must not take the menu with it —\n\t\t\t\t// the link degrades to the surface slug.\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The Report-a-bug target: the explicit `reportBugUrl` when given,\n\t\t * otherwise a new-issue deep-link on the app's forge, pre-filled with\n\t\t * a title naming the surface the report came from.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedReportBugUrl() {\n\t\t\tif (this.reportBugUrl) {\n\t\t\t\treturn this.reportBugUrl\n\t\t\t}\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// buildBugReportUrl owns both the host (one resolveForge for the\n\t\t\t// whole suggestion flow) and the bug-report issue FORM. This was\n\t\t\t// hand-rolled here against a local copy of the forge host map that\n\t\t\t// defaulted to Codeberg, so a menu mounted without a CnAppRoot sent\n\t\t\t// bug reports to a different host than the Request-a-feature item\n\t\t\t// directly above it — and it linked the BLANK issue form, so every\n\t\t\t// in-product report arrived with no steps, no expected/actual and\n\t\t\t// no severity.\n\t\t\t//\n\t\t\t// The headline must be ENGLISH: the `title` prop is already\n\t\t\t// translated (CnDashboardPage's getWidgetTitle is the display\n\t\t\t// chokepoint), so a report from a French UI read \"[BUG] Activité\n\t\t\t// récente\" and one from a Russian UI was in Cyrillic — unreadable\n\t\t\t// to a maintainer, even though the English msgid was sitting in the\n\t\t\t// manifest. `cnWidgetTitleSource` hands back that manifest string,\n\t\t\t// skipping any user-typed customTitle for the same reason.\n\t\t\t//\n\t\t\t// With no dashboard ancestor to ask, fall back to the surface slug\n\t\t\t// rather than the translated prop: a slug is English by\n\t\t\t// construction, and \"always English\" is the point. The localized\n\t\t\t// title is deliberately not carried in the URL at all — see\n\t\t\t// buildBugReportUrl for why it was dropped.\n\t\t\treturn buildBugReportUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The Request-a-feature target: the forge's feature-request issue\n\t\t * FORM, built exactly like resolvedReportBugUrl — same repo, same\n\t\t * forge, same English-headline rules (see that computed for why the\n\t\t * headline is never the translated title). Empty when no repo can\n\t\t * be resolved, in which case the click handler warns and does\n\t\t * nothing rather than open a broken link.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRequestFeatureUrl() {\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trefreshing(busy) {\n\t\t\tif (!busy && this.closeWhenIdle) {\n\t\t\t\tthis.closeWhenIdle = false\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Refresh click — emits `@refresh`, then runs the built-in default\n\t\t * (emit on `refreshChannel`) unless a host called\n\t\t * `event.preventDefault()` on the second handler arg. The item spins\n\t\t * and the menu stays open until every promise handed to `waitUntil`\n\t\t * (on the event or the bus payload) settles, or 15 s pass, and the\n\t\t * host's `refreshing` is false; then the menu closes.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRefreshClick() {\n\t\t\tif (this.refreshBusy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst work = []\n\t\t\tconst waitUntil = (promise) => {\n\t\t\t\twork.push(Promise.resolve(promise))\n\t\t\t}\n\t\t\tconst ev = createSyntheticEvent(waitUntil)\n\t\t\tthis.refreshPending = true\n\t\t\tconst startedAt = Date.now()\n\t\t\t/**\n\t\t\t * @event refresh User clicked the Refresh item. Payload:\n\t\t\t * `{ widgetId, title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default (event-bus\n\t\t\t * emit on `refreshChannel`), and its `waitUntil(promise)` to keep\n\t\t\t * the item spinning until that work settles.\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (!ev.defaultPrevented) {\n\t\t\t\temitOnBus(this.refreshChannel, {\n\t\t\t\t\twidgetId: this.widgetId,\n\t\t\t\t\ttitle: this.title,\n\t\t\t\t\twaitUntil,\n\t\t\t\t})\n\t\t\t}\n\t\t\tlet ceiling\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.allSettled(work),\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tceiling = setTimeout(resolve, MAX_REFRESH_WAIT_MS)\n\t\t\t\t}),\n\t\t\t])\n\t\t\tclearTimeout(ceiling)\n\t\t\tconst hold = MIN_REFRESH_SPIN_MS - (Date.now() - startedAt)\n\t\t\tif (hold > 0) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, hold))\n\t\t\t}\n\t\t\tthis.refreshPending = false\n\t\t\tif (this.refreshing) {\n\t\t\t\tthis.closeWhenIdle = true\n\t\t\t} else {\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Request-a-feature click — emits `@request-feature`. The item is a\n\t\t * link to the forge's feature-request form, so the browser opens it\n\t\t * unless a host called `event.preventDefault()`, which then cancels\n\t\t * the link. With no `cnFeatureRequestRepo` the item is a button and\n\t\t * this only warns.\n\t\t *\n\t\t * @param {Event} [nativeEvent] The link's click event.\n\t\t * @return {void}\n\t\t */\n\t\tonRequestFeatureClick(nativeEvent) {\n\t\t\tconst ev = createSyntheticEvent()\n\t\t\t/**\n\t\t\t * @event request-feature User clicked the Request a feature\n\t\t\t * item. Payload: `{ widgetId, title }`. Handlers may call the\n\t\t\t * second arg's `preventDefault()` to suppress the built-in\n\t\t\t * default (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (ev.defaultPrevented) {\n\t\t\t\tif (nativeEvent && typeof nativeEvent.preventDefault === 'function') {\n\t\t\t\t\tnativeEvent.preventDefault()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.resolvedRequestFeatureUrl) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnActionsMenu] Cannot open the feature-request form: missing cnFeatureRequestRepo inject (mount under CnAppRoot or bind a custom @request-feature listener).')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["_createBlock","_createTextVNode","_createVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnActionsMenu.vue3.js","sources":["../../../../src/components/CnActionsMenu/CnActionsMenu.vue?vue&type=template&id=74d4ebf3&lang.js"],"sourcesContent":["<!--\n CnActionsMenu — Shared \"…\" overflow Actions menu.\n\n Renders the canonical action set that appears on every Conduction\n surface — Refresh, then the mandatory trio Request a feature / Report a\n bug / Documentation — inside a single NcActions overflow. Request a\n feature opens the forge's feature-request issue form directly, exactly\n like Report a bug (team decision 2026-09-04: the in-product suggestion\n modal is gone — the forge is where the conversation happens, in English).\n Used by CnWidgetWrapper (widgets) and the page-level headers of\n CnDetailPage / CnDashboardPage so the three surfaces stay in lockstep.\n\n The trio is not optional and not conditional on configuration: each item\n resolves its own target (a forge new-issue deep-link for the bug report,\n `cnDocumentationBaseUrl` + the surface's `docsAnchor` for the docs link),\n so a host that passes no URLs still renders all three. That is the point\n — the items used to be per-host markup, and OpenRegister's widgets shipped\n without the Documentation entry while OpenCatalogi's were inconsistent.\n-->\n<template>\n\t<!-- Root <template v-if> (Vue 3 native fragment, renders no DOM node — was\n\t vue-frag <Fragment>) so NcActions stays in its host's flex/grid flow. -->\n\t<template v-if=\"hasOverflowMenu\">\n\t\t<NcActions\n\t\t\t:forceMenu=\"true\"\n\t\t\t:forceName=\"true\"\n\t\t\t:menuName=\"actionsMenuLabel\"\n\t\t\t:open=\"menuOpen\"\n\t\t\t:data-testid=\"`${testidBase}-actions`\"\n\t\t\t@update:open=\"menuOpen = $event\">\n\t\t\t<template #icon>\n\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t</template>\n\t\t\t<!-- Stays open while refreshing; onRefreshClick closes the menu once the refresh settles. -->\n\t\t\t<NcActionButton\n\t\t\t\tv-if=\"showRefresh\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-refresh`\"\n\t\t\t\t:disabled=\"refreshBusy\"\n\t\t\t\t:closeAfterClick=\"false\"\n\t\t\t\t@click=\"onRefreshClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"refreshBusy\" :size=\"20\" />\n\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ refreshLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<!-- @slot primary-items The surface's OWN actions — a page's\n\t\t\t manifest `headerActions`, say — rendered above the canonical\n\t\t\t trio. They sit here rather than in `#action-items` because a\n\t\t\t case's Add party belongs above Report a bug, not under it.\n\t\t\t The caller owns the trailing NcActionSeparator: only the\n\t\t\t caller knows whether its v-for produced any items, and a\n\t\t\t separator rendered here would strand itself when it did\n\t\t\t not. -->\n\t\t\t<slot name=\"primary-items\" />\n\t\t\t<!-- The canonical trio — Request a feature / Report a bug /\n\t\t\t Documentation — renders on EVERY surface. None of the three\n\t\t\t is conditional on a URL being configured any more: each\n\t\t\t resolves its own target (see resolvedDocumentationUrl /\n\t\t\t resolvedReportBugUrl), so a host that forgets to pass one\n\t\t\t still gets a working item instead of a silently missing one.\n\t\t\t `showRequestFeature` / `showReportBug` / `showDocumentation`\n\t\t\t exist only for the rare surface that must suppress one\n\t\t\t deliberately; they all default to true. -->\n\t\t\t<!-- A real link whenever the form's URL is known, so it can be\n\t\t\t middle-clicked or copied; a button only for a host with no\n\t\t\t URL that handles @request-feature itself. -->\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showRequestFeature && resolvedRequestFeatureUrl\"\n\t\t\t\t:href=\"resolvedRequestFeatureUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionButton\n\t\t\t\tv-else-if=\"showRequestFeature\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-request-feature`\"\n\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t@click=\"onRequestFeatureClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LightbulbOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ requestFeatureLabel }}\n\t\t\t</NcActionButton>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showReportBug && resolvedReportBugUrl\"\n\t\t\t\t:href=\"resolvedReportBugUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-report-bug`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BugOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ reportBugLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<NcActionLink\n\t\t\t\tv-if=\"showDocumentation && resolvedDocumentationUrl\"\n\t\t\t\t:href=\"resolvedDocumentationUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:data-testid=\"`${testidBase}-action-documentation`\"\n\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ documentationLabel }}\n\t\t\t</NcActionLink>\n\t\t\t<!-- @slot action-items Additional NcActionButton-family items\n\t\t\t rendered inside the overflow menu, after the built-in\n\t\t\t Refresh + Request-a-feature / Report-a-bug / Documentation\n\t\t\t group. -->\n\t\t\t<slot name=\"action-items\" />\n\t\t</NcActions>\n\t</template>\n</template>\n\n<script>\nimport { emit as emitOnBus } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport BugOutline from 'vue-material-design-icons/BugOutline.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport LightbulbOutline from 'vue-material-design-icons/LightbulbOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport { buildBugReportUrl, buildFeatureRequestUrl, DEFAULT_FORGE } from '../../utils/forge.js'\n\n/**\n * The fleet's per-app documentation site, derived from the app id. Used only\n * when no `documentationUrl` prop and no `cnDocumentationBaseUrl` inject are\n * available, so that the Documentation item is never absent — an app that\n * hosts its docs anywhere else provides the base instead.\n *\n * @param {string} appId Consuming app's slug.\n * @return {string} Documentation base URL, or '' when the app id is unknown.\n */\nfunction defaultDocsBase(appId) {\n\tconst id = String(appId || '').trim()\n\tif (!id) {\n\t\treturn ''\n\t}\n\treturn `https://${id}.conduction.nl/docs/`\n}\n\n/**\n * Resolve a documentation deep-link from a base URL and a per-widget\n * anchor. An anchor already starting with `#`, `/` or a `scheme://` is\n * used as written (respectively appended, resolved against the base's\n * origin, or taken whole); a bare slug becomes a `#fragment`, which is\n * how a docs page addresses one section of itself.\n *\n * @param {string} base Documentation base URL.\n * @param {string} anchor Per-widget anchor / path fragment.\n * @return {string} The resolved URL, or '' when there is no base to build on.\n */\nexport function resolveDocsUrl(base, anchor) {\n\tconst a = String(anchor || '').trim()\n\tif (a.includes('://')) {\n\t\treturn a\n\t}\n\tconst b = String(base || '').trim()\n\tif (!b) {\n\t\treturn ''\n\t}\n\tif (!a) {\n\t\treturn b\n\t}\n\tif (a.startsWith('#')) {\n\t\treturn `${b.replace(/#.*$/, '')}${a}`\n\t}\n\tif (a.startsWith('/')) {\n\t\ttry {\n\t\t\treturn new URL(a, b).toString()\n\t\t} catch {\n\t\t\treturn `${b.replace(/\\/+$/, '')}${a}`\n\t\t}\n\t}\n\treturn `${b.replace(/#.*$/, '').replace(/\\/+$/, '')}#${a}`\n}\n\n/**\n * Build a synthetic event object handed to host listeners alongside the\n * action payload. Mirrors the Vue 3 / DOM Event API enough to let a host\n * call `event.preventDefault()` to suppress the menu's built-in default\n * handler. Because Vue's `$emit` is synchronous, the same object also\n * propagates up through wrapping components (e.g. CnWidgetWrapper\n * re-emitting `@refresh`), so a host listener on the outer component can\n * still suppress the default.\n *\n * `waitUntil(promise)` lets a listener keep the Refresh item spinning, and the\n * menu open, until that promise settles.\n *\n * @param {(promise: Promise<unknown>) => void} [waitUntil] Collector for refresh work.\n * @return {{defaultPrevented: boolean, preventDefault: () => void, waitUntil: (promise: Promise<unknown>) => void}}\n */\nfunction createSyntheticEvent(waitUntil = () => {}) {\n\tconst ev = {\n\t\tdefaultPrevented: false,\n\t\tpreventDefault() {\n\t\t\tthis.defaultPrevented = true\n\t\t},\n\t\twaitUntil,\n\t}\n\treturn ev\n}\n\n/** Shortest time the Refresh spinner shows, so a fast refresh is still visible. */\nconst MIN_REFRESH_SPIN_MS = 400\n\n/** Longest the Refresh item waits on `waitUntil` work; axios has no default timeout. */\nconst MAX_REFRESH_WAIT_MS = 15000\n\n/**\n * CnActionsMenu — the shared built-in overflow Actions menu.\n *\n * Renders Refresh plus the mandatory trio Request a feature / Report a bug /\n * Documentation. The trio is unconditional: the bug link is built from the\n * app's forge repo and the docs link from the app-wide documentation base\n * plus this surface's `docsAnchor`, so no host can ship a menu missing one.\n * Pass `docsAnchor` per widget type — that is what makes Documentation open\n * that widget's own section instead of the docs homepage.\n *\n * ```vue\n * <CnActionsMenu\n * :widget-id=\"resolvedWidgetId\"\n * :title=\"displayTitle\"\n * :surface=\"`widget:${resolvedWidgetId}`\"\n * docs-anchor=\"open-cases\"\n * testid-base=\"cn-widget-wrapper\"\n * @refresh=\"(p, e) => $emit('refresh', p, e)\"\n * @request-feature=\"(p, e) => $emit('request-feature', p, e)\">\n * <template #action-items><slot name=\"action-items\" /></template>\n * </CnActionsMenu>\n * ```\n */\nexport default {\n\tname: 'CnActionsMenu',\n\n\tcomponents: {\n\t\tNcActions,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcLoadingIcon,\n\t\tDotsHorizontal,\n\t\tRefresh,\n\t\tLightbulbOutline,\n\t\tBookOpenVariant,\n\t\tBugOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consuming app's slug (e.g. \"pipelinq\"). Provided by CnAppRoot.\n\t\t * Defaults to empty string when no CnAppRoot ancestor exists.\n\t\t */\n\t\tcnAppId: { default: () => '' },\n\t\t/**\n\t\t * Repo slug both forge deep-links target (e.g.\n\t\t * `ConductionNL/pipelinq`) — the Request-a-feature and Report-a-bug\n\t\t * new-issue forms. Provided by CnAppRoot from the manifest's\n\t\t * `nav.featureRequestRepo` field (with fallback to\n\t\t * `ConductionNL/<appId>`). Empty when no ancestor — the default\n\t\t * handler warns and skips opening rather than open a broken link.\n\t\t */\n\t\tcnFeatureRequestRepo: { default: () => '' },\n\t\t/**\n\t\t * Forge config (`{type, baseUrl}`) both new-issue deep-links are\n\t\t * built against. Provided by CnAppRoot from `manifest.nav.forge`.\n\t\t * Defaults to DEFAULT_FORGE when no CnAppRoot ancestor exists —\n\t\t * a third hardcoded Codeberg default lived here, so a menu mounted\n\t\t * standalone contradicted both the fleet default and the app it was\n\t\t * reporting for.\n\t\t */\n\t\tcnFeatureRequestForge: { default: () => ({ ...DEFAULT_FORGE }) },\n\t\t/**\n\t\t * Resolver for a widget's manifest title — the AUTHORED English\n\t\t * source string — provided by CnDashboardPage as\n\t\t * `(widgetId) => string`. The `title` prop this component receives\n\t\t * has already been through the host translate function\n\t\t * — CnDashboardPage's getWidgetTitle is the display chokepoint — and\n\t\t * may also be a user-typed customTitle in the user's own language, so\n\t\t * it is the wrong thing to put in a bug-report title. Returns '' when\n\t\t * no dashboard ancestor provides it (a standalone widget, a detail\n\t\t * page) or the widget def carries no title, and the link falls back\n\t\t * to the surface slug.\n\t\t */\n\t\tcnWidgetTitleSource: { default: () => () => '' },\n\t\t/**\n\t\t * App-wide documentation base URL (e.g.\n\t\t * `https://pipelinq.conduction.nl/docs`), provided by CnAppRoot from\n\t\t * `manifest.nav.documentationUrl`. Every widget's Documentation item\n\t\t * is built from this base plus the widget's own `docsAnchor`, so the\n\t\t * link lands on that widget's section rather than the docs homepage.\n\t\t * Empty when no ancestor provides one — the host's explicit\n\t\t * `documentationUrl` prop then has to carry the whole URL.\n\t\t */\n\t\tcnDocumentationBaseUrl: { default: () => '' },\n\t},\n\n\tinheritAttrs: false,\n\n\tprops: {\n\t\t/**\n\t\t * Whether the Refresh item renders. The parent surface is\n\t\t * responsible for any opt-out aliasing (e.g. CnWidgetWrapper's\n\t\t * `hideRefresh`) and passes the resolved boolean here.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRefresh: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the Request-a-feature item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowRequestFeature: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit documentation link target, opened in a new tab. Wins over\n\t\t * the `cnDocumentationBaseUrl` + `docsAnchor` pair. Leave empty (the\n\t\t * default) to let the menu build the per-widget deep-link itself.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * This surface's own section in the app's documentation, appended to\n\t\t * the app-wide `cnDocumentationBaseUrl`. A bare slug (`open-cases`)\n\t\t * becomes a `#fragment`; a value starting with `/` is resolved as a\n\t\t * path; a full `scheme://` URL is used as written. Supplying it is\n\t\t * what makes the Documentation item land on THIS widget's section\n\t\t * rather than the docs homepage.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tdocsAnchor: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the Documentation item renders. Defaults to true — the\n\t\t * canonical trio is meant to be present on every surface; set false\n\t\t * only where a docs link genuinely cannot exist.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowDocumentation: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Whether the \"Report a bug\" item renders.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowReportBug: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Explicit \"Report a bug\" target. Empty (the default) builds a\n\t\t * new-issue deep-link on the app's forge from the injected\n\t\t * `cnFeatureRequestRepo` + `cnFeatureRequestForge`, pre-filled with\n\t\t * the surface's title.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\treportBugUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Pre-translated label for the Report-a-bug action. */\n\t\treportBugLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Report a bug'),\n\t\t},\n\n\t\t/**\n\t\t * Pre-translated label for the Documentation item. Defaults to the\n\t\t * lib's translation of \"Documentation\".\n\t\t */\n\t\tdocumentationLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Documentation'),\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded on the `@refresh` / `@request-feature`\n\t\t * payloads (as `widgetId`) and on the `cn:widget:refresh`\n\t\t * event-bus payload. The parent resolves it (explicit id or\n\t\t * slugified title).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Human-readable title carried on action payloads.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable `surface` slug naming where the menu sits (e.g.\n\t\t * `widget:<id>`, `detail:<id>`, `dashboard:<id>`). Used as the\n\t\t * English headline fallback for both new-issue deep-links when no\n\t\t * authored title can be recovered.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Optional `specRef` slug. Accepted for backward compatibility with\n\t\t * hosts that bound it for the removed in-product suggestion modal;\n\t\t * no longer forwarded anywhere (the forge issue form asks for its\n\t\t * own context).\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tspecRef: { // eslint-disable-line vue/no-unused-properties -- published prop kept so hosts that still bind it do not leak it into $attrs\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether a refresh is currently in flight. While true, the Refresh\n\t\t * item is disabled and shows a loading spinner for exactly as long as\n\t\t * this stays true — so the spinner reflects the real refresh time.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\trefreshing: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Event-bus channel the default Refresh handler emits on when no\n\t\t * host listener suppresses it. Widgets use `cn:widget:refresh`;\n\t\t * page surfaces pass `cn:page:refresh`.\n\t\t */\n\t\trefreshChannel: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn:widget:refresh',\n\t\t},\n\n\t\t/** Pre-translated label for the Refresh action. */\n\t\trefreshLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Refresh'),\n\t\t},\n\n\t\t/** Pre-translated label for the Request-a-feature action. */\n\t\trequestFeatureLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Request a feature'),\n\t\t},\n\n\t\t/** Pre-translated aria-label / tooltip for the overflow trigger. */\n\t\tactionsMenuLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Actions'),\n\t\t},\n\n\t\t/**\n\t\t * Prefix for the `data-testid`s emitted on the menu container and\n\t\t * its items: `<base>-actions` (container), `<base>-action-refresh`,\n\t\t * `<base>-action-request-feature`, `<base>-action-report-bug`,\n\t\t * `<base>-action-documentation`.\n\t\t * Lets each host keep its own stable testids.\n\t\t */\n\t\ttestidBase: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cn-actions-menu',\n\t\t},\n\t},\n\n\temits: ['refresh', 'request-feature'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Whether the overflow menu is open. */\n\t\t\tmenuOpen: false,\n\t\t\t/** Whether a refresh this menu started is still settling. */\n\t\t\trefreshPending: false,\n\t\t\t/** Close the menu once the host's `refreshing` falls back to false. */\n\t\t\tcloseWhenIdle: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Whether the Refresh item spins: the host's flag or our own pending refresh. */\n\t\trefreshBusy() {\n\t\t\treturn this.refreshing || this.refreshPending\n\t\t},\n\n\t\t/**\n\t\t * Whether the overflow `…` menu renders at all. True when at least\n\t\t * one built-in item is visible OR the caller provided an\n\t\t * `action-items` slot.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasOverflowMenu() {\n\t\t\tif (this.showRefresh) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showDocumentation && this.resolvedDocumentationUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showReportBug && this.resolvedReportBugUrl) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.showRequestFeature) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (this.$slots['primary-items']) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Boolean(this.$slots['action-items']) || Boolean(this.$slots && this.$slots['action-items'])\n\t\t},\n\n\t\t/**\n\t\t * The Documentation item's target: the explicit `documentationUrl`\n\t\t * when given, otherwise the app-wide base deep-linked with this\n\t\t * surface's `docsAnchor`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDocumentationUrl() {\n\t\t\tif (this.documentationUrl) {\n\t\t\t\treturn this.docsAnchor\n\t\t\t\t\t? resolveDocsUrl(this.documentationUrl, this.docsAnchor)\n\t\t\t\t\t: this.documentationUrl\n\t\t\t}\n\t\t\tif (this.cnDocumentationBaseUrl) {\n\t\t\t\treturn resolveDocsUrl(this.cnDocumentationBaseUrl, this.docsAnchor)\n\t\t\t}\n\t\t\t// Last resort so the item is never simply MISSING — an absent\n\t\t\t// Documentation entry is the defect this menu exists to prevent.\n\t\t\t// The fleet's convention is one docs site per app id; an app that\n\t\t\t// hosts its docs elsewhere sets `cnDocumentationBaseUrl` on\n\t\t\t// CnAppRoot, and the warning below says so.\n\t\t\treturn resolveDocsUrl(defaultDocsBase(this.cnAppId), this.docsAnchor)\n\t\t},\n\n\t\t/**\n\t\t * This surface's title AS AUTHORED, for anything that must not be\n\t\t * localized. Asks the injected dashboard resolver for the widget's\n\t\t * manifest source string; '' when nothing can supply one.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceTitle() {\n\t\t\tconst resolve = this.cnWidgetTitleSource\n\t\t\tif (typeof resolve !== 'function' || !this.widgetId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn String(resolve(this.widgetId) || '').trim()\n\t\t\t} catch {\n\t\t\t\t// A host resolver that throws must not take the menu with it —\n\t\t\t\t// the link degrades to the surface slug.\n\t\t\t\treturn ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The Report-a-bug target: the explicit `reportBugUrl` when given,\n\t\t * otherwise a new-issue deep-link on the app's forge, pre-filled with\n\t\t * a title naming the surface the report came from.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedReportBugUrl() {\n\t\t\tif (this.reportBugUrl) {\n\t\t\t\treturn this.reportBugUrl\n\t\t\t}\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// buildBugReportUrl owns both the host (one resolveForge for the\n\t\t\t// whole suggestion flow) and the bug-report issue FORM. This was\n\t\t\t// hand-rolled here against a local copy of the forge host map that\n\t\t\t// defaulted to Codeberg, so a menu mounted without a CnAppRoot sent\n\t\t\t// bug reports to a different host than the Request-a-feature item\n\t\t\t// directly above it — and it linked the BLANK issue form, so every\n\t\t\t// in-product report arrived with no steps, no expected/actual and\n\t\t\t// no severity.\n\t\t\t//\n\t\t\t// The headline must be ENGLISH: the `title` prop is already\n\t\t\t// translated (CnDashboardPage's getWidgetTitle is the display\n\t\t\t// chokepoint), so a report from a French UI read \"[BUG] Activité\n\t\t\t// récente\" and one from a Russian UI was in Cyrillic — unreadable\n\t\t\t// to a maintainer, even though the English msgid was sitting in the\n\t\t\t// manifest. `cnWidgetTitleSource` hands back that manifest string,\n\t\t\t// skipping any user-typed customTitle for the same reason.\n\t\t\t//\n\t\t\t// With no dashboard ancestor to ask, fall back to the surface slug\n\t\t\t// rather than the translated prop: a slug is English by\n\t\t\t// construction, and \"always English\" is the point. The localized\n\t\t\t// title is deliberately not carried in the URL at all — see\n\t\t\t// buildBugReportUrl for why it was dropped.\n\t\t\treturn buildBugReportUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The Request-a-feature target: the forge's feature-request issue\n\t\t * FORM, built exactly like resolvedReportBugUrl — same repo, same\n\t\t * forge, same English-headline rules (see that computed for why the\n\t\t * headline is never the translated title). Empty when no repo can\n\t\t * be resolved, in which case the click handler warns and does\n\t\t * nothing rather than open a broken link.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRequestFeatureUrl() {\n\t\t\tconst repo = String(this.cnFeatureRequestRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(this.cnFeatureRequestForge, repo, {\n\t\t\t\ttitle: this.sourceTitle,\n\t\t\t\tsurface: this.surface || this.widgetId,\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trefreshing(busy) {\n\t\t\tif (!busy && this.closeWhenIdle) {\n\t\t\t\tthis.closeWhenIdle = false\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Refresh click — emits `@refresh`, then runs the built-in default\n\t\t * (emit on `refreshChannel`) unless a host called\n\t\t * `event.preventDefault()` on the second handler arg. The item spins\n\t\t * and the menu stays open until every promise handed to `waitUntil`\n\t\t * (on the event or the bus payload) settles, or 15 s pass, and the\n\t\t * host's `refreshing` is false; then the menu closes.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onRefreshClick() {\n\t\t\tif (this.refreshBusy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst work = []\n\t\t\tconst waitUntil = (promise) => {\n\t\t\t\twork.push(Promise.resolve(promise))\n\t\t\t}\n\t\t\tconst ev = createSyntheticEvent(waitUntil)\n\t\t\tthis.refreshPending = true\n\t\t\tconst startedAt = Date.now()\n\t\t\t/**\n\t\t\t * @event refresh User clicked the Refresh item. Payload:\n\t\t\t * `{ widgetId, title }`. Handlers may call the second arg's\n\t\t\t * `preventDefault()` to suppress the built-in default (event-bus\n\t\t\t * emit on `refreshChannel`), and its `waitUntil(promise)` to keep\n\t\t\t * the item spinning until that work settles.\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('refresh', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (!ev.defaultPrevented) {\n\t\t\t\temitOnBus(this.refreshChannel, {\n\t\t\t\t\twidgetId: this.widgetId,\n\t\t\t\t\ttitle: this.title,\n\t\t\t\t\twaitUntil,\n\t\t\t\t})\n\t\t\t}\n\t\t\tlet ceiling\n\t\t\tawait Promise.race([\n\t\t\t\tPromise.allSettled(work),\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tceiling = setTimeout(resolve, MAX_REFRESH_WAIT_MS)\n\t\t\t\t}),\n\t\t\t])\n\t\t\tclearTimeout(ceiling)\n\t\t\tconst hold = MIN_REFRESH_SPIN_MS - (Date.now() - startedAt)\n\t\t\tif (hold > 0) {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, hold))\n\t\t\t}\n\t\t\tthis.refreshPending = false\n\t\t\tif (this.refreshing) {\n\t\t\t\tthis.closeWhenIdle = true\n\t\t\t} else {\n\t\t\t\tthis.menuOpen = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Request-a-feature click — emits `@request-feature`. The item is a\n\t\t * link to the forge's feature-request form, so the browser opens it\n\t\t * unless a host called `event.preventDefault()`, which then cancels\n\t\t * the link. With no `cnFeatureRequestRepo` the item is a button and\n\t\t * this only warns.\n\t\t *\n\t\t * @param {Event} [nativeEvent] The link's click event.\n\t\t * @return {void}\n\t\t */\n\t\tonRequestFeatureClick(nativeEvent) {\n\t\t\tconst ev = createSyntheticEvent()\n\t\t\t/**\n\t\t\t * @event request-feature User clicked the Request a feature\n\t\t\t * item. Payload: `{ widgetId, title }`. Handlers may call the\n\t\t\t * second arg's `preventDefault()` to suppress the built-in\n\t\t\t * default (opening the forge's feature-request issue form).\n\t\t\t * @type {{ widgetId: string, title: string }}\n\t\t\t */\n\t\t\tthis.$emit('request-feature', { widgetId: this.widgetId, title: this.title }, ev)\n\t\t\tif (ev.defaultPrevented) {\n\t\t\t\tif (nativeEvent && typeof nativeEvent.preventDefault === 'function') {\n\t\t\t\t\tnativeEvent.preventDefault()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.resolvedRequestFeatureUrl) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnActionsMenu] Cannot open the feature-request form: missing cnFeatureRequestRepo inject (mount under CnAppRoot or bind a custom @request-feature listener).')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["_createBlock","_createTextVNode","_renderSlot","_createVNode"],"mappings":";;;;;;;;;;;;;UAyCiB,QAAe,CAAA,eAAA;;;AAE5B,QAAA,SAAS,EAAC,IAAA;AACV,QAAA,SAAS,EAAE;AACX,QAAA,QAAQ,EAAE,MAAK,CAAA,gBAAA;AACf,QAAA,IAAI,EAAE,KAAQ,CAAA,QAAA;qBACH,KAAK,MAAU,CAAA,UAAA,CAAA,QAAA,CAAA;uBACf,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,KAAQ,CAAA,QAAA,GAAG,MAAO,CAAA,CAAA;;4BAEF;qBAAA,CAAA,yBAAA,EAAA,EAAZ,IAAI,EAAG,EAAC,EAAA,CAAA;;yBAGrB,MAWY;WAVV,MAAW,CAAA,WAAA;4BADbA,WAWY,CAAA,yBAAA,EAAA;;AATf,gBAAA,aAAW,KAAM,MAAS,CAAA,UAAA,CAAA,eAAA,CAAA;wBAClB,EAAE,QAAW,CAAA,WAAA;AAClB,gBAAA,eAAY,EAAC,KAAK;uBAChB,EAAE,QAAc,CAAA,cAAA;;AACX,gBAAA,IAAI,gBACiC;mBAA1B,QAAW,CAAA,WAAA;+CAAe,CAAA,wBAAA,EAAA;;AAAZ,wBAAA,IAAG,IAAK;;+CACd,CAAA,kBAAA,EAAA;;AAAZ,wBAAA,IAAI,EAAC;;;iCACZ,MACP;AADO,kBAAAC,eAAA,CAAA,GACP,mBAAA,MAAW,CAAA,YAAA,CAAA,EAAA,CAAA,YAAA;;;;;UAUfC,UAA4B,CAAA,IAAA,CAAA,MAAA,EAAA,eAAA,CAAA;AActB,UAAA,CAAA,MAAA,CAAA,kBAAkB,IAAA,QAAA,CAAA,yBAAA;uCAUd,CAAA,uBAAA,EAAA;;AATT,gBAAA,IAAI,EAAE,QAAQ,CAAA,yBAAA;AACf,gBAAA,MAAM,EAAC,QAAI;AACV,gBAAA,aAAW,KAAK,MAAU,CAAA,UAAA,CAAA,uBAAA,CAAA;AAC1B,gBAAA,eAAe,EAAE,IAAI;AACrB,gBAAA,OAAK,EAAE,QAAM,CAAA,qBAAA;;AACH,gBAAA,IAAI,UACd,MAAsB;kBAAtBC,WAAsB,CAAA,2BAAA,EAAA,EAAH,IAAG,EAAA,EAAA,EAAA,CAAA;;iCACZ;AAAA,kBAAAF,eAAA,CAAA,sBACR,MAAmB,CAAA,mBAAA,CAAA,EAAA,CAAA,YAAA;;;;eAGX,MAAE,CAAA,kBAAA;8BADbD,WASgB,CAAA,yBAAA,EAAA;;AAPf,kBAAA,aAAU,KAAA,MAAA,CAAA,UAAA,CAAA,uBAAA,CAAA;AACV,kBAAA,eAAe,EAAE,IAAI;AACrB,kBAAA,OAAK,EAAE,QAAqB,CAAA,qBAAA;;AAClB,kBAAA,IAAG,UACb,MAA+B;oBAA/BG,WAA+B,CAAA,2BAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;;mCACjB,MACX;AADW,oBAAAF,eAAA,CAAA,GACX,mBAAG,MAAY,CAAA,mBAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAGT,UAAA,CAAA,MAAA,CAAA,aAAa,IAAI,QAAA,CAAA,oBAAA;;;AACtB,gBAAA,IAAI,EAAE,QAAM,CAAA,oBAAA;AACb,gBAAA,MAAM,EAAC,QAAQ;AACX,gBAAA,kBAAa,MAAU,CAAA,UAAA,CAAA,kBAAA,CAAA;+BACX,EAAE,IAAI;;AACX,gBAAA,IAAE,UACZ,MAAyB;kBAAzBE,WAAyB,CAAA,qBAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;;iCACb,MACT;AADS,kBAAAF,eAAA,CAAA,GACT,mBAAG,MAAI,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnAdminSettingsShell.vue2.js","sources":["../../../../src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-admin-settings-shell\">\n\t\t<!-- Page title header — the uniform \"<App> Settings / Configure your <App> installation\" block.\n\t\t Uses NcSettingsSection directly (not CnSettingsSection) so the description subtitle and\n\t\t doc-url icon render — CnSettingsSection repurposes those props and does not forward them. -->\n\t\t<NcSettingsSection\n\t\t\t:name=\"resolvedTitle\"\n\t\t\t:description=\"resolvedDescription\"\n\t\t\t:docUrl=\"docUrl\" />\n\n\t\t<!-- Version information card (version, up-to-date check, re-import, support footer) -->\n\t\t<CnVersionInfoCard\n\t\t\tv-if=\"showVersionCard\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appVersion=\"resolvedVersion\"\n\t\t\t:configuredVersion=\"resolvedConfiguredVersion\"\n\t\t\t:isUpToDate=\"resolvedIsUpToDate\"\n\t\t\t:showUpdateButton=\"showUpdateButton\"\n\t\t\t:updating=\"updating\"\n\t\t\t:title=\"versionTitle\"\n\t\t\t:description=\"resolvedVersionDescription\"\n\t\t\t@update=\"onUpdate\">\n\t\t\t<template #actions>\n\t\t\t\t<!-- Canonical \"Re-import configuration\" action (POST /apps/<appId>/api/settings/load) -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showReimport\"\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"reimporting\"\n\t\t\t\t\t@click=\"reimport\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcLoadingIcon v-if=\"reimporting\" :size=\"20\" />\n\t\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ reimporting ? importingLabel : reimportLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- Run the first-time setup wizard on demand (ADR-042). -->\n\t\t\t\t<NcButton v-if=\"showSetup\" data-testid=\"cn-admin-run-setup\" @click=\"setupWizardOpen = true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<AutoFix :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ setupLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- \"Help us / suggest a feature\" — a direct link to the forge's\n\t\t\t\t feature-request issue form (team decision 2026-09-04: the\n\t\t\t\t in-product suggestion modal is gone; the forge is where\n\t\t\t\t the conversation happens, in English). -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showHelp && helpUrl\"\n\t\t\t\t\t:href=\"helpUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<HelpCircleOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ helpLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- @slot actions Extra action buttons rendered next to the built-in update / re-import buttons in the version card header. -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</template>\n\n\t\t\t<template #footer>\n\t\t\t\t<!-- @slot footer Replaces the default support/SLA footer inside the version card. -->\n\t\t\t\t<slot name=\"footer\">\n\t\t\t\t\t<div v-if=\"showSupport\" class=\"cn-support-info\">\n\t\t\t\t\t\t<h4>{{ supportTitle }}</h4>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t{{ supportLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"slaEmail\">\n\t\t\t\t\t\t\t{{ slaLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</template>\n\n\t\t\t<template #additional-items>\n\t\t\t\t<!-- @slot version-items Extra key/value rows appended inside the version card details. -->\n\t\t\t\t<slot name=\"version-items\" />\n\t\t\t</template>\n\t\t</CnVersionInfoCard>\n\n\t\t<!--\n\t\t\tOrganisation credential broker (ADR-079 Step 2).\n\n\t\t\tThis is the ONE home for org-wide credentials. It used to live in a\n\t\t\tgeneric modal on CnAppRoot, rendered from `manifest.adminSettings[]`\n\t\t\tand gated on app ownership — but no app ever declared that array, so\n\t\t\tthe surface was unreachable in every app in the fleet. It belongs\n\t\t\there: an org-wide secret store is app-level configuration, and\n\t\t\t/settings/admin/<app> is authorized by Nextcloud server-side rather\n\t\t\tthan by a client-side flag.\n\n\t\t\tOpt-in, because only an app that actually brokers credentials should\n\t\t\tshow it — the manifest `credentials[]` declarations drive the\n\t\t\tinformational \"apps requesting credentials\" list inside.\n\t\t-->\n\t\t<CnCredentials\n\t\t\tv-if=\"showOrganisationCredentials\"\n\t\t\tscope=\"organisation\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appCredentials=\"appCredentials\"\n\t\t\tdata-testid=\"cn-admin-organisation-credentials\" />\n\n\t\t<!-- @slot default The app's own settings sections, rendered below the version card. -->\n\t\t<slot />\n\n\t\t<!-- First-time setup wizard, opened from the admin page (ADR-042). -->\n\t\t<CnSetupWizard\n\t\t\tv-if=\"showSetup && setupWizardOpen\"\n\t\t\t:appId=\"appId\"\n\t\t\t:steps=\"setupSteps\"\n\t\t\t@complete=\"setupWizardOpen = false\"\n\t\t\t@close=\"setupWizardOpen = false\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon, NcSettingsSection } from '@nextcloud/vue'\nimport AutoFix from 'vue-material-design-icons/AutoFix.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnCredentials from '../CnCredentials/CnCredentials.vue'\nimport CnSetupWizard from '../CnSetupWizard/CnSetupWizard.vue'\nimport { buildFeatureRequestUrl } from '../../utils/forge.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnVersionInfoCard } from '../CnVersionInfoCard/index.js'\n\n/**\n * CnAdminSettingsShell — the canonical chrome for a Conduction app's Nextcloud\n * admin settings page.\n *\n * Renders, in fleet-standard order:\n * 1. a page title header (\"<App> Settings\" / \"Configure your <App> installation\" + doc-url),\n * 2. a CnVersionInfoCard (version from `loadState`, up-to-date badge, a\n * \"Re-import configuration\" button wired to the AppHost endpoint\n * `POST /apps/<appId>/api/settings/load`, and a support/SLA footer),\n * 3. the app's own settings sections (default slot).\n *\n * Every app's `AdminRoot.vue` collapses to a thin wrapper so the chrome can\n * never drift between apps again.\n *\n * Basic usage\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"shillinq\"\n * app-name=\"Shillinq\"\n * doc-url=\"https://shillinq.conduction.nl/docs/intro\">\n * <MyRegisterMapping />\n * <MyFeatureSettings />\n * </CnAdminSettingsShell>\n * ```\n *\n * Real up-to-date check (when the backend exposes it)\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"opencatalogi\" app-name=\"OpenCatalogi\"\n * :app-version=\"running\" :configured-version=\"configured\"\n * :is-up-to-date=\"running === configured\" />\n * ```\n */\nexport default {\n\tname: 'CnAdminSettingsShell',\n\n\tcomponents: {\n\t\tNcSettingsSection,\n\t\tCnCredentials,\n\t\tCnVersionInfoCard,\n\t\tCnSetupWizard,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tRefresh,\n\t\tAutoFix,\n\t\tHelpCircleOutline,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the organisation credential broker on this admin page\n\t\t * (ADR-079 Step 2). Opt-in: only an app that actually brokers org-wide\n\t\t * secrets should surface it.\n\t\t *\n\t\t * This replaces the generic `manifest.adminSettings[]` modal that used\n\t\t * to live on CnAppRoot. That modal was gated on app OWNERSHIP and on an\n\t\t * array no app in the fleet ever declared, so the broker was\n\t\t * unreachable everywhere. Here it is reachable and the access decision\n\t\t * is Nextcloud's, made server-side for /settings/admin/<app>.\n\t\t */\n\t\tshowOrganisationCredentials: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The app's manifest `credentials[]` declarations, forwarded to the\n\t\t * broker to drive its informational \"apps requesting credentials\"\n\t\t * list. Only read when `showOrganisationCredentials` is true.\n\t\t */\n\t\tappCredentials: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The Nextcloud app id (used for the default re-import endpoint + version loadState). */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Human-readable application name shown in the header and version card. */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Running app version. When empty, read from\n\t\t * `loadState(appId, 'version', 'Unknown')` (provided by AppHost's\n\t\t * GenericAdminSettings::getForm()).\n\t\t */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page title. Defaults to \"<appName> Settings\". */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description. Defaults to \"Configure your <appName> installation\". */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Documentation URL (renders the info icon next to the title). */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the version card. */\n\t\tshowVersionCard: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Version card heading. */\n\t\tversionTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Version card description. Defaults to \"Information about the current <appName> installation\". */\n\t\tversionDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Configured version (for apps that track a separate config version).\n\t\t * When omitted, read from `loadState(appId, 'configuredVersion', '')`\n\t\t * (AppHost stamps it on each config import).\n\t\t */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the installation is up to date. Drives the badge/button in the\n\t\t * version card. When left null, the shell reads the REAL value from\n\t\t * `loadState(appId, 'isUpToDate', true)` — AppHost's GenericAdminSettings\n\t\t * provides it by comparing the running version to the imported config\n\t\t * version. Pass an explicit boolean to override; do NOT hardcode true.\n\t\t */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether to show the version card's up-to-date / update button. */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether an app update is in progress (drives the update button spinner). */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the \"Re-import configuration\" action. */\n\t\tshowReimport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Override the re-import endpoint. Defaults to the canonical AppHost\n\t\t * route `/apps/<appId>/api/settings/load`.\n\t\t */\n\t\treimportUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the default support footer. */\n\t\tshowSupport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Support contact email. */\n\t\tsupportEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'support@conduction.nl',\n\t\t},\n\n\t\t/** SLA contact email (set to '' to hide the SLA line). */\n\t\tslaEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'sales@conduction.nl',\n\t\t},\n\n\t\t/** Show a \"Run setup wizard\" action that opens CnSetupWizard (ADR-042). */\n\t\tshowSetup: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** The `manifest.setup.steps` array passed to CnSetupWizard. */\n\t\tsetupSteps: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Show a \"Help us / suggest a feature\" link to the forge's feature-request form. */\n\t\tshowHelp: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** `<owner>/<repo>` GitHub slug the feature-request link targets. */\n\t\thelpRepo: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update', 'reimported', 'reimport-error'],\n\n\tdata() {\n\t\treturn {\n\t\t\treimporting: false,\n\t\t\tsetupWizardOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The \"Help us\" link target: the forge's feature-request issue form\n\t\t * for `helpRepo`, on the fleet-default forge. Empty (hiding the\n\t\t * button) when no repo is configured.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thelpUrl() {\n\t\t\tconst repo = String(this.helpRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(null, repo)\n\t\t},\n\n\t\t/** @return {string} The running version, falling back to AppHost initial state. */\n\t\tresolvedVersion() {\n\t\t\tif (this.appVersion) {\n\t\t\t\treturn this.appVersion\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'version', 'Unknown')\n\t\t},\n\n\t\t/** @return {string} Configured version, falling back to AppHost initial state. */\n\t\tresolvedConfiguredVersion() {\n\t\t\treturn this.configuredVersion || loadState(this.appId, 'configuredVersion', '')\n\t\t},\n\n\t\t/** @return {boolean} Real up-to-date signal: explicit prop wins, else AppHost initial state. */\n\t\tresolvedIsUpToDate() {\n\t\t\tif (this.isUpToDate !== null) {\n\t\t\t\treturn this.isUpToDate\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'isUpToDate', true)\n\t\t},\n\n\t\t/** @return {string} Page title, defaulting to \"<appName> Settings\". */\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', '{app} Settings', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Page description. */\n\t\tresolvedDescription() {\n\t\t\treturn this.description || t('nextcloud-vue', 'Configure your {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Version card description. */\n\t\tresolvedVersionDescription() {\n\t\t\treturn this.versionDescription || t('nextcloud-vue', 'Information about the current {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Re-import endpoint. */\n\t\tresolvedReimportUrl() {\n\t\t\treturn prefixUrl(this.reimportUrl) || generateUrl('/apps/{appId}/api/settings/load', { appId: this.appId })\n\t\t},\n\n\t\t/** @return {string} Re-import button label. */\n\t\treimportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Re-import configuration')\n\t\t},\n\n\t\t/** @return {string} Re-import in-progress label. */\n\t\timportingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Importing…')\n\t\t},\n\n\t\t/** @return {string} Support footer heading. */\n\t\tsupportTitle() {\n\t\t\treturn t('nextcloud-vue', 'Support')\n\t\t},\n\n\t\t/** @return {string} Support footer line. */\n\t\tsupportLine() {\n\t\t\treturn t('nextcloud-vue', 'For support, contact us at')\n\t\t},\n\n\t\t/** @return {string} SLA footer line. */\n\t\tslaLine() {\n\t\t\treturn t('nextcloud-vue', 'For a Service Level Agreement (SLA), contact')\n\t\t},\n\n\t\t/** @return {string} Setup-wizard button label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Run setup wizard')\n\t\t},\n\n\t\t/** @return {string} Help / suggest-feature button label. */\n\t\thelpLabel() {\n\t\t\treturn t('nextcloud-vue', 'Help us')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/** Forward the version card's update-button click to the parent. */\n\t\tonUpdate() {\n\t\t\t/**\n\t\t\t * @event update Emitted when the version card's update button is clicked.\n\t\t\t */\n\t\t\tthis.$emit('update')\n\t\t},\n\n\t\t/**\n\t\t * Re-import the app's OpenRegister configuration via the canonical\n\t\t * AppHost endpoint, then emit the result so the parent can refresh.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync reimport() {\n\t\t\tif (this.reimporting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reimporting = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(this.resolvedReimportUrl)\n\t\t\t\tconst data = response?.data ?? {}\n\t\t\t\t// AppHost returns { success, message, ... }; a bare 2xx also counts.\n\t\t\t\tif (data.success === false) {\n\t\t\t\t\tthrow new Error(data.message || t('nextcloud-vue', 'Re-import failed'))\n\t\t\t\t}\n\t\t\t\tshowSuccess(data.message || t('nextcloud-vue', 'Configuration re-imported successfully'))\n\t\t\t\t/**\n\t\t\t\t * @event reimported Emitted after a successful configuration re-import.\n\t\t\t\t * @type {object} The AppHost response payload.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimported', data)\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error?.response?.data?.message || error?.message || t('nextcloud-vue', 'Re-import failed')\n\t\t\t\tshowError(message)\n\t\t\t\t/**\n\t\t\t\t * @event reimport-error Emitted when a configuration re-import fails.\n\t\t\t\t * @type {Error} The error that caused the failure.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimport-error', error)\n\t\t\t} finally {\n\t\t\t\tthis.reimporting = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-admin-settings-shell {\n\tmax-width: 900px;\n}\n\n.cn-support-info {\n\tmargin-top: 16px;\n\tpadding-top: 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-support-info h4 {\n\tmargin: 0 0 8px 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-support-info p {\n\tmargin: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-support-info a {\n\tcolor: var(--color-primary-element);\n}\n</style>\n"],"names":["CnCredentials","CnVersionInfoCard","CnSetupWizard","t","axios"],"mappings":"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"}
1
+ {"version":3,"file":"CnAdminSettingsShell.vue2.js","sources":["../../../../src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-admin-settings-shell\">\n\t\t<!-- Page title header — the uniform \"<App> Settings / Configure your <App> installation\" block.\n\t\t Uses NcSettingsSection directly (not CnSettingsSection) so the description subtitle and\n\t\t doc-url icon render — CnSettingsSection repurposes those props and does not forward them. -->\n\t\t<NcSettingsSection\n\t\t\t:name=\"resolvedTitle\"\n\t\t\t:description=\"resolvedDescription\"\n\t\t\t:docUrl=\"docUrl\" />\n\n\t\t<!-- Version information card (version, up-to-date check, re-import, support footer) -->\n\t\t<CnVersionInfoCard\n\t\t\tv-if=\"showVersionCard\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appVersion=\"resolvedVersion\"\n\t\t\t:configuredVersion=\"resolvedConfiguredVersion\"\n\t\t\t:isUpToDate=\"resolvedIsUpToDate\"\n\t\t\t:showUpdateButton=\"showUpdateButton\"\n\t\t\t:updating=\"updating\"\n\t\t\t:title=\"versionTitle\"\n\t\t\t:description=\"resolvedVersionDescription\"\n\t\t\t@update=\"onUpdate\">\n\t\t\t<template #actions>\n\t\t\t\t<!-- Canonical \"Re-import configuration\" action (POST /apps/<appId>/api/settings/load) -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showReimport\"\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"reimporting\"\n\t\t\t\t\t@click=\"reimport\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcLoadingIcon v-if=\"reimporting\" :size=\"20\" />\n\t\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ reimporting ? importingLabel : reimportLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- Run the first-time setup wizard on demand (ADR-042). -->\n\t\t\t\t<NcButton v-if=\"showSetup\" data-testid=\"cn-admin-run-setup\" @click=\"setupWizardOpen = true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<AutoFix :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ setupLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- \"Help us / suggest a feature\" — a direct link to the forge's\n\t\t\t\t feature-request issue form (team decision 2026-09-04: the\n\t\t\t\t in-product suggestion modal is gone; the forge is where\n\t\t\t\t the conversation happens, in English). -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showHelp && helpUrl\"\n\t\t\t\t\t:href=\"helpUrl\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<HelpCircleOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ helpLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- @slot actions Extra action buttons rendered next to the built-in update / re-import buttons in the version card header. -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</template>\n\n\t\t\t<template #footer>\n\t\t\t\t<!-- @slot footer Replaces the default support/SLA footer inside the version card. -->\n\t\t\t\t<slot name=\"footer\">\n\t\t\t\t\t<div v-if=\"showSupport\" class=\"cn-support-info\">\n\t\t\t\t\t\t<h4>{{ supportTitle }}</h4>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t{{ supportLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"slaEmail\">\n\t\t\t\t\t\t\t{{ slaLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</template>\n\n\t\t\t<template #additional-items>\n\t\t\t\t<!-- @slot version-items Extra key/value rows appended inside the version card details. -->\n\t\t\t\t<slot name=\"version-items\" />\n\t\t\t</template>\n\t\t</CnVersionInfoCard>\n\n\t\t<!--\n\t\t\tOrganisation credential broker (ADR-079 Step 2).\n\n\t\t\tThis is the ONE home for org-wide credentials. It used to live in a\n\t\t\tgeneric modal on CnAppRoot, rendered from `manifest.adminSettings[]`\n\t\t\tand gated on app ownership — but no app ever declared that array, so\n\t\t\tthe surface was unreachable in every app in the fleet. It belongs\n\t\t\there: an org-wide secret store is app-level configuration, and\n\t\t\t/settings/admin/<app> is authorized by Nextcloud server-side rather\n\t\t\tthan by a client-side flag.\n\n\t\t\tOpt-in, because only an app that actually brokers credentials should\n\t\t\tshow it — the manifest `credentials[]` declarations drive the\n\t\t\tinformational \"apps requesting credentials\" list inside.\n\t\t-->\n\t\t<CnCredentials\n\t\t\tv-if=\"showOrganisationCredentials\"\n\t\t\tscope=\"organisation\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appCredentials=\"appCredentials\"\n\t\t\tdata-testid=\"cn-admin-organisation-credentials\" />\n\n\t\t<!-- @slot default The app's own settings sections, rendered below the version card. -->\n\t\t<slot />\n\n\t\t<!-- First-time setup wizard, opened from the admin page (ADR-042). -->\n\t\t<CnSetupWizard\n\t\t\tv-if=\"showSetup && setupWizardOpen\"\n\t\t\t:appId=\"appId\"\n\t\t\t:steps=\"setupSteps\"\n\t\t\t@complete=\"setupWizardOpen = false\"\n\t\t\t@close=\"setupWizardOpen = false\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon, NcSettingsSection } from '@nextcloud/vue'\nimport AutoFix from 'vue-material-design-icons/AutoFix.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnCredentials from '../CnCredentials/CnCredentials.vue'\nimport CnSetupWizard from '../CnSetupWizard/CnSetupWizard.vue'\nimport { buildFeatureRequestUrl } from '../../utils/forge.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnVersionInfoCard } from '../CnVersionInfoCard/index.js'\n\n/**\n * CnAdminSettingsShell — the canonical chrome for a Conduction app's Nextcloud\n * admin settings page.\n *\n * Renders, in fleet-standard order:\n * 1. a page title header (\"<App> Settings\" / \"Configure your <App> installation\" + doc-url),\n * 2. a CnVersionInfoCard (version from `loadState`, up-to-date badge, a\n * \"Re-import configuration\" button wired to the AppHost endpoint\n * `POST /apps/<appId>/api/settings/load`, and a support/SLA footer),\n * 3. the app's own settings sections (default slot).\n *\n * Every app's `AdminRoot.vue` collapses to a thin wrapper so the chrome can\n * never drift between apps again.\n *\n * Basic usage\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"shillinq\"\n * app-name=\"Shillinq\"\n * doc-url=\"https://shillinq.conduction.nl/docs/intro\">\n * <MyRegisterMapping />\n * <MyFeatureSettings />\n * </CnAdminSettingsShell>\n * ```\n *\n * Real up-to-date check (when the backend exposes it)\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"opencatalogi\" app-name=\"OpenCatalogi\"\n * :app-version=\"running\" :configured-version=\"configured\"\n * :is-up-to-date=\"running === configured\" />\n * ```\n */\nexport default {\n\tname: 'CnAdminSettingsShell',\n\n\tcomponents: {\n\t\tNcSettingsSection,\n\t\tCnCredentials,\n\t\tCnVersionInfoCard,\n\t\tCnSetupWizard,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tRefresh,\n\t\tAutoFix,\n\t\tHelpCircleOutline,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Render the organisation credential broker on this admin page\n\t\t * (ADR-079 Step 2). Opt-in: only an app that actually brokers org-wide\n\t\t * secrets should surface it.\n\t\t *\n\t\t * This replaces the generic `manifest.adminSettings[]` modal that used\n\t\t * to live on CnAppRoot. That modal was gated on app OWNERSHIP and on an\n\t\t * array no app in the fleet ever declared, so the broker was\n\t\t * unreachable everywhere. Here it is reachable and the access decision\n\t\t * is Nextcloud's, made server-side for /settings/admin/<app>.\n\t\t */\n\t\tshowOrganisationCredentials: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The app's manifest `credentials[]` declarations, forwarded to the\n\t\t * broker to drive its informational \"apps requesting credentials\"\n\t\t * list. Only read when `showOrganisationCredentials` is true.\n\t\t */\n\t\tappCredentials: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The Nextcloud app id (used for the default re-import endpoint + version loadState). */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Human-readable application name shown in the header and version card. */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Running app version. When empty, read from\n\t\t * `loadState(appId, 'version', 'Unknown')` (provided by AppHost's\n\t\t * GenericAdminSettings::getForm()).\n\t\t */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page title. Defaults to \"<appName> Settings\". */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description. Defaults to \"Configure your <appName> installation\". */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Documentation URL (renders the info icon next to the title). */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the version card. */\n\t\tshowVersionCard: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Version card heading. */\n\t\tversionTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Version card description. Defaults to \"Information about the current <appName> installation\". */\n\t\tversionDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Configured version (for apps that track a separate config version).\n\t\t * When omitted, read from `loadState(appId, 'configuredVersion', '')`\n\t\t * (AppHost stamps it on each config import).\n\t\t */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the installation is up to date. Drives the badge/button in the\n\t\t * version card. When left null, the shell reads the REAL value from\n\t\t * `loadState(appId, 'isUpToDate', true)` — AppHost's GenericAdminSettings\n\t\t * provides it by comparing the running version to the imported config\n\t\t * version. Pass an explicit boolean to override; do NOT hardcode true.\n\t\t */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether to show the version card's up-to-date / update button. */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether an app update is in progress (drives the update button spinner). */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the \"Re-import configuration\" action. */\n\t\tshowReimport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Override the re-import endpoint. Defaults to the canonical AppHost\n\t\t * route `/apps/<appId>/api/settings/load`.\n\t\t */\n\t\treimportUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the default support footer. */\n\t\tshowSupport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Support contact email. */\n\t\tsupportEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'support@conduction.nl',\n\t\t},\n\n\t\t/** SLA contact email (set to '' to hide the SLA line). */\n\t\tslaEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'sales@conduction.nl',\n\t\t},\n\n\t\t/** Show a \"Run setup wizard\" action that opens CnSetupWizard (ADR-042). */\n\t\tshowSetup: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** The `manifest.setup.steps` array passed to CnSetupWizard. */\n\t\tsetupSteps: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Show a \"Help us / suggest a feature\" link to the forge's feature-request form. */\n\t\tshowHelp: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** `<owner>/<repo>` GitHub slug the feature-request link targets. */\n\t\thelpRepo: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update', 'reimported', 'reimport-error'],\n\n\tdata() {\n\t\treturn {\n\t\t\treimporting: false,\n\t\t\tsetupWizardOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The \"Help us\" link target: the forge's feature-request issue form\n\t\t * for `helpRepo`, on the fleet-default forge. Empty (hiding the\n\t\t * button) when no repo is configured.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thelpUrl() {\n\t\t\tconst repo = String(this.helpRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(null, repo)\n\t\t},\n\n\t\t/** @return {string} The running version, falling back to AppHost initial state. */\n\t\tresolvedVersion() {\n\t\t\tif (this.appVersion) {\n\t\t\t\treturn this.appVersion\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'version', 'Unknown')\n\t\t},\n\n\t\t/** @return {string} Configured version, falling back to AppHost initial state. */\n\t\tresolvedConfiguredVersion() {\n\t\t\treturn this.configuredVersion || loadState(this.appId, 'configuredVersion', '')\n\t\t},\n\n\t\t/** @return {boolean} Real up-to-date signal: explicit prop wins, else AppHost initial state. */\n\t\tresolvedIsUpToDate() {\n\t\t\tif (this.isUpToDate !== null) {\n\t\t\t\treturn this.isUpToDate\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'isUpToDate', true)\n\t\t},\n\n\t\t/** @return {string} Page title, defaulting to \"<appName> Settings\". */\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', '{app} Settings', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Page description. */\n\t\tresolvedDescription() {\n\t\t\treturn this.description || t('nextcloud-vue', 'Configure your {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Version card description. */\n\t\tresolvedVersionDescription() {\n\t\t\treturn this.versionDescription || t('nextcloud-vue', 'Information about the current {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Re-import endpoint. */\n\t\tresolvedReimportUrl() {\n\t\t\treturn prefixUrl(this.reimportUrl) || generateUrl('/apps/{appId}/api/settings/load', { appId: this.appId })\n\t\t},\n\n\t\t/** @return {string} Re-import button label. */\n\t\treimportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Re-import configuration')\n\t\t},\n\n\t\t/** @return {string} Re-import in-progress label. */\n\t\timportingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Importing…')\n\t\t},\n\n\t\t/** @return {string} Support footer heading. */\n\t\tsupportTitle() {\n\t\t\treturn t('nextcloud-vue', 'Support')\n\t\t},\n\n\t\t/** @return {string} Support footer line. */\n\t\tsupportLine() {\n\t\t\treturn t('nextcloud-vue', 'For support, contact us at')\n\t\t},\n\n\t\t/** @return {string} SLA footer line. */\n\t\tslaLine() {\n\t\t\treturn t('nextcloud-vue', 'For a Service Level Agreement (SLA), contact')\n\t\t},\n\n\t\t/** @return {string} Setup-wizard button label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Run setup wizard')\n\t\t},\n\n\t\t/** @return {string} Help / suggest-feature button label. */\n\t\thelpLabel() {\n\t\t\treturn t('nextcloud-vue', 'Help us')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/** Forward the version card's update-button click to the parent. */\n\t\tonUpdate() {\n\t\t\t/**\n\t\t\t * @event update Emitted when the version card's update button is clicked.\n\t\t\t */\n\t\t\tthis.$emit('update')\n\t\t},\n\n\t\t/**\n\t\t * Re-import the app's OpenRegister configuration via the canonical\n\t\t * AppHost endpoint, then emit the result so the parent can refresh.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync reimport() {\n\t\t\tif (this.reimporting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reimporting = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(this.resolvedReimportUrl)\n\t\t\t\tconst data = response?.data ?? {}\n\t\t\t\t// AppHost returns { success, message, ... }; a bare 2xx also counts.\n\t\t\t\tif (data.success === false) {\n\t\t\t\t\tthrow new Error(data.message || t('nextcloud-vue', 'Re-import failed'))\n\t\t\t\t}\n\t\t\t\tshowSuccess(data.message || t('nextcloud-vue', 'Configuration re-imported successfully'))\n\t\t\t\t/**\n\t\t\t\t * @event reimported Emitted after a successful configuration re-import.\n\t\t\t\t * @type {object} The AppHost response payload.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimported', data)\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error?.response?.data?.message || error?.message || t('nextcloud-vue', 'Re-import failed')\n\t\t\t\tshowError(message)\n\t\t\t\t/**\n\t\t\t\t * @event reimport-error Emitted when a configuration re-import fails.\n\t\t\t\t * @type {Error} The error that caused the failure.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimport-error', error)\n\t\t\t} finally {\n\t\t\t\tthis.reimporting = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-admin-settings-shell {\n\tmax-width: 900px;\n}\n\n.cn-support-info {\n\tmargin-top: 16px;\n\tpadding-top: 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-support-info h4 {\n\tmargin: 0 0 8px 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-support-info p {\n\tmargin: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-support-info a {\n\tcolor: var(--color-primary-element);\n}\n</style>\n"],"names":["CnCredentials","CnVersionInfoCard","CnSetupWizard","t","axios"],"mappings":"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"}
@@ -83,8 +83,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
83
83
  ? (openBlock(), createBlock(_component_NcButton, {
84
84
  key: 2,
85
85
  href: $options.helpUrl,
86
- target: "_blank",
87
- rel: "noopener noreferrer"
86
+ target: "_blank"
88
87
  }, {
89
88
  icon: withCtx(() => [
90
89
  createVNode(_component_HelpCircleOutline, { size: 20 })