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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  12. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  13. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  15. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  16. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  17. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  18. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  19. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  20. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  26. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  28. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  34. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  38. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  40. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  48. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  52. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  54. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  55. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  56. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  57. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  58. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  60. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  62. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  65. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  67. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  69. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  70. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  71. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  73. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  75. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  76. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  78. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  80. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  82. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  85. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  86. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  87. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  88. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  89. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  90. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  92. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  93. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  94. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  96. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  102. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  103. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  108. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  109. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  110. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  117. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  123. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  124. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  125. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  130. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  131. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  132. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  137. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  139. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  141. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  143. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  144. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  149. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  150. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  151. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  156. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  157. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  158. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  163. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  164. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  165. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  171. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  172. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  177. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  178. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  179. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  184. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  186. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  188. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  195. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  196. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  201. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  202. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  203. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  208. package/dist/esm/l10n/en.json.js +1 -0
  209. package/dist/esm/l10n/en.json.js.map +1 -1
  210. package/dist/esm/l10n/nl.json.js +1 -0
  211. package/dist/esm/l10n/nl.json.js.map +1 -1
  212. package/dist/esm/nextcloud-vue.css +71 -7
  213. package/dist/esm/utils/actionLink.js +5 -0
  214. package/dist/esm/utils/actionLink.js.map +1 -1
  215. package/dist/esm/utils/actionsDispatcher.js +16 -1
  216. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  217. package/dist/esm/utils/linkNavigation.js +6 -3
  218. package/dist/esm/utils/linkNavigation.js.map +1 -1
  219. package/dist/esm/utils/rowAuxClick.js +30 -5
  220. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  221. package/dist/esm/utils/safeHref.js +18 -3
  222. package/dist/esm/utils/safeHref.js.map +1 -1
  223. package/dist/nextcloud-vue.cjs.js +809 -383
  224. package/dist/nextcloud-vue.cjs.js.map +2 -2
  225. package/dist/nextcloud-vue.css +71 -7
  226. package/l10n/en.json +1 -0
  227. package/l10n/nl.json +1 -0
  228. package/package.json +1 -1
  229. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  230. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  231. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  232. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  233. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  234. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  235. package/src/components/CnDataTable/CnDataTable.md +1 -1
  236. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  237. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  238. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  239. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  240. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  241. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  242. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  243. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  244. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  245. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  246. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  247. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  248. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  249. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  250. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  251. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  252. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  253. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  254. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  255. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  256. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  257. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  258. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  259. package/src/components/CnTabs/CnTabs.vue +7 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  261. package/src/css/table.css +26 -0
  262. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  263. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  264. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  265. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  266. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  267. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  268. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  269. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  270. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  271. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  272. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  273. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  274. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  275. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  276. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  277. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  278. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  279. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  280. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  281. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  282. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  283. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  284. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  285. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  286. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  287. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  288. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  289. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  290. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  291. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  292. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  293. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  294. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  295. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  296. package/src/utils/actionLink.js +5 -0
  297. package/src/utils/actionsDispatcher.js +15 -0
  298. package/src/utils/linkNavigation.js +6 -3
  299. package/src/utils/rowAuxClick.js +29 -4
  300. package/src/utils/safeHref.js +18 -3
@@ -1 +1 @@
1
- {"version":3,"file":"CnXwikiTab.vue2.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t:rel=\"banner.ctaHref ? 'noopener noreferrer' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, so the row renders as a plain\n\t\t * (non-anchored) NcListItem rather than a dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\treturn String(page.url ?? '')\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["CnXwikiPagePicker","CnXwikiPageCreate","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnXwikiTab.vue2.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, or surfaced an unsafe scheme, so\n\t\t * the row renders as a plain (non-anchored) NcListItem rather than a\n\t\t * dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\tconst url = String(page.url ?? '')\n\t\t\treturn url && safeHref(url) !== '#' ? url : ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["CnXwikiPagePicker","CnXwikiPageCreate","t"],"mappings":"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"}
@@ -61,14 +61,13 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
61
61
  class: "cn-xwiki-tab__banner-cta",
62
62
  href: $options.banner.ctaHref || undefined,
63
63
  target: $options.banner.ctaHref ? '_blank' : undefined,
64
- rel: $options.banner.ctaHref ? 'noopener noreferrer' : undefined,
65
64
  onClick: $options.banner.ctaHandler
66
65
  }, {
67
66
  default: withCtx(() => [
68
67
  createTextVNode(toDisplayString($options.banner.ctaLabel), 1 /* TEXT */)
69
68
  ]),
70
69
  _: 1 /* STABLE */
71
- }, 8 /* PROPS */, ["href", "target", "rel", "onClick"]))
70
+ }, 8 /* PROPS */, ["href", "target", "onClick"]))
72
71
  : createCommentVNode("v-if", true)
73
72
  ], 2 /* CLASS */))
74
73
  : createCommentVNode("v-if", true),
@@ -151,8 +150,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
151
150
  class: "cn-xwiki-tab__open",
152
151
  closeAfterClick: true,
153
152
  href: $options.pageHref(page),
154
- target: "_blank",
155
- rel: "noopener noreferrer"
153
+ target: "_blank"
156
154
  }, {
157
155
  icon: withCtx(() => [
158
156
  createVNode(_component_OpenInNew, { size: 20 })
@@ -1 +1 @@
1
- {"version":3,"file":"CnXwikiTab.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue?vue&type=template&id=4b3fb212&lang.js"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t:rel=\"banner.ctaHref ? 'noopener noreferrer' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, so the row renders as a plain\n\t\t * (non-anchored) NcListItem rather than a dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\treturn String(page.url ?? '')\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createTextVNode","_createVNode","_createBlock"],"mappings":"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"}
1
+ {"version":3,"file":"CnXwikiTab.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue?vue&type=template&id=4b3fb212&lang.js"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, or surfaced an unsafe scheme, so\n\t\t * the row renders as a plain (non-anchored) NcListItem rather than a\n\t\t * dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\tconst url = String(page.url ?? '')\n\t\t\treturn url && safeHref(url) !== '#' ? url : ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createBlock","_createTextVNode","_createVNode","_openBlock"],"mappings":"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"}
@@ -369,6 +369,7 @@ var translations = {
369
369
  "One of": "One of",
370
370
  Open: "Open",
371
371
  "Open access:": "Open access:",
372
+ "Open row": "Open row",
372
373
  Operator: "Operator",
373
374
  Order: "Order",
374
375
  "Owner:": "Owner:",
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -369,6 +369,7 @@ var translations = {
369
369
  "One of": "Één van",
370
370
  Open: "Openen",
371
371
  "Open access:": "Openbare toegang:",
372
+ "Open row": "Rij openen",
372
373
  Operator: "Operator",
373
374
  Order: "Volgorde",
374
375
  "Owner:": "Eigenaar:",
@@ -1 +1 @@
1
- {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -364,6 +364,32 @@
364
364
  background-color: var(--color-primary-light);
365
365
  }
366
366
 
367
+ /* A row with a route is a real link (see CnDataTable's row link): the anchor
368
+ in its first cell is stretched over the whole row. The row's own controls
369
+ sit above it so they stay usable; keep the list in step with NESTED_CONTROL
370
+ in utils/rowAuxClick.js. */
371
+ .cn-table-row--linked {
372
+ position: relative;
373
+ }
374
+
375
+ .cn-table-row__link {
376
+ position: absolute;
377
+ inset: 0;
378
+ cursor: pointer;
379
+ }
380
+
381
+ .cn-table-row__link:focus-visible {
382
+ outline: 2px solid var(--color-main-text);
383
+ outline-offset: -2px;
384
+ }
385
+
386
+ .cn-table-row--linked .cn-table-col--checkbox,
387
+ .cn-table-row--linked .cn-table-col--actions,
388
+ .cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
389
+ position: relative;
390
+ z-index: 1;
391
+ }
392
+
367
393
  /* Column Types */
368
394
  .cn-table-col--checkbox {
369
395
  width: 50px;
@@ -5995,6 +6021,32 @@ svg.leaflet-image-layer.leaflet-interactive path {
5995
6021
  background-color: var(--color-primary-light);
5996
6022
  }
5997
6023
 
6024
+ /* A row with a route is a real link (see CnDataTable's row link): the anchor
6025
+ in its first cell is stretched over the whole row. The row's own controls
6026
+ sit above it so they stay usable; keep the list in step with NESTED_CONTROL
6027
+ in utils/rowAuxClick.js. */
6028
+ .cn-table-row--linked {
6029
+ position: relative;
6030
+ }
6031
+
6032
+ .cn-table-row__link {
6033
+ position: absolute;
6034
+ inset: 0;
6035
+ cursor: pointer;
6036
+ }
6037
+
6038
+ .cn-table-row__link:focus-visible {
6039
+ outline: 2px solid var(--color-main-text);
6040
+ outline-offset: -2px;
6041
+ }
6042
+
6043
+ .cn-table-row--linked .cn-table-col--checkbox,
6044
+ .cn-table-row--linked .cn-table-col--actions,
6045
+ .cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
6046
+ position: relative;
6047
+ z-index: 1;
6048
+ }
6049
+
5998
6050
  /* Column Types */
5999
6051
  .cn-table-col--checkbox {
6000
6052
  width: 50px;
@@ -9701,14 +9753,18 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
9701
9753
  background: none;
9702
9754
  border: none;
9703
9755
  padding: 6px 0;
9704
- cursor: pointer;
9705
9756
  text-align: left;
9706
9757
  color: inherit;
9707
9758
  font: inherit;
9708
9759
  text-decoration: none;
9709
9760
  box-sizing: border-box;
9710
9761
  }
9711
- .cn-email-card__open:hover .cn-email-card__subject[data-v-fda51a6a] {
9762
+
9763
+ /* Only a row with Mail ids is a link; the rest must not look clickable. */
9764
+ a.cn-email-card__open[data-v-fda51a6a] {
9765
+ cursor: pointer;
9766
+ }
9767
+ a.cn-email-card__open:hover .cn-email-card__subject[data-v-fda51a6a] {
9712
9768
  color: var(--color-primary-element);
9713
9769
  }
9714
9770
  .cn-email-card__avatar[data-v-fda51a6a] {
@@ -9949,10 +10005,14 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
9949
10005
  border-radius: var(--border-radius-large, 8px);
9950
10006
  color: inherit;
9951
10007
  text-decoration: none;
9952
- cursor: pointer;
9953
10008
  position: relative;
9954
10009
  }
9955
- .cn-email-tab__row[data-v-0bcebbac]:hover {
10010
+
10011
+ /* Only a row with Mail ids is a link; the rest must not look clickable. */
10012
+ a.cn-email-tab__row[data-v-0bcebbac] {
10013
+ cursor: pointer;
10014
+ }
10015
+ a.cn-email-tab__row[data-v-0bcebbac]:hover {
9956
10016
  background-color: var(--color-background-hover);
9957
10017
  }
9958
10018
  .cn-email-tab__unread-dot[data-v-0bcebbac] {
@@ -17677,7 +17737,11 @@ to { background-position: -200% 0;
17677
17737
  }
17678
17738
 
17679
17739
  /* A fade over the clipped edge, only on the side that hides tabs. Stops a
17680
- pixel above the bar's rule so the rule keeps its full colour. */
17740
+ pixel above the bar's rule so the rule keeps its full colour.
17741
+
17742
+ z-index 2 so the fades outrank a lifted tab: CnTabsWidget puts the open tab
17743
+ at 1, and a tie goes to DOM order, which would draw that tab over the start
17744
+ fade (it precedes the tabs) while the end fade still covered it. */
17681
17745
  .cn-tabs__strip[data-v-5c1a056f]::before,
17682
17746
  .cn-tabs__strip[data-v-5c1a056f]::after {
17683
17747
  content: '';
@@ -17686,7 +17750,7 @@ to { background-position: -200% 0;
17686
17750
  pointer-events: none;
17687
17751
  position: absolute;
17688
17752
  width: 56px;
17689
- z-index: 1;
17753
+ z-index: 2;
17690
17754
  }
17691
17755
  .cn-tabs__strip[data-v-5c1a056f]::before {
17692
17756
  background: linear-gradient(to right, var(--color-main-background) 30%, transparent);
@@ -17720,7 +17784,7 @@ to { background-position: -200% 0;
17720
17784
  padding: 0;
17721
17785
  position: absolute;
17722
17786
  width: 28px;
17723
- z-index: 2;
17787
+ z-index: 3;
17724
17788
  }
17725
17789
 
17726
17790
  /* Nextcloud's `button:hover` rule would otherwise fill the chevron. */
@@ -63,6 +63,11 @@ function resolveItemActionLink(action, item, router) {
63
63
  * on an in-app link that opens in place goes through the router; a URL, a
64
64
  * new-tab target or a modified click is left to the browser.
65
65
  *
66
+ * Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and
67
+ * bars using it must still emit their own events on click, and without an
68
+ * installed router `NcButton :to` falls back to a button that goes nowhere,
69
+ * while an `<a href>` still navigates.
70
+ *
66
71
  * @param {MouseEvent} event The click event.
67
72
  * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.
68
73
  * @param {object} [router] The app's router.
@@ -1 +1 @@
1
- {"version":3,"file":"actionLink.js","sources":["../../../src/utils/actionLink.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n *\n * actionLink — render a menu/bar action that only navigates as a real link.\n *\n * An action descriptor may carry `href` (a URL) or `to` (a vue-router\n * location), each either a value or a function of the item the menu acts on.\n * The rendering component turns it into an `<a href>`; a plain click on an\n * in-app `to` is routed through the router, anything else is the browser's.\n *\n * @module utils/actionLink\n */\n\nimport { followLinkClick } from './linkNavigation.js'\n\n/**\n * The href of an in-app router location. A string is a route PATH and goes\n * through the router as well, so a hash-history app gets its `#`.\n *\n * @param {string|object|null|undefined} to A route path or vue-router location.\n * @param {object} [router] The app's router.\n * @return {string} The href, or '' when there is no router or it cannot resolve.\n */\nexport function routeHref(to, router) {\n\tif (!to || !router || typeof router.resolve !== 'function') {\n\t\treturn ''\n\t}\n\t// A path string, unlike resolveHref's finished URL; resolved as a string so its query survives.\n\ttry {\n\t\treturn router.resolve(to).href || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * The link an action descriptor renders as for one item, or null when it\n * renders as a button: no `href` / `to`, or a `to` the router cannot resolve.\n *\n * @param {object} action The action descriptor (`href`, `to`, `linkTarget`).\n * @param {unknown} item The row / target item a function-valued field is called with.\n * @param {object} [router] The app's router.\n * @return {{href: string, to: (string|object|null), target: (string|undefined)}|null} The link, or null.\n */\nexport function resolveItemActionLink(action, item, router) {\n\tif (!action) {\n\t\treturn null\n\t}\n\tconst target = action.linkTarget || undefined\n\tconst href = typeof action.href === 'function' ? action.href(item) : action.href\n\tif (typeof href === 'string' && href.length > 0) {\n\t\treturn { href, to: null, target }\n\t}\n\tconst to = typeof action.to === 'function' ? action.to(item) : action.to\n\tconst resolved = routeHref(to, router)\n\treturn resolved ? { href: resolved, to, target } : null\n}\n\n/**\n * Click handler for a link from {@link resolveItemActionLink}: a plain click\n * on an in-app link that opens in place goes through the router; a URL, a\n * new-tab target or a modified click is left to the browser.\n *\n * @param {MouseEvent} event The click event.\n * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.\n * @param {object} [router] The app's router.\n * @return {boolean} True when the router navigated.\n */\nexport function followItemActionLink(event, link, router) {\n\tif (!link || !link.to || (link.target && link.target !== '_self')) {\n\t\treturn false\n\t}\n\treturn followLinkClick(event, link.to, router)\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE;AACtC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC7D,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA,CAAC,IAAI;AACL,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,EAAE,CAAC,MAAM;AACT,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;AAC5D,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,IAAI,UAAS;AAC9C,CAAC,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAI;AACjF,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAClD,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AACnC,EAAE;AACF,CAAC,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAE;AACzE,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAC;AACvC,CAAC,OAAO,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAC1D,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE;AACpE,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;AAC/C;;;;"}
1
+ {"version":3,"file":"actionLink.js","sources":["../../../src/utils/actionLink.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n *\n * actionLink — render a menu/bar action that only navigates as a real link.\n *\n * An action descriptor may carry `href` (a URL) or `to` (a vue-router\n * location), each either a value or a function of the item the menu acts on.\n * The rendering component turns it into an `<a href>`; a plain click on an\n * in-app `to` is routed through the router, anything else is the browser's.\n *\n * @module utils/actionLink\n */\n\nimport { followLinkClick } from './linkNavigation.js'\n\n/**\n * The href of an in-app router location. A string is a route PATH and goes\n * through the router as well, so a hash-history app gets its `#`.\n *\n * @param {string|object|null|undefined} to A route path or vue-router location.\n * @param {object} [router] The app's router.\n * @return {string} The href, or '' when there is no router or it cannot resolve.\n */\nexport function routeHref(to, router) {\n\tif (!to || !router || typeof router.resolve !== 'function') {\n\t\treturn ''\n\t}\n\t// A path string, unlike resolveHref's finished URL; resolved as a string so its query survives.\n\ttry {\n\t\treturn router.resolve(to).href || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * The link an action descriptor renders as for one item, or null when it\n * renders as a button: no `href` / `to`, or a `to` the router cannot resolve.\n *\n * @param {object} action The action descriptor (`href`, `to`, `linkTarget`).\n * @param {unknown} item The row / target item a function-valued field is called with.\n * @param {object} [router] The app's router.\n * @return {{href: string, to: (string|object|null), target: (string|undefined)}|null} The link, or null.\n */\nexport function resolveItemActionLink(action, item, router) {\n\tif (!action) {\n\t\treturn null\n\t}\n\tconst target = action.linkTarget || undefined\n\tconst href = typeof action.href === 'function' ? action.href(item) : action.href\n\tif (typeof href === 'string' && href.length > 0) {\n\t\treturn { href, to: null, target }\n\t}\n\tconst to = typeof action.to === 'function' ? action.to(item) : action.to\n\tconst resolved = routeHref(to, router)\n\treturn resolved ? { href: resolved, to, target } : null\n}\n\n/**\n * Click handler for a link from {@link resolveItemActionLink}: a plain click\n * on an in-app link that opens in place goes through the router; a URL, a\n * new-tab target or a modified click is left to the browser.\n *\n * Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and\n * bars using it must still emit their own events on click, and without an\n * installed router `NcButton :to` falls back to a button that goes nowhere,\n * while an `<a href>` still navigates.\n *\n * @param {MouseEvent} event The click event.\n * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.\n * @param {object} [router] The app's router.\n * @return {boolean} True when the router navigated.\n */\nexport function followItemActionLink(event, link, router) {\n\tif (!link || !link.to || (link.target && link.target !== '_self')) {\n\t\treturn false\n\t}\n\treturn followLinkClick(event, link.to, router)\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE;AACtC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC7D,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA,CAAC,IAAI;AACL,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,EAAE,CAAC,MAAM;AACT,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;AAC5D,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,IAAI,UAAS;AAC9C,CAAC,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAI;AACjF,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAClD,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AACnC,EAAE;AACF,CAAC,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAE;AACzE,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAC;AACvC,CAAC,OAAO,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAC1D,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE;AACpE,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;AAC/C;;;;"}
@@ -335,6 +335,21 @@ function interpolateActionTarget(target, ctx) {
335
335
  return interpolateActionString(target || '', ctx || {})
336
336
  }
337
337
 
338
+ // The tokens interpolateActionString resolves; a bare `@` or `{` is not one.
339
+ const ACTION_TARGET_TOKEN = /@(?:objectId|object\.|page\.|workspace\.|config\.|range\.)|\{objectId\}/;
340
+
341
+ /**
342
+ * Whether an action target carries a token that interpolation would resolve,
343
+ * so it can only be known once the page context is. A `mailto:` address or a
344
+ * URL with an `@handle` in it has none.
345
+ *
346
+ * @param {string} target The action's raw `target`.
347
+ * @return {boolean}
348
+ */
349
+ function hasActionTargetTokens(target) {
350
+ return typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)
351
+ }
352
+
338
353
  /**
339
354
  * The link an action renders as when its only job is to navigate to a target
340
355
  * known at render time: `navigate` (token-interpolated like the dispatcher)
@@ -987,5 +1002,5 @@ function dispatchAction(action, context = {}) {
987
1002
  }
988
1003
  }
989
1004
 
990
- export { actionLink, buildOnSuccessRoute, dispatchAction, interpolateActionTarget, isExternalActionTarget, postRunNode, resolveCreateOverrideHandler, resolveObjectOpType, resolveRegisteredHandler, savedObjectId };
1005
+ export { actionLink, buildOnSuccessRoute, dispatchAction, hasActionTargetTokens, interpolateActionTarget, isExternalActionTarget, postRunNode, resolveCreateOverrideHandler, resolveObjectOpType, resolveRegisteredHandler, savedObjectId };
991
1006
  //# sourceMappingURL=actionsDispatcher.js.map