@conduction/nextcloud-vue 2.58.0 → 2.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) 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/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +100 -3
  90. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  92. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  93. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  94. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  95. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  96. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  97. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  98. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  101. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  102. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  103. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  108. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  109. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  110. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  116. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  117. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  118. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  123. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  124. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  125. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  130. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  131. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  132. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  137. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  139. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  141. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  143. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  144. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  149. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  150. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  151. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  156. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  157. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  158. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  163. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  164. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  165. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  170. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  171. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  172. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  177. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  178. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  179. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  184. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  186. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  188. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  189. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  194. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  195. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  196. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  201. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  202. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  203. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  208. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  209. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  210. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  211. package/dist/esm/l10n/en.json.js +1 -0
  212. package/dist/esm/l10n/en.json.js.map +1 -1
  213. package/dist/esm/l10n/nl.json.js +1 -0
  214. package/dist/esm/l10n/nl.json.js.map +1 -1
  215. package/dist/esm/nextcloud-vue.css +71 -7
  216. package/dist/esm/utils/actionLink.js +5 -0
  217. package/dist/esm/utils/actionLink.js.map +1 -1
  218. package/dist/esm/utils/actionsDispatcher.js +16 -1
  219. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  220. package/dist/esm/utils/linkNavigation.js +6 -3
  221. package/dist/esm/utils/linkNavigation.js.map +1 -1
  222. package/dist/esm/utils/rowAuxClick.js +30 -5
  223. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  224. package/dist/esm/utils/safeHref.js +18 -3
  225. package/dist/esm/utils/safeHref.js.map +1 -1
  226. package/dist/nextcloud-vue.cjs.js +909 -386
  227. package/dist/nextcloud-vue.cjs.js.map +2 -2
  228. package/dist/nextcloud-vue.css +71 -7
  229. package/l10n/en.json +1 -0
  230. package/l10n/nl.json +1 -0
  231. package/package.json +1 -1
  232. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  233. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  234. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  235. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  236. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  237. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  238. package/src/components/CnDataTable/CnDataTable.md +1 -1
  239. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  240. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  241. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  242. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  243. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  244. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  245. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  246. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  247. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  248. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  249. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  250. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  251. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  252. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  253. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  254. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  255. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  256. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  257. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  258. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  259. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  260. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +100 -3
  261. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  262. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  263. package/src/components/CnTabs/CnTabs.vue +7 -3
  264. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  265. package/src/css/table.css +26 -0
  266. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  267. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  268. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  269. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  270. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  271. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  272. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  273. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  274. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  275. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  276. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  277. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  278. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  279. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  280. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  281. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  282. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  283. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  284. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  285. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  286. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  287. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  288. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  289. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  290. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  291. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  292. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  293. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  294. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  295. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  296. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  297. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  298. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  299. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  300. package/src/utils/actionLink.js +5 -0
  301. package/src/utils/actionsDispatcher.js +15 -0
  302. package/src/utils/linkNavigation.js +6 -3
  303. package/src/utils/rowAuxClick.js +29 -4
  304. package/src/utils/safeHref.js +18 -3
@@ -5757,13 +5757,17 @@ async function runSelfImportRequest({ register, schema, file }) {
5757
5757
  * also fire `auxclick` for the right button, so a row that listens to it must
5758
5758
  * filter both out itself.
5759
5759
  *
5760
- * Whoever opens a row in a new tab calls `preventDefault()` on the event, so a
5761
- * second listener for the same click (a host behind a library default) can
5760
+ * Whoever opens a row in a new tab marks the event with `markNewTabHandled`, so
5761
+ * a second listener for the same click (a host behind a library default) can
5762
5762
  * check `isNewTabHandled` and not open a second tab.
5763
5763
  *
5764
5764
  * @module utils/rowAuxClick
5765
5765
  */
5766
5766
 
5767
+ // Events that opened a new tab. Not `defaultPrevented`, which any unrelated
5768
+ // handler can set on a modified or middle click.
5769
+ const newTabHandled = new WeakSet();
5770
+
5767
5771
  const NESTED_CONTROL = 'a, button, input, select, textarea, label, summary, [role="button"], [role="checkbox"], [role="link"], [contenteditable="true"]';
5768
5772
 
5769
5773
  /**
@@ -5797,6 +5801,21 @@ function isRowMiddleClick(event) {
5797
5801
  return Boolean(event && event.button === 1 && !isFromNestedControl(event))
5798
5802
  }
5799
5803
 
5804
+ /**
5805
+ * Cancel a middle-button press on a clickable row or card body, so the
5806
+ * browser does not start autoscroll (Chrome/Edge on Windows) instead of the
5807
+ * middle click opening the row. A press on a nested control, a link
5808
+ * included, keeps its default.
5809
+ *
5810
+ * @param {MouseEvent} event The mousedown event.
5811
+ * @return {void}
5812
+ */
5813
+ function preventMiddleClickAutoscroll(event) {
5814
+ if (event && event.button === 1 && !isFromNestedControl(event) && typeof event.preventDefault === 'function') {
5815
+ event.preventDefault();
5816
+ }
5817
+ }
5818
+
5800
5819
  /**
5801
5820
  * Whether `openRowTarget` would open this click in a new tab.
5802
5821
  *
@@ -5814,18 +5833,24 @@ function isNewTabClick(event) {
5814
5833
  * @return {boolean}
5815
5834
  */
5816
5835
  function isNewTabHandled(event) {
5817
- return Boolean(isNewTabClick(event) && event.defaultPrevented)
5836
+ return Boolean(isNewTabClick(event) && newTabHandled.has(event))
5818
5837
  }
5819
5838
 
5820
5839
  /**
5821
5840
  * Mark a new-tab click as handled after opening it, see `isNewTabHandled`.
5841
+ * Also prevents the event's default, so the browser does not act on the
5842
+ * click as well.
5822
5843
  *
5823
5844
  * @param {MouseEvent|KeyboardEvent|null|undefined} event The click event.
5824
5845
  * @param {boolean} opened Whether the target was opened.
5825
5846
  * @return {void}
5826
5847
  */
5827
5848
  function markNewTabHandled(event, opened) {
5828
- if (opened && isNewTabClick(event) && typeof event.preventDefault === 'function') {
5849
+ if (!opened || !isNewTabClick(event)) {
5850
+ return
5851
+ }
5852
+ newTabHandled.add(event);
5853
+ if (typeof event.preventDefault === 'function') {
5829
5854
  event.preventDefault();
5830
5855
  }
5831
5856
  }
@@ -5900,8 +5925,11 @@ function resolveHref(target, router) {
5900
5925
  * click is routed through the router; a modified click, or one a handler
5901
5926
  * already prevented, is left to the browser.
5902
5927
  *
5928
+ * Unlike `resolveHref`, a string target is a router path, so pair the two
5929
+ * with a location object (or `{ path }`) for the href and click to agree.
5930
+ *
5903
5931
  * @param {MouseEvent} event The click event.
5904
- * @param {string|object} target The router location the link points at.
5932
+ * @param {string|object} target The router location the link points at; a string is a router path.
5905
5933
  * @param {object} [router] The app's router.
5906
5934
  * @return {boolean} True when the app navigated.
5907
5935
  */
@@ -5927,8 +5955,8 @@ function followLinkClick(event, target, router) {
5927
5955
  *
5928
5956
  * A click that came from a control inside the surface (a button, a link, a
5929
5957
  * checkbox) is left to that control. Opening a new tab marks the event with
5930
- * `preventDefault()`, and an event already marked that way is skipped, so
5931
- * two listeners on the same click never open two tabs.
5958
+ * `markNewTabHandled`, and an event already marked is skipped, so two
5959
+ * listeners on the same click never open two tabs.
5932
5960
  *
5933
5961
  * @param {MouseEvent|KeyboardEvent|null|undefined} event The click event.
5934
5962
  * @param {string|object} target A URL, or a vue-router location.
@@ -6026,6 +6054,11 @@ function resolveItemActionLink(action, item, router) {
6026
6054
  * on an in-app link that opens in place goes through the router; a URL, a
6027
6055
  * new-tab target or a modified click is left to the browser.
6028
6056
  *
6057
+ * Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and
6058
+ * bars using it must still emit their own events on click, and without an
6059
+ * installed router `NcButton :to` falls back to a button that goes nowhere,
6060
+ * while an `<a href>` still navigates.
6061
+ *
6029
6062
  * @param {MouseEvent} event The click event.
6030
6063
  * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.
6031
6064
  * @param {object} [router] The app's router.
@@ -6447,6 +6480,21 @@ function interpolateActionTarget(target, ctx) {
6447
6480
  return interpolateActionString(target || '', ctx || {})
6448
6481
  }
6449
6482
 
6483
+ // The tokens interpolateActionString resolves; a bare `@` or `{` is not one.
6484
+ const ACTION_TARGET_TOKEN = /@(?:objectId|object\.|page\.|workspace\.|config\.|range\.)|\{objectId\}/;
6485
+
6486
+ /**
6487
+ * Whether an action target carries a token that interpolation would resolve,
6488
+ * so it can only be known once the page context is. A `mailto:` address or a
6489
+ * URL with an `@handle` in it has none.
6490
+ *
6491
+ * @param {string} target The action's raw `target`.
6492
+ * @return {boolean}
6493
+ */
6494
+ function hasActionTargetTokens(target) {
6495
+ return typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)
6496
+ }
6497
+
6450
6498
  /**
6451
6499
  * The link an action renders as when its only job is to navigate to a target
6452
6500
  * known at render time: `navigate` (token-interpolated like the dispatcher)
@@ -15200,6 +15248,20 @@ const __sfc_main$5Y = script$62;
15200
15248
  * @module utils/safeHref
15201
15249
  */
15202
15250
 
15251
+ /**
15252
+ * Whether a URL is protocol-relative the way a browser reads it: leading
15253
+ * control characters and spaces are dropped, tabs and newlines are ignored
15254
+ * anywhere, and a backslash counts as `/`.
15255
+ *
15256
+ * @param {string} url The URL.
15257
+ * @return {boolean}
15258
+ */
15259
+ function isProtocolRelative(url) {
15260
+ // eslint-disable-next-line no-control-regex
15261
+ const normalized = url.replace(/[\t\n\r]/g, '').replace(/^[\u0000-\u0020]+/, '');
15262
+ return /^[/\\]{2}/.test(normalized)
15263
+ }
15264
+
15203
15265
  /**
15204
15266
  * Validate a URL and return it only if the scheme is safe for `:href`.
15205
15267
  *
@@ -15212,7 +15274,8 @@ const __sfc_main$5Y = script$62;
15212
15274
  * - `javascript:...`
15213
15275
  * - `data:...`
15214
15276
  * - `vbscript:...`
15215
- * - Protocol-relative `//attacker.com/...` (ambiguous origin)
15277
+ * - Protocol-relative `//attacker.com/...` (ambiguous origin), also as
15278
+ * `/\attacker.com` or with leading whitespace
15216
15279
  * - Any other unrecognised scheme
15217
15280
  * - `null`, `undefined`, empty string
15218
15281
  *
@@ -15234,7 +15297,7 @@ function safeHref(url) {
15234
15297
  }
15235
15298
  // Reject protocol-relative URLs — `//attacker.com/x` looks like a relative
15236
15299
  // path but resolves to an arbitrary origin, bypassing same-origin intent.
15237
- if (url.startsWith('//')) {
15300
+ if (isProtocolRelative(url)) {
15238
15301
  return '#'
15239
15302
  }
15240
15303
  // Allow root-relative paths (same-origin navigation)
@@ -15279,7 +15342,7 @@ function safeImageSrc(url) {
15279
15342
  return url
15280
15343
  }
15281
15344
  // Reject protocol-relative
15282
- if (url.startsWith('//')) {
15345
+ if (isProtocolRelative(url)) {
15283
15346
  return ''
15284
15347
  }
15285
15348
  try {
@@ -16929,9 +16992,11 @@ var script$5_ = {
16929
16992
 
16930
16993
  /**
16931
16994
  * Convenience navigation (folded from CnTableWidget): a function that
16932
- * receives the clicked row and returns a vue-router route to push. When
16933
- * set, a row click navigates there (the `row-click` event still fires);
16934
- * a ctrl/cmd/shift or middle click opens it in a new tab.
16995
+ * receives a row and returns the vue-router route it opens. When set,
16996
+ * each row renders as a real link to that route, stretched over the
16997
+ * row: a click navigates there (the `row-click` event still fires), and
16998
+ * a ctrl/cmd/shift or middle click opens it in a new tab. A table whose
16999
+ * row click selects (`selectable` without `rowClickToView`) gets no link.
16935
17000
  *
16936
17001
  * @type {((row: object) => object)|null}
16937
17002
  */
@@ -16954,7 +17019,7 @@ var script$5_ = {
16954
17019
  },
16955
17020
  },
16956
17021
 
16957
- emits: ['row-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
17022
+ emits: ['row-click', 'row-aux-click', 'row-context-menu', 'select', 'select-all', 'sort', 'view-all'],
16958
17023
 
16959
17024
  setup() {
16960
17025
  // Tell a deliberate row click apart from a text-selection drag.
@@ -17104,6 +17169,32 @@ var script$5_ = {
17104
17169
  *
17105
17170
  * @return {Array<{key: string, order: 'asc'|'desc'}>}
17106
17171
  */
17172
+ /**
17173
+ * The link each row opens, keyed by row key: the `rowClickRoute`
17174
+ * location and its href. Empty when rows have no route, or when a row
17175
+ * click selects instead of navigating.
17176
+ *
17177
+ * @return {{[key: string]: {target: object, href: string}}}
17178
+ */
17179
+ rowLinks() {
17180
+ const links = {};
17181
+ if (!this.rowClickRoute || !this.$router || (this.selectable && !this.rowClickToView)) {
17182
+ return links
17183
+ }
17184
+ for (const row of this.effectiveRows) {
17185
+ const route = this.rowClickRoute(row);
17186
+ if (!route) {
17187
+ continue
17188
+ }
17189
+ const target = typeof route === 'string' ? { path: route } : route;
17190
+ const href = resolveHref(target, this.$router);
17191
+ if (href) {
17192
+ links[String(row[this.rowKey])] = { target, href };
17193
+ }
17194
+ }
17195
+ return links
17196
+ },
17197
+
17107
17198
  effectiveSortKeys() {
17108
17199
  if (this.sortKeys && this.sortKeys.length > 0) {
17109
17200
  return this.sortKeys
@@ -17580,9 +17671,23 @@ var script$5_ = {
17580
17671
  },
17581
17672
 
17582
17673
  /**
17583
- * Row-body middle click: emits `row-click` like a click, so the host
17584
- * (or `rowClickRoute`) can open the row in a new tab. Ignored for other
17585
- * buttons, nested controls, drags and select-on-click tables.
17674
+ * Row mousedown: record the press for the drag guard, and on a row a
17675
+ * middle click opens, keep the browser from starting autoscroll.
17676
+ *
17677
+ * @param {MouseEvent} event The mousedown event.
17678
+ */
17679
+ onRowMouseDown(event) {
17680
+ this.onPointerDown(event);
17681
+ if (!this.selectable || this.rowClickToView) {
17682
+ preventMiddleClickAutoscroll(event);
17683
+ }
17684
+ },
17685
+
17686
+ /**
17687
+ * Row-body middle click: emits `row-aux-click`, not `row-click`, so an
17688
+ * existing `row-click` listener that navigates never moves the current
17689
+ * tab away; `rowClickRoute` still opens the row in a new tab. Ignored
17690
+ * for other buttons, nested controls, drags and select-on-click tables.
17586
17691
  *
17587
17692
  * @param {object} row The clicked row object
17588
17693
  * @param {MouseEvent} event The originating auxclick event.
@@ -17594,23 +17699,39 @@ var script$5_ = {
17594
17699
  if (this.selectable && !this.rowClickToView) {
17595
17700
  return
17596
17701
  }
17597
- this.emitRowClick(row, event);
17702
+ /**
17703
+ * @event row-aux-click Emitted on a row-body middle click, under the same conditions as `row-click`, so a host can open the row in a new tab (see `openRowTarget`). Payload: `(row, event)` — the clicked row object and the native auxclick event.
17704
+ * @type {object} The clicked row object.
17705
+ */
17706
+ this.$emit('row-aux-click', row, event);
17707
+ this.followRowClickRoute(row, event);
17598
17708
  },
17599
17709
 
17600
17710
  /**
17601
17711
  * Emit `row-click` and follow `rowClickRoute` when set.
17602
17712
  *
17603
17713
  * @param {object} row The clicked row object
17604
- * @param {MouseEvent} [event] The originating click or auxclick event.
17714
+ * @param {MouseEvent} [event] The originating click event.
17605
17715
  */
17606
17716
  emitRowClick(row, event) {
17607
17717
  /**
17608
- * @event row-click Emitted on a row-body click for navigation, and on a middle click (auxclick). Fires when `selectable` is false, OR when `rowClickToView` is set (selection then happens via the checkbox column). Payload: `(row, event)` — the clicked row object and the native click/auxclick event, so a host can open the row in a new tab on a ctrl/cmd/shift or middle click (see `openRowTarget`).
17718
+ * @event row-click Emitted on a row-body click for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set (selection then happens via the checkbox column). Payload: `(row, event)` — the clicked row object and the native click event, so a host can open the row in a new tab on a ctrl/cmd/shift click (see `openRowTarget`). A middle click emits `row-aux-click` instead.
17609
17719
  * @type {object} The clicked row object.
17610
17720
  */
17611
17721
  this.$emit('row-click', row, event);
17612
- // A ctrl/cmd/shift or middle click opens the route in a new tab,
17613
- // unless a row-click listener already did.
17722
+ this.followRowClickRoute(row, event);
17723
+ },
17724
+
17725
+ /**
17726
+ * Follow `rowClickRoute` for a row click: in place, or in a new tab on
17727
+ * a ctrl/cmd/shift or middle click.
17728
+ *
17729
+ * @param {object} row The clicked row object
17730
+ * @param {MouseEvent} [event] The originating click or auxclick event.
17731
+ */
17732
+ followRowClickRoute(row, event) {
17733
+ // A new-tab click opens the route in a new tab, unless a listener
17734
+ // already did.
17614
17735
  if (this.rowClickRoute && this.$router && !isNewTabHandled(event)) {
17615
17736
  const route = this.rowClickRoute(row);
17616
17737
  if (route) {
@@ -17619,14 +17740,57 @@ var script$5_ = {
17619
17740
  }
17620
17741
  },
17621
17742
 
17743
+ /**
17744
+ * A plain or alt click on a row link routes in place; a new-tab click
17745
+ * is left to the browser, which opens the href itself.
17746
+ *
17747
+ * @param {object} row The row the link belongs to.
17748
+ * @param {MouseEvent} event The click event.
17749
+ */
17750
+ onRowLinkClick(row, event) {
17751
+ const link = this.rowLinks[String(row[this.rowKey])];
17752
+ if (!link) {
17753
+ return
17754
+ }
17755
+ // Alt-click on a link downloads it; a row opens like a plain click.
17756
+ if (event.altKey && !isNewTabClick(event) && !event.defaultPrevented) {
17757
+ event.preventDefault();
17758
+ this.$router.push(link.target).catch(() => {});
17759
+ return
17760
+ }
17761
+ followLinkClick(event, link.target, this.$router);
17762
+ },
17763
+
17764
+ /**
17765
+ * The row link's accessible name: the row's first cell when it holds
17766
+ * plain text, else a generic name.
17767
+ *
17768
+ * @param {object} row The row.
17769
+ * @param {object} col The first data column.
17770
+ * @return {string}
17771
+ */
17772
+ rowLinkLabel(row, col) {
17773
+ const value = this.cellValue(row, col);
17774
+ if (['string', 'number'].includes(typeof value) && String(value).trim() !== '') {
17775
+ return String(value)
17776
+ }
17777
+ return l10n.translate('nextcloud-vue', 'Open row')
17778
+ },
17779
+
17622
17780
  /**
17623
17781
  * Row right-click: forward the row + originating event so a host can
17624
- * open a context menu (the browser default is prevented).
17782
+ * open a context menu. The browser menu is prevented, except on a row
17783
+ * link when no host listens, so its link actions stay available.
17625
17784
  *
17626
17785
  * @param {object} row The right-clicked row object.
17627
17786
  * @param {MouseEvent} event The originating contextmenu event.
17628
17787
  */
17629
17788
  onRowContextMenu(row, event) {
17789
+ const fromRowLink = event.target?.closest?.('.cn-table-row__link');
17790
+ // `$.vnode.props`, not `$attrs`: a declared emit is stripped from `$attrs`.
17791
+ if (!fromRowLink || this.$.vnode.props?.onRowContextMenu) {
17792
+ event.preventDefault();
17793
+ }
17630
17794
  /**
17631
17795
  * @event row-context-menu Emitted on a row right-click (contextmenu) for hosts that render a context menu.
17632
17796
  * @type {{ row: object, event: MouseEvent }}
@@ -17788,18 +17952,19 @@ const _hoisted_16$1b = {
17788
17952
  key: 1,
17789
17953
  class: "cn-table-col--icon"
17790
17954
  };
17791
- const _hoisted_17$12 = {
17792
- key: 1,
17955
+ const _hoisted_17$12 = ["href", "aria-label", "onClick"];
17956
+ const _hoisted_18$T = {
17957
+ key: 2,
17793
17958
  class: "cn-table-row-indicators",
17794
17959
  "data-testid": "cn-row-indicators"
17795
17960
  };
17796
- const _hoisted_18$T = ["title", "data-testid"];
17797
- const _hoisted_19$L = { class: "hidden-visually" };
17798
- const _hoisted_20$E = {
17961
+ const _hoisted_19$L = ["title", "data-testid"];
17962
+ const _hoisted_20$E = { class: "hidden-visually" };
17963
+ const _hoisted_21$C = {
17799
17964
  key: 3,
17800
17965
  class: "cn-data-table__footer"
17801
17966
  };
17802
- const _hoisted_21$C = ["href"];
17967
+ const _hoisted_22$z = ["href"];
17803
17968
 
17804
17969
  function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17805
17970
  const _component_NcLoadingIcon = vue$1.resolveComponent("NcLoadingIcon");
@@ -17907,14 +18072,15 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17907
18072
  key: row[$props.rowKey],
17908
18073
  class: vue$1.normalizeClass(["cn-table-row", [
17909
18074
  $options.isSelected(row) ? 'cn-table-row--selected' : '',
18075
+ $options.rowLinks[String(row[$props.rowKey])] ? 'cn-table-row--linked' : '',
17910
18076
  $props.rowClass ? $props.rowClass(row) : '',
17911
18077
  ]]),
17912
18078
  "data-testid": "cn-object-row",
17913
18079
  "data-testid-row-id": row[$props.rowKey],
17914
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
18080
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onRowMouseDown && $options.onRowMouseDown(...args))),
17915
18081
  onClick: $event => ($options.onRowClick(row, $event)),
17916
18082
  onAuxclick: $event => ($options.onRowAuxClick(row, $event)),
17917
- onContextmenu: vue$1.withModifiers($event => ($options.onRowContextMenu(row, $event)), ["prevent"])
18083
+ onContextmenu: $event => ($options.onRowContextMenu(row, $event))
17918
18084
  }, [
17919
18085
  ($props.selectable)
17920
18086
  ? (vue$1.openBlock(), vue$1.createElementBlock("td", {
@@ -17945,15 +18111,26 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17945
18111
  style: vue$1.normalizeStyle(col.width ? { maxWidth: col.width } : {}),
17946
18112
  onMouseenter: _cache[2] || (_cache[2] = (...args) => ($options.titleWhenClipped && $options.titleWhenClipped(...args)))
17947
18113
  }, [
18114
+ (colIndex === 0 && $options.rowLinks[String(row[$props.rowKey])])
18115
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
18116
+ key: 0,
18117
+ class: "cn-table-row__link",
18118
+ href: $options.rowLinks[String(row[$props.rowKey])].href,
18119
+ "aria-label": $options.rowLinkLabel(row, col),
18120
+ draggable: "false",
18121
+ "data-testid": "cn-row-link",
18122
+ onClick: $event => ($options.onRowLinkClick(row, $event))
18123
+ }, null, 8 /* PROPS */, _hoisted_17$12))
18124
+ : vue$1.createCommentVNode("v-if", true),
17948
18125
  (colIndex === 0)
17949
18126
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnLockIndicator, {
17950
- key: 0,
18127
+ key: 1,
17951
18128
  object: row,
17952
18129
  size: 16
17953
18130
  }, null, 8 /* PROPS */, ["object"]))
17954
18131
  : vue$1.createCommentVNode("v-if", true),
17955
18132
  (colIndex === 0 && $options.indicatorsFor(row).shown.length > 0)
17956
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_17$12, [
18133
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_18$T, [
17957
18134
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.indicatorsFor(row).shown, (indicator) => {
17958
18135
  return (vue$1.openBlock(), vue$1.createElementBlock("span", {
17959
18136
  key: indicator.id || indicator.field,
@@ -17965,8 +18142,8 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
17965
18142
  name: indicator.icon || 'InformationOutline',
17966
18143
  size: 16
17967
18144
  }, null, 8 /* PROPS */, ["name"]),
17968
- vue$1.createElementVNode("span", _hoisted_19$L, vue$1.toDisplayString(indicator.text), 1 /* TEXT */)
17969
- ], 8 /* PROPS */, _hoisted_18$T))
18145
+ vue$1.createElementVNode("span", _hoisted_20$E, vue$1.toDisplayString(indicator.text), 1 /* TEXT */)
18146
+ ], 8 /* PROPS */, _hoisted_19$L))
17970
18147
  }), 128 /* KEYED_FRAGMENT */))
17971
18148
  ]))
17972
18149
  : vue$1.createCommentVNode("v-if", true),
@@ -18004,7 +18181,7 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
18004
18181
  ], 2 /* CLASS */)
18005
18182
  ], 8 /* PROPS */, _hoisted_5$3W)),
18006
18183
  (_ctx.$slots.footer || ($props.viewAllRoute && $options.totalRowCount > $options.effectiveRows.length))
18007
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_20$E, [
18184
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_21$C, [
18008
18185
  vue$1.renderSlot(_ctx.$slots, "footer", {
18009
18186
  total: $options.totalRowCount,
18010
18187
  shown: $options.effectiveRows.length
@@ -18015,7 +18192,7 @@ function render$5_(_ctx, _cache, $props, $setup, $data, $options) {
18015
18192
  class: "cn-data-table__view-all",
18016
18193
  href: $options.viewAllHref,
18017
18194
  onClick: _cache[6] || (_cache[6] = (...args) => ($options.onViewAll && $options.onViewAll(...args)))
18018
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_21$C))
18195
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_22$z))
18019
18196
  : (vue$1.openBlock(), vue$1.createElementBlock("button", {
18020
18197
  key: 1,
18021
18198
  type: "button",
@@ -51199,12 +51376,12 @@ const _hoisted_22$y = {
51199
51376
  class: "cn-icon-browser-panel__error",
51200
51377
  role: "alert"
51201
51378
  };
51202
- const _hoisted_23$o = ["placeholder", "aria-label"];
51203
- const _hoisted_24$m = {
51379
+ const _hoisted_23$p = ["placeholder", "aria-label"];
51380
+ const _hoisted_24$n = {
51204
51381
  key: 3,
51205
51382
  class: "cn-icon-browser-panel__grid"
51206
51383
  };
51207
- const _hoisted_25$i = ["title", "aria-label", "onClick"];
51384
+ const _hoisted_25$j = ["title", "aria-label", "onClick"];
51208
51385
  const _hoisted_26$f = ["src", "alt"];
51209
51386
  const _hoisted_27$b = {
51210
51387
  key: 0,
@@ -51395,12 +51572,12 @@ function render$5X(_ctx, _cache, $props, $setup, $data, $options) {
51395
51572
  class: "cn-icon-browser-panel__search",
51396
51573
  placeholder: $options.t('nextcloud-vue', 'Search icons…'),
51397
51574
  "aria-label": $options.t('nextcloud-vue', 'Search icons')
51398
- }, null, 8 /* PROPS */, _hoisted_23$o)), [
51575
+ }, null, 8 /* PROPS */, _hoisted_23$p)), [
51399
51576
  [vue$1.vModelText, $data.customQuery]
51400
51577
  ])
51401
51578
  : vue$1.createCommentVNode("v-if", true),
51402
51579
  ($options.customVisibleIcons.length > 0)
51403
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$m, [
51580
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$n, [
51404
51581
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.customVisibleIcons, (icon) => {
51405
51582
  return (vue$1.openBlock(), vue$1.createElementBlock("button", {
51406
51583
  key: icon.id || icon.url,
@@ -51419,7 +51596,7 @@ function render$5X(_ctx, _cache, $props, $setup, $data, $options) {
51419
51596
  ($props.showLabels)
51420
51597
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_27$b, vue$1.toDisplayString(icon.label), 1 /* TEXT */))
51421
51598
  : vue$1.createCommentVNode("v-if", true)
51422
- ], 10 /* CLASS, PROPS */, _hoisted_25$i))
51599
+ ], 10 /* CLASS, PROPS */, _hoisted_25$j))
51423
51600
  }), 128 /* KEYED_FRAGMENT */))
51424
51601
  ]))
51425
51602
  : vue$1.createCommentVNode("v-if", true),
@@ -61199,9 +61376,9 @@ const _hoisted_19$I = { class: "cn-activity-tab__day-label" };
61199
61376
  const _hoisted_20$B = { class: "cn-activity-tab__day-count" };
61200
61377
  const _hoisted_21$z = { class: "cn-activity-tab__list" };
61201
61378
  const _hoisted_22$w = { class: "cn-activity-tab__subject" };
61202
- const _hoisted_23$n = { class: "cn-activity-tab__avatar-wrap" };
61203
- const _hoisted_24$l = { class: "cn-activity-tab__subname" };
61204
- const _hoisted_25$h = { class: "cn-activity-tab__actor" };
61379
+ const _hoisted_23$o = { class: "cn-activity-tab__avatar-wrap" };
61380
+ const _hoisted_24$m = { class: "cn-activity-tab__subname" };
61381
+ const _hoisted_25$i = { class: "cn-activity-tab__actor" };
61205
61382
  const _hoisted_26$e = { class: "cn-activity-tab__time" };
61206
61383
  const _hoisted_27$a = {
61207
61384
  key: 0,
@@ -61318,7 +61495,7 @@ function render$5S(_ctx, _cache, $props, $setup, $data, $options) {
61318
61495
  vue$1.createElementVNode("span", _hoisted_22$w, vue$1.toDisplayString($options.subjectFor(entry)), 1 /* TEXT */)
61319
61496
  ]),
61320
61497
  icon: vue$1.withCtx(() => [
61321
- vue$1.createElementVNode("span", _hoisted_23$n, [
61498
+ vue$1.createElementVNode("span", _hoisted_23$o, [
61322
61499
  vue$1.createVNode(_component_NcAvatar, {
61323
61500
  user: $options.avatarUser(entry),
61324
61501
  displayName: $options.actorFor(entry),
@@ -61335,8 +61512,8 @@ function render$5S(_ctx, _cache, $props, $setup, $data, $options) {
61335
61512
  ])
61336
61513
  ]),
61337
61514
  subname: vue$1.withCtx(() => [
61338
- vue$1.createElementVNode("span", _hoisted_24$l, [
61339
- vue$1.createElementVNode("span", _hoisted_25$h, vue$1.toDisplayString($options.actorFor(entry)), 1 /* TEXT */)
61515
+ vue$1.createElementVNode("span", _hoisted_24$m, [
61516
+ vue$1.createElementVNode("span", _hoisted_25$i, vue$1.toDisplayString($options.actorFor(entry)), 1 /* TEXT */)
61340
61517
  ])
61341
61518
  ]),
61342
61519
  _: 2 /* DYNAMIC */
@@ -61615,8 +61792,9 @@ var script$5R = {
61615
61792
  return `cn-analytics-card__badge--type-${type ?? 'unknown'}`
61616
61793
  },
61617
61794
 
61795
+ // A provider URL is used only when it is a safe scheme; else the app link.
61618
61796
  reportUrl(report) {
61619
- if (report && report.url) {
61797
+ if (report && report.url && safeHref(report.url) !== '#') {
61620
61798
  return report.url
61621
61799
  }
61622
61800
  const id = this.reportKey(report);
@@ -62507,8 +62685,9 @@ var script$5O = {
62507
62685
  return l10n.translate('nextcloud-vue', 'Latest value')
62508
62686
  },
62509
62687
 
62688
+ // A provider URL is used only when it is a safe scheme; else the app link.
62510
62689
  reportUrl(report) {
62511
- if (report && report.url) {
62690
+ if (report && report.url && safeHref(report.url) !== '#') {
62512
62691
  return report.url
62513
62692
  }
62514
62693
  const id = this.reportKey(report);
@@ -62740,8 +62919,7 @@ function render$5O(_ctx, _cache, $props, $setup, $data, $options) {
62740
62919
  vue$1.createVNode(_component_NcButton, {
62741
62920
  variant: "primary",
62742
62921
  href: $props.analyticsAppUrl,
62743
- target: "_blank",
62744
- rel: "noopener noreferrer"
62922
+ target: "_blank"
62745
62923
  }, {
62746
62924
  icon: vue$1.withCtx(() => [
62747
62925
  vue$1.createVNode(_component_ChartBar, { size: 20 })
@@ -62788,8 +62966,7 @@ function render$5O(_ctx, _cache, $props, $setup, $data, $options) {
62788
62966
  vue$1.createVNode(_component_NcActionLink, {
62789
62967
  closeAfterClick: true,
62790
62968
  href: $options.reportUrl(report),
62791
- target: "_blank",
62792
- rel: "noopener noreferrer"
62969
+ target: "_blank"
62793
62970
  }, {
62794
62971
  icon: vue$1.withCtx(() => [
62795
62972
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -63673,6 +63850,11 @@ var script$5L = {
63673
63850
  return bookmark.title || bookmark.url || ''
63674
63851
  },
63675
63852
 
63853
+ // Bookmark URLs are user-entered (bookmarklets are `javascript:`), so only a safe one is a link.
63854
+ hasSafeUrl(bookmark) {
63855
+ return safeHref(bookmark.url) !== '#'
63856
+ },
63857
+
63676
63858
  chipSubtitle(bookmark) {
63677
63859
  return bookmark.description || bookmark.url || this.bookmarkTitle(bookmark)
63678
63860
  },
@@ -63758,55 +63940,61 @@ var script$5L = {
63758
63940
  const _hoisted_1$5w = ["title"];
63759
63941
  const _hoisted_2$5h = ["src"];
63760
63942
  const _hoisted_3$4J = ["href"];
63761
- const _hoisted_4$4h = {
63943
+ const _hoisted_4$4h = { key: 3 };
63944
+ const _hoisted_5$3L = {
63762
63945
  key: 1,
63763
63946
  class: "cn-bookmarks-card__empty"
63764
63947
  };
63765
- const _hoisted_5$3L = {
63948
+ const _hoisted_6$3t = {
63766
63949
  key: 0,
63767
63950
  class: "cn-bookmarks-card__empty"
63768
63951
  };
63769
- const _hoisted_6$3t = {
63952
+ const _hoisted_7$34 = {
63770
63953
  key: 1,
63771
63954
  class: "cn-bookmarks-card__empty"
63772
63955
  };
63773
- const _hoisted_7$34 = {
63956
+ const _hoisted_8$2J = {
63774
63957
  key: 2,
63775
63958
  class: "cn-bookmarks-card__headline"
63776
63959
  };
63777
- const _hoisted_8$2J = { class: "cn-bookmarks-card__headline-line" };
63778
- const _hoisted_9$2v = {
63960
+ const _hoisted_9$2v = { class: "cn-bookmarks-card__headline-line" };
63961
+ const _hoisted_10$2c = {
63779
63962
  key: 0,
63780
63963
  class: "cn-bookmarks-card__headline-recent"
63781
63964
  };
63782
- const _hoisted_10$2c = ["src"];
63783
- const _hoisted_11$1T = ["href"];
63784
- const _hoisted_12$1I = {
63965
+ const _hoisted_11$1T = ["src"];
63966
+ const _hoisted_12$1I = ["href"];
63967
+ const _hoisted_13$1A = { key: 3 };
63968
+ const _hoisted_14$1r = {
63785
63969
  key: 1,
63786
63970
  class: "cn-bookmarks-card__view-all"
63787
63971
  };
63788
- const _hoisted_13$1A = ["href"];
63789
- const _hoisted_14$1r = {
63972
+ const _hoisted_15$1g = ["href"];
63973
+ const _hoisted_16$15 = {
63790
63974
  key: 0,
63791
63975
  class: "cn-bookmarks-card__empty"
63792
63976
  };
63793
- const _hoisted_15$1g = {
63977
+ const _hoisted_17$Y = {
63794
63978
  key: 1,
63795
63979
  class: "cn-bookmarks-card__empty"
63796
63980
  };
63797
- const _hoisted_16$15 = {
63981
+ const _hoisted_18$N = {
63798
63982
  key: 2,
63799
63983
  class: "cn-bookmarks-card__list"
63800
63984
  };
63801
- const _hoisted_17$Y = { class: "cn-bookmarks-card__row-icon" };
63802
- const _hoisted_18$N = ["src", "onError"];
63803
- const _hoisted_19$F = { class: "cn-bookmarks-card__row-main" };
63804
- const _hoisted_20$z = ["href"];
63805
- const _hoisted_21$x = {
63985
+ const _hoisted_19$F = { class: "cn-bookmarks-card__row-icon" };
63986
+ const _hoisted_20$z = ["src", "onError"];
63987
+ const _hoisted_21$x = { class: "cn-bookmarks-card__row-main" };
63988
+ const _hoisted_22$v = ["href"];
63989
+ const _hoisted_23$n = {
63990
+ key: 1,
63991
+ class: "cn-bookmarks-card__title"
63992
+ };
63993
+ const _hoisted_24$l = {
63806
63994
  key: 3,
63807
63995
  class: "cn-bookmarks-card__view-all"
63808
63996
  };
63809
- const _hoisted_22$v = ["href"];
63997
+ const _hoisted_25$h = ["href"];
63810
63998
 
63811
63999
  function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63812
64000
  const _component_NcLoadingIcon = vue$1.resolveComponent("NcLoadingIcon");
@@ -63841,26 +64029,29 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63841
64029
  key: 1,
63842
64030
  size: 14
63843
64031
  })),
63844
- vue$1.createElementVNode("a", {
63845
- href: $data.entity.url,
63846
- target: "_blank",
63847
- rel: "noopener noreferrer"
63848
- }, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 9 /* TEXT, PROPS */, _hoisted_3$4J)
64032
+ ($options.hasSafeUrl($data.entity))
64033
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64034
+ key: 2,
64035
+ href: $data.entity.url,
64036
+ target: "_blank",
64037
+ rel: "noopener noreferrer"
64038
+ }, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 9 /* TEXT, PROPS */, _hoisted_3$4J))
64039
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_4$4h, vue$1.toDisplayString($options.bookmarkTitle($data.entity)), 1 /* TEXT */))
63849
64040
  ], 8 /* PROPS */, _hoisted_1$5w))
63850
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_4$4h, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64041
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_5$3L, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63851
64042
  ], 64 /* STABLE_FRAGMENT */))
63852
64043
  : ($props.surface === 'user-dashboard' || $props.surface === 'app-dashboard')
63853
64044
  ? (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 2 }, [
63854
64045
  ($data.degraded)
63855
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_5$3L, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
64046
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$3t, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
63856
64047
  : ($data.bookmarks.length === 0)
63857
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$3t, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63858
- : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$34, [
63859
- vue$1.createElementVNode("div", _hoisted_8$2J, [
64048
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$34, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64049
+ : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$2J, [
64050
+ vue$1.createElementVNode("div", _hoisted_9$2v, [
63860
64051
  vue$1.createElementVNode("strong", null, vue$1.toDisplayString($options.countHeadline), 1 /* TEXT */)
63861
64052
  ]),
63862
64053
  ($options.mostRecent)
63863
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_9$2v, [
64054
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_10$2c, [
63864
64055
  ($options.faviconUrl($options.mostRecent))
63865
64056
  ? (vue$1.openBlock(), vue$1.createElementBlock("img", {
63866
64057
  key: 0,
@@ -63868,41 +64059,44 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63868
64059
  alt: "",
63869
64060
  class: "cn-bookmarks-card__favicon",
63870
64061
  onError: _cache[1] || (_cache[1] = $event => ($options.onFaviconError($options.mostRecent)))
63871
- }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_10$2c))
64062
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_11$1T))
63872
64063
  : (vue$1.openBlock(), vue$1.createBlock(_component_Bookmark, {
63873
64064
  key: 1,
63874
64065
  size: 14
63875
64066
  })),
63876
- vue$1.createElementVNode("a", {
63877
- href: $options.mostRecent.url,
63878
- target: "_blank",
63879
- rel: "noopener noreferrer"
63880
- }, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 9 /* TEXT, PROPS */, _hoisted_11$1T)
64067
+ ($options.hasSafeUrl($options.mostRecent))
64068
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64069
+ key: 2,
64070
+ href: $options.mostRecent.url,
64071
+ target: "_blank",
64072
+ rel: "noopener noreferrer"
64073
+ }, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 9 /* TEXT, PROPS */, _hoisted_12$1I))
64074
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_13$1A, vue$1.toDisplayString($options.bookmarkTitle($options.mostRecent)), 1 /* TEXT */))
63881
64075
  ]))
63882
64076
  : vue$1.createCommentVNode("v-if", true),
63883
64077
  ($data.bookmarks.length > 1)
63884
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_12$1I, [
64078
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_14$1r, [
63885
64079
  vue$1.createElementVNode("a", {
63886
64080
  href: $props.bookmarksAppUrl,
63887
64081
  target: "_blank",
63888
64082
  rel: "noopener noreferrer"
63889
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_13$1A)
64083
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_15$1g)
63890
64084
  ]))
63891
64085
  : vue$1.createCommentVNode("v-if", true)
63892
64086
  ]))
63893
64087
  ], 64 /* STABLE_FRAGMENT */))
63894
64088
  : (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 3 }, [
63895
64089
  ($data.degraded)
63896
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_14$1r, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
64090
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_16$15, vue$1.toDisplayString($data.degraded), 1 /* TEXT */))
63897
64091
  : ($data.bookmarks.length === 0)
63898
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_15$1g, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
63899
- : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_16$15, [
64092
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_17$Y, vue$1.toDisplayString($props.emptyLabel), 1 /* TEXT */))
64093
+ : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_18$N, [
63900
64094
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.displayedBookmarks, (bookmark) => {
63901
64095
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
63902
64096
  key: $options.bookmarkKey(bookmark),
63903
64097
  class: "cn-bookmarks-card__row"
63904
64098
  }, [
63905
- vue$1.createElementVNode("div", _hoisted_17$Y, [
64099
+ vue$1.createElementVNode("div", _hoisted_19$F, [
63906
64100
  ($options.faviconUrl(bookmark))
63907
64101
  ? (vue$1.openBlock(), vue$1.createElementBlock("img", {
63908
64102
  key: 0,
@@ -63910,30 +64104,33 @@ function render$5L(_ctx, _cache, $props, $setup, $data, $options) {
63910
64104
  alt: "",
63911
64105
  class: "cn-bookmarks-card__favicon",
63912
64106
  onError: $event => ($options.onFaviconError(bookmark))
63913
- }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_18$N))
64107
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_20$z))
63914
64108
  : (vue$1.openBlock(), vue$1.createBlock(_component_Bookmark, {
63915
64109
  key: 1,
63916
64110
  size: 14
63917
64111
  }))
63918
64112
  ]),
63919
- vue$1.createElementVNode("div", _hoisted_19$F, [
63920
- vue$1.createElementVNode("a", {
63921
- href: bookmark.url,
63922
- target: "_blank",
63923
- rel: "noopener noreferrer",
63924
- class: "cn-bookmarks-card__title"
63925
- }, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 9 /* TEXT, PROPS */, _hoisted_20$z)
64113
+ vue$1.createElementVNode("div", _hoisted_21$x, [
64114
+ ($options.hasSafeUrl(bookmark))
64115
+ ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
64116
+ key: 0,
64117
+ href: bookmark.url,
64118
+ target: "_blank",
64119
+ rel: "noopener noreferrer",
64120
+ class: "cn-bookmarks-card__title"
64121
+ }, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 9 /* TEXT, PROPS */, _hoisted_22$v))
64122
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_23$n, vue$1.toDisplayString($options.bookmarkTitle(bookmark)), 1 /* TEXT */))
63926
64123
  ])
63927
64124
  ]))
63928
64125
  }), 128 /* KEYED_FRAGMENT */))
63929
64126
  ])),
63930
64127
  ($data.bookmarks.length > $data.COMPACT_LIMIT)
63931
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_21$x, [
64128
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_24$l, [
63932
64129
  vue$1.createElementVNode("a", {
63933
64130
  href: $props.bookmarksAppUrl,
63934
64131
  target: "_blank",
63935
64132
  rel: "noopener noreferrer"
63936
- }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_22$v)
64133
+ }, vue$1.toDisplayString($props.viewAllLabel), 9 /* TEXT, PROPS */, _hoisted_25$h)
63937
64134
  ]))
63938
64135
  : vue$1.createCommentVNode("v-if", true)
63939
64136
  ], 64 /* STABLE_FRAGMENT */))
@@ -64643,6 +64840,23 @@ var script$5I = {
64643
64840
  return safeHref(bookmark.url)
64644
64841
  },
64645
64842
 
64843
+ /**
64844
+ * Whether the bookmark's URL passed `safeHref`, so its row is a link.
64845
+ *
64846
+ * @param {object} bookmark The bookmark row.
64847
+ * @return {boolean}
64848
+ */
64849
+ hasSafeUrl(bookmark) {
64850
+ return this.bookmarkHref(bookmark) !== '#'
64851
+ },
64852
+
64853
+ // NcListItem always renders an anchor; one without a safe URL must not follow `#`.
64854
+ onBookmarkClick(bookmark, event) {
64855
+ if (!this.hasSafeUrl(bookmark)) {
64856
+ event?.preventDefault?.();
64857
+ }
64858
+ },
64859
+
64646
64860
  bookmarkTags(bookmark) {
64647
64861
  const tags = bookmark.tags;
64648
64862
  if (!Array.isArray(tags)) {
@@ -64785,8 +64999,7 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64785
64999
  vue$1.createVNode(_component_NcButton, {
64786
65000
  variant: "primary",
64787
65001
  href: $props.bookmarksAppUrl,
64788
- target: "_blank",
64789
- rel: "noopener noreferrer"
65002
+ target: "_blank"
64790
65003
  }, {
64791
65004
  icon: vue$1.withCtx(() => [
64792
65005
  vue$1.createVNode(_component_Bookmark, { size: 20 })
@@ -64826,8 +65039,9 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64826
65039
  name: $options.bookmarkTitle(bookmark),
64827
65040
  bold: true,
64828
65041
  href: $options.bookmarkHref(bookmark),
64829
- target: "_blank",
64830
- forceDisplayActions: true
65042
+ target: $options.hasSafeUrl(bookmark) ? '_blank' : undefined,
65043
+ forceDisplayActions: true,
65044
+ onClick: $event => ($options.onBookmarkClick(bookmark, $event))
64831
65045
  }, {
64832
65046
  icon: vue$1.withCtx(() => [
64833
65047
  vue$1.createElementVNode("span", _hoisted_10$2a, [
@@ -64865,20 +65079,22 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64865
65079
  : vue$1.createCommentVNode("v-if", true)
64866
65080
  ]),
64867
65081
  actions: vue$1.withCtx(() => [
64868
- vue$1.createVNode(_component_NcActionLink, {
64869
- closeAfterClick: true,
64870
- href: $options.bookmarkHref(bookmark),
64871
- target: "_blank",
64872
- rel: "noopener noreferrer"
64873
- }, {
64874
- icon: vue$1.withCtx(() => [
64875
- vue$1.createVNode(_component_OpenInNew, { size: 20 })
64876
- ]),
64877
- default: vue$1.withCtx(() => [
64878
- vue$1.createTextVNode(" " + vue$1.toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
64879
- ]),
64880
- _: 1 /* STABLE */
64881
- }, 8 /* PROPS */, ["href"]),
65082
+ ($options.hasSafeUrl(bookmark))
65083
+ ? (vue$1.openBlock(), vue$1.createBlock(_component_NcActionLink, {
65084
+ key: 0,
65085
+ closeAfterClick: true,
65086
+ href: $options.bookmarkHref(bookmark),
65087
+ target: "_blank"
65088
+ }, {
65089
+ icon: vue$1.withCtx(() => [
65090
+ vue$1.createVNode(_component_OpenInNew, { size: 20 })
65091
+ ]),
65092
+ default: vue$1.withCtx(() => [
65093
+ vue$1.createTextVNode(" " + vue$1.toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
65094
+ ]),
65095
+ _: 1 /* STABLE */
65096
+ }, 8 /* PROPS */, ["href"]))
65097
+ : vue$1.createCommentVNode("v-if", true),
64882
65098
  vue$1.createVNode(_component_NcActionButton, {
64883
65099
  closeAfterClick: true,
64884
65100
  onClick: $event => ($options.unlinkBookmark(bookmark))
@@ -64893,7 +65109,7 @@ function render$5I(_ctx, _cache, $props, $setup, $data, $options) {
64893
65109
  }, 8 /* PROPS */, ["onClick"])
64894
65110
  ]),
64895
65111
  _: 2 /* DYNAMIC */
64896
- }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href"]))
65112
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href", "target", "onClick"]))
64897
65113
  }), 128 /* KEYED_FRAGMENT */))
64898
65114
  ])
64899
65115
  ])),
@@ -66968,8 +67184,9 @@ var script$5D = {
66968
67184
  return typeof emoji === 'string' ? emoji.trim() : ''
66969
67185
  },
66970
67186
 
67187
+ // A provider URL is used only when it is a safe scheme; else the app link.
66971
67188
  pageUrl(page) {
66972
- if (typeof page.url === 'string' && page.url !== '') {
67189
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
66973
67190
  return page.url
66974
67191
  }
66975
67192
  const d = this.dataOf(page);
@@ -67922,8 +68139,9 @@ var script$5A = {
67922
68139
  return text
67923
68140
  },
67924
68141
 
68142
+ // A provider URL is used only when it is a safe scheme; else the app link.
67925
68143
  pageUrl(page) {
67926
- if (typeof page.url === 'string' && page.url !== '') {
68144
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
67927
68145
  return page.url
67928
68146
  }
67929
68147
  const d = this.dataOf(page);
@@ -68205,8 +68423,7 @@ function render$5A(_ctx, _cache, $props, $setup, $data, $options) {
68205
68423
  vue$1.createVNode(_component_NcButton, {
68206
68424
  variant: "primary",
68207
68425
  href: $props.collectivesAppUrl,
68208
- target: "_blank",
68209
- rel: "noopener noreferrer"
68426
+ target: "_blank"
68210
68427
  }, {
68211
68428
  icon: vue$1.withCtx(() => [
68212
68429
  vue$1.createVNode(_component_BookOpenPageVariant, { size: 20 })
@@ -68267,8 +68484,7 @@ function render$5A(_ctx, _cache, $props, $setup, $data, $options) {
68267
68484
  vue$1.createVNode(_component_NcActionLink, {
68268
68485
  closeAfterClick: true,
68269
68486
  href: $options.pageUrl(page),
68270
- target: "_blank",
68271
- rel: "noopener noreferrer"
68487
+ target: "_blank"
68272
68488
  }, {
68273
68489
  icon: vue$1.withCtx(() => [
68274
68490
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -70733,7 +70949,7 @@ var script$5t = {
70733
70949
  },
70734
70950
 
70735
70951
  rowUrl(row) {
70736
- if (row.url) {
70952
+ if (row.url && safeHref(row.url) !== '#') {
70737
70953
  return row.url
70738
70954
  }
70739
70955
  const projectId = row.projectId ?? row.project_id ?? row.data?.projectid ?? row.data?.project_id ?? null;
@@ -71606,7 +71822,7 @@ var script$5q = {
71606
71822
  },
71607
71823
 
71608
71824
  rowUrl(row) {
71609
- if (row.url) {
71825
+ if (row.url && safeHref(row.url) !== '#') {
71610
71826
  return row.url
71611
71827
  }
71612
71828
  const projectId = row.projectId ?? row.project_id ?? row.data?.projectid ?? row.data?.project_id ?? null;
@@ -71880,8 +72096,7 @@ function render$5q(_ctx, _cache, $props, $setup, $data, $options) {
71880
72096
  vue$1.createVNode(_component_NcButton, {
71881
72097
  variant: "primary",
71882
72098
  href: $props.cospendAppUrl,
71883
- target: "_blank",
71884
- rel: "noopener noreferrer"
72099
+ target: "_blank"
71885
72100
  }, {
71886
72101
  icon: vue$1.withCtx(() => [
71887
72102
  vue$1.createVNode(_component_CurrencyEur, { size: 20 })
@@ -72219,7 +72434,7 @@ var script$5p = {
72219
72434
  },
72220
72435
 
72221
72436
  cardUrl(card) {
72222
- if (card.url) {
72437
+ if (card.url && safeHref(card.url) !== '#') {
72223
72438
  return card.url
72224
72439
  }
72225
72440
  const boardId = card.boardId ?? card.board?.id ?? '';
@@ -73282,7 +73497,7 @@ var script$5m = {
73282
73497
  },
73283
73498
 
73284
73499
  cardUrl(card) {
73285
- if (card.url) {
73500
+ if (card.url && safeHref(card.url) !== '#') {
73286
73501
  return card.url
73287
73502
  }
73288
73503
  const boardId = card.boardId ?? card.board?.id ?? '';
@@ -73601,8 +73816,7 @@ function render$5m(_ctx, _cache, $props, $setup, $data, $options) {
73601
73816
  vue$1.createVNode(_component_NcButton, {
73602
73817
  variant: "primary",
73603
73818
  href: $props.deckAppUrl,
73604
- target: "_blank",
73605
- rel: "noopener noreferrer"
73819
+ target: "_blank"
73606
73820
  }, {
73607
73821
  icon: vue$1.withCtx(() => [
73608
73822
  vue$1.createVNode(_component_ViewColumnOutline, { size: 20 })
@@ -74988,8 +75202,7 @@ function render$5j(_ctx, _cache, $props, $setup, $data, $options) {
74988
75202
  vue$1.createVNode(_component_NcButton, {
74989
75203
  variant: "primary",
74990
75204
  href: $options.composeUrl,
74991
- target: "_blank",
74992
- rel: "noopener noreferrer"
75205
+ target: "_blank"
74993
75206
  }, {
74994
75207
  icon: vue$1.withCtx(() => [
74995
75208
  vue$1.createVNode(_component_EmailEditOutline, { size: 18 })
@@ -79140,6 +79353,8 @@ var script$5e = {
79140
79353
  methods: {
79141
79354
  t: l10n.translate,
79142
79355
 
79356
+ preventMiddleClickAutoscroll,
79357
+
79143
79358
  /**
79144
79359
  * Hold the file input element from its function ref.
79145
79360
  *
@@ -79984,10 +80199,10 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
79984
80199
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
79985
80200
  class: vue$1.normalizeClass(["cn-files-browser", { 'cn-files-browser--dragging': $data.dragging }]),
79986
80201
  "data-testid": "cn-files-browser",
79987
- onDragenter: _cache[14] || (_cache[14] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
79988
- onDragover: _cache[15] || (_cache[15] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
79989
- onDragleave: _cache[16] || (_cache[16] = vue$1.withModifiers($event => ($data.dragging = false), ["prevent"])),
79990
- onDrop: _cache[17] || (_cache[17] = vue$1.withModifiers((...args) => ($options.onDrop && $options.onDrop(...args)), ["prevent"]))
80202
+ onDragenter: _cache[16] || (_cache[16] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
80203
+ onDragover: _cache[17] || (_cache[17] = vue$1.withModifiers($event => ($data.dragging = true), ["prevent"])),
80204
+ onDragleave: _cache[18] || (_cache[18] = vue$1.withModifiers($event => ($data.dragging = false), ["prevent"])),
80205
+ onDrop: _cache[19] || (_cache[19] = vue$1.withModifiers((...args) => ($options.onDrop && $options.onDrop(...args)), ["prevent"]))
79991
80206
  }, [
79992
80207
  vue$1.createElementVNode("div", _hoisted_1$53, [
79993
80208
  vue$1.createVNode(_component_NcBreadcrumbs, { class: "cn-files-browser__crumbs" }, {
@@ -80221,6 +80436,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80221
80436
  "data-testid": "cn-files-browser-row",
80222
80437
  "data-name": node.basename,
80223
80438
  onClick: $event => ($options.onRowClick(node, $event)),
80439
+ onMousedown: _cache[3] || (_cache[3] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
80224
80440
  onAuxclick: $event => ($options.onRowAuxClick(node, $event))
80225
80441
  }, [
80226
80442
  vue$1.createElementVNode("td", _hoisted_14$1b, [
@@ -80348,7 +80564,6 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80348
80564
  key: 2,
80349
80565
  href: $options.permalink(node),
80350
80566
  target: "_blank",
80351
- rel: "noopener noreferrer",
80352
80567
  closeAfterClick: true
80353
80568
  }, {
80354
80569
  icon: vue$1.withCtx(() => [
@@ -80373,6 +80588,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80373
80588
  "data-testid": "cn-files-browser-linked-row",
80374
80589
  "data-name": item.name,
80375
80590
  onClick: $event => ($options.openLinked(item)),
80591
+ onMousedown: _cache[7] || (_cache[7] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
80376
80592
  onAuxclick: $event => ($options.onLinkedAuxClick(item, $event))
80377
80593
  }, [
80378
80594
  vue$1.createElementVNode("td", _hoisted_20$t, [
@@ -80403,7 +80619,7 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80403
80619
  key: 0,
80404
80620
  href: item.noteHref,
80405
80621
  class: "cn-files-browser__note-link",
80406
- onClick: _cache[3] || (_cache[3] = vue$1.withModifiers(() => {}, ["stop"]))
80622
+ onClick: _cache[4] || (_cache[4] = vue$1.withModifiers(() => {}, ["stop"]))
80407
80623
  }, vue$1.toDisplayString(item.note), 9 /* TEXT, PROPS */, _hoisted_24$i))
80408
80624
  : (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 1 }, [
80409
80625
  vue$1.createTextVNode(vue$1.toDisplayString(item.note), 1 /* TEXT */)
@@ -80426,8 +80642,8 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80426
80642
  }), 128 /* KEYED_FRAGMENT */)),
80427
80643
  vue$1.createElementVNode("td", {
80428
80644
  class: "cn-files-browser__col-actions",
80429
- onClick: _cache[4] || (_cache[4] = vue$1.withModifiers(() => {}, ["stop"])),
80430
- onAuxclick: _cache[5] || (_cache[5] = vue$1.withModifiers(() => {}, ["stop"]))
80645
+ onClick: _cache[5] || (_cache[5] = vue$1.withModifiers(() => {}, ["stop"])),
80646
+ onAuxclick: _cache[6] || (_cache[6] = vue$1.withModifiers(() => {}, ["stop"]))
80431
80647
  }, [
80432
80648
  vue$1.createVNode(_component_NcActions, {
80433
80649
  forceMenu: true,
@@ -80439,7 +80655,6 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80439
80655
  key: 0,
80440
80656
  href: item.href,
80441
80657
  target: "_blank",
80442
- rel: "noopener noreferrer",
80443
80658
  closeAfterClick: true,
80444
80659
  "data-testid": "cn-files-browser-linked-open"
80445
80660
  }, {
@@ -80483,11 +80698,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80483
80698
  name: $props.renameLabel,
80484
80699
  size: "small",
80485
80700
  "data-testid": "cn-files-browser-rename",
80486
- onClosing: _cache[9] || (_cache[9] = $event => ($data.renaming = null))
80701
+ onClosing: _cache[11] || (_cache[11] = $event => ($data.renaming = null))
80487
80702
  }, {
80488
80703
  actions: vue$1.withCtx(() => [
80489
80704
  vue$1.createVNode(_component_NcButton, {
80490
- onClick: _cache[8] || (_cache[8] = $event => ($data.renaming = null))
80705
+ onClick: _cache[10] || (_cache[10] = $event => ($data.renaming = null))
80491
80706
  }, {
80492
80707
  default: vue$1.withCtx(() => [
80493
80708
  vue$1.createTextVNode(vue$1.toDisplayString($options.t('nextcloud-vue', 'Cancel')), 1 /* TEXT */)
@@ -80509,11 +80724,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80509
80724
  default: vue$1.withCtx(() => [
80510
80725
  vue$1.createElementVNode("form", {
80511
80726
  class: "cn-files-browser__new-folder",
80512
- onSubmit: _cache[7] || (_cache[7] = vue$1.withModifiers((...args) => ($options.rename && $options.rename(...args)), ["prevent"]))
80727
+ onSubmit: _cache[9] || (_cache[9] = vue$1.withModifiers((...args) => ($options.rename && $options.rename(...args)), ["prevent"]))
80513
80728
  }, [
80514
80729
  vue$1.createVNode(_component_NcTextField, {
80515
80730
  modelValue: $data.renameName,
80516
- "onUpdate:modelValue": _cache[6] || (_cache[6] = $event => (($data.renameName) = $event)),
80731
+ "onUpdate:modelValue": _cache[8] || (_cache[8] = $event => (($data.renameName) = $event)),
80517
80732
  label: $options.t('nextcloud-vue', 'New name'),
80518
80733
  error: $data.renameError !== '',
80519
80734
  helperText: $data.renameError,
@@ -80530,11 +80745,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80530
80745
  name: $props.newFolderLabel,
80531
80746
  size: "small",
80532
80747
  "data-testid": "cn-files-browser-new-folder",
80533
- onClosing: _cache[13] || (_cache[13] = $event => ($data.newFolderOpen = false))
80748
+ onClosing: _cache[15] || (_cache[15] = $event => ($data.newFolderOpen = false))
80534
80749
  }, {
80535
80750
  actions: vue$1.withCtx(() => [
80536
80751
  vue$1.createVNode(_component_NcButton, {
80537
- onClick: _cache[12] || (_cache[12] = $event => ($data.newFolderOpen = false))
80752
+ onClick: _cache[14] || (_cache[14] = $event => ($data.newFolderOpen = false))
80538
80753
  }, {
80539
80754
  default: vue$1.withCtx(() => [
80540
80755
  vue$1.createTextVNode(vue$1.toDisplayString($options.t('nextcloud-vue', 'Cancel')), 1 /* TEXT */)
@@ -80556,11 +80771,11 @@ function render$5e(_ctx, _cache, $props, $setup, $data, $options) {
80556
80771
  default: vue$1.withCtx(() => [
80557
80772
  vue$1.createElementVNode("form", {
80558
80773
  class: "cn-files-browser__new-folder",
80559
- onSubmit: _cache[11] || (_cache[11] = vue$1.withModifiers((...args) => ($options.createFolder && $options.createFolder(...args)), ["prevent"]))
80774
+ onSubmit: _cache[13] || (_cache[13] = vue$1.withModifiers((...args) => ($options.createFolder && $options.createFolder(...args)), ["prevent"]))
80560
80775
  }, [
80561
80776
  vue$1.createVNode(_component_NcTextField, {
80562
80777
  modelValue: $data.newFolderName,
80563
- "onUpdate:modelValue": _cache[10] || (_cache[10] = $event => (($data.newFolderName) = $event)),
80778
+ "onUpdate:modelValue": _cache[12] || (_cache[12] = $event => (($data.newFolderName) = $event)),
80564
80779
  label: $options.t('nextcloud-vue', 'Folder name'),
80565
80780
  error: $data.newFolderError !== '',
80566
80781
  helperText: $data.newFolderError,
@@ -81378,7 +81593,6 @@ function render$5d(_ctx, _cache, $props, $setup, $data, $options) {
81378
81593
  key: 2,
81379
81594
  href: $options.showInFilesUrl(file),
81380
81595
  target: "_blank",
81381
- rel: "noopener noreferrer",
81382
81596
  closeAfterClick: true
81383
81597
  }, {
81384
81598
  icon: vue$1.withCtx(() => [
@@ -81623,7 +81837,7 @@ var script$5c = {
81623
81837
  },
81624
81838
 
81625
81839
  opUrl(op) {
81626
- return op.url || this.flowSettingsUrl
81840
+ return op.url && safeHref(op.url) !== '#' ? op.url : this.flowSettingsUrl
81627
81841
  },
81628
81842
 
81629
81843
  shortClass(className) {
@@ -82290,7 +82504,7 @@ var script$5a = {
82290
82504
  },
82291
82505
 
82292
82506
  opUrl(op) {
82293
- return op.url || this.flowSettingsUrl
82507
+ return op.url && safeHref(op.url) !== '#' ? op.url : this.flowSettingsUrl
82294
82508
  },
82295
82509
 
82296
82510
  shortClass(className) {
@@ -82576,8 +82790,7 @@ function render$5a(_ctx, _cache, $props, $setup, $data, $options) {
82576
82790
  vue$1.createVNode(_component_NcButton, {
82577
82791
  variant: "primary",
82578
82792
  href: $props.flowSettingsUrl,
82579
- target: "_blank",
82580
- rel: "noopener noreferrer"
82793
+ target: "_blank"
82581
82794
  }, {
82582
82795
  icon: vue$1.withCtx(() => [
82583
82796
  vue$1.createVNode(_component_SitemapOutline, { size: 20 })
@@ -82929,8 +83142,9 @@ var script$59 = {
82929
83142
  return form.title || form.id || l10n.translate('nextcloud-vue', 'Untitled form')
82930
83143
  },
82931
83144
 
83145
+ // A provider URL is used only when it is a safe scheme; else the app link.
82932
83146
  formUrl(form) {
82933
- if (form.url) {
83147
+ if (form.url && safeHref(form.url) !== '#') {
82934
83148
  return form.url
82935
83149
  }
82936
83150
  if (form.hash) {
@@ -83970,8 +84184,9 @@ var script$56 = {
83970
84184
  return form.description || ''
83971
84185
  },
83972
84186
 
84187
+ // A provider URL is used only when it is a safe scheme; else the app link.
83973
84188
  formUrl(form) {
83974
- if (form.url) {
84189
+ if (form.url && safeHref(form.url) !== '#') {
83975
84190
  return form.url
83976
84191
  }
83977
84192
  if (form.hash) {
@@ -84280,8 +84495,7 @@ function render$56(_ctx, _cache, $props, $setup, $data, $options) {
84280
84495
  vue$1.createVNode(_component_NcButton, {
84281
84496
  variant: "primary",
84282
84497
  href: $props.formsAppUrl,
84283
- target: "_blank",
84284
- rel: "noopener noreferrer"
84498
+ target: "_blank"
84285
84499
  }, {
84286
84500
  icon: vue$1.withCtx(() => [
84287
84501
  vue$1.createVNode(_component_ClipboardText, { size: 20 })
@@ -84331,8 +84545,7 @@ function render$56(_ctx, _cache, $props, $setup, $data, $options) {
84331
84545
  vue$1.createVNode(_component_NcActionLink, {
84332
84546
  closeAfterClick: true,
84333
84547
  href: $options.formUrl(form),
84334
- target: "_blank",
84335
- rel: "noopener noreferrer"
84548
+ target: "_blank"
84336
84549
  }, {
84337
84550
  icon: vue$1.withCtx(() => [
84338
84551
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -84632,8 +84845,9 @@ var script$55 = {
84632
84845
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
84633
84846
  },
84634
84847
 
84848
+ // A provider URL is used only when it is a safe scheme; else the app link.
84635
84849
  pointUrl(point) {
84636
- if (typeof point.url === 'string' && point.url !== '') {
84850
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
84637
84851
  return point.url
84638
84852
  }
84639
84853
  const lat = this.pointLat(point);
@@ -85549,8 +85763,9 @@ var script$52 = {
85549
85763
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
85550
85764
  },
85551
85765
 
85766
+ // A provider URL is used only when it is a safe scheme; else the app link.
85552
85767
  pointUrl(point) {
85553
- if (typeof point.url === 'string' && point.url !== '') {
85768
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
85554
85769
  return point.url
85555
85770
  }
85556
85771
  if (this.pointHasCoords(point)) {
@@ -85781,8 +85996,7 @@ function render$52(_ctx, _cache, $props, $setup, $data, $options) {
85781
85996
  vue$1.createVNode(_component_NcButton, {
85782
85997
  variant: "primary",
85783
85998
  href: $props.mapsAppUrl,
85784
- target: "_blank",
85785
- rel: "noopener noreferrer"
85999
+ target: "_blank"
85786
86000
  }, {
85787
86001
  icon: vue$1.withCtx(() => [
85788
86002
  vue$1.createVNode(_component_MapMarker, { size: 20 })
@@ -85851,8 +86065,7 @@ function render$52(_ctx, _cache, $props, $setup, $data, $options) {
85851
86065
  vue$1.createVNode(_component_NcActionLink, {
85852
86066
  closeAfterClick: true,
85853
86067
  href: $options.pointUrl(point),
85854
- target: "_blank",
85855
- rel: "noopener noreferrer"
86068
+ target: "_blank"
85856
86069
  }, {
85857
86070
  icon: vue$1.withCtx(() => [
85858
86071
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -88020,7 +88233,8 @@ var script$4Z = {
88020
88233
  },
88021
88234
 
88022
88235
  wpUrl(wp) {
88023
- return wp.url ?? wp._links?.self?.href ?? this.openprojectAppUrl
88236
+ const url = wp.url ?? wp._links?.self?.href;
88237
+ return url && safeHref(url) !== '#' ? url : this.openprojectAppUrl
88024
88238
  },
88025
88239
 
88026
88240
  wpStatus(wp) {
@@ -89250,7 +89464,8 @@ var script$4W = {
89250
89464
  },
89251
89465
 
89252
89466
  wpUrl(wp) {
89253
- return wp.url ?? wp._links?.self?.href ?? this.openprojectAppUrl
89467
+ const url = wp.url ?? wp._links?.self?.href;
89468
+ return url && safeHref(url) !== '#' ? url : this.openprojectAppUrl
89254
89469
  },
89255
89470
 
89256
89471
  wpStatus(wp) {
@@ -89516,8 +89731,7 @@ function render$4W(_ctx, _cache, $props, $setup, $data, $options) {
89516
89731
  vue$1.createVNode(_component_NcButton, {
89517
89732
  variant: "primary",
89518
89733
  href: $props.openconnectorUrl,
89519
- target: "_blank",
89520
- rel: "noopener noreferrer"
89734
+ target: "_blank"
89521
89735
  }, {
89522
89736
  icon: vue$1.withCtx(() => [
89523
89737
  vue$1.createVNode(_component_CogOutline, { size: 20 })
@@ -89540,8 +89754,7 @@ function render$4W(_ctx, _cache, $props, $setup, $data, $options) {
89540
89754
  vue$1.createVNode(_component_NcButton, {
89541
89755
  variant: "secondary",
89542
89756
  href: $props.openprojectAppUrl,
89543
- target: "_blank",
89544
- rel: "noopener noreferrer"
89757
+ target: "_blank"
89545
89758
  }, {
89546
89759
  icon: vue$1.withCtx(() => [
89547
89760
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -89897,7 +90110,7 @@ var script$4V = {
89897
90110
  },
89898
90111
 
89899
90112
  albumUrl(album) {
89900
- if (album && album.url) {
90113
+ if (album && album.url && safeHref(album.url) !== '#') {
89901
90114
  return album.url
89902
90115
  }
89903
90116
  const name = this.albumName(album);
@@ -90680,7 +90893,7 @@ var script$4S = {
90680
90893
  },
90681
90894
 
90682
90895
  albumUrl(album) {
90683
- if (album && album.url) {
90896
+ if (album && album.url && safeHref(album.url) !== '#') {
90684
90897
  return album.url
90685
90898
  }
90686
90899
  const id = this.albumKey(album);
@@ -90943,8 +91156,7 @@ function render$4S(_ctx, _cache, $props, $setup, $data, $options) {
90943
91156
  vue$1.createVNode(_component_NcButton, {
90944
91157
  variant: "primary",
90945
91158
  href: $props.photosAppUrl,
90946
- target: "_blank",
90947
- rel: "noopener noreferrer"
91159
+ target: "_blank"
90948
91160
  }, {
90949
91161
  icon: vue$1.withCtx(() => [
90950
91162
  vue$1.createVNode(_component_ImageIcon, { size: 20 })
@@ -91213,7 +91425,7 @@ var script$4R = {
91213
91425
  },
91214
91426
 
91215
91427
  pollUrl(poll) {
91216
- if (poll.url) {
91428
+ if (poll.url && safeHref(poll.url) !== '#') {
91217
91429
  return poll.url
91218
91430
  }
91219
91431
  const id = poll.id ?? '';
@@ -92289,7 +92501,7 @@ var script$4O = {
92289
92501
  },
92290
92502
 
92291
92503
  pollUrl(poll) {
92292
- if (poll.url) {
92504
+ if (poll.url && safeHref(poll.url) !== '#') {
92293
92505
  return poll.url
92294
92506
  }
92295
92507
  const id = this.pollKey(poll);
@@ -92535,8 +92747,7 @@ function render$4O(_ctx, _cache, $props, $setup, $data, $options) {
92535
92747
  vue$1.createVNode(_component_NcButton, {
92536
92748
  variant: "primary",
92537
92749
  href: $props.pollsAppUrl,
92538
- target: "_blank",
92539
- rel: "noopener noreferrer"
92750
+ target: "_blank"
92540
92751
  }, {
92541
92752
  icon: vue$1.withCtx(() => [
92542
92753
  vue$1.createVNode(_component_Poll, { size: 20 })
@@ -93979,8 +94190,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
93979
94190
  vue$1.createVNode(_component_NcButton, {
93980
94191
  variant: "primary",
93981
94192
  href: $props.filesAppUrl,
93982
- target: "_blank",
93983
- rel: "noopener noreferrer"
94193
+ target: "_blank"
93984
94194
  }, {
93985
94195
  icon: vue$1.withCtx(() => [
93986
94196
  vue$1.createVNode(_component_FolderOutline, { size: 20 })
@@ -94066,8 +94276,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
94066
94276
  vue$1.createVNode(_component_NcActionLink, {
94067
94277
  closeAfterClick: true,
94068
94278
  href: $props.filesAppUrl,
94069
- target: "_blank",
94070
- rel: "noopener noreferrer"
94279
+ target: "_blank"
94071
94280
  }, {
94072
94281
  icon: vue$1.withCtx(() => [
94073
94282
  vue$1.createVNode(_component_FolderOutline, { size: 20 })
@@ -94107,8 +94316,7 @@ function render$4L(_ctx, _cache, $props, $setup, $data, $options) {
94107
94316
  vue$1.createVNode(_component_NcButton, {
94108
94317
  variant: "tertiary",
94109
94318
  href: $props.filesAppUrl,
94110
- target: "_blank",
94111
- rel: "noopener noreferrer"
94319
+ target: "_blank"
94112
94320
  }, {
94113
94321
  icon: vue$1.withCtx(() => [
94114
94322
  vue$1.createVNode(_component_FolderOutline, { size: 18 })
@@ -94745,8 +94953,9 @@ var script$4I = {
94745
94953
  return stripMarker(raw) || String(this.roomKey(room))
94746
94954
  },
94747
94955
 
94956
+ // A provider URL is used only when it is a safe scheme; else the app link.
94748
94957
  roomUrl(room) {
94749
- if (room.url) {
94958
+ if (room.url && safeHref(room.url) !== '#') {
94750
94959
  return room.url
94751
94960
  }
94752
94961
  const token = room.token ?? room.id ?? '';
@@ -95478,8 +95687,9 @@ var script$4F = {
95478
95687
  return stripMarker(raw) || String(this.roomKey(room))
95479
95688
  },
95480
95689
 
95690
+ // A provider URL is used only when it is a safe scheme; else the app link.
95481
95691
  roomUrl(room) {
95482
- if (room.url) {
95692
+ if (room.url && safeHref(room.url) !== '#') {
95483
95693
  return room.url
95484
95694
  }
95485
95695
  const token = room.roomToken ?? room.token ?? room.id ?? '';
@@ -95816,8 +96026,7 @@ function render$4F(_ctx, _cache, $props, $setup, $data, $options) {
95816
96026
  vue$1.createVNode(_component_NcButton, {
95817
96027
  variant: "primary",
95818
96028
  href: $props.talkAppUrl,
95819
- target: "_blank",
95820
- rel: "noopener noreferrer"
96029
+ target: "_blank"
95821
96030
  }, {
95822
96031
  icon: vue$1.withCtx(() => [
95823
96032
  vue$1.createVNode(_component_ChatOutline, { size: 20 })
@@ -95854,8 +96063,7 @@ function render$4F(_ctx, _cache, $props, $setup, $data, $options) {
95854
96063
  vue$1.createVNode(_component_NcActionLink, {
95855
96064
  closeAfterClick: true,
95856
96065
  href: $options.roomUrl(room),
95857
- target: "_blank",
95858
- rel: "noopener noreferrer"
96066
+ target: "_blank"
95859
96067
  }, {
95860
96068
  icon: vue$1.withCtx(() => [
95861
96069
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -97099,7 +97307,7 @@ var script$4C = {
97099
97307
  },
97100
97308
 
97101
97309
  rowUrl(row) {
97102
- if (row.url) {
97310
+ if (row.url && safeHref(row.url) !== '#') {
97103
97311
  return row.url
97104
97312
  }
97105
97313
  const kind = this.rowKind(row);
@@ -97967,7 +98175,7 @@ var script$4z = {
97967
98175
  },
97968
98176
 
97969
98177
  rowUrl(row) {
97970
- if (row.url) {
98178
+ if (row.url && safeHref(row.url) !== '#') {
97971
98179
  return row.url
97972
98180
  }
97973
98181
  const kind = this.rowKind(row);
@@ -98285,8 +98493,7 @@ function render$4z(_ctx, _cache, $props, $setup, $data, $options) {
98285
98493
  vue$1.createVNode(_component_NcButton, {
98286
98494
  variant: "primary",
98287
98495
  href: $props.timeTrackerAppUrl,
98288
- target: "_blank",
98289
- rel: "noopener noreferrer"
98496
+ target: "_blank"
98290
98497
  }, {
98291
98498
  icon: vue$1.withCtx(() => [
98292
98499
  vue$1.createVNode(_component_Clock, { size: 20 })
@@ -99214,8 +99421,10 @@ var script$4x = {
99214
99421
  return String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))
99215
99422
  },
99216
99423
 
99424
+ // An unsafe scheme is treated like a missing URL.
99217
99425
  pageUrl(page) {
99218
- return page.url ?? ''
99426
+ const url = page.url ?? '';
99427
+ return url && safeHref(url) !== '#' ? url : ''
99219
99428
  },
99220
99429
 
99221
99430
  breadcrumbLabel(page) {
@@ -100290,15 +100499,17 @@ var script$4u = {
100290
100499
 
100291
100500
  /**
100292
100501
  * External XWiki deep-link for the page. Empty string when the
100293
- * provider didn't surface a `url`, so the row renders as a plain
100294
- * (non-anchored) NcListItem rather than a dead link.
100502
+ * provider didn't surface a `url`, or surfaced an unsafe scheme, so
100503
+ * the row renders as a plain (non-anchored) NcListItem rather than a
100504
+ * dead link.
100295
100505
  *
100296
100506
  * @param {object} page Provider row.
100297
100507
  *
100298
100508
  * @return {string} Absolute XWiki URL or ''.
100299
100509
  */
100300
100510
  pageHref(page) {
100301
- return String(page.url ?? '')
100511
+ const url = String(page.url ?? '');
100512
+ return url && safeHref(url) !== '#' ? url : ''
100302
100513
  },
100303
100514
 
100304
100515
  breadcrumbLabel(page) {
@@ -100481,14 +100692,13 @@ function render$4u(_ctx, _cache, $props, $setup, $data, $options) {
100481
100692
  class: "cn-xwiki-tab__banner-cta",
100482
100693
  href: $options.banner.ctaHref || undefined,
100483
100694
  target: $options.banner.ctaHref ? '_blank' : undefined,
100484
- rel: $options.banner.ctaHref ? 'noopener noreferrer' : undefined,
100485
100695
  onClick: $options.banner.ctaHandler
100486
100696
  }, {
100487
100697
  default: vue$1.withCtx(() => [
100488
100698
  vue$1.createTextVNode(vue$1.toDisplayString($options.banner.ctaLabel), 1 /* TEXT */)
100489
100699
  ]),
100490
100700
  _: 1 /* STABLE */
100491
- }, 8 /* PROPS */, ["href", "target", "rel", "onClick"]))
100701
+ }, 8 /* PROPS */, ["href", "target", "onClick"]))
100492
100702
  : vue$1.createCommentVNode("v-if", true)
100493
100703
  ], 2 /* CLASS */))
100494
100704
  : vue$1.createCommentVNode("v-if", true),
@@ -100571,8 +100781,7 @@ function render$4u(_ctx, _cache, $props, $setup, $data, $options) {
100571
100781
  class: "cn-xwiki-tab__open",
100572
100782
  closeAfterClick: true,
100573
100783
  href: $options.pageHref(page),
100574
- target: "_blank",
100575
- rel: "noopener noreferrer"
100784
+ target: "_blank"
100576
100785
  }, {
100577
100786
  icon: vue$1.withCtx(() => [
100578
100787
  vue$1.createVNode(_component_OpenInNew, { size: 20 })
@@ -105493,16 +105702,20 @@ var script$4q = {
105493
105702
  /**
105494
105703
  * A link entry was clicked: route a plain in-app click, leave the rest to
105495
105704
  * the browser, and emit `action` as a button would. The `handler` is not
105496
- * called, since navigating is what the link already does.
105705
+ * called, since navigating is what the link already does. A modified
105706
+ * click opens a new tab, so nothing is emitted in this one.
105497
105707
  *
105498
105708
  * @param {object} action The action definition.
105499
105709
  * @param {object} link The resolved link.
105500
105710
  * @param {MouseEvent} event The click event.
105501
105711
  */
105502
105712
  onLinkAction(action, link, event) {
105713
+ if (isModifiedClick(event)) {
105714
+ return
105715
+ }
105503
105716
  followItemActionLink(event, link, this.$router);
105504
105717
  /**
105505
- * @event action User picked an entry. Payload: the action's label and the row. A button entry has already run its `handler`; a link entry navigates instead.
105718
+ * @event action User picked an entry. Payload: the action's label and the row. A button entry has already run its `handler`; a link entry navigates instead, and a modified (new-tab) click on a link emits nothing.
105506
105719
  * @type {{ action: string, row: object|null }}
105507
105720
  */
105508
105721
  this.$emit('action', { action: action.label, row: this.row });
@@ -105751,7 +105964,7 @@ var script$4p = {
105751
105964
  },
105752
105965
  },
105753
105966
 
105754
- emits: ['created', 'row-click', 'view-all', 'files-dropped'],
105967
+ emits: ['created', 'row-click', 'row-aux-click', 'view-all', 'files-dropped'],
105755
105968
 
105756
105969
  data() {
105757
105970
  return {
@@ -106744,29 +106957,60 @@ var script$4p = {
106744
106957
 
106745
106958
  /**
106746
106959
  * Navigate to a configured detail route on row click (when `rowRoute`
106747
- * is set and a router is available); a ctrl/cmd/shift or middle click
106748
- * opens it in a new tab.
106960
+ * is set and a router is available); a ctrl/cmd/shift click opens it
106961
+ * in a new tab.
106749
106962
  *
106750
106963
  * @param {object} row The clicked object row.
106751
- * @param {MouseEvent} [event] The originating click/auxclick event.
106964
+ * @param {MouseEvent} [event] The originating click event.
106752
106965
  * @return {void}
106753
106966
  */
106754
106967
  onRowClick(row, event) {
106755
- const route = this.content.rowRoute;
106756
- const id = row && (row.id || (row['@self'] && row['@self'].id));
106757
- if (route && id && this.$router) {
106758
- markNewTabHandled(event, openRowTarget(event, { name: route, params: { id } }, this.$router));
106759
- }
106968
+ this.openRowRoute(row, event);
106760
106969
  /**
106761
106970
  * @event row-click Emitted with the clicked object (for hosts that
106762
- * want to handle navigation themselves), on a click or middle click.
106763
- * Payload: `(row, event)`, the second being the native click/auxclick
106764
- * event.
106971
+ * want to handle navigation themselves). Payload: `(row, event)`, the
106972
+ * second being the native click event. A middle click emits
106973
+ * `row-aux-click` instead.
106765
106974
  * @type {object}
106766
106975
  */
106767
106976
  this.$emit('row-click', row, event);
106768
106977
  },
106769
106978
 
106979
+ /**
106980
+ * A row middle click: opens the configured detail route in a new tab
106981
+ * and emits `row-aux-click`, not `row-click`.
106982
+ *
106983
+ * @param {object} row The clicked object row.
106984
+ * @param {MouseEvent} event The originating auxclick event.
106985
+ * @return {void}
106986
+ */
106987
+ onRowAuxClick(row, event) {
106988
+ this.openRowRoute(row, event);
106989
+ /**
106990
+ * @event row-aux-click Emitted with the middle-clicked object, for
106991
+ * opening it in a new tab. Payload: `(row, event)`, the second being
106992
+ * the native auxclick event.
106993
+ * @type {object}
106994
+ */
106995
+ this.$emit('row-aux-click', row, event);
106996
+ },
106997
+
106998
+ /**
106999
+ * Open `content.rowRoute` for a row: in place, or in a new tab on a
107000
+ * ctrl/cmd/shift or middle click.
107001
+ *
107002
+ * @param {object} row The clicked object row.
107003
+ * @param {MouseEvent} [event] The originating event.
107004
+ * @return {void}
107005
+ */
107006
+ openRowRoute(row, event) {
107007
+ const route = this.content.rowRoute;
107008
+ const id = row && (row.id || (row['@self'] && row['@self'].id));
107009
+ if (route && id && this.$router) {
107010
+ markNewTabHandled(event, openRowTarget(event, { name: route, params: { id } }, this.$router));
107011
+ }
107012
+ },
107013
+
106770
107014
  /**
106771
107015
  * Dispatch one declared row action. A `handler` action gets the row
106772
107016
  * appended as its last argument, the same convention CnWidgetObjectTable
@@ -106795,8 +107039,7 @@ var script$4p = {
106795
107039
  * @return {object} `{ href, linkTarget }`, `{ to }`, or `{}`.
106796
107040
  */
106797
107041
  rowActionLink(action) {
106798
- const target = typeof action.target === 'string' ? action.target : '';
106799
- if (/[@{]/.test(target)) {
107042
+ if (hasActionTargetTokens(action.target)) {
106800
107043
  return {}
106801
107044
  }
106802
107045
  const link = actionLink(action, { router: this.$router || null });
@@ -107219,6 +107462,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107219
107462
  sortOrder: $data.localSort.dir || 'asc',
107220
107463
  borderless: "",
107221
107464
  onRowClick: $options.onRowClick,
107465
+ onRowAuxClick: $options.onRowAuxClick,
107222
107466
  onSelect: $options.onSelect,
107223
107467
  onSort: $options.onSort
107224
107468
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -107234,7 +107478,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107234
107478
  key: "0"
107235
107479
  }
107236
107480
  : undefined
107237
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onSelect", "onSort"])
107481
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onRowAuxClick", "onSelect", "onSort"])
107238
107482
  ]))
107239
107483
  }), 128 /* KEYED_FRAGMENT */))
107240
107484
  ]))
@@ -107250,6 +107494,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107250
107494
  sortOrder: $data.localSort.dir || 'asc',
107251
107495
  borderless: "",
107252
107496
  onRowClick: $options.onRowClick,
107497
+ onRowAuxClick: $options.onRowAuxClick,
107253
107498
  onSelect: $options.onSelect,
107254
107499
  onSort: $options.onSort
107255
107500
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -107265,7 +107510,7 @@ function render$4p(_ctx, _cache, $props, $setup, $data, $options) {
107265
107510
  key: "0"
107266
107511
  }
107267
107512
  : undefined
107268
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onSelect", "onSort"])
107513
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["columns", "rows", "loading", "emptyText", "selectable", "selectedIds", "sortKey", "sortOrder", "onRowClick", "onRowAuxClick", "onSelect", "onSort"])
107269
107514
  ])),
107270
107515
  ($options.showPager)
107271
107516
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnPagination, {
@@ -108772,7 +109017,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108772
109017
  key: 1,
108773
109018
  href: $options.resolvedRequestFeatureUrl,
108774
109019
  target: "_blank",
108775
- rel: "noopener noreferrer",
108776
109020
  "data-testid": `${$props.testidBase}-action-request-feature`,
108777
109021
  closeAfterClick: true,
108778
109022
  onClick: $options.onRequestFeatureClick
@@ -108806,7 +109050,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108806
109050
  key: 3,
108807
109051
  href: $options.resolvedReportBugUrl,
108808
109052
  target: "_blank",
108809
- rel: "noopener noreferrer",
108810
109053
  "data-testid": `${$props.testidBase}-action-report-bug`,
108811
109054
  closeAfterClick: true
108812
109055
  }, {
@@ -108824,7 +109067,6 @@ function render$4n(_ctx, _cache, $props, $setup, $data, $options) {
108824
109067
  key: 4,
108825
109068
  href: $options.resolvedDocumentationUrl,
108826
109069
  target: "_blank",
108827
- rel: "noopener noreferrer",
108828
109070
  "data-testid": `${$props.testidBase}-action-documentation`,
108829
109071
  closeAfterClick: true
108830
109072
  }, {
@@ -109809,6 +110051,26 @@ const CORE_TABS = ['files', 'notes', 'tags', 'tasks', 'auditTrail', 'shares'];
109809
110051
  /** One-time guard so the legacy-path deprecation warning logs only once. */
109810
110052
  let legacyWarned = false;
109811
110053
 
110054
+ /**
110055
+ * Schema titles by numeric schema id, shared by every widget on the page so a
110056
+ * schema is asked for once. OpenRegister's `/uses` and `/used` answer
110057
+ * `@self.schema` as that id ("120"), which is not a word anyone can read.
110058
+ *
110059
+ * @type {Map<string, Promise<string>>}
110060
+ */
110061
+ const schemaTitleCache = new Map();
110062
+
110063
+ /**
110064
+ * Whether a value is a bare number, the way OpenRegister names a schema by id.
110065
+ *
110066
+ * @param {string|number|undefined|null} value The value.
110067
+ * @return {boolean}
110068
+ */
110069
+ function isNumericId(value) {
110070
+ return (typeof value === 'number' && Number.isFinite(value))
110071
+ || (typeof value === 'string' && /^\d+$/.test(value.trim()))
110072
+ }
110073
+
109812
110074
  /**
109813
110075
  * Leaf groups surfaced by the aggregated `/relations` endpoint, in tab order.
109814
110076
  * `responseKey` is the key in the `/relations` payload; `integrationId` is the
@@ -109891,6 +110153,14 @@ var script$4l = {
109891
110153
  NcEmptyContent: vue.NcEmptyContent,
109892
110154
  },
109893
110155
 
110156
+ inject: {
110157
+ /**
110158
+ * The host app's translator (CnAppRoot provides it), so a schema title
110159
+ * reads in the app's language. Without it a title reads as stored.
110160
+ */
110161
+ cnTranslate: { default: () => (key) => key },
110162
+ },
110163
+
109894
110164
  props: {
109895
110165
  /** Widget title shown in the header. */
109896
110166
  title: {
@@ -110154,6 +110424,8 @@ var script$4l = {
110154
110424
  * @type {HTMLInputElement|null}
110155
110425
  */
110156
110426
  fileInputEl: null,
110427
+ /** Schema titles by numeric schema id, for object rows. */
110428
+ schemaTitles: {},
110157
110429
  /** Whether any section/tab is currently fetching. */
110158
110430
  loading: false,
110159
110431
  /** True once the first fetch has completed (gates the empty state). */
@@ -110846,9 +111118,74 @@ var script$4l = {
110846
111118
  self.name,
110847
111119
  raw.summary,
110848
111120
  raw.description,
110849
- ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v)) || self.schema || String(id);
110850
- const meta = self.schema || raw.schema || '';
110851
- return { id, label, meta: typeof meta === 'string' ? meta : '', raw }
111121
+ ].find((v) => typeof v === 'string' && v.trim() && !isUuid(v))
111122
+ || [raw.givenName, raw.familyName].filter((v) => typeof v === 'string' && v.trim()).join(' ');
111123
+ // OpenRegister names the schema by numeric id: show its title, never the number.
111124
+ const schema = this.schemaName(self.schema || raw.schema);
111125
+ const finalLabel = label || schema || String(id);
111126
+ return { id, label: finalLabel, meta: schema === finalLabel ? '' : schema, raw }
111127
+ },
111128
+
111129
+ /**
111130
+ * How a row names its schema: the translated title for a numeric id
111131
+ * (empty until it is read, or when it cannot be), a slug as it is.
111132
+ *
111133
+ * @param {string|number|undefined|null} schema - `@self.schema` of the related object.
111134
+ * @return {string}
111135
+ */
111136
+ schemaName(schema) {
111137
+ if (isNumericId(schema)) {
111138
+ const title = this.schemaTitles[String(schema).trim()];
111139
+ return title ? this.cnTranslate(title) : ''
111140
+ }
111141
+ return typeof schema === 'string' ? schema : ''
111142
+ },
111143
+
111144
+ /**
111145
+ * Read the titles of the numeric schema ids in these envelopes once,
111146
+ * before the rows are built, so no row shows a number first.
111147
+ *
111148
+ * @param {Array<object|null>} envelopes - The `{ results }` payloads.
111149
+ * @return {Promise<void>}
111150
+ */
111151
+ async resolveSchemaTitles(envelopes) {
111152
+ const ids = new Set();
111153
+ for (const envelope of envelopes) {
111154
+ for (const raw of ((envelope && envelope.results) || [])) {
111155
+ const schema = (raw && (raw['@self'] || {}).schema) ?? (raw && raw.schema);
111156
+ if (isNumericId(schema)) {
111157
+ ids.add(String(schema).trim());
111158
+ }
111159
+ }
111160
+ }
111161
+ const titles = { ...this.schemaTitles };
111162
+ await Promise.all([...ids].filter((id) => !(id in titles)).map(async (id) => {
111163
+ if (!schemaTitleCache.has(id)) {
111164
+ schemaTitleCache.set(id, this.fetchSchemaTitle(id));
111165
+ }
111166
+ titles[id] = await schemaTitleCache.get(id);
111167
+ }));
111168
+ this.schemaTitles = titles;
111169
+ },
111170
+
111171
+ /**
111172
+ * GET one schema's title; '' when it cannot be read.
111173
+ *
111174
+ * @param {string} id - The numeric schema id.
111175
+ * @return {Promise<string>}
111176
+ */
111177
+ async fetchSchemaTitle(id) {
111178
+ try {
111179
+ const response = await fetch(router.generateUrl('/apps/openregister/api/schemas/{id}', { id }), { method: 'GET', headers: buildHeaders() });
111180
+ if (!response.ok) {
111181
+ return ''
111182
+ }
111183
+ const schema = await response.json();
111184
+ const title = schema && (schema.title || schema.slug);
111185
+ return typeof title === 'string' ? title : ''
111186
+ } catch {
111187
+ return ''
111188
+ }
110852
111189
  },
110853
111190
 
110854
111191
  /**
@@ -110952,6 +111289,7 @@ var script$4l = {
110952
111289
  const groups = [];
110953
111290
 
110954
111291
  if (this.showObjects) {
111292
+ await this.resolveSchemaTitles([uses, used, contracts]);
110955
111293
  const objectItems = this.mergeObjectResults([uses, used, contracts]);
110956
111294
  groups.push({ key: 'objects', label: this.objectsLabel, icon: 'FileTreeOutline', integrationId: '', items: objectItems, total: objectItems.length });
110957
111295
  }
@@ -111077,6 +111415,7 @@ var script$4l = {
111077
111415
  calls.push(store.fetchContracts(type, id));
111078
111416
  }
111079
111417
  const groups = await Promise.all(calls);
111418
+ await this.resolveSchemaTitles(groups.map((results) => ({ results: results || [] })));
111080
111419
  const seen = new Set();
111081
111420
  const merged = [];
111082
111421
  for (const group of groups) {
@@ -121958,8 +122297,7 @@ function render$41(_ctx, _cache, $props, $setup, $data, $options) {
121958
122297
  vue$1.createVNode(_component_NcButton, {
121959
122298
  variant: "primary",
121960
122299
  href: $options.docsUrl,
121961
- target: "_blank",
121962
- rel: "noopener"
122300
+ target: "_blank"
121963
122301
  }, {
121964
122302
  icon: vue$1.withCtx(() => [
121965
122303
  vue$1.createVNode(_component_OpenInNew, { size: 18 })
@@ -123842,7 +124180,7 @@ var script$3Z = {
123842
124180
  },
123843
124181
  },
123844
124182
 
123845
- emits: ['click', 'select'],
124183
+ emits: ['click', 'select', 'aux-click'],
123846
124184
 
123847
124185
  setup() {
123848
124186
  // Tell a deliberate card click apart from a text-selection drag.
@@ -123968,14 +124306,28 @@ var script$3Z = {
123968
124306
  return
123969
124307
  }
123970
124308
  /**
123971
- * @event click Emitted when a non-selectable (or `clickToView`) card is clicked or middle-clicked. Payload: `(object, event)` — the card's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.
124309
+ * @event click Emitted when a non-selectable (or `clickToView`) card is clicked. Payload: `(object, event)` — the card's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.
123972
124310
  * @type {object} The card's object.
123973
124311
  */
123974
124312
  this.$emit('click', this.object, event);
123975
124313
  },
123976
124314
 
123977
124315
  /**
123978
- * Card-body middle click: emits `click` like a navigating click.
124316
+ * Card mousedown: record the press for the drag guard, and on a card a
124317
+ * middle click opens, keep the browser from starting autoscroll.
124318
+ *
124319
+ * @param {MouseEvent} event The mousedown event.
124320
+ */
124321
+ onCardMouseDown(event) {
124322
+ this.onPointerDown(event);
124323
+ if (!this.selectable || this.clickToView) {
124324
+ preventMiddleClickAutoscroll(event);
124325
+ }
124326
+ },
124327
+
124328
+ /**
124329
+ * Card-body middle click: emits `aux-click`, not `click`, so an existing
124330
+ * `click` listener that navigates never moves the current tab away.
123979
124331
  * Ignored on a select-on-click card, on nested controls and on drags.
123980
124332
  *
123981
124333
  * @param {MouseEvent} event The auxclick event.
@@ -123987,7 +124339,11 @@ var script$3Z = {
123987
124339
  if (this.selectable && !this.clickToView) {
123988
124340
  return
123989
124341
  }
123990
- this.$emit('click', this.object, event);
124342
+ /**
124343
+ * @event aux-click Emitted when a non-selectable (or `clickToView`) card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.
124344
+ * @type {object} The card's object.
124345
+ */
124346
+ this.$emit('aux-click', this.object, event);
123991
124347
  },
123992
124348
  },
123993
124349
  };
@@ -124018,7 +124374,7 @@ function render$3Z(_ctx, _cache, $props, $setup, $data, $options) {
124018
124374
 
124019
124375
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
124020
124376
  class: vue$1.normalizeClass(["cn-object-card", { 'cn-object-card--selected': $props.selected }]),
124021
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
124377
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onCardMouseDown && $options.onCardMouseDown(...args))),
124022
124378
  onClick: _cache[6] || (_cache[6] = $event => ($options.onCardClick($event))),
124023
124379
  onAuxclick: _cache[7] || (_cache[7] = $event => ($options.onCardAuxClick($event)))
124024
124380
  }, [
@@ -136734,10 +137090,9 @@ var script$3w = {
136734
137090
  * @return {void}
136735
137091
  */
136736
137092
  dispatchAction({ actionType, url, value }) {
137093
+ // An `external` entry with a URL is a real link (see linkAttrsFor);
137094
+ // one without a URL has nothing to open.
136737
137095
  switch (actionType) {
136738
- case ACTION_TYPES$1.EXTERNAL:
136739
- this.handleExternal(url);
136740
- break
136741
137096
  case ACTION_TYPES$1.INTERNAL:
136742
137097
  this.$emit('internal-action', url);
136743
137098
  break
@@ -136748,20 +137103,6 @@ var script$3w = {
136748
137103
  break
136749
137104
  }
136750
137105
  },
136751
-
136752
- /**
136753
- * Open an external URL in a new tab; `noopener,noreferrer` prevents
136754
- * the opened page reaching back via `window.opener`.
136755
- *
136756
- * @param {string} url the URL to open.
136757
- * @return {void}
136758
- */
136759
- handleExternal(url) {
136760
- if (typeof url !== 'string' || url === '') {
136761
- return
136762
- }
136763
- window.open(url, '_blank', 'noopener,noreferrer');
136764
- },
136765
137106
  },
136766
137107
  };
136767
137108
 
@@ -146317,18 +146658,14 @@ var script$3b = {
146317
146658
  },
146318
146659
 
146319
146660
  /**
146320
- * Handle a row click — descend into folders, open files in the Files app.
146661
+ * Handle a folder row click by descending into it. A file row is a
146662
+ * real link to the Files app and never reaches this.
146321
146663
  *
146322
- * @param {object} item the clicked item.
146664
+ * @param {object} item the clicked folder item.
146323
146665
  * @return {void}
146324
146666
  */
146325
146667
  onItemClick(item) {
146326
- if (item.isFolder) {
146327
- const next = this.joinPath(this.currentSubPath, item.name);
146328
- this.navigateTo(next);
146329
- } else {
146330
- this.openFileInFilesApp(item.fileId);
146331
- }
146668
+ this.navigateTo(this.joinPath(this.currentSubPath, item.name));
146332
146669
  },
146333
146670
 
146334
146671
  /**
@@ -146371,19 +146708,6 @@ var script$3b = {
146371
146708
  return `${trimmedBase}/${trimmedName}`
146372
146709
  },
146373
146710
 
146374
- /**
146375
- * Deep-link a file into the Nextcloud Files app in a new tab.
146376
- *
146377
- * @param {number|string} fileId the Nextcloud file id.
146378
- * @return {void}
146379
- */
146380
- openFileInFilesApp(fileId) {
146381
- const url = this.fileUrl(fileId);
146382
- if (url) {
146383
- window.open(url, '_blank', 'noopener,noreferrer');
146384
- }
146385
- },
146386
-
146387
146711
  /**
146388
146712
  * The Files-app permalink for a file.
146389
146713
  *
@@ -148470,7 +148794,8 @@ const DEBOUNCE_MS = 200;
148470
148794
  * Data origin (decoupling seam): all data flows through a consumer-supplied
148471
148795
  * `dataSource` prop OR the `cnSpendAnalyticsSource` injection — an object
148472
148796
  * exposing `fetchSummary(args)`, `fetchVendorCommitments(args)`,
148473
- * `fetchNarrative(args)`, and optionally `resolveDeepLink(app, kind, id)`. The
148797
+ * `fetchNarrative(args)`, and optionally `resolveDeepLink(app, kind, id)`
148798
+ * (pure and synchronous: it runs for every row on every render). The
148474
148799
  * renderer imports NO financeq / procest / launchpad service module and never
148475
148800
  * calls axios itself; the consuming app (typically over GraphQL) owns the
148476
148801
  * transport. The `requires.graphql` hint lives only in the registry entry, not
@@ -148507,8 +148832,9 @@ var script$37 = {
148507
148832
  * Consumer-supplied data source overriding the
148508
148833
  * `cnSpendAnalyticsSource` injection. Must expose `fetchSummary`,
148509
148834
  * `fetchVendorCommitments`, and `fetchNarrative`; may expose
148510
- * `resolveDeepLink`. When `null` the injection (then the empty state)
148511
- * is used.
148835
+ * `resolveDeepLink`, which must be pure and synchronous, since it is
148836
+ * called for every row on every render. When `null` the injection
148837
+ * (then the empty state) is used.
148512
148838
  *
148513
148839
  * @type {object|null}
148514
148840
  */
@@ -154248,19 +154574,6 @@ var script$2$ = {
154248
154574
  },
154249
154575
 
154250
154576
  computed: {
154251
- /**
154252
- * Each run's link href by uuid, resolved once per render.
154253
- *
154254
- * @return {{[uuid: string]: string}}
154255
- */
154256
- runHrefs() {
154257
- const out = {};
154258
- for (const run of [...this.rows, ...this.completedRows]) {
154259
- out[run.uuid] = this.runHref(run);
154260
- }
154261
- return out
154262
- },
154263
-
154264
154577
  /**
154265
154578
  * Effective translate function: the explicit prop, then the injected
154266
154579
  * host one, then `@nextcloud/l10n` under the library's own app id.
@@ -154720,15 +155033,15 @@ function render$2$(_ctx, _cache, $props, $setup, $data, $options) {
154720
155033
  ($options.rows.length === 0)
154721
155034
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$1L, vue$1.toDisplayString($options.emptyLabel), 1 /* TEXT */))
154722
155035
  : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_7$1x, [
154723
- (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.rows, (run) => {
155036
+ (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.rows, (run, index) => {
154724
155037
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
154725
- key: run.uuid,
155038
+ key: run.uuid || `row-${index}`,
154726
155039
  class: vue$1.normalizeClass(["cn-flow-runs-widget__row", { 'cn-flow-runs-widget__row--linked': $options.isLinked }]),
154727
155040
  "data-status": run.status
154728
155041
  }, [
154729
- (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHrefs[run.uuid] ? 'a' : 'div'), {
155042
+ (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHref(run) ? 'a' : 'div'), {
154730
155043
  class: "cn-flow-runs-widget__row-content",
154731
- href: $options.runHrefs[run.uuid] || undefined,
155044
+ href: $options.runHref(run) || undefined,
154732
155045
  onClick: $event => ($options.onRowClick($event, run))
154733
155046
  }, {
154734
155047
  default: vue$1.withCtx(() => [
@@ -154756,15 +155069,15 @@ function render$2$(_ctx, _cache, $props, $setup, $data, $options) {
154756
155069
  ($setup.completedError)
154757
155070
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_16$u, vue$1.toDisplayString($options.tr('Could not load the run history')), 1 /* TEXT */))
154758
155071
  : (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_17$s, [
154759
- (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.completedRows, (run) => {
155072
+ (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.completedRows, (run, index) => {
154760
155073
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
154761
- key: run.uuid,
155074
+ key: run.uuid || `completed-${index}`,
154762
155075
  class: vue$1.normalizeClass(["cn-flow-runs-widget__row cn-flow-runs-widget__row--terminal", { 'cn-flow-runs-widget__row--linked': $options.isLinked }]),
154763
155076
  "data-status": run.status
154764
155077
  }, [
154765
- (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHrefs[run.uuid] ? 'a' : 'div'), {
155078
+ (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.runHref(run) ? 'a' : 'div'), {
154766
155079
  class: "cn-flow-runs-widget__row-content",
154767
- href: $options.runHrefs[run.uuid] || undefined,
155080
+ href: $options.runHref(run) || undefined,
154768
155081
  onClick: $event => ($options.onRowClick($event, run))
154769
155082
  }, {
154770
155083
  default: vue$1.withCtx(() => [
@@ -158749,6 +159062,8 @@ var script$2Z = {
158749
159062
  },
158750
159063
 
158751
159064
  methods: {
159065
+ preventMiddleClickAutoscroll,
159066
+
158752
159067
  /**
158753
159068
  * Start (or restart) the refetch interval, unless polling is off.
158754
159069
  *
@@ -159057,6 +159372,7 @@ function render$2Z(_ctx, _cache, $props, $setup, $data, $options) {
159057
159372
  class: "cn-tasks-widget__row",
159058
159373
  "data-state": task.state,
159059
159374
  onClick: $event => ($options.onRowClick(task, $event)),
159375
+ onMousedown: _cache[1] || (_cache[1] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
159060
159376
  onAuxclick: $event => ($options.onRowAuxClick(task, $event))
159061
159377
  }, [
159062
159378
  vue$1.createElementVNode("span", _hoisted_8$1l, [
@@ -161549,7 +161865,6 @@ function render$2T(_ctx, _cache, $props, $setup, $data, $options) {
161549
161865
  variant: "tertiary",
161550
161866
  href: $options.savedHref,
161551
161867
  target: "_blank",
161552
- rel: "noopener noreferrer",
161553
161868
  "data-testid": "cn-interaction-form-open"
161554
161869
  }, {
161555
161870
  icon: vue$1.withCtx(() => [
@@ -169718,8 +170033,7 @@ function render$2C(_ctx, _cache, $props, $setup, $data, $options) {
169718
170033
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
169719
170034
  key: 2,
169720
170035
  href: $options.helpUrl,
169721
- target: "_blank",
169722
- rel: "noopener noreferrer"
170036
+ target: "_blank"
169723
170037
  }, {
169724
170038
  icon: vue$1.withCtx(() => [
169725
170039
  vue$1.createVNode(_component_HelpCircleOutline, { size: 20 })
@@ -170216,7 +170530,7 @@ var script$2B = {
170216
170530
  },
170217
170531
  },
170218
170532
 
170219
- emits: ['card-click', 'moved', 'refused', 'stale'],
170533
+ emits: ['card-click', 'card-aux-click', 'moved', 'refused', 'stale'],
170220
170534
 
170221
170535
  data() {
170222
170536
  return {
@@ -170296,6 +170610,8 @@ var script$2B = {
170296
170610
  methods: {
170297
170611
  t: l10n.translate,
170298
170612
 
170613
+ preventMiddleClickAutoscroll,
170614
+
170299
170615
  /**
170300
170616
  * Open one card. The pointer and the keyboard both come through here,
170301
170617
  * so a reader on Enter reaches the same record as a reader on click.
@@ -170306,13 +170622,15 @@ var script$2B = {
170306
170622
  */
170307
170623
  openCard(card, event) {
170308
170624
  /**
170309
- * @event card-click Emitted when a reader opens a card, by click, Enter or middle click. Payload: `(card, event)` — the card row and the native event, so the host can open it in a new tab on a ctrl/cmd/shift or middle click.
170625
+ * @event card-click Emitted when a reader opens a card, by click or Enter. Payload: `(card, event)` — the card row and the native event, so the host can open it in a new tab on a ctrl/cmd/shift click. A middle click emits `card-aux-click` instead.
170310
170626
  */
170311
170627
  this.$emit('card-click', card, event);
170312
170628
  },
170313
170629
 
170314
170630
  /**
170315
- * Middle click on a card's open button: open it like a click would.
170631
+ * Middle click on a card's open button: emits `card-aux-click`, not
170632
+ * `card-click`, so an existing listener that navigates never moves the
170633
+ * current tab away.
170316
170634
  *
170317
170635
  * @param {object} card The card the reader picked.
170318
170636
  * @param {MouseEvent} event The auxclick event.
@@ -170320,7 +170638,10 @@ var script$2B = {
170320
170638
  */
170321
170639
  onCardAuxClick(card, event) {
170322
170640
  if (isRowMiddleClick(event)) {
170323
- this.openCard(card, event);
170641
+ /**
170642
+ * @event card-aux-click Emitted when a reader middle-clicks a card, for opening it in a new tab (see `openRowTarget`). Payload: `(card, event)` — the card row and the native auxclick event.
170643
+ */
170644
+ this.$emit('card-aux-click', card, event);
170324
170645
  }
170325
170646
  },
170326
170647
 
@@ -170545,7 +170866,7 @@ function render$2B(_ctx, _cache, $props, $setup, $data, $options) {
170545
170866
  role: "listitem",
170546
170867
  "data-testid": "cn-board-column",
170547
170868
  "data-column": column.key,
170548
- onDragover: _cache[0] || (_cache[0] = vue$1.withModifiers(() => {}, ["prevent"])),
170869
+ onDragover: _cache[1] || (_cache[1] = vue$1.withModifiers(() => {}, ["prevent"])),
170549
170870
  onDrop: $event => ($options.onDrop(column, $event))
170550
170871
  }, [
170551
170872
  vue$1.createElementVNode("h3", _hoisted_7$1j, [
@@ -170582,6 +170903,7 @@ function render$2B(_ctx, _cache, $props, $setup, $data, $options) {
170582
170903
  "data-card-id": $options.cardKey(card),
170583
170904
  "aria-label": $options.cardLabel(card, column),
170584
170905
  onClick: $event => ($options.openCard(card, $event)),
170906
+ onMousedown: _cache[0] || (_cache[0] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
170585
170907
  onAuxclick: $event => ($options.onCardAuxClick(card, $event))
170586
170908
  }, vue$1.toDisplayString($options.openLabel), 41 /* TEXT, PROPS, NEED_HYDRATION */, _hoisted_11$J),
170587
170909
  ($options.canMove)
@@ -170720,7 +171042,7 @@ var script$2A = {
170720
171042
  },
170721
171043
  },
170722
171044
 
170723
- emits: ['click', 'select'],
171045
+ emits: ['click', 'select', 'aux-click'],
170724
171046
 
170725
171047
  computed: {
170726
171048
  /**
@@ -170755,6 +171077,14 @@ var script$2A = {
170755
171077
  const listeners = { select: () => this.toggleSelect(object) };
170756
171078
  if (!this.selectable || this.clickToView) {
170757
171079
  listeners.click = (_card, event) => this.$emit('click', object, event);
171080
+ // A middle click, kept off `click` so a navigating listener stays put.
171081
+ listeners['aux-click'] = (_card, event) => {
171082
+ /**
171083
+ * @event aux-click Emitted when a navigating card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.
171084
+ * @type {object} The card's object.
171085
+ */
171086
+ this.$emit('aux-click', object, event);
171087
+ };
170758
171088
  }
170759
171089
  return listeners
170760
171090
  },
@@ -171060,7 +171390,7 @@ var script$2z = {
171060
171390
  },
171061
171391
  },
171062
171392
 
171063
- emits: ['row-click'],
171393
+ emits: ['row-click', 'row-aux-click'],
171064
171394
 
171065
171395
  computed: {
171066
171396
  /** @return {object} The layout. */
@@ -171103,23 +171433,27 @@ var script$2z = {
171103
171433
  methods: {
171104
171434
  t: l10n.translate,
171105
171435
 
171436
+ preventMiddleClickAutoscroll,
171437
+
171106
171438
  /**
171107
171439
  * Open one record. Both the bar on the axis and the label of an
171108
171440
  * undated row come through here, so the two paths cannot drift.
171109
171441
  *
171110
171442
  * @param {object} row The record the reader picked.
171111
- * @param {MouseEvent} [event] The click or middle-click event.
171443
+ * @param {MouseEvent} [event] The click event.
171112
171444
  * @return {void} Nothing.
171113
171445
  */
171114
171446
  openRow(row, event) {
171115
171447
  /**
171116
- * @event row-click Emitted when a reader opens a record, from its bar on the axis or from the label of an undated row, on a click or a middle click. Payload: `(row, event)` — the row and the native click/auxclick event, so the host can open it in a new tab on a ctrl/cmd/shift or middle click.
171448
+ * @event row-click Emitted when a reader opens a record, from its bar on the axis or from the label of an undated row. Payload: `(row, event)` — the row and the native click event, so the host can open it in a new tab on a ctrl/cmd/shift click. A middle click emits `row-aux-click` instead.
171117
171449
  */
171118
171450
  this.$emit('row-click', row, event);
171119
171451
  },
171120
171452
 
171121
171453
  /**
171122
- * Middle click on a bar: open the record like a click would.
171454
+ * Middle click on a bar or an undated row's label: emits
171455
+ * `row-aux-click`, not `row-click`, so an existing listener that
171456
+ * navigates never moves the current tab away.
171123
171457
  *
171124
171458
  * @param {object} row The record the reader picked.
171125
171459
  * @param {MouseEvent} event The auxclick event.
@@ -171127,7 +171461,10 @@ var script$2z = {
171127
171461
  */
171128
171462
  onAuxClick(row, event) {
171129
171463
  if (isRowMiddleClick(event)) {
171130
- this.openRow(row, event);
171464
+ /**
171465
+ * @event row-aux-click Emitted when a reader middle-clicks a record's bar or undated-row label, for opening it in a new tab (see `openRowTarget`). Payload: `(row, event)` — the row and the native auxclick event.
171466
+ */
171467
+ this.$emit('row-aux-click', row, event);
171131
171468
  }
171132
171469
  },
171133
171470
 
@@ -171292,6 +171629,7 @@ function render$2z(_ctx, _cache, $props, $setup, $data, $options) {
171292
171629
  style: vue$1.normalizeStyle($options.barStyle(bar)),
171293
171630
  "aria-label": $options.barLabel(bar),
171294
171631
  onClick: $event => ($options.openRow(bar.row, $event)),
171632
+ onMousedown: _cache[0] || (_cache[0] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
171295
171633
  onAuxclick: $event => ($options.onAuxClick(bar.row, $event))
171296
171634
  }, vue$1.toDisplayString($options.barText(bar)), 45 /* TEXT, STYLE, PROPS, NEED_HYDRATION */, _hoisted_5$1D))
171297
171635
  }), 128 /* KEYED_FRAGMENT */))
@@ -171310,6 +171648,7 @@ function render$2z(_ctx, _cache, $props, $setup, $data, $options) {
171310
171648
  "data-row-id": $options.rowKeyOf(row),
171311
171649
  "aria-label": $options.unplannedLabelFor(row),
171312
171650
  onClick: $event => ($options.openRow(row, $event)),
171651
+ onMousedown: _cache[1] || (_cache[1] = (...args) => ($options.preventMiddleClickAutoscroll && $options.preventMiddleClickAutoscroll(...args))),
171313
171652
  onAuxclick: $event => ($options.onAuxClick(row, $event))
171314
171653
  }, vue$1.toDisplayString($options.nameOf(row)), 41 /* TEXT, PROPS, NEED_HYDRATION */, _hoisted_8$18))
171315
171654
  }), 128 /* KEYED_FRAGMENT */))
@@ -171398,7 +171737,7 @@ var script$2y = {
171398
171737
  // again from `$emit('click', object)` — twice per click, with different
171399
171738
  // payloads. Declaring the names here removes them from `$attrs`, which is
171400
171739
  // also what stops VTU v2 recording the native DOM event into `emitted()`.
171401
- emits: ['select', 'click'],
171740
+ emits: ['select', 'click', 'aux-click'],
171402
171741
 
171403
171742
  setup() {
171404
171743
  // Tell a deliberate row click apart from a text-selection drag.
@@ -171489,15 +171828,29 @@ var script$2y = {
171489
171828
  return
171490
171829
  }
171491
171830
  /**
171492
- * @event click Emitted when a non-selectable row is clicked or middle-clicked (navigation). Payload: `(object, event)` — the row's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click.
171831
+ * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.
171493
171832
  * @type {object} The row's object.
171494
171833
  */
171495
171834
  this.$emit('click', this.object, event);
171496
171835
  },
171497
171836
 
171498
171837
  /**
171499
- * Row-body middle click: emits `click` like a click on a
171500
- * non-selectable row.
171838
+ * Row mousedown: record the press for the drag guard, and on a
171839
+ * non-selectable row keep a middle press from starting autoscroll.
171840
+ *
171841
+ * @param {MouseEvent} event The mousedown event.
171842
+ */
171843
+ onRowMouseDown(event) {
171844
+ this.onPointerDown(event);
171845
+ if (!this.selectable) {
171846
+ preventMiddleClickAutoscroll(event);
171847
+ }
171848
+ },
171849
+
171850
+ /**
171851
+ * Row-body middle click on a non-selectable row: emits `aux-click`, not
171852
+ * `click`, so an existing `click` listener that navigates never moves
171853
+ * the current tab away.
171501
171854
  *
171502
171855
  * @param {MouseEvent} event The auxclick event.
171503
171856
  */
@@ -171505,7 +171858,11 @@ var script$2y = {
171505
171858
  if (this.selectable || !isRowMiddleClick(event)) {
171506
171859
  return
171507
171860
  }
171508
- this.$emit('click', this.object, event);
171861
+ /**
171862
+ * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.
171863
+ * @type {object} The row's object.
171864
+ */
171865
+ this.$emit('aux-click', this.object, event);
171509
171866
  },
171510
171867
  },
171511
171868
  };
@@ -171533,7 +171890,7 @@ function render$2y(_ctx, _cache, $props, $setup, $data, $options) {
171533
171890
 
171534
171891
  return (vue$1.openBlock(), vue$1.createElementBlock("div", {
171535
171892
  class: vue$1.normalizeClass(["cn-object-row", { 'cn-object-row--selected': $props.selected }]),
171536
- onMousedown: _cache[5] || (_cache[5] = (...args) => (_ctx.onPointerDown && _ctx.onPointerDown(...args))),
171893
+ onMousedown: _cache[5] || (_cache[5] = (...args) => ($options.onRowMouseDown && $options.onRowMouseDown(...args))),
171537
171894
  onClick: _cache[6] || (_cache[6] = $event => ($options.onRowClick($event))),
171538
171895
  onAuxclick: _cache[7] || (_cache[7] = $event => ($options.onRowAuxClick($event)))
171539
171896
  }, [
@@ -171705,7 +172062,7 @@ var script$2x = {
171705
172062
  },
171706
172063
  },
171707
172064
 
171708
- emits: ['click', 'select'],
172065
+ emits: ['click', 'select', 'aux-click'],
171709
172066
 
171710
172067
  computed: {
171711
172068
  /**
@@ -171736,6 +172093,7 @@ var script$2x = {
171736
172093
  const listeners = { select: () => this.toggleSelect(object) };
171737
172094
  if (!this.selectable) {
171738
172095
  listeners.click = (_row, event) => this.emitClick(object, event);
172096
+ listeners['aux-click'] = (_row, event) => this.emitAuxClick(object, event);
171739
172097
  }
171740
172098
  return listeners
171741
172099
  },
@@ -171744,16 +172102,31 @@ var script$2x = {
171744
172102
  * Emit `click` for a non-selectable row (navigation).
171745
172103
  *
171746
172104
  * @param {object} object The clicked row's object.
171747
- * @param {MouseEvent} [event] The native click/auxclick event.
172105
+ * @param {MouseEvent} [event] The native click event.
171748
172106
  */
171749
172107
  emitClick(object, event) {
171750
172108
  /**
171751
- * @event click Emitted when a non-selectable row is clicked or middle-clicked (navigation). Payload: `(object, event)` — the row's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click.
172109
+ * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.
171752
172110
  * @type {object} The clicked row's object.
171753
172111
  */
171754
172112
  this.$emit('click', object, event);
171755
172113
  },
171756
172114
 
172115
+ /**
172116
+ * Emit `aux-click` for a middle click on a non-selectable row, kept off
172117
+ * `click` so a navigating listener never moves the current tab away.
172118
+ *
172119
+ * @param {object} object The clicked row's object.
172120
+ * @param {MouseEvent} event The native auxclick event.
172121
+ */
172122
+ emitAuxClick(object, event) {
172123
+ /**
172124
+ * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.
172125
+ * @type {object} The clicked row's object.
172126
+ */
172127
+ this.$emit('aux-click', object, event);
172128
+ },
172129
+
171757
172130
  toggleSelect(object) {
171758
172131
  const id = object[this.rowKey];
171759
172132
  const newIds = this.isSelected(object)
@@ -183711,13 +184084,17 @@ var script$2q = {
183711
184084
  /**
183712
184085
  * A link entry was clicked: route a plain in-app click, leave the rest to
183713
184086
  * the browser, and emit `action` as a button would. The `handler` is not
183714
- * called, since navigating is what the link already does.
184087
+ * called, since navigating is what the link already does. A modified
184088
+ * click opens a new tab, so nothing is emitted in this one.
183715
184089
  *
183716
184090
  * @param {object} action The action descriptor.
183717
184091
  * @param {object} link The resolved link.
183718
184092
  * @param {MouseEvent} event The click event.
183719
184093
  */
183720
184094
  onLinkAction(action, link, event) {
184095
+ if (isModifiedClick(event)) {
184096
+ return
184097
+ }
183721
184098
  followItemActionLink(event, link, this.$router);
183722
184099
  this.$emit('action', { action: action.label, row: this.targetItem });
183723
184100
  },
@@ -226880,12 +227257,17 @@ var script$1P = {
226880
227257
 
226881
227258
  /**
226882
227259
  * Add button click: a plain click on an in-app link routes in place,
226883
- * anything else on a link is the browser's. Emits `add` either way.
227260
+ * anything else on a link is the browser's. Emits `add`, except for a
227261
+ * modified click on a link, which opens in a new tab: a host `@add`
227262
+ * would otherwise run in the tab the user is leaving.
226884
227263
  *
226885
227264
  * @param {MouseEvent} event The click event.
226886
227265
  */
226887
227266
  onAddClick(event) {
226888
227267
  if (this.addLink) {
227268
+ if (isModifiedClick(event)) {
227269
+ return
227270
+ }
226889
227271
  followItemActionLink(event, this.addLink, this.$router);
226890
227272
  }
226891
227273
  this.$emit('add');
@@ -226893,13 +227275,17 @@ var script$1P = {
226893
227275
 
226894
227276
  /**
226895
227277
  * A header link entry was clicked: route a plain in-app click and emit
226896
- * `header-action` as the button would.
227278
+ * `header-action` as the button would. A modified click is the
227279
+ * browser's alone (a new tab), so nothing is emitted for it.
226897
227280
  *
226898
227281
  * @param {object} entry The header action.
226899
227282
  * @param {object} link The resolved link.
226900
227283
  * @param {MouseEvent} event The click event.
226901
227284
  */
226902
227285
  onHeaderLinkClick(entry, link, event) {
227286
+ if (isModifiedClick(event)) {
227287
+ return
227288
+ }
226903
227289
  followItemActionLink(event, link, this.$router);
226904
227290
  this.$emit('header-action', { action: entry.id, id: entry.id });
226905
227291
  },
@@ -227192,8 +227578,7 @@ function render$1P(_ctx, _cache, $props, $setup, $data, $options) {
227192
227578
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcActionLink, {
227193
227579
  key: 0,
227194
227580
  href: $props.documentationUrl,
227195
- target: "_blank",
227196
- rel: "noopener noreferrer"
227581
+ target: "_blank"
227197
227582
  }, {
227198
227583
  icon: vue$1.withCtx(() => [
227199
227584
  vue$1.createVNode(_component_BookOpenVariantOutline, { size: 20 })
@@ -235256,19 +235641,39 @@ function resolveRowToken(value, row) {
235256
235641
  }
235257
235642
 
235258
235643
  /**
235259
- * The route params a `handler: "navigate"` action pushes for a row: the row id,
235260
- * overridden by the declared `params` after the `{field}` token grammar. A
235261
- * token naming a field the row lacks is dropped.
235644
+ * The implicit `{ id }` param for a row, only when the named route declares
235645
+ * `:id`: vue-router warns about (and drops) a param its path does not take.
235646
+ * Without a router to ask, or for a route it does not know, the id is kept.
235262
235647
  *
235263
- * @param {object} action Manifest action descriptor.
235648
+ * @param {object} [router] The app's router.
235649
+ * @param {string} name The route name.
235264
235650
  * @param {object} row The row.
235265
235651
  * @param {string} rowKey The row's id field.
235652
+ * @return {object} `{ id }`, or an empty object.
235653
+ */
235654
+ function rowIdParam(router, name, row, rowKey) {
235655
+ const routes = typeof router?.getRoutes === 'function' ? router.getRoutes() : null;
235656
+ const route = routes ? routes.find((r) => r.name === name) : null;
235657
+ if (route && !/:id\b/.test(route.path)) {
235658
+ return {}
235659
+ }
235660
+ return { id: row?.[rowKey] }
235661
+ }
235662
+
235663
+ /**
235664
+ * The route params a `handler: "navigate"` action pushes for a row: the row id
235665
+ * (when the route takes one), overridden by the declared `params` after the
235666
+ * `{field}` token grammar. A token naming a field the row lacks is dropped.
235667
+ *
235668
+ * @param {object} action Manifest action descriptor.
235669
+ * @param {object} row The row.
235670
+ * @param {object} ctx Dispatch context (`rowKey`, `router`).
235266
235671
  * @param {boolean} warn Whether to warn about a dropped param.
235267
235672
  * @return {object} The params.
235268
235673
  */
235269
- function navigateParams(action, row, rowKey, warn) {
235674
+ function navigateParams(action, row, ctx, warn) {
235270
235675
  const declaredParams = (action.params && typeof action.params === 'object') ? action.params : null;
235271
- const params = { id: row?.[rowKey] };
235676
+ const params = rowIdParam(ctx.router, action.route, row, ctx.rowKey);
235272
235677
  for (const [key, declared] of Object.entries(declaredParams || {})) {
235273
235678
  const { resolved, value } = resolveRowToken(declared, row);
235274
235679
  if (resolved) {
@@ -235307,7 +235712,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235307
235712
  return null
235308
235713
  }
235309
235714
  if (type === 'open-page') {
235310
- return { target: { name: target, params: { id: row?.[ctx.rowKey] } }, external: false }
235715
+ return { target: { name: target, params: rowIdParam(ctx.router, target, row, ctx.rowKey) }, external: false }
235311
235716
  }
235312
235717
  return { target, external: isExternalActionTarget(target) }
235313
235718
  }
@@ -235315,7 +235720,7 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235315
235720
  if (typeof action.route !== 'string' || action.route.length === 0) {
235316
235721
  return null
235317
235722
  }
235318
- return { target: { name: action.route, params: navigateParams(action, row, ctx.rowKey, warn) }, external: false }
235723
+ return { target: { name: action.route, params: navigateParams(action, row, ctx, warn) }, external: false }
235319
235724
  }
235320
235725
  return null
235321
235726
  }
@@ -235334,8 +235739,8 @@ function resolveActionTarget(action, row, ctx, warn = false) {
235334
235739
  * - `open-modal` → not wired for index actions; falls back to `@action`.
235335
235740
  *
235336
235741
  * Handler dispatch (`type: 'handler'`, the default) reads `action.handler`:
235337
- * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`,
235338
- * merged with the `action.params` map (declared params win — so a
235742
+ * - `navigate` → $router.push to `action.route` with `{ id: row[rowKey] }`
235743
+ * (when the route declares `:id`), merged with the `action.params` map (declared params win — so a
235339
235744
  * "New X" action can navigate to a detail route with `{ id: "new" }`).
235340
235745
  * Param strings run the `{field}` row-token grammar: `"{id}"` resolves to
235341
235746
  * `row.id` (type preserved), `"item-{id}"` interpolates, and a brace-less
@@ -235406,7 +235811,7 @@ function resolveActionHandler(action, ctx) {
235406
235811
  // `{field}` row-token grammar first — an unresolved token is dropped
235407
235812
  // rather than pushed as a literal `%7Bid%7D` path segment.
235408
235813
  return (row) => {
235409
- ctx.router.push({ name: route, params: navigateParams(action, row, ctx.rowKey, true) });
235814
+ ctx.router.push({ name: route, params: navigateParams(action, row, ctx, true) });
235410
235815
  }
235411
235816
  }
235412
235817
 
@@ -236619,7 +237024,8 @@ function namedFilterToQuery(values) {
236619
237024
  * @event {object} mass-export — Mass export confirmed. Payload: { ids, format }
236620
237025
  * @event {object} mass-import — Mass import confirmed. Payload: import data
236621
237026
  * @event {void} refresh — Refresh button clicked
236622
- * @event {object} row-click — Table row or card clicked or middle-clicked. Payload: (row, event) — the row object and the native click/auxclick event
237027
+ * @event {object} row-click — Table row or card clicked. Payload: (row, event) — the row object and the native click event
237028
+ * @event {object} row-aux-click — Table row or card middle-clicked. Payload: (row, event) — the row object and the native auxclick event
236623
237029
  * @event {{ key: string, order: string }} sort — Column sort changed
236624
237030
  * @event {number} page-changed — Pagination page changed
236625
237031
  * @event {number} page-size-changed — Pagination page size changed
@@ -238192,6 +238598,7 @@ var script$1y = {
238192
238598
  'quick-filter-change',
238193
238599
  'refresh',
238194
238600
  'row-click',
238601
+ 'row-aux-click',
238195
238602
  'search',
238196
238603
  'select',
238197
238604
  'sort',
@@ -238434,6 +238841,9 @@ var script$1y = {
238434
238841
  * that is what Add does (no host `@add` listener) and the router can
238435
238842
  * resolve it. The bar then renders Add as a real link; null otherwise.
238436
238843
  *
238844
+ * `$.vnode.props` is not reactive, so an `add` listener attached or
238845
+ * removed after mount does not re-evaluate this.
238846
+ *
238437
238847
  * @return {string|object|null}
238438
238848
  */
238439
238849
  addLinkTo() {
@@ -241189,21 +241599,60 @@ var script$1y = {
241189
241599
  /**
241190
241600
  * Row/card click: toggles selection when `selectable` (covers the custom
241191
241601
  * `cardComponent` path), otherwise emits `row-click` for navigation. A
241192
- * ctrl/cmd/shift or middle click opens a named source's row in a new tab.
241602
+ * ctrl/cmd/shift click opens a named source's row in a new tab.
241193
241603
  *
241194
241604
  * The `@event` block below sits directly against its `$emit`, and must
241195
241605
  * stay there. vue-docgen binds an event's description to the emit it
241196
241606
  * IMMEDIATELY precedes.
241197
241607
  *
241198
241608
  * @param {object} row The clicked row object
241199
- * @param {MouseEvent|KeyboardEvent} [event] The originating click/auxclick event.
241609
+ * @param {MouseEvent|KeyboardEvent} [event] The originating click event.
241200
241610
  */
241201
241611
  onRowClick(row, event) {
241612
+ if (!this.routeClickedRow(row, event)) {
241613
+ return
241614
+ }
241615
+ /**
241616
+ * @event row-click Emitted on a row/card click for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set and something can open the row (selection then happens via the checkbox). Payload: `(row, event)` — the clicked row and the native click event (absent for a keyboard shortcut or map marker), so a host can open the row in a new tab on a ctrl/cmd/shift click with `openRowTarget`. A middle click emits `row-aux-click` instead.
241617
+ * @type {object} The clicked row object.
241618
+ */
241619
+ this.$emit('row-click', ...(event ? [row, event] : [row]));
241620
+ },
241621
+
241622
+ /**
241623
+ * Row/card middle click: opens a named source's row in a new tab and
241624
+ * emits `row-aux-click`, not `row-click`, so a host whose `row-click`
241625
+ * listener navigates never moves the current tab away.
241626
+ *
241627
+ * @param {object} row The clicked row object
241628
+ * @param {MouseEvent} event The originating auxclick event.
241629
+ */
241630
+ onRowAuxClick(row, event) {
241631
+ if (!this.routeClickedRow(row, event)) {
241632
+ return
241633
+ }
241634
+ /**
241635
+ * @event row-aux-click Emitted on a row/card middle click, under the same conditions as `row-click`, so a host can open the row in a new tab with `openRowTarget`. Payload: `(row, event)` — the clicked row and the native auxclick event.
241636
+ * @type {object} The clicked row object.
241637
+ */
241638
+ this.$emit('row-aux-click', row, event);
241639
+ },
241640
+
241641
+ /**
241642
+ * The shared part of a row click and a middle click: on a selectable
241643
+ * page a plain click toggles selection instead, and a named source opens
241644
+ * its own row.
241645
+ *
241646
+ * @param {object} row The clicked row object
241647
+ * @param {MouseEvent|KeyboardEvent} [event] The originating event.
241648
+ * @return {boolean} Whether the click navigates, so the caller emits.
241649
+ */
241650
+ routeClickedRow(row, event) {
241202
241651
  if (this.selectable && !this.rowClickOpens) {
241203
241652
  if (!event || event.button === undefined || event.button === 0) {
241204
241653
  this.onSelect(this.toggleIdInArray(this.internalSelectedIds, row[this.rowKey]));
241205
241654
  }
241206
- return
241655
+ return false
241207
241656
  }
241208
241657
  // A named source knows where its rows live. Emitting only would leave
241209
241658
  // the click inert on a manifest page, which has no listener to bind —
@@ -241250,11 +241699,7 @@ var script$1y = {
241250
241699
  }
241251
241700
  }
241252
241701
  }
241253
- /**
241254
- * @event row-click Emitted on a row/card click (or middle click) for navigation. Fires when `selectable` is false, OR when `rowClickToView` is set and something can open the row (selection then happens via the checkbox). Payload: `(row, event)` — the clicked row and the native click/auxclick event (absent for a keyboard shortcut or map marker), so a host can open the row in a new tab on a ctrl/cmd/shift or middle click with `openRowTarget`.
241255
- * @type {object} The clicked row object.
241256
- */
241257
- this.$emit('row-click', ...(event ? [row, event] : [row]));
241702
+ return true
241258
241703
  },
241259
241704
 
241260
241705
  /**
@@ -241268,17 +241713,31 @@ var script$1y = {
241268
241713
  return typeof Event !== 'undefined' && value instanceof Event
241269
241714
  },
241270
241715
 
241716
+ /**
241717
+ * Mousedown on a custom list/card component's root: when a middle click
241718
+ * opens the row, keep the browser from starting autoscroll.
241719
+ *
241720
+ * @param {MouseEvent} event The mousedown event.
241721
+ * @return {void}
241722
+ */
241723
+ onCustomItemMouseDown(event) {
241724
+ if (!this.selectable || this.rowClickOpens) {
241725
+ preventMiddleClickAutoscroll(event);
241726
+ }
241727
+ },
241728
+
241271
241729
  /**
241272
241730
  * Middle click on a custom list/card component's root: open the row
241273
- * like a click would.
241731
+ * like a middle click on a built-in card would. Skipped when something
241732
+ * inside the component already opened it in a new tab.
241274
241733
  *
241275
241734
  * @param {object} row The component's row.
241276
241735
  * @param {MouseEvent} event The auxclick event.
241277
241736
  * @return {void}
241278
241737
  */
241279
241738
  onCustomItemAuxClick(row, event) {
241280
- if (isRowMiddleClick(event)) {
241281
- this.onRowClick(row, event);
241739
+ if (isRowMiddleClick(event) && !isNewTabHandled(event)) {
241740
+ this.onRowAuxClick(row, event);
241282
241741
  }
241283
241742
  },
241284
241743
 
@@ -242685,6 +243144,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242685
243144
  onSort: $options.onSortEvent,
242686
243145
  onSelect: $options.onSelect,
242687
243146
  onRowClick: $options.onRowClick,
243147
+ onRowAuxClick: $options.onRowAuxClick,
242688
243148
  onRowContextMenu: $options.onRowContextMenu
242689
243149
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242690
243150
  vue$1.renderList($options.slotColumns, (col) => {
@@ -242785,7 +243245,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242785
243245
  key: "1"
242786
243246
  }
242787
243247
  : undefined
242788
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rowIcon", "rowIndicators", "rowIndicatorCap", "rows", "sortKey", "sortOrder", "sortKeys", "selectable", "rowClickToView", "selectedIds", "rowKey", "emptyText", "excludeColumns", "includeColumns", "columnOverrides", "rowClass", "onSort", "onSelect", "onRowClick", "onRowContextMenu"]))
243248
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rowIcon", "rowIndicators", "rowIndicatorCap", "rows", "sortKey", "sortOrder", "sortKeys", "selectable", "rowClickToView", "selectedIds", "rowKey", "emptyText", "excludeColumns", "includeColumns", "columnOverrides", "rowClass", "onSort", "onSelect", "onRowClick", "onRowAuxClick", "onRowContextMenu"]))
242789
243249
  : ($data.currentViewMode === 'map')
242790
243250
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnMapWidget, {
242791
243251
  key: 3,
@@ -242811,8 +243271,9 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242811
243271
  runTransition: $props.runTransition,
242812
243272
  paged: $options.isPaged,
242813
243273
  onCardClick: $options.onRowClick,
243274
+ onCardAuxClick: $options.onRowAuxClick,
242814
243275
  onMoved: $options.onBoardMoved
242815
- }, null, 8 /* PROPS */, ["rows", "statusFieldSchema", "statusField", "cardFields", "swimlaneField", "rowKey", "runTransition", "paged", "onCardClick", "onMoved"]))
243276
+ }, null, 8 /* PROPS */, ["rows", "statusFieldSchema", "statusField", "cardFields", "swimlaneField", "rowKey", "runTransition", "paged", "onCardClick", "onCardAuxClick", "onMoved"]))
242816
243277
  : ($data.currentViewMode === 'dateAxis')
242817
243278
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnDateAxisView, {
242818
243279
  key: 5,
@@ -242822,8 +243283,9 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242822
243283
  laneField: $props.dateAxis.laneField || '',
242823
243284
  labelField: $props.dateAxis.labelField || '',
242824
243285
  rowKey: $props.rowKey,
242825
- onRowClick: $options.onRowClick
242826
- }, null, 8 /* PROPS */, ["rows", "startField", "endField", "laneField", "labelField", "rowKey", "onRowClick"]))
243286
+ onRowClick: $options.onRowClick,
243287
+ onRowAuxClick: $options.onRowAuxClick
243288
+ }, null, 8 /* PROPS */, ["rows", "startField", "endField", "laneField", "labelField", "rowKey", "onRowClick", "onRowAuxClick"]))
242827
243289
  : ($data.currentViewMode === 'list')
242828
243290
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnObjectList, {
242829
243291
  key: 6,
@@ -242835,6 +243297,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242835
243297
  rowKey: $props.rowKey,
242836
243298
  emptyText: $props.emptyText,
242837
243299
  onClick: $options.onRowClick,
243300
+ onAuxClick: $options.onRowAuxClick,
242838
243301
  onSelect: $options.onSelect
242839
243302
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242840
243303
  (_ctx.$slots['list-item'])
@@ -242859,9 +243322,10 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242859
243322
  register: $props.register,
242860
243323
  selected: selected,
242861
243324
  onClick: (...args) => $options.onRowClick(object, args.find($options.isDomEvent)),
243325
+ onMousedown: $options.onCustomItemMouseDown,
242862
243326
  onAuxclick: $event => ($options.onCustomItemAuxClick(object, $event)),
242863
243327
  onSelect: $event => ($options.onSelect($options.toggleIdInArray($data.internalSelectedIds, object[$props.rowKey])))
242864
- }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onAuxclick", "onSelect"]))
243328
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onMousedown", "onAuxclick", "onSelect"]))
242865
243329
  ]),
242866
243330
  key: "1"
242867
243331
  }
@@ -242899,7 +243363,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242899
243363
  key: "4"
242900
243364
  }
242901
243365
  : undefined
242902
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "config", "selectable", "selectedIds", "rowKey", "emptyText", "onClick", "onSelect"]))
243366
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "config", "selectable", "selectedIds", "rowKey", "emptyText", "onClick", "onAuxClick", "onSelect"]))
242903
243367
  : (vue$1.openBlock(), vue$1.createBlock(_component_CnCardGrid, {
242904
243368
  key: 7,
242905
243369
  objects: $options.displayObjects,
@@ -242910,6 +243374,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242910
243374
  rowKey: $props.rowKey,
242911
243375
  emptyText: $props.emptyText,
242912
243376
  onClick: $options.onRowClick,
243377
+ onAuxClick: $options.onRowAuxClick,
242913
243378
  onSelect: $options.onSelect
242914
243379
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
242915
243380
  (_ctx.$slots.card)
@@ -242934,9 +243399,10 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242934
243399
  register: $props.register,
242935
243400
  selected: selected,
242936
243401
  onClick: (...args) => $options.onRowClick(object, args.find($options.isDomEvent)),
243402
+ onMousedown: $options.onCustomItemMouseDown,
242937
243403
  onAuxclick: $event => ($options.onCustomItemAuxClick(object, $event)),
242938
243404
  onSelect: $event => ($options.onSelect($options.toggleIdInArray($data.internalSelectedIds, object[$props.rowKey])))
242939
- }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onAuxclick", "onSelect"]))
243405
+ }, null, 40 /* PROPS, NEED_HYDRATION */, ["item", "object", "schema", "register", "selected", "onClick", "onMousedown", "onAuxclick", "onSelect"]))
242940
243406
  ]),
242941
243407
  key: "1"
242942
243408
  }
@@ -242956,7 +243422,7 @@ function render$1y(_ctx, _cache, $props, $setup, $data, $options) {
242956
243422
  key: "2"
242957
243423
  }
242958
243424
  : undefined
242959
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "selectable", "clickToView", "selectedIds", "rowKey", "emptyText", "onClick", "onSelect"])),
243425
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["objects", "schema", "selectable", "clickToView", "selectedIds", "rowKey", "emptyText", "onClick", "onAuxClick", "onSelect"])),
242960
243426
  vue$1.createVNode(_component_CnContextMenu, {
242961
243427
  open: $setup.contextMenuOpen,
242962
243428
  "onUpdate:open": _cache[21] || (_cache[21] = $event => (($setup.contextMenuOpen) = $event)),
@@ -256271,8 +256737,9 @@ var script$1a = {
256271
256737
  * (`@objectId` / `@object.<field>` / `@workspace.<key>`) AND provided on
256272
256738
  * `cnSectionContext` for host section components that inject. Mirrors the
256273
256739
  * `cnObjectContext` ref the abstract list/stat widgets already read.
256740
+ * `setObject(object)` shows an object a section saved without a re-fetch.
256274
256741
  *
256275
- * @return {{objectId: (string|null), object: (object|null), register: string, schema: string}}
256742
+ * @return {{objectId: (string|null), object: (object|null), register: string, schema: string, setObject: function(object): void}}
256276
256743
  */
256277
256744
  sectionContext() {
256278
256745
  const resolved = this.resolvedSidebar || {};
@@ -256282,6 +256749,7 @@ var script$1a = {
256282
256749
  register: resolved.register || this.register || this.sidebarProps?.register || '',
256283
256750
  schema: resolved.schema || this.schema || this.resolvedObjectType || this.sidebarProps?.schema || '',
256284
256751
  config: this.cnAppConfigRef,
256752
+ setObject: (object) => this.setCurrentObject(object),
256285
256753
  }
256286
256754
  },
256287
256755
  },
@@ -256778,6 +257246,32 @@ var script$1a = {
256778
257246
  this.$emit('related-row-click', payload);
256779
257247
  },
256780
257248
 
257249
+ /**
257250
+ * Replace the page's object in the store cache, for a section that saved
257251
+ * it and holds the saved version. An object with another id is ignored.
257252
+ *
257253
+ * @param {object} object The saved object.
257254
+ */
257255
+ setCurrentObject(object) {
257256
+ const store = this.effectiveObjectStore;
257257
+ const type = this.resolvedObjectType;
257258
+ if (!store || !type || !this.objectId || !object) {
257259
+ // eslint-disable-next-line no-console -- tells the integrating section its save is not shown
257260
+ console.warn('[CnDetailPage] setObject ignored: the page has no object store, type or id');
257261
+ return
257262
+ }
257263
+ const id = object.id ?? object['@self']?.id;
257264
+ if (id !== undefined && id !== null && String(id) !== String(this.objectId)) {
257265
+ // eslint-disable-next-line no-console -- tells the integrating section its save is not shown
257266
+ console.warn(`[CnDetailPage] setObject ignored: object ${id} is not the page's object ${this.objectId}`);
257267
+ return
257268
+ }
257269
+ store.objects = {
257270
+ ...store.objects,
257271
+ [type]: { ...(store.objects?.[type] || {}), [this.objectId]: object },
257272
+ };
257273
+ },
257274
+
256781
257275
  /**
256782
257276
  * Schema-driven fetch entry point — no-op outside the
256783
257277
  * `register`+`schema`+`objectId` mode. Registers the type on
@@ -273549,14 +274043,21 @@ var script$F = {
273549
274043
  */
273550
274044
  'action',
273551
274045
  /**
273552
- * @event row-click Emitted when a log row's body is clicked or
273553
- * middle-clicked, whether or not `rowDetail` opened the detail dialog —
273554
- * so a host can navigate instead of (or as well as) showing the dialog.
273555
- * Payload: `(row, event)`, the second being the native click/auxclick
273556
- * event.
274046
+ * @event row-click Emitted when a log row's body is clicked, whether or
274047
+ * not `rowDetail` opened the detail dialog — so a host can navigate
274048
+ * instead of (or as well as) showing the dialog. Payload: `(row, event)`,
274049
+ * the second being the native click event. A middle click emits
274050
+ * `row-aux-click` instead.
273557
274051
  * @type {object}
273558
274052
  */
273559
274053
  'row-click',
274054
+ /**
274055
+ * @event row-aux-click Emitted when a log row's body is middle-clicked,
274056
+ * for opening it in a new tab. Payload: `(row, event)`, the second being
274057
+ * the native auxclick event.
274058
+ * @type {object}
274059
+ */
274060
+ 'row-aux-click',
273560
274061
  ],
273561
274062
 
273562
274063
  setup(props) {
@@ -274059,26 +274560,43 @@ var script$F = {
274059
274560
  /**
274060
274561
  * Handle a row-body click: navigate to `rowRoute` when one is declared,
274061
274562
  * else open the detail dialog when `rowDetail` is set. Always re-emits
274062
- * so a host can do its own thing regardless. A ctrl/cmd/shift or middle
274063
- * click opens `rowRoute` in a new tab; a middle click never opens the
274064
- * dialog.
274563
+ * so a host can do its own thing regardless. A ctrl/cmd/shift click
274564
+ * opens `rowRoute` in a new tab.
274065
274565
  *
274066
274566
  * @param {object} row The clicked log entry.
274067
- * @param {MouseEvent} [event] The originating click/auxclick event.
274567
+ * @param {MouseEvent} [event] The originating click event.
274068
274568
  */
274069
274569
  onRowClick(row, event) {
274070
274570
  if (this.rowRoute) {
274071
274571
  markNewTabHandled(event, openRowTarget(event, { name: this.rowRoute, params: { id: row?.[this.rowKey] } }, this.$router));
274072
- } else if (this.rowDetail && !(event && event.button === 1)) {
274572
+ } else if (this.rowDetail) {
274073
274573
  this.detailRow = row;
274074
274574
  }
274075
274575
  /**
274076
- * @event row-click Emitted when a log row's body is clicked or middle-clicked. Payload: `(row, event)` — the log entry and the native click/auxclick event.
274576
+ * @event row-click Emitted when a log row's body is clicked. Payload: `(row, event)` — the log entry and the native click event.
274077
274577
  * @type {object}
274078
274578
  */
274079
274579
  this.$emit('row-click', row, event);
274080
274580
  },
274081
274581
 
274582
+ /**
274583
+ * Handle a row-body middle click: open `rowRoute` in a new tab, never
274584
+ * the detail dialog, and emit `row-aux-click` rather than `row-click`.
274585
+ *
274586
+ * @param {object} row The clicked log entry.
274587
+ * @param {MouseEvent} event The originating auxclick event.
274588
+ */
274589
+ onRowAuxClick(row, event) {
274590
+ if (this.rowRoute) {
274591
+ markNewTabHandled(event, openRowTarget(event, { name: this.rowRoute, params: { id: row?.[this.rowKey] } }, this.$router));
274592
+ }
274593
+ /**
274594
+ * @event row-aux-click Emitted when a log row's body is middle-clicked. Payload: `(row, event)` — the log entry and the native auxclick event.
274595
+ * @type {object}
274596
+ */
274597
+ this.$emit('row-aux-click', row, event);
274598
+ },
274599
+
274082
274600
  /** Close the row-detail dialog. */
274083
274601
  closeDetail() {
274084
274602
  this.detailRow = null;
@@ -274190,7 +274708,8 @@ function render$F(_ctx, _cache, $props, $setup, $data, $options) {
274190
274708
  sortKeys: $options.effectiveSortKeys,
274191
274709
  emptyText: $props.emptyText,
274192
274710
  onSort: $options.onSort,
274193
- onRowClick: $options.onRowClick
274711
+ onRowClick: $options.onRowClick,
274712
+ onRowAuxClick: $options.onRowAuxClick
274194
274713
  }, vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
274195
274714
  vue$1.renderList($options.slotColumns, (col) => {
274196
274715
  return {
@@ -274212,7 +274731,7 @@ function render$F(_ctx, _cache, $props, $setup, $data, $options) {
274212
274731
  key: "0"
274213
274732
  }
274214
274733
  : undefined
274215
- ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rows", "rowKey", "fixedLayout", "sortKey", "sortOrder", "sortKeys", "emptyText", "onSort", "onRowClick"]),
274734
+ ]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["schema", "columns", "rows", "rowKey", "fixedLayout", "sortKey", "sortOrder", "sortKeys", "emptyText", "onSort", "onRowClick", "onRowAuxClick"]),
274216
274735
  ($options.paginationState && $options.paginationState.pages > 1)
274217
274736
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnPagination, {
274218
274737
  key: 0,
@@ -276900,7 +277419,8 @@ function render$y(_ctx, _cache, $props, $setup, $data, $options) {
276900
277419
  showEditAction: false,
276901
277420
  actions: $options.rowActions,
276902
277421
  rowClickToView: "",
276903
- onRowClick: $options.openFlow
277422
+ onRowClick: $options.openFlow,
277423
+ onRowAuxClick: $options.openFlow
276904
277424
  }, {
276905
277425
  "header-actions": vue$1.withCtx(() => [
276906
277426
  vue$1.createVNode(_component_NcButton, {
@@ -276917,7 +277437,7 @@ function render$y(_ctx, _cache, $props, $setup, $data, $options) {
276917
277437
  }, 8 /* PROPS */, ["to"])
276918
277438
  ]),
276919
277439
  _: 1 /* STABLE */
276920
- }, 8 /* PROPS */, ["title", "description", "columns", "objects", "loading", "actions", "onRowClick"]))
277440
+ }, 8 /* PROPS */, ["title", "description", "columns", "objects", "loading", "actions", "onRowClick", "onRowAuxClick"]))
276921
277441
  }
276922
277442
 
276923
277443
  script$y.render = render$y;
@@ -283168,6 +283688,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283168
283688
  ? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.resolvedComponent), vue$1.mergeProps({ key: $options.pageRenderKey }, { ..._ctx.$attrs, ...$options.resolvedProps }, {
283169
283689
  onView: $options.onRowOpen,
283170
283690
  onRowClick: $options.onRowOpen,
283691
+ onRowAuxClick: $options.onRowOpen,
283171
283692
  onEditOpen: $options.onRowOpen,
283172
283693
  onConfigure: _cache[0] || (_cache[0] = $event => ($data.showConfigModal = true))
283173
283694
  }), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -283204,7 +283725,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283204
283725
  key: "0"
283205
283726
  }
283206
283727
  : undefined
283207
- ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onEditOpen"]))
283728
+ ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
283208
283729
  : vue$1.createCommentVNode("v-if", true),
283209
283730
  ($options.widgetsBySlot.has('header-actions'))
283210
283731
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetGrid, {
@@ -283246,6 +283767,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283246
283767
  ? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent($options.resolvedComponent), vue$1.mergeProps({ key: $options.pageRenderKey }, { ..._ctx.$attrs, ...$options.resolvedProps }, {
283247
283768
  onView: $options.onRowOpen,
283248
283769
  onRowClick: $options.onRowOpen,
283770
+ onRowAuxClick: $options.onRowOpen,
283249
283771
  onEditOpen: $options.onRowOpen,
283250
283772
  onConfigure: _cache[1] || (_cache[1] = $event => ($data.showConfigModal = true))
283251
283773
  }), vue$1.createSlots({ _: 2 /* DYNAMIC */ }, [
@@ -283282,7 +283804,7 @@ function render$q(_ctx, _cache, $props, $setup, $data, $options) {
283282
283804
  key: "0"
283283
283805
  }
283284
283806
  : undefined
283285
- ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onEditOpen"]))
283807
+ ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["onView", "onRowClick", "onRowAuxClick", "onEditOpen"]))
283286
283808
  : vue$1.createCommentVNode("v-if", true),
283287
283809
  (!$options.hasRenderableBody)
283288
283810
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_2$A, [
@@ -296211,8 +296733,7 @@ function render$7(_ctx, _cache, $props, $setup, $data, $options) {
296211
296733
  key: 0,
296212
296734
  variant: "primary",
296213
296735
  href: $options.resolvedSuggestUrl,
296214
- target: "_blank",
296215
- rel: "noopener noreferrer"
296736
+ target: "_blank"
296216
296737
  }, {
296217
296738
  icon: vue$1.withCtx(() => [
296218
296739
  vue$1.createVNode(_component_Plus, { size: 20 })
@@ -300263,6 +300784,7 @@ var translations$s = {
300263
300784
  "One of": "One of",
300264
300785
  Open: "Open",
300265
300786
  "Open access:": "Open access:",
300787
+ "Open row": "Open row",
300266
300788
  Operator: "Operator",
300267
300789
  Order: "Order",
300268
300790
  "Owner:": "Owner:",
@@ -301468,6 +301990,7 @@ var translations$c = {
301468
301990
  "One of": "Één van",
301469
301991
  Open: "Openen",
301470
301992
  "Open access:": "Openbare toegang:",
301993
+ "Open row": "Rij openen",
301471
301994
  Operator: "Operator",
301472
301995
  Order: "Volgorde",
301473
301996
  "Owner:": "Eigenaar:",