@conduction/nextcloud-vue 2.56.0-beta.3 → 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 (314) 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/CnAppRoot/CnAppRoot.vue2.js +21 -1
  12. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  13. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +1 -1
  14. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  15. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  16. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  17. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  18. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  19. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  20. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  21. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  22. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  23. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  24. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  26. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  28. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  30. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  32. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  33. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  34. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  35. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  38. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  40. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  42. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  43. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  44. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  47. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  48. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  49. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  50. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  52. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  54. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  55. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  56. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  57. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  58. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  59. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  60. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  61. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  62. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  64. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  65. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  66. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  67. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  68. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  69. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  70. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  71. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  73. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  75. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  76. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  77. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  78. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  80. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  82. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  84. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  85. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  86. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  87. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  88. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  89. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  90. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  91. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  92. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  93. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  94. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  95. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  96. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +49 -5
  97. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  98. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +1 -1
  99. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  100. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  101. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  102. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  103. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  104. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  105. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  106. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  107. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  108. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  109. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  110. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  111. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  113. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  115. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  117. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  119. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  120. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  121. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  122. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  123. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  124. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  125. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  126. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  127. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  128. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  129. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  130. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  131. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  132. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  133. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  134. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  135. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  136. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  137. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  138. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  139. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  141. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  142. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  143. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  144. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  146. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  147. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  148. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  149. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  150. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  151. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  152. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  153. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  154. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  155. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  156. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  157. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  158. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  159. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  160. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  161. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  162. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  163. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  164. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  165. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  166. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  167. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  168. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  169. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  170. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  171. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  172. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  173. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  174. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  175. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  176. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  177. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  178. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  179. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  180. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  181. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  182. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  183. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  184. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  185. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  186. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  187. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  188. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  189. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  190. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  191. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  192. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  193. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  194. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  195. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  196. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  197. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  198. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  199. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  200. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  201. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  202. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  203. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  204. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  205. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  206. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  207. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  208. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  209. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  210. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  211. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  212. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  213. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  214. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  215. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  216. package/dist/esm/l10n/en.json.js +2 -0
  217. package/dist/esm/l10n/en.json.js.map +1 -1
  218. package/dist/esm/l10n/nl.json.js +2 -0
  219. package/dist/esm/l10n/nl.json.js.map +1 -1
  220. package/dist/esm/nextcloud-vue.css +78 -7
  221. package/dist/esm/utils/actionLink.js +5 -0
  222. package/dist/esm/utils/actionLink.js.map +1 -1
  223. package/dist/esm/utils/actionsDispatcher.js +16 -1
  224. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  225. package/dist/esm/utils/linkNavigation.js +6 -3
  226. package/dist/esm/utils/linkNavigation.js.map +1 -1
  227. package/dist/esm/utils/rowAuxClick.js +30 -5
  228. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  229. package/dist/esm/utils/safeHref.js +18 -3
  230. package/dist/esm/utils/safeHref.js.map +1 -1
  231. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  232. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  233. package/dist/nextcloud-vue.cjs.js +885 -393
  234. package/dist/nextcloud-vue.cjs.js.map +2 -2
  235. package/dist/nextcloud-vue.css +78 -7
  236. package/l10n/en.json +2 -0
  237. package/l10n/nl.json +2 -0
  238. package/package.json +1 -1
  239. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  240. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  241. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  242. package/src/components/CnAppRoot/CnAppRoot.vue +31 -2
  243. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  244. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  245. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  246. package/src/components/CnDataTable/CnDataTable.md +1 -1
  247. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  248. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  249. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  250. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  251. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  252. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  253. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  254. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  255. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  256. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  257. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  258. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  259. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  260. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  261. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  262. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  263. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  264. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  265. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  266. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  267. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  268. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  269. package/src/components/CnSetupWizard/CnSetupWizard.vue +57 -6
  270. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  271. package/src/components/CnTabs/CnTabs.vue +7 -3
  272. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  273. package/src/css/table.css +26 -0
  274. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  275. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  276. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  277. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  278. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  279. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  280. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  281. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  282. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  283. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  284. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  285. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  286. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  287. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  288. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  289. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  290. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  291. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  292. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  293. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  294. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  295. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  296. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  297. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  298. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  299. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  300. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  301. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  302. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  303. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  304. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  305. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  306. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  307. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  308. package/src/schemas/app-manifest-v2.schema.json +2 -1
  309. package/src/utils/actionLink.js +5 -0
  310. package/src/utils/actionsDispatcher.js +15 -0
  311. package/src/utils/linkNavigation.js +6 -3
  312. package/src/utils/rowAuxClick.js +29 -4
  313. package/src/utils/safeHref.js +18 -3
  314. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -98,8 +98,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
98
98
  createVNode(_component_NcButton, {
99
99
  variant: "primary",
100
100
  href: $props.bookmarksAppUrl,
101
- target: "_blank",
102
- rel: "noopener noreferrer"
101
+ target: "_blank"
103
102
  }, {
104
103
  icon: withCtx(() => [
105
104
  createVNode(_component_Bookmark, { size: 20 })
@@ -139,8 +138,9 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
139
138
  name: $options.bookmarkTitle(bookmark),
140
139
  bold: true,
141
140
  href: $options.bookmarkHref(bookmark),
142
- target: "_blank",
143
- forceDisplayActions: true
141
+ target: $options.hasSafeUrl(bookmark) ? '_blank' : undefined,
142
+ forceDisplayActions: true,
143
+ onClick: $event => ($options.onBookmarkClick(bookmark, $event))
144
144
  }, {
145
145
  icon: withCtx(() => [
146
146
  createElementVNode("span", _hoisted_10, [
@@ -178,20 +178,22 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
178
178
  : createCommentVNode("v-if", true)
179
179
  ]),
180
180
  actions: withCtx(() => [
181
- createVNode(_component_NcActionLink, {
182
- closeAfterClick: true,
183
- href: $options.bookmarkHref(bookmark),
184
- target: "_blank",
185
- rel: "noopener noreferrer"
186
- }, {
187
- icon: withCtx(() => [
188
- createVNode(_component_OpenInNew, { size: 20 })
189
- ]),
190
- default: withCtx(() => [
191
- createTextVNode(" " + toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
192
- ]),
193
- _: 1 /* STABLE */
194
- }, 8 /* PROPS */, ["href"]),
181
+ ($options.hasSafeUrl(bookmark))
182
+ ? (openBlock(), createBlock(_component_NcActionLink, {
183
+ key: 0,
184
+ closeAfterClick: true,
185
+ href: $options.bookmarkHref(bookmark),
186
+ target: "_blank"
187
+ }, {
188
+ icon: withCtx(() => [
189
+ createVNode(_component_OpenInNew, { size: 20 })
190
+ ]),
191
+ default: withCtx(() => [
192
+ createTextVNode(" " + toDisplayString($options.t('nextcloud-vue', 'Open bookmark')), 1 /* TEXT */)
193
+ ]),
194
+ _: 1 /* STABLE */
195
+ }, 8 /* PROPS */, ["href"]))
196
+ : createCommentVNode("v-if", true),
195
197
  createVNode(_component_NcActionButton, {
196
198
  closeAfterClick: true,
197
199
  onClick: $event => ($options.unlinkBookmark(bookmark))
@@ -206,7 +208,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
206
208
  }, 8 /* PROPS */, ["onClick"])
207
209
  ]),
208
210
  _: 2 /* DYNAMIC */
209
- }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href"]))
211
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["name", "href", "target", "onClick"]))
210
212
  }), 128 /* KEYED_FRAGMENT */))
211
213
  ])
212
214
  ])),
@@ -1 +1 @@
1
- {"version":3,"file":"CnBookmarksTab.vue3.js","sources":["../../../../../src/integrations/builtin/bookmarks/CnBookmarksTab.vue?vue&type=template&id=56da56a8&lang.js"],"sourcesContent":["<!--\n CnBookmarksTab — bespoke sidebar tab for the `bookmarks` integration.\n\n Replaces the generic CnIntegrationTab for the `bookmarks` leaf: renders\n URL preview cards (favicon, title, URL, description snippet, tag chips)\n one per linked bookmark. Talks to the same OpenRegister\n pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/bookmarks`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\BookmarksProvider`\n (which uses NC Bookmarks' own BookmarkMapper filtered by an `or:{uuid}`\n tag). Payload shape: `{ id, title, url, description, tags, added }`.\n\n Surface behaviour:\n - Empty state with \"Open Bookmarks\" CTA when no linked URLs.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n - Tag chips above the list filter the displayed rows client-side per\n the integration-bookmarks spec (Tag-Aware Display).\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses the favicon, the description snippet, and the Bookmarks-side\n tags — three signals case-workers rely on to triage which reference is\n relevant. The bespoke tab surfaces them per row.\n\n See `openregister/openspec/changes/integration-bookmarks/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption principle).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-bookmarks-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-bookmarks-tab__banner\" role=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" />\n\t\t\t<span>{{ degraded }}</span>\n\t\t</div>\n\n\t\t<div class=\"cn-bookmarks-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" @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 bookmark') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" @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 bookmark') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<div v-else-if=\"error\" class=\"cn-bookmarks-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"bookmarks.length === 0\" class=\"cn-sidebar-tab__empty cn-bookmarks-tab__empty\">\n\t\t\t<Bookmark :size=\"32\" class=\"cn-bookmarks-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"bookmarksAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openBookmarksLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else>\n\t\t\t<div v-if=\"allTags.length > 0\" class=\"cn-bookmarks-tab__filters\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tag in allTags\"\n\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip\"\n\t\t\t\t\t:class=\"{ 'cn-bookmarks-tab__chip--active': activeTag === tag }\"\n\t\t\t\t\t@click=\"toggleTagFilter(tag)\">\n\t\t\t\t\t{{ tag }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"activeTag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip cn-bookmarks-tab__chip--clear\"\n\t\t\t\t\t@click=\"activeTag = ''\">\n\t\t\t\t\t{{ clearFilterLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<ul class=\"cn-bookmarks-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"bookmark in filteredBookmarks\"\n\t\t\t\t\t:key=\"bookmarkKey(bookmark)\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__row\"\n\t\t\t\t\t:name=\"bookmarkTitle(bookmark)\"\n\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__row-icon\">\n\t\t\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url\" :title=\"bookmark.url\">\n\t\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url-text\">{{ displayUrl(bookmark) }}</span>\n\t\t\t\t\t\t\t<OpenInNew :size=\"12\" class=\"cn-bookmarks-tab__url-ext\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #extra>\n\t\t\t\t\t\t<span v-if=\"bookmark.description\" class=\"cn-bookmarks-tab__description\">\n\t\t\t\t\t\t\t{{ bookmark.description }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"bookmarkTags(bookmark).length > 0\" class=\"cn-bookmarks-tab__tags\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"tag in bookmarkTags(bookmark)\"\n\t\t\t\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\t\t\t\tclass=\"cn-bookmarks-tab__tag\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\t\t\t\t:label=\"tag\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open bookmark') }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkBookmark(bookmark)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink bookmark') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<CnBookmarkPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnBookmarkCreate\n\t\t\tv-if=\"createOpen\"\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, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport Bookmark from 'vue-material-design-icons/Bookmark.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 CnBookmarkCreate from '../../../components/CnBookmarkCreate/CnBookmarkCreate.vue'\nimport CnBookmarkPicker from '../../../components/CnBookmarkPicker/CnBookmarkPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { safeHref } from '../../../utils/safeHref.js'\n\n/**\n * CnBookmarksTab — bespoke URL preview list for the `bookmarks`\n * integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint with\n * favicon, title, URL, description, and Bookmarks-side tag chips. Tag\n * chips at the top filter the visible rows client-side. Tier-2: adds\n * link/create modals and per-row unlink.\n */\nexport default {\n\tname: 'CnBookmarksTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookmark,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnBookmarkPicker,\n\t\tCnBookmarkCreate,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'bookmarks'`). */\n\t\tintegrationId: { type: String, default: 'bookmarks' },\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 bookmarks linked yet') },\n\t\t/** Pre-translated \"Open Bookmarks\" CTA label. */\n\t\topenBookmarksLabel: { type: String, default: () => t('nextcloud-vue', 'Open Bookmarks') },\n\t\t/** Pre-translated banner when Bookmarks is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Bookmarks is currently unavailable.') },\n\t\t/** Pre-translated \"Clear filter\" chip label. */\n\t\tclearFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Clear filter') },\n\t\t/** URL of the NC Bookmarks app entry. */\n\t\tbookmarksAppUrl: { type: String, default: '/index.php/apps/bookmarks' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tbookmarks: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tactiveTag: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tallTags() {\n\t\t\tconst set = new Set()\n\t\t\tfor (const b of this.bookmarks) {\n\t\t\t\tfor (const tag of this.bookmarkTags(b)) {\n\t\t\t\t\tset.add(tag)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Array.from(set).sort()\n\t\t},\n\n\t\tfilteredBookmarks() {\n\t\t\tif (!this.activeTag) {\n\t\t\t\treturn this.bookmarks\n\t\t\t}\n\t\t\treturn this.bookmarks.filter((b) => this.bookmarkTags(b).includes(this.activeTag))\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.fetchBookmarks()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchBookmarks()\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 bookmark endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tbookmarksEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/bookmarks`\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\tbookmarkId(bookmark) {\n\t\t\treturn bookmark.bookmarkId ?? bookmark.id ?? ''\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.bookmarksEndpoint()), {\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.fetchBookmarks()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This bookmark is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\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('[CnBookmarksTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\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.bookmarksEndpoint()}/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.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\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('[CnBookmarksTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkBookmark(bookmark) {\n\t\t\tconst id = this.bookmarkId(bookmark)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/${id}`), {\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.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\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('[CnBookmarksTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tbookmarkKey(bookmark) {\n\t\t\treturn bookmark.id ?? bookmark.url ?? ''\n\t\t},\n\n\t\tbookmarkTitle(bookmark) {\n\t\t\treturn bookmark.title || bookmark.url || ''\n\t\t},\n\n\t\t/**\n\t\t * Host (+ path) of the bookmark URL for the subline — drops the\n\t\t * scheme and trailing slash so the row reads like NC Bookmarks\n\t\t * (\"example.com/spec\" rather than \"https://example.com/spec/\").\n\t\t * Falls back to the raw URL when it cannot be parsed.\n\t\t *\n\t\t * @param {object} bookmark Bookmark row.\n\t\t * @return {string} Display URL.\n\t\t */\n\t\tdisplayUrl(bookmark) {\n\t\t\tconst raw = bookmark.url || ''\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw)\n\t\t\t\tconst path = url.pathname === '/' ? '' : url.pathname.replace(/\\/$/, '')\n\t\t\t\treturn `${url.host}${path}${url.search}`\n\t\t\t} catch {\n\t\t\t\treturn raw\n\t\t\t}\n\t\t},\n\n\t\t// Bookmark URLs are user data; block javascript:/data: schemes.\n\t\tbookmarkHref(bookmark) {\n\t\t\treturn safeHref(bookmark.url)\n\t\t},\n\n\t\tbookmarkTags(bookmark) {\n\t\t\tconst tags = bookmark.tags\n\t\t\tif (!Array.isArray(tags)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn tags.filter((tag) => typeof tag === 'string' && tag !== '' && !tag.startsWith('or:'))\n\t\t},\n\n\t\ttoggleTagFilter(tag) {\n\t\t\tthis.activeTag = this.activeTag === tag ? '' : tag\n\t\t},\n\n\t\tasync fetchBookmarks() {\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.error = ''\n\t\t\tthis.degraded = ''\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.bookmarks = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\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('[CnBookmarksTab] failed to fetch bookmarks', err)\n\t\t\t\tthis.bookmarks = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\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-bookmarks-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-bookmarks-tab__banner {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 10px;\n\tmargin-bottom: 10px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n\tfont-size: 0.9em;\n}\n\n.cn-bookmarks-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-bookmarks-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-bookmarks-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n\tmargin-bottom: 10px;\n}\n\n.cn-bookmarks-tab__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tborder: 1px solid var(--color-border);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tfont-size: 0.8em;\n\tcursor: pointer;\n}\n\n.cn-bookmarks-tab__chip:hover {\n\tbackground: var(--color-background-darker, var(--color-background-hover));\n}\n\n.cn-bookmarks-tab__chip--active {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-bookmarks-tab__chip--clear {\n\tfont-style: italic;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-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/* Favicon / fallback glyph rendered inside NcListItem's #icon slot,\n sized like a real NC Bookmarks site icon. */\n.cn-bookmarks-tab__row-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n/* Truncated URL subline with a trailing external-link affordance. */\n.cn-bookmarks-tab__url {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tmax-width: 100%;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__url-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-bookmarks-tab__url-ext {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__description {\n\tdisplay: -webkit-box;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 1;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-bookmarks-tab__tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tmargin-top: 2px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_createTextVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":"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"}
1
+ {"version":3,"file":"CnBookmarksTab.vue3.js","sources":["../../../../../src/integrations/builtin/bookmarks/CnBookmarksTab.vue?vue&type=template&id=56da56a8&lang.js"],"sourcesContent":["<!--\n CnBookmarksTab — bespoke sidebar tab for the `bookmarks` integration.\n\n Replaces the generic CnIntegrationTab for the `bookmarks` leaf: renders\n URL preview cards (favicon, title, URL, description snippet, tag chips)\n one per linked bookmark. Talks to the same OpenRegister\n pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/bookmarks`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\BookmarksProvider`\n (which uses NC Bookmarks' own BookmarkMapper filtered by an `or:{uuid}`\n tag). Payload shape: `{ id, title, url, description, tags, added }`.\n\n Surface behaviour:\n - Empty state with \"Open Bookmarks\" CTA when no linked URLs.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n - Tag chips above the list filter the displayed rows client-side per\n the integration-bookmarks spec (Tag-Aware Display).\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses the favicon, the description snippet, and the Bookmarks-side\n tags — three signals case-workers rely on to triage which reference is\n relevant. The bespoke tab surfaces them per row.\n\n See `openregister/openspec/changes/integration-bookmarks/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption principle).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-bookmarks-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-bookmarks-tab__banner\" role=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" />\n\t\t\t<span>{{ degraded }}</span>\n\t\t</div>\n\n\t\t<div class=\"cn-bookmarks-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" @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 bookmark') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" @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 bookmark') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<div v-else-if=\"error\" class=\"cn-bookmarks-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"bookmarks.length === 0\" class=\"cn-sidebar-tab__empty cn-bookmarks-tab__empty\">\n\t\t\t<Bookmark :size=\"32\" class=\"cn-bookmarks-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"bookmarksAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openBookmarksLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else>\n\t\t\t<div v-if=\"allTags.length > 0\" class=\"cn-bookmarks-tab__filters\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tag in allTags\"\n\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip\"\n\t\t\t\t\t:class=\"{ 'cn-bookmarks-tab__chip--active': activeTag === tag }\"\n\t\t\t\t\t@click=\"toggleTagFilter(tag)\">\n\t\t\t\t\t{{ tag }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"activeTag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip cn-bookmarks-tab__chip--clear\"\n\t\t\t\t\t@click=\"activeTag = ''\">\n\t\t\t\t\t{{ clearFilterLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<ul class=\"cn-bookmarks-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"bookmark in filteredBookmarks\"\n\t\t\t\t\t:key=\"bookmarkKey(bookmark)\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__row\"\n\t\t\t\t\t:name=\"bookmarkTitle(bookmark)\"\n\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t:target=\"hasSafeUrl(bookmark) ? '_blank' : undefined\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"onBookmarkClick(bookmark, $event)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__row-icon\">\n\t\t\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url\" :title=\"bookmark.url\">\n\t\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url-text\">{{ displayUrl(bookmark) }}</span>\n\t\t\t\t\t\t\t<OpenInNew :size=\"12\" class=\"cn-bookmarks-tab__url-ext\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #extra>\n\t\t\t\t\t\t<span v-if=\"bookmark.description\" class=\"cn-bookmarks-tab__description\">\n\t\t\t\t\t\t\t{{ bookmark.description }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"bookmarkTags(bookmark).length > 0\" class=\"cn-bookmarks-tab__tags\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"tag in bookmarkTags(bookmark)\"\n\t\t\t\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\t\t\t\tclass=\"cn-bookmarks-tab__tag\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\t\t\t\t:label=\"tag\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"hasSafeUrl(bookmark)\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open bookmark') }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkBookmark(bookmark)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink bookmark') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<CnBookmarkPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnBookmarkCreate\n\t\t\tv-if=\"createOpen\"\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, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport Bookmark from 'vue-material-design-icons/Bookmark.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 CnBookmarkCreate from '../../../components/CnBookmarkCreate/CnBookmarkCreate.vue'\nimport CnBookmarkPicker from '../../../components/CnBookmarkPicker/CnBookmarkPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { safeHref } from '../../../utils/safeHref.js'\n\n/**\n * CnBookmarksTab — bespoke URL preview list for the `bookmarks`\n * integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint with\n * favicon, title, URL, description, and Bookmarks-side tag chips. Tag\n * chips at the top filter the visible rows client-side. Tier-2: adds\n * link/create modals and per-row unlink.\n */\nexport default {\n\tname: 'CnBookmarksTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookmark,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnBookmarkPicker,\n\t\tCnBookmarkCreate,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'bookmarks'`). */\n\t\tintegrationId: { type: String, default: 'bookmarks' },\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 bookmarks linked yet') },\n\t\t/** Pre-translated \"Open Bookmarks\" CTA label. */\n\t\topenBookmarksLabel: { type: String, default: () => t('nextcloud-vue', 'Open Bookmarks') },\n\t\t/** Pre-translated banner when Bookmarks is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Bookmarks is currently unavailable.') },\n\t\t/** Pre-translated \"Clear filter\" chip label. */\n\t\tclearFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Clear filter') },\n\t\t/** URL of the NC Bookmarks app entry. */\n\t\tbookmarksAppUrl: { type: String, default: '/index.php/apps/bookmarks' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tbookmarks: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tactiveTag: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tallTags() {\n\t\t\tconst set = new Set()\n\t\t\tfor (const b of this.bookmarks) {\n\t\t\t\tfor (const tag of this.bookmarkTags(b)) {\n\t\t\t\t\tset.add(tag)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Array.from(set).sort()\n\t\t},\n\n\t\tfilteredBookmarks() {\n\t\t\tif (!this.activeTag) {\n\t\t\t\treturn this.bookmarks\n\t\t\t}\n\t\t\treturn this.bookmarks.filter((b) => this.bookmarkTags(b).includes(this.activeTag))\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.fetchBookmarks()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchBookmarks()\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 bookmark endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tbookmarksEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/bookmarks`\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\tbookmarkId(bookmark) {\n\t\t\treturn bookmark.bookmarkId ?? bookmark.id ?? ''\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.bookmarksEndpoint()), {\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.fetchBookmarks()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This bookmark is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\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('[CnBookmarksTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\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.bookmarksEndpoint()}/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.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\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('[CnBookmarksTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkBookmark(bookmark) {\n\t\t\tconst id = this.bookmarkId(bookmark)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/${id}`), {\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.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\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('[CnBookmarksTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tbookmarkKey(bookmark) {\n\t\t\treturn bookmark.id ?? bookmark.url ?? ''\n\t\t},\n\n\t\tbookmarkTitle(bookmark) {\n\t\t\treturn bookmark.title || bookmark.url || ''\n\t\t},\n\n\t\t/**\n\t\t * Host (+ path) of the bookmark URL for the subline — drops the\n\t\t * scheme and trailing slash so the row reads like NC Bookmarks\n\t\t * (\"example.com/spec\" rather than \"https://example.com/spec/\").\n\t\t * Falls back to the raw URL when it cannot be parsed.\n\t\t *\n\t\t * @param {object} bookmark Bookmark row.\n\t\t * @return {string} Display URL.\n\t\t */\n\t\tdisplayUrl(bookmark) {\n\t\t\tconst raw = bookmark.url || ''\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw)\n\t\t\t\tconst path = url.pathname === '/' ? '' : url.pathname.replace(/\\/$/, '')\n\t\t\t\treturn `${url.host}${path}${url.search}`\n\t\t\t} catch {\n\t\t\t\treturn raw\n\t\t\t}\n\t\t},\n\n\t\t// Bookmark URLs are user data; block javascript:/data: schemes.\n\t\tbookmarkHref(bookmark) {\n\t\t\treturn safeHref(bookmark.url)\n\t\t},\n\n\t\t/**\n\t\t * Whether the bookmark's URL passed `safeHref`, so its row is a link.\n\t\t *\n\t\t * @param {object} bookmark The bookmark row.\n\t\t * @return {boolean}\n\t\t */\n\t\thasSafeUrl(bookmark) {\n\t\t\treturn this.bookmarkHref(bookmark) !== '#'\n\t\t},\n\n\t\t// NcListItem always renders an anchor; one without a safe URL must not follow `#`.\n\t\tonBookmarkClick(bookmark, event) {\n\t\t\tif (!this.hasSafeUrl(bookmark)) {\n\t\t\t\tevent?.preventDefault?.()\n\t\t\t}\n\t\t},\n\n\t\tbookmarkTags(bookmark) {\n\t\t\tconst tags = bookmark.tags\n\t\t\tif (!Array.isArray(tags)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn tags.filter((tag) => typeof tag === 'string' && tag !== '' && !tag.startsWith('or:'))\n\t\t},\n\n\t\ttoggleTagFilter(tag) {\n\t\t\tthis.activeTag = this.activeTag === tag ? '' : tag\n\t\t},\n\n\t\tasync fetchBookmarks() {\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.error = ''\n\t\t\tthis.degraded = ''\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.bookmarks = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\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('[CnBookmarksTab] failed to fetch bookmarks', err)\n\t\t\t\tthis.bookmarks = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\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-bookmarks-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-bookmarks-tab__banner {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 10px;\n\tmargin-bottom: 10px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n\tfont-size: 0.9em;\n}\n\n.cn-bookmarks-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-bookmarks-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-bookmarks-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n\tmargin-bottom: 10px;\n}\n\n.cn-bookmarks-tab__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tborder: 1px solid var(--color-border);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tfont-size: 0.8em;\n\tcursor: pointer;\n}\n\n.cn-bookmarks-tab__chip:hover {\n\tbackground: var(--color-background-darker, var(--color-background-hover));\n}\n\n.cn-bookmarks-tab__chip--active {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-bookmarks-tab__chip--clear {\n\tfont-style: italic;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-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/* Favicon / fallback glyph rendered inside NcListItem's #icon slot,\n sized like a real NC Bookmarks site icon. */\n.cn-bookmarks-tab__row-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n/* Truncated URL subline with a trailing external-link affordance. */\n.cn-bookmarks-tab__url {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tmax-width: 100%;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__url-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-bookmarks-tab__url-ext {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__description {\n\tdisplay: -webkit-box;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 1;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-bookmarks-tab__tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tmargin-top: 2px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_createTextVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { NcLoadingIcon } from '@nextcloud/vue';
3
3
  import BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue';
4
4
  import __sfc_main from '../../../components/CnDetailCard/CnDetailCard.vue.js';
5
5
  import { stripMarker } from '../../utils/marker.js';
6
+ import { safeHref } from '../../../utils/safeHref.js';
6
7
  import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
7
8
 
8
9
  const VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'];
@@ -139,8 +140,9 @@ var script = {
139
140
  return typeof emoji === 'string' ? emoji.trim() : ''
140
141
  },
141
142
 
143
+ // A provider URL is used only when it is a safe scheme; else the app link.
142
144
  pageUrl(page) {
143
- if (typeof page.url === 'string' && page.url !== '') {
145
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
144
146
  return page.url
145
147
  }
146
148
  const d = this.dataOf(page);
@@ -1 +1 @@
1
- {"version":3,"file":"CnCollectivesCard.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\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\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\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 ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\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.degraded = ''\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\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\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('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\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('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\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-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
1
+ {"version":3,"file":"CnCollectivesCard.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\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\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\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 ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\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.degraded = ''\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\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\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('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\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('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\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-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnCollectivesCard.vue3.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue?vue&type=template&id=0b91825d&lang.js"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\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\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\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 ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\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.degraded = ''\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\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\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('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\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('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\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-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createElementVNode","_createTextVNode","_toDisplayString","_openBlock","_createVNode"],"mappings":";;;;AAoDU,EAAA,KAAK,EAAC,iCAAiC;AAAE,EAAA,aAAO,EAAA,IAAA;;;;;AAQlB,EAAA,KAAA,EAAA,sCAAA;;;;AAIb,EAAA,KAAK,EAAC,+DAAiD;;;;AAIlE,EAAA,KAAK,EAAC,4BAAU;;;;AAKrB,EAAA,KAAA,EAAA,4BAAA;;;;AAGL,EAAA,KAAA,EAAA,4BAAA;;;;AAGS,EAAA,KAAK,EAAC,+BAAqB;;AACjC,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,oCAAA,GAAA;;;;;;AAIE,EAAA,KAAK,EAAC,iCAA0B;AAAA,EAAA,aAAA,EAAA,IAAA;;;;;AAQG,EAAA,KAAC,EAAA,0CAAA;;;;AAId,EAAA,KAAI,EAAA,+BAAA;;;;;AAWb,EAAA,KAAK,EAAC,4BAA4B;;;;AAGhD,EAAA,KAAA,EAAA,4BAAA;;;;AAGI,EAAA,KAAK,EAAC,2BAA2B;;;AAKvC,EAAA,KAAA,EAAA,iCAAA;AAAA,EAAA,aAAA,EAAA,IAAA;;;;;;;;;;;;;;;;;;;uBA3ELA;AAAa,IAAA,KAAK,EAAE,QAAS,CAAA,SAAA;AAAG,IAAA,IAAI,EAAE,QAAQ,CAAA,QAAA;AAAG,IAAA,WAAW,EAAE,MAAW,CAAA,WAAA;;qBACxE,MAA8B;OAAX,KAAO,CAAA,OAAA;wBAA1BA,WAA8B,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;WAGX,MAAO,CAAA,OAAA,KAAA,eAAA;0BAA3BC,kBAsBU,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;;gCArBVD,kBAeM,CAAA,MAAA,EAAA;;AAbL,oBAAA,KAAK,EAAC,2BAA2B;oBAChC,KAAK,EAAE,QAAY,CAAA,YAAA,CAAC,KAAM,CAAA,MAAA,CAAA;;AAC3B,oBAAAE,kBAAA,CAGO,QAHP,UAGO,EAAA;AAFM,sBAAA,CAAA,QAAA,CAAA,SAAA,CAAA,KAAA,CAAA,MAAA,CAAA;wCAAZF,kBAAY,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAAA,4BAAAE,eAAA,CAAAC,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,KAAA,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;wCACZL,WAAG,CAAA,8BAAA,EAAA;;AAAA,4BAAA,IAAA,EAAA,EAAA;;;oBAEJG,kBAG2C,CAAA,GAAA,EAAA;sBAFzC,IAAE,EAAA,QAAA,CAAA,OAAA,CAAA,KAAA,CAAA,MAAA,CAAA;AACH,sBAAA,MAAM,EAAC,QAAQ;AACf,sBAAA,GAAI,EAAA,UAAU;AAAI,qBAAA,EAAAE,eAAA,CAAA,QAAA,CAAA,SAAS,CAAC,KAAM,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AACvB,oBAAA,CAAA,QAAA,CAAA,eAAe,CAAC,KAAM,CAAA,MAAA,CAAA;AAAjC,yBAAAC,SAAA,EAAA,EAAAL,kBAAA,CAEM,QAFN,UAEM,EAF6B,KACjC,GAAEI,eAAA,CAAA,QAAA,CAAA,eAAA,CAAA,KAAA,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;mBAGW,MAAK,CAAA,KAAA;AAAnB,qBAAAC,SAAA,EAAA,EAAAL,kBAAA,CAGA,QAHA,UAGA,EAAA;sBAFAM,WAAgC,CAAA,8BAAA,EAAA,EAAb,IAAK,EAAE,EAAE,EAAA,CAAA;AAC7B,sBAAAJ,kBAAA,CAAM,8BAAA,MAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;oDAEqB,CAAA,MAAA,YAAA,EAAAE,eAAA,CAAA,MAAA,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;AAIT,YAAA,CAAA,MAAA,CAAA,OAAO,yBAAU,MAAA,CAAA,OAAA,KAAA,eAAA;4BAAlCJ,kBA+BO,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;iBA9BF,KAAA,CAAA,QAAA;kCAAND,kBAEI,CAAA,KAAA,EAFJ,UAEI,EAAAI,eAAA,CADF,KAAE,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;AAEH,oBAAA,CAAA,KAAA,CAAA,KAAA,CAAA,MAAA,KAAA,CAAA;sDAEG,CAAA,KAAA,YAAA,EAAAA,eAAA,CADF,MAAU,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;AAEX,uBAAAC,SAAA,EAAA,EAAAL,kBAAA,CAuBC,OAvBD,UAuBC,EAAA;AAtBH,wBAAAE,kBAAA,CAEM,OAFN,WAEM,EAAA;AADL,0BAAAA,kBAAA,CAAG,gCAAA,QAAA,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;;6DAcE,kBAAA,EAAA;AAXL,8BAAAA,kBAAA,CAGO,QAHP,WAGO,EAAA;AAFM,gCAAA,CAAA,QAAA,CAAA,SAAA,CAAA,QAAA,CAAA,UAAA,CAAA;kDAAZF,kBAAY,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAAA,sCAAAE,eAAA,CAAAC,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,QAAA,CAAA,UAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;kDACZL,WAAyC,CAAA,8BAAA,EAAA;;AAAZ,sCAAA,IAAI,EAAE,EAAE;;;8BAEtCG,kBAGG,CAAA,GAAA,EAAA;gCAFA,IAAG,EAAE,QAAO,CAAA,OAAA,CAAC,QAAW,CAAA,UAAA,CAAA;AAC3B,gCAAA,MAAO,EAAC,QAAM;AACb,gCAAA,GAAE,EAAA,UAAA;AAAA,+BAAA,EAAAE,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,QAAA,CAAA,UAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;AACS,8BAAA,CAAA,QAAA,CAAA,eAAe,CAAC,QAAU,CAAA,UAAA,CAAA;AAAtC,mCAAAC,SAAA,EAAA,EAAAL,kBAAA,CAEO,QAFP,WAEO,EAFmC,KACzC,GAAAI,eAAA,CAAA,QAAA,CAAA,eAAA,CAAA,QAAA,CAAA,UAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;AAGS,wBAAA,CAAA,KAAA,CAAA,KAAK,CAAC,MAAM,GAAA,CAAA;AAAtB,6BAAAC,SAAA,EAAA,EAAAL,kBAAA,CAKK,OALL,WAKK,EAAA;8BAJLE,kBAGM,CAAA,GAAA,EAAA;AAFJ,gCAAA,IAAI,EAAE,MAAiB,CAAA,iBAAA;AACxB,gCAAA,MAAM,EAAC,QAAQ;AACf,gCAAA,GAAG,EAAC,UAAC;iDAAA,MAAA,CAAA,YAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;;;;;;iBAOG,KAAQ,CAAA,QAAA;kCAAhBF,kBAEG,CAAA,KAAA,EAFH,WAEG,EAAAI,eAAA,CADF,KAAQ,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;AAEL,oBAAA,CAAA,KAAA,CAAA,KAAA,CAAA,MAAA,KAAA,CAAA;sDAEH,CAAA,KAAA,aAAA,EAAAA,eAAA,CADA,MAAC,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;AAEL,uBAAAC,SAAA,EAAA,EAAAL,kBAAA,OAAA;0CACCA,8CACgB,QAAS,CAAA,cAAA,EAAA,CAAjB,IAAI,KAAA;+CADZA;4BAEE,GAAG,EAAE,QAAO,CAAA,OAAA,CAAC,IAAA,CAAA;AACd,4BAAA,KAAK,EAAC,0BAA0B;;AAChC,4BAAAE,kBAAA,SAAA;AACO,8BAAA,CAAA,QAAA,CAAA,SAAA,CAAA,IAAA,CAAA;gDAANF,kBAAM,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAAA,oCAAAE,eAAA,CAAAC,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;gDACNL,WAAS,CAAA,8BAAA,EAAA;;AAAA,oCAAA,IAAA,EAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnCollectivesCard.vue3.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue?vue&type=template&id=0b91825d&lang.js"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\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\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\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 ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\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.degraded = ''\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\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\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('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\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('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\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-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createElementVNode","_createTextVNode","_toDisplayString","_openBlock","_createVNode"],"mappings":"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"}
@@ -11,6 +11,7 @@ import Plus from 'vue-material-design-icons/Plus.vue';
11
11
  import __sfc_main$1 from '../../../components/CnCollectivePageCreate/CnCollectivePageCreate.vue.js';
12
12
  import __sfc_main from '../../../components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js';
13
13
  import { stripMarker } from '../../utils/marker.js';
14
+ import { safeHref } from '../../../utils/safeHref.js';
14
15
  import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
15
16
 
16
17
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
@@ -175,8 +176,9 @@ var script = {
175
176
  return text
176
177
  },
177
178
 
179
+ // A provider URL is used only when it is a safe scheme; else the app link.
178
180
  pageUrl(page) {
179
- if (typeof page.url === 'string' && page.url !== '') {
181
+ if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
180
182
  return page.url
181
183
  }
182
184
  const d = this.dataOf(page);