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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
  6. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
  7. package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
  12. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  13. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
  14. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  15. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
  16. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  17. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  18. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
  19. package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
  20. package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
  22. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
  26. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
  28. package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  33. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
  34. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  35. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
  36. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  37. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
  38. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
  40. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  46. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
  48. package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
  52. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  53. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
  54. package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
  55. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
  56. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
  57. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
  58. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
  60. package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
  62. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
  65. package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
  67. package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
  69. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  70. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
  71. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  72. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
  73. package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
  74. package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
  75. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
  76. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  78. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
  80. package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
  81. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
  82. package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
  83. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  84. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
  85. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  86. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
  87. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
  88. package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
  89. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
  90. package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
  91. package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
  92. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
  93. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
  94. package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  96. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  99. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
  100. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  101. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
  102. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
  103. package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
  104. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
  105. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
  106. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
  107. package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
  108. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
  109. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
  110. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
  111. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
  112. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
  113. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
  114. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
  115. package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
  116. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
  117. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
  118. package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
  119. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
  120. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
  121. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
  122. package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
  123. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
  124. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
  125. package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
  126. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
  127. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
  128. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
  129. package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
  130. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
  131. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  132. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  133. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
  134. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  135. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
  136. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  137. package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
  138. package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
  139. package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
  140. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
  141. package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
  142. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
  143. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
  144. package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
  145. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
  146. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
  147. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
  148. package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
  149. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
  150. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
  151. package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
  152. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
  153. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
  154. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
  155. package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
  156. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
  157. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
  158. package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
  159. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
  160. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
  161. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
  162. package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
  163. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
  164. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
  165. package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
  166. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
  167. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
  168. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
  169. package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
  170. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
  171. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
  172. package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
  173. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
  174. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
  175. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
  176. package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
  177. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
  178. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
  179. package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
  180. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
  181. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
  182. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
  183. package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
  184. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
  185. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
  186. package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
  187. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
  188. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
  189. package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
  190. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
  191. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
  192. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
  193. package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
  194. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
  195. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
  196. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
  197. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
  198. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
  199. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
  200. package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
  201. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
  202. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
  203. package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
  204. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
  205. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
  206. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
  207. package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
  208. package/dist/esm/l10n/en.json.js +1 -0
  209. package/dist/esm/l10n/en.json.js.map +1 -1
  210. package/dist/esm/l10n/nl.json.js +1 -0
  211. package/dist/esm/l10n/nl.json.js.map +1 -1
  212. package/dist/esm/nextcloud-vue.css +71 -7
  213. package/dist/esm/utils/actionLink.js +5 -0
  214. package/dist/esm/utils/actionLink.js.map +1 -1
  215. package/dist/esm/utils/actionsDispatcher.js +16 -1
  216. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  217. package/dist/esm/utils/linkNavigation.js +6 -3
  218. package/dist/esm/utils/linkNavigation.js.map +1 -1
  219. package/dist/esm/utils/rowAuxClick.js +30 -5
  220. package/dist/esm/utils/rowAuxClick.js.map +1 -1
  221. package/dist/esm/utils/safeHref.js +18 -3
  222. package/dist/esm/utils/safeHref.js.map +1 -1
  223. package/dist/nextcloud-vue.cjs.js +809 -383
  224. package/dist/nextcloud-vue.cjs.js.map +2 -2
  225. package/dist/nextcloud-vue.css +71 -7
  226. package/l10n/en.json +1 -0
  227. package/l10n/nl.json +1 -0
  228. package/package.json +1 -1
  229. package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
  230. package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
  231. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
  232. package/src/components/CnBoardView/CnBoardView.vue +13 -5
  233. package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
  234. package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
  235. package/src/components/CnDataTable/CnDataTable.md +1 -1
  236. package/src/components/CnDataTable/CnDataTable.vue +131 -17
  237. package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
  238. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  239. package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
  240. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
  241. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
  242. package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
  243. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
  244. package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
  245. package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
  246. package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
  247. package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
  248. package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
  249. package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
  250. package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
  251. package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
  252. package/src/components/CnObjectList/CnObjectList.vue +19 -3
  253. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
  254. package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
  255. package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
  256. package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
  257. package/src/components/CnRowActions/CnRowActions.vue +7 -2
  258. package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
  259. package/src/components/CnTabs/CnTabs.vue +7 -3
  260. package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
  261. package/src/css/table.css +26 -0
  262. package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
  263. package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
  264. package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
  265. package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
  266. package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
  267. package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
  268. package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
  269. package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
  270. package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
  271. package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
  272. package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
  273. package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
  274. package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
  275. package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
  276. package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
  277. package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
  278. package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
  279. package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
  280. package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
  281. package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
  282. package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
  283. package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
  284. package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
  285. package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
  286. package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
  287. package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
  288. package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
  289. package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
  290. package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
  291. package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
  292. package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
  293. package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
  294. package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
  295. package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
  296. package/src/utils/actionLink.js +5 -0
  297. package/src/utils/actionsDispatcher.js +15 -0
  298. package/src/utils/linkNavigation.js +6 -3
  299. package/src/utils/rowAuxClick.js +29 -4
  300. package/src/utils/safeHref.js +18 -3
@@ -1 +1 @@
1
- {"version":3,"file":"CnPollsTab.vue3.js","sources":["../../../../../src/integrations/builtin/polls/CnPollsTab.vue?vue&type=template&id=abac3b8c&lang.js"],"sourcesContent":["<!--\n CnPollsTab — bespoke sidebar tab for the `polls` integration.\n\n Replaces the generic CnIntegrationTab for the `polls` leaf: renders a\n live vote tally for each linked NC Polls poll, mirroring the real NC\n Polls list look. Each row foregrounds a poll-type icon (text vs date\n poll), the bold poll question/title, an open / closed status chip\n (CnStatusBadge), a meta line with participant + option counts, a\n relative expiry (NcDateTime) when a deadline is present, and a\n per-option vote-tally progress bar. A trailing \"Open in Polls\" action\n per row deep-links to `/index.php/apps/polls/vote/{id}`.\n\n Tier-2 surface (this commit):\n - \"Link existing poll\" → opens CnPollPicker (modal)\n - \"Create new poll\" → opens CnPollCreate (modal)\n - Per-row unlink → DELETE …/polls/{pollId}\n\n Talks to the OpenRegister Tier-2 poll-link endpoints\n GET /api/objects/{r}/{s}/{id}/polls — list\n POST /api/objects/{r}/{s}/{id}/polls — link existing\n POST /api/objects/{r}/{s}/{id}/polls/new — create + link\n DELETE /api/objects/{r}/{s}/{id}/polls/{pollId} — unlink\n GET /api/integrations/polls/available — picker source\n served by `OCA\\OpenRegister\\Controller\\PollLinksController`.\n\n Surface behaviour:\n - Empty state with \"Open Polls\" CTA when no linked polls.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n See `openregister/openspec/changes/integration-polls/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-polls-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-polls-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-polls-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 poll') }}\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 poll') }}\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-polls-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"polls.length === 0\" class=\"cn-sidebar-tab__empty cn-polls-tab__empty\">\n\t\t\t<Poll :size=\"32\" class=\"cn-polls-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=\"pollsAppUrl\"\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<Poll :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openPollsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<ul v-else class=\"cn-polls-tab__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"poll in polls\"\n\t\t\t\t:key=\"pollKey(poll)\"\n\t\t\t\tclass=\"cn-polls-tab__row\"\n\t\t\t\t:class=\"{ 'cn-polls-tab__row--closed': isClosed(poll) }\">\n\t\t\t\t<div class=\"cn-polls-tab__row-header\">\n\t\t\t\t\t<span class=\"cn-polls-tab__row-icon\" :title=\"typeLabel(poll)\" :aria-label=\"typeLabel(poll)\">\n\t\t\t\t\t\t<CalendarRange v-if=\"isDatePoll(poll)\" :size=\"20\" />\n\t\t\t\t\t\t<FormatListChecks v-else :size=\"20\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pollUrl(poll)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__title\">{{ pollTitle(poll) }}</a>\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t:label=\"statusLabel(poll)\"\n\t\t\t\t\t\t:variant=\"statusVariant(poll)\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__status\" />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Unlink poll')\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__unlink\"\n\t\t\t\t\t\t@click=\"unlinkPoll(poll)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"18\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-polls-tab__meta\">\n\t\t\t\t\t<span class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<AccountMultiple :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<span>{{ voterMetaLabel(poll) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pollOptions(poll).length > 0\" class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<FormatListBulleted :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<span>{{ optionMetaLabel(poll) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"deadlineMs(poll) !== null\" class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<ClockOutline :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tclass=\"cn-polls-tab__time\"\n\t\t\t\t\t\t\t:timestamp=\"deadlineMs(poll)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\n\t\t\t\t<ul v-if=\"pollOptions(poll).length > 0\" class=\"cn-polls-tab__options\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"opt in pollOptions(poll)\"\n\t\t\t\t\t\t:key=\"optionKey(opt)\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__option\">\n\t\t\t\t\t\t<div class=\"cn-polls-tab__option-label\">\n\t\t\t\t\t\t\t<span class=\"cn-polls-tab__option-text\">{{ optionLabel(opt) }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-polls-tab__option-count\">\n\t\t\t\t\t\t\t\t{{ optionCount(opt) }} ({{ optionPercent(poll, opt) }}%)\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"cn-polls-tab__option-bar\"\n\t\t\t\t\t\t\trole=\"progressbar\"\n\t\t\t\t\t\t\t:aria-valuenow=\"optionPercent(poll, opt)\"\n\t\t\t\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t\t\t\taria-valuemax=\"100\">\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclass=\"cn-polls-tab__option-bar-fill\"\n\t\t\t\t\t\t\t\t:style=\"{ width: optionPercent(poll, opt) + '%' }\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"pollDescription(poll)\" class=\"cn-polls-tab__description\">\n\t\t\t\t\t{{ pollDescription(poll) }}\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<CnPollPicker\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<CnPollCreate\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 { NcButton, NcDateTime, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport CalendarRange from 'vue-material-design-icons/CalendarRange.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport FormatListBulleted from 'vue-material-design-icons/FormatListBulleted.vue'\nimport FormatListChecks from 'vue-material-design-icons/FormatListChecks.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Poll from 'vue-material-design-icons/Poll.vue'\nimport CnPollCreate from '../../../components/CnPollCreate/CnPollCreate.vue'\nimport CnPollPicker from '../../../components/CnPollPicker/CnPollPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\n/**\n * CnPollsTab — bespoke live-tally list for the `polls` integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint that\n * mirror the real NC Polls list: type icon, bold question, open/closed\n * status chip, participant + option counts, a relative expiry, and\n * per-option vote-tally progress bars. Tier-2: includes link/create\n * modals and per-row unlink.\n */\nexport default {\n\tname: 'CnPollsTab',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcLoadingIcon,\n\t\tCnStatusBadge,\n\t\tAccountMultiple,\n\t\tAlertCircleOutline,\n\t\tCalendarRange,\n\t\tClockOutline,\n\t\tFormatListBulleted,\n\t\tFormatListChecks,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tPlus,\n\t\tPoll,\n\t\tCnPollPicker,\n\t\tCnPollCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'polls'`). */\n\t\tintegrationId: { type: String, default: 'polls' },\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 polls linked yet') },\n\t\t/** Pre-translated label for the \"Open in Polls\" CTA. */\n\t\topenPollsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Polls') },\n\t\t/** Pre-translated banner when Polls is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Polls is currently unavailable.') },\n\t\t/** URL of the NC Polls app entry. */\n\t\tpollsAppUrl: { type: String, default: '/index.php/apps/polls' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpolls: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\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.fetchPolls()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPolls()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPolls()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn prefixUrl(`${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 polls endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tpollsEndpoint() {\n\t\t\treturn prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/polls`)\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(this.pollsEndpoint(), {\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.fetchPolls()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This poll is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link poll.')\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('[CnPollsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link poll.')\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(`${this.pollsEndpoint()}/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.fetchPolls()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create poll.')\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('[CnPollsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create poll.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoll(poll) {\n\t\t\tconst pollId = this.pollKey(poll)\n\t\t\tif (!pollId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(`${this.pollsEndpoint()}/${pollId}`, {\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.fetchPolls()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink poll.')\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('[CnPollsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink poll.')\n\t\t\t}\n\t\t},\n\n\t\tpollKey(poll) {\n\t\t\treturn poll.pollId ?? poll.id ?? poll.reference ?? ''\n\t\t},\n\n\t\tpollTitle(poll) {\n\t\t\tconst raw = poll.title ?? poll.pollTitle ?? poll.name ?? this.pollKey(poll)\n\t\t\t// Strip any legacy `[or:{uuid}]` marker from displayed title\n\t\t\t// via the shared helper (ADR-019).\n\t\t\treturn stripMarker(raw) || String(raw)\n\t\t},\n\n\t\tpollDescription(poll) {\n\t\t\treturn stripMarker(poll.description)\n\t\t},\n\n\t\tpollUrl(poll) {\n\t\t\tif (poll.url) {\n\t\t\t\treturn poll.url\n\t\t\t}\n\t\t\tconst id = this.pollKey(poll)\n\t\t\treturn id ? `/index.php/apps/polls/vote/${id}` : this.pollsAppUrl\n\t\t},\n\n\t\tpollType(poll) {\n\t\t\treturn poll.type ?? poll.pollType ?? ''\n\t\t},\n\n\t\tisDatePoll(poll) {\n\t\t\tconst type = String(this.pollType(poll)).toLowerCase()\n\t\t\treturn type.indexOf('date') !== -1\n\t\t},\n\n\t\ttypeLabel(poll) {\n\t\t\treturn this.isDatePoll(poll)\n\t\t\t\t? t('nextcloud-vue', 'Date poll')\n\t\t\t\t: t('nextcloud-vue', 'Text poll')\n\t\t},\n\n\t\tpollOptions(poll) {\n\t\t\tconst opts = poll.options ?? poll.results ?? poll.optionResults ?? []\n\t\t\treturn Array.isArray(opts) ? opts : []\n\t\t},\n\n\t\toptionKey(opt) {\n\t\t\treturn opt.id ?? opt.key ?? opt.text ?? ''\n\t\t},\n\n\t\toptionLabel(opt) {\n\t\t\treturn opt.text ?? opt.label ?? opt.name ?? String(this.optionKey(opt))\n\t\t},\n\n\t\toptionCount(opt) {\n\t\t\tconst n = Number(opt.votes ?? opt.count ?? opt.voteCount ?? 0)\n\t\t\treturn Number.isFinite(n) ? n : 0\n\t\t},\n\n\t\toptionPercent(poll, opt) {\n\t\t\tconst total = this.totalVotes(poll)\n\t\t\tif (total <= 0) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.round((this.optionCount(opt) / total) * 100)\n\t\t},\n\n\t\ttotalVotes(poll) {\n\t\t\treturn this.pollOptions(poll).reduce((sum, o) => sum + this.optionCount(o), 0)\n\t\t},\n\n\t\tvoterCount(poll) {\n\t\t\tconst n = Number(poll.voterCount ?? poll.voters ?? poll.participants ?? 0)\n\t\t\treturn Number.isFinite(n) && n > 0 ? n : this.totalVotes(poll)\n\t\t},\n\n\t\tvoterMetaLabel(poll) {\n\t\t\tconst voters = this.voterCount(poll)\n\t\t\treturn t('nextcloud-vue', '{n} participants', { n: voters })\n\t\t},\n\n\t\toptionMetaLabel(poll) {\n\t\t\tconst count = this.pollOptions(poll).length\n\t\t\treturn t('nextcloud-vue', '{n} options', { n: count })\n\t\t},\n\n\t\tdeadline(poll) {\n\t\t\treturn poll.deadline ?? poll.expire ?? poll.expiresAt ?? null\n\t\t},\n\n\t\tdeadlineMs(poll) {\n\t\t\tconst v = this.deadline(poll)\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\t// Treat as unix seconds when it's small enough to be a 10-digit epoch.\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\tisClosed(poll) {\n\t\t\tconst ms = this.deadlineMs(poll)\n\t\t\tif (ms === null) {\n\t\t\t\t// Without a deadline, fall back to a `closed` flag if present.\n\t\t\t\treturn poll.closed === true || poll.status === 'closed'\n\t\t\t}\n\t\t\treturn ms <= Date.now()\n\t\t},\n\n\t\tstatusLabel(poll) {\n\t\t\treturn this.isClosed(poll)\n\t\t\t\t? t('nextcloud-vue', 'Closed')\n\t\t\t\t: t('nextcloud-vue', 'Open')\n\t\t},\n\n\t\tstatusVariant(poll) {\n\t\t\treturn this.isClosed(poll) ? 'default' : 'success'\n\t\t},\n\n\t\tasync fetchPolls() {\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(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.polls = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.polls = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.polls = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load polls.')\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('[CnPollsTab] failed to fetch polls', err)\n\t\t\t\tthis.polls = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load polls.')\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-polls-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-polls-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-polls-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-polls-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-polls-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-polls-tab__row {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 10px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tborder-left: 3px solid var(--color-primary-element);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-polls-tab__row--closed {\n\tborder-left-color: var(--color-border-dark, var(--color-border));\n\tbackground: transparent;\n\topacity: 0.78;\n}\n\n.cn-polls-tab__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-polls-tab__row-icon {\n\tdisplay: inline-flex;\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__row--closed .cn-polls-tab__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__title {\n\tflex: 1;\n\tmin-width: 0;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\tfont-weight: 600;\n}\n\na.cn-polls-tab__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-polls-tab__status {\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 28px;\n}\n\n.cn-polls-tab__meta-item {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-polls-tab__meta-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__time {\n\tfont-size: 1em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__options {\n\tlist-style: none;\n\tmargin: 4px 0 0;\n\tpadding: 0 0 0 28px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-polls-tab__option {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-polls-tab__option-label {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n}\n\n.cn-polls-tab__option-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n}\n\n.cn-polls-tab__option-count {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__option-bar {\n\theight: 6px;\n\tborder-radius: 3px;\n\tbackground: var(--color-background-dark);\n\toverflow: hidden;\n}\n\n.cn-polls-tab__option-bar-fill {\n\theight: 100%;\n\tbackground: var(--color-primary-element, #21468B);\n\ttransition: width 0.2s ease;\n}\n\n.cn-polls-tab__description {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 28px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createTextVNode","_toDisplayString","_normalizeClass","_createBlock","_renderList"],"mappings":";;AAmEM,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,6BAAO,GAAA;;;AACI,EAAA,KAAA,EAAA,sBAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;AAKhB,MAAA,UAAA,GAAA,EAAA,KAAM,EAAA,uBAAuB,GAAA;;;AAgBlB,EAAA,KAAA,EAAA,qBAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;;;AAGD,EAAA,KAAA,EAAA,2CAAA;;;;AAcJ,EAAA,KAAK,EAAC,oBAAoB;;AAM9B,MAAA,UAAA,GAAA,EAAA,KAAI,EAAE,0BAA0B,GAAA;;;AA0BhC,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,oBAAQ,GAAA;AACZ,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,yBAAS,GAAA;;;AAIf,EAAA,KAAA,EAAA,yBAAA;;;;AAIoB,EAAA,KAAA,EAAA,yBAAA;;;;AASR,EAAA,KAAA,EAAA,uBAAA;;AAKZ,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,4BAAU,GAAA;AACrB,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AA/FF,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;KACS;AAAR,SAAAD,SAAA,EAAA,EAAAC,kBAAA,CAGG,OAHH,UAGG,EAAA;qBAFM,CAAA,6BAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;AACV,UAAAC,kBAAA,CAAmB,8BAAX,KAAQ,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;AAGlB,IAAAA,kBAAA,CAaM,OAbN,UAaM,EAAA;MAZLC,WAKW,CAAA,mBAAA,EAAA;AALT,QAAA,OAAA,EAAA,WAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,UAAA;;AACS,QAAA,IAAK,UACd,MAAkB;UAAlBA,WAAkB,CAAA,sBAAA,EAAA,EAAJ,IAAI,EAAA,EAAA,EAAA,CAAA;;yBACR,MACX;AADW,UAAAC,eAAA,CAAA,GACX,mBAAG,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,oBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;MAEHD,WAKS,CAAA,mBAAA,EAAA;AALD,QAAA,OAAO,EAAC,SAAS;AAAE,QAAA,OAAK,EAAE,QAAU,CAAA,UAAA;;AAClC,QAAA,IAAI,UACb,MAAkB;UAAlBA,WAAkB,CAAA,eAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;;yBACT;AAAA,UAAAC,eAAA,CAAA,sBACL,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,iBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;KAIiB,KAAO,CAAA,OAAA;iCAAI,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;SAChB,KAAA,CAAA,KAAA;0CAEV,CAAA,KAAA,YAAA,EAAAC,eAAA,CADF,KAAK,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AAEM,UAAA,CAAA,KAAA,CAAA,KAAA,CAAA,MAAA,KAAA,CAAA;6CAaR,iBAAA,EAAA;yBAZ2B,CAAA,eAAA,EAAA;AAA1B,gBAAA,IAAI,EAAE,EAAE;AAAE,gBAAA,KAAK,EAAC,0BAAU;;AAC/B,cAAAH,kBAAA,CAAQ,2BAAJ,MAAI,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;cACPC;AACA,gBAAA,OAAK,EAAC,SAAS;oBACZ,EAAE,MAAW,CAAA,WAAA;sBACZ,EAAC,QAAQ;AACb,gBAAA,GAAC,EAAC,qBAAa;;AACL,gBAAA,IAAG,gBACH;6BAAA,CAAA,eAAA,EAAA,EAAJ,IAAI,EAAA,EAAA,EAAA,CAAA;;iCACD,MACX;AADW,kBAAAC,eAAA,CAAA,GACX,mBAAG,MAAE,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAGJ,aAAAJ,SAAA,EAAA,EAAAC,kBAAA,OAAA;8EAEc,KAAK,CAAA,KAAA,EAAA,CAAb,IAAI,KAAA;;kBACV,GAAG,EAAE,QAAC,CAAA,OAAA,CAAA,IAAA,CAAA;AACN,kBAAA,KAAI,EAAAK,cAAA,CAAA,CAAA,mBAAoB,EACc,EAAA,2BAAA,EAAA,QAAA,CAAA,QAAQ,CAAC,IAAI,CAAA,EAAA,CAAA,CAAA;;AAClD,kBAAAJ,kBAAA,CAwBI,OAxBJ,UAwBI,EAAA;oBAvBLA,kBAGO,CAAA,MAAA,EAAA;AAHD,sBAAA,KAAA,EAAA,wBAAA;sBAAA,KAAA,EAAA,QAAA,CAAA,SAAA,CAAA,IAAA,CAAA;sBAAA,YAAA,EAAA,QAAA,CAAA,SAAA,CAAA,IAAA,CAAA;;AACgB,sBAAA,CAAA,QAAA,CAAA,UAAS,CAAE,IAAI,CAAA;wCAApCK,WAAoD,CAAA,wBAAA,EAAA;;AAAZ,4BAAA,IAAI,EAAE,EAAE;;wCAChDA,WAAsC,CAAA,2BAAA,EAAA;;AAAZ,4BAAA,IAAI,EAAE,EAAE;;;sCAM/B,CAAA,GAAA,EAAA;sBAHF,IAAI,EAAE,QAAO,CAAA,OAAA,CAAC,IAAI,CAAA;AAClB,sBAAA,MAAK,EAAC,QAAQ;AACf,sBAAA,GAAG,EAAC,UAAC;AACL,sBAAA,KAAG,EAAA,qBAAA;AAAA,qBAAA,EAAAF,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;+BAKiB,CAAA,wBAAA,EAAA;sBAHpB,KAAM,EAAE,QAAW,CAAA,WAAA,CAAC,IAAI,CAAA;sBACvB,OAAA,EAAA,QAAA,CAAA,aAAA,CAAA,IAAA,CAAA;AACD,sBAAA,IAAI,EAAC,OAAO;AACZ,sBAAA,KAAK,EAAC,sBAAc;;+BASV,CAAA,mBAAA,EAAA;AAPV,sBAAA,OAAO,EAAC,wBAAwB;AAC/B,sBAAA,YAAU,EAAE,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,aAAA,CAAA;AACb,sBAAA,KAAI,EAAE,sBAAqB;6BACtB,EAAA,MAAA,KAAE,QAAU,CAAA,UAAA,CAAC,IAAI,CAAA,CAAA;;AAChB,sBAAA,IAAA,UACN,MAAI;wBAAJF,WAAI,CAAA,kBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;;;;AAKJ,kBAAAD,kBAAA,CAgBG,OAhBH,WAgBG,EAAA;AAfH,oBAAAA,kBAAA,CAGK,QAHL,WAGK,EAAA;sBAFLC,WAAG,CAAA,0BAAA,EAAA;AAAA,wBAAA,IAAA,EAAA,EAAA;AAAA,wBAAA,KAAA,EAAA,yBAAA;;sBACFD,kBAAoC,CAAA,MAAA,EAAA,IAAA,EAAAG,eAAA,CAA7B,QAAc,CAAA,cAAA,CAAC,IAAI,CAAA,CAAA,EAAA,CAAA,YAAA;;qBAEvB,QAAA,CAAA,WAAA,CAAA,IAAA,CAAA,CAAA,MAAA,GAAA,CAAA;yDAGC,mBAAA,EAAA;0BAFNF,WAAG,CAAA,6BAAA,EAAA;AAAA,4BAAA,IAAA,EAAA,EAAA;AAAA,4BAAA,KAAA,EAAA,yBAAA;;0BACHD,kBAAE,CAAA,MAAA,EAAA,IAAA,EAAAG,eAAA,CAAA,QAAA,CAAA,eAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;AAES,oBAAA,CAAA,QAAA,CAAA,UAAU,CAAC,IAAG,CAAA,KAAA,IAAA;AAA1B,yBAAAL,SAAA,EAAA,EAAAC,kBAAA,CAMO,QANP,WAMO,EAAA;0BALNE,WAAG,CAAA,uBAAA,EAAA;AAAA,4BAAA,IAAA,EAAA,EAAA;AAAA,4BAAA,KAAA,EAAA,yBAAA;;0BACHA,WAGQ,CAAA,qBAAA,EAAA;AAFR,4BAAA,KAAA,EAAA,oBAAA;;AAEC,4BAAA,YAAO,EAAA,OAAA;;;;;mBAIA,QAAS,CAAA,WAAA,CAAA,IAAA,CAAA,CAAA,MAAA,GAAA,CAAA;AAAnB,uBAAAH,SAAA,EAAA,EAAAC,kBAAA,OAAA;qEAEU,EAAA,IAAA,EAAAO,UAAA,CAAA,QAAA,CAAA,WAAA,CAAA,IAAA,IAAD,GAAC,KAAA;;4BACP,GAAG,EAAE,QAAO,CAAA,SAAA,CAAA,GAAA,CAAA;AACb,4BAAA,KAAK,EAAC,sBAAiB;;AACvB,4BAAAN,kBAAA,QAAA;AACA,8BAAAA,kBAAA,CAAA,MAAA,EAAA,WAAA,EAAAG,eAAA,CAAA,QAAA,CAAA,WAAA,CAAA,GAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnPollsTab.vue3.js","sources":["../../../../../src/integrations/builtin/polls/CnPollsTab.vue?vue&type=template&id=abac3b8c&lang.js"],"sourcesContent":["<!--\n CnPollsTab — bespoke sidebar tab for the `polls` integration.\n\n Replaces the generic CnIntegrationTab for the `polls` leaf: renders a\n live vote tally for each linked NC Polls poll, mirroring the real NC\n Polls list look. Each row foregrounds a poll-type icon (text vs date\n poll), the bold poll question/title, an open / closed status chip\n (CnStatusBadge), a meta line with participant + option counts, a\n relative expiry (NcDateTime) when a deadline is present, and a\n per-option vote-tally progress bar. A trailing \"Open in Polls\" action\n per row deep-links to `/index.php/apps/polls/vote/{id}`.\n\n Tier-2 surface (this commit):\n - \"Link existing poll\" → opens CnPollPicker (modal)\n - \"Create new poll\" → opens CnPollCreate (modal)\n - Per-row unlink → DELETE …/polls/{pollId}\n\n Talks to the OpenRegister Tier-2 poll-link endpoints\n GET /api/objects/{r}/{s}/{id}/polls — list\n POST /api/objects/{r}/{s}/{id}/polls — link existing\n POST /api/objects/{r}/{s}/{id}/polls/new — create + link\n DELETE /api/objects/{r}/{s}/{id}/polls/{pollId} — unlink\n GET /api/integrations/polls/available — picker source\n served by `OCA\\OpenRegister\\Controller\\PollLinksController`.\n\n Surface behaviour:\n - Empty state with \"Open Polls\" CTA when no linked polls.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n See `openregister/openspec/changes/integration-polls/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-polls-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-polls-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-polls-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 poll') }}\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 poll') }}\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-polls-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"polls.length === 0\" class=\"cn-sidebar-tab__empty cn-polls-tab__empty\">\n\t\t\t<Poll :size=\"32\" class=\"cn-polls-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=\"pollsAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Poll :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openPollsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<ul v-else class=\"cn-polls-tab__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"poll in polls\"\n\t\t\t\t:key=\"pollKey(poll)\"\n\t\t\t\tclass=\"cn-polls-tab__row\"\n\t\t\t\t:class=\"{ 'cn-polls-tab__row--closed': isClosed(poll) }\">\n\t\t\t\t<div class=\"cn-polls-tab__row-header\">\n\t\t\t\t\t<span class=\"cn-polls-tab__row-icon\" :title=\"typeLabel(poll)\" :aria-label=\"typeLabel(poll)\">\n\t\t\t\t\t\t<CalendarRange v-if=\"isDatePoll(poll)\" :size=\"20\" />\n\t\t\t\t\t\t<FormatListChecks v-else :size=\"20\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pollUrl(poll)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__title\">{{ pollTitle(poll) }}</a>\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t:label=\"statusLabel(poll)\"\n\t\t\t\t\t\t:variant=\"statusVariant(poll)\"\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__status\" />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Unlink poll')\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__unlink\"\n\t\t\t\t\t\t@click=\"unlinkPoll(poll)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"18\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-polls-tab__meta\">\n\t\t\t\t\t<span class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<AccountMultiple :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<span>{{ voterMetaLabel(poll) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pollOptions(poll).length > 0\" class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<FormatListBulleted :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<span>{{ optionMetaLabel(poll) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"deadlineMs(poll) !== null\" class=\"cn-polls-tab__meta-item\">\n\t\t\t\t\t\t<ClockOutline :size=\"14\" class=\"cn-polls-tab__meta-icon\" />\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tclass=\"cn-polls-tab__time\"\n\t\t\t\t\t\t\t:timestamp=\"deadlineMs(poll)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\n\t\t\t\t<ul v-if=\"pollOptions(poll).length > 0\" class=\"cn-polls-tab__options\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"opt in pollOptions(poll)\"\n\t\t\t\t\t\t:key=\"optionKey(opt)\"\n\t\t\t\t\t\tclass=\"cn-polls-tab__option\">\n\t\t\t\t\t\t<div class=\"cn-polls-tab__option-label\">\n\t\t\t\t\t\t\t<span class=\"cn-polls-tab__option-text\">{{ optionLabel(opt) }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-polls-tab__option-count\">\n\t\t\t\t\t\t\t\t{{ optionCount(opt) }} ({{ optionPercent(poll, opt) }}%)\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"cn-polls-tab__option-bar\"\n\t\t\t\t\t\t\trole=\"progressbar\"\n\t\t\t\t\t\t\t:aria-valuenow=\"optionPercent(poll, opt)\"\n\t\t\t\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t\t\t\taria-valuemax=\"100\">\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclass=\"cn-polls-tab__option-bar-fill\"\n\t\t\t\t\t\t\t\t:style=\"{ width: optionPercent(poll, opt) + '%' }\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"pollDescription(poll)\" class=\"cn-polls-tab__description\">\n\t\t\t\t\t{{ pollDescription(poll) }}\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<CnPollPicker\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<CnPollCreate\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 { NcButton, NcDateTime, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountMultiple from 'vue-material-design-icons/AccountMultiple.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport CalendarRange from 'vue-material-design-icons/CalendarRange.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport FormatListBulleted from 'vue-material-design-icons/FormatListBulleted.vue'\nimport FormatListChecks from 'vue-material-design-icons/FormatListChecks.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Poll from 'vue-material-design-icons/Poll.vue'\nimport CnPollCreate from '../../../components/CnPollCreate/CnPollCreate.vue'\nimport CnPollPicker from '../../../components/CnPollPicker/CnPollPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\n/**\n * CnPollsTab — bespoke live-tally list for the `polls` integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint that\n * mirror the real NC Polls list: type icon, bold question, open/closed\n * status chip, participant + option counts, a relative expiry, and\n * per-option vote-tally progress bars. Tier-2: includes link/create\n * modals and per-row unlink.\n */\nexport default {\n\tname: 'CnPollsTab',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcLoadingIcon,\n\t\tCnStatusBadge,\n\t\tAccountMultiple,\n\t\tAlertCircleOutline,\n\t\tCalendarRange,\n\t\tClockOutline,\n\t\tFormatListBulleted,\n\t\tFormatListChecks,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tPlus,\n\t\tPoll,\n\t\tCnPollPicker,\n\t\tCnPollCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'polls'`). */\n\t\tintegrationId: { type: String, default: 'polls' },\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 polls linked yet') },\n\t\t/** Pre-translated label for the \"Open in Polls\" CTA. */\n\t\topenPollsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Polls') },\n\t\t/** Pre-translated banner when Polls is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Polls is currently unavailable.') },\n\t\t/** URL of the NC Polls app entry. */\n\t\tpollsAppUrl: { type: String, default: '/index.php/apps/polls' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpolls: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\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.fetchPolls()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPolls()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPolls()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn prefixUrl(`${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 polls endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tpollsEndpoint() {\n\t\t\treturn prefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/polls`)\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(this.pollsEndpoint(), {\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.fetchPolls()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This poll is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link poll.')\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('[CnPollsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link poll.')\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(`${this.pollsEndpoint()}/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.fetchPolls()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create poll.')\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('[CnPollsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create poll.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoll(poll) {\n\t\t\tconst pollId = this.pollKey(poll)\n\t\t\tif (!pollId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(`${this.pollsEndpoint()}/${pollId}`, {\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.fetchPolls()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink poll.')\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('[CnPollsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink poll.')\n\t\t\t}\n\t\t},\n\n\t\tpollKey(poll) {\n\t\t\treturn poll.pollId ?? poll.id ?? poll.reference ?? ''\n\t\t},\n\n\t\tpollTitle(poll) {\n\t\t\tconst raw = poll.title ?? poll.pollTitle ?? poll.name ?? this.pollKey(poll)\n\t\t\t// Strip any legacy `[or:{uuid}]` marker from displayed title\n\t\t\t// via the shared helper (ADR-019).\n\t\t\treturn stripMarker(raw) || String(raw)\n\t\t},\n\n\t\tpollDescription(poll) {\n\t\t\treturn stripMarker(poll.description)\n\t\t},\n\n\t\tpollUrl(poll) {\n\t\t\tif (poll.url && safeHref(poll.url) !== '#') {\n\t\t\t\treturn poll.url\n\t\t\t}\n\t\t\tconst id = this.pollKey(poll)\n\t\t\treturn id ? `/index.php/apps/polls/vote/${id}` : this.pollsAppUrl\n\t\t},\n\n\t\tpollType(poll) {\n\t\t\treturn poll.type ?? poll.pollType ?? ''\n\t\t},\n\n\t\tisDatePoll(poll) {\n\t\t\tconst type = String(this.pollType(poll)).toLowerCase()\n\t\t\treturn type.indexOf('date') !== -1\n\t\t},\n\n\t\ttypeLabel(poll) {\n\t\t\treturn this.isDatePoll(poll)\n\t\t\t\t? t('nextcloud-vue', 'Date poll')\n\t\t\t\t: t('nextcloud-vue', 'Text poll')\n\t\t},\n\n\t\tpollOptions(poll) {\n\t\t\tconst opts = poll.options ?? poll.results ?? poll.optionResults ?? []\n\t\t\treturn Array.isArray(opts) ? opts : []\n\t\t},\n\n\t\toptionKey(opt) {\n\t\t\treturn opt.id ?? opt.key ?? opt.text ?? ''\n\t\t},\n\n\t\toptionLabel(opt) {\n\t\t\treturn opt.text ?? opt.label ?? opt.name ?? String(this.optionKey(opt))\n\t\t},\n\n\t\toptionCount(opt) {\n\t\t\tconst n = Number(opt.votes ?? opt.count ?? opt.voteCount ?? 0)\n\t\t\treturn Number.isFinite(n) ? n : 0\n\t\t},\n\n\t\toptionPercent(poll, opt) {\n\t\t\tconst total = this.totalVotes(poll)\n\t\t\tif (total <= 0) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.round((this.optionCount(opt) / total) * 100)\n\t\t},\n\n\t\ttotalVotes(poll) {\n\t\t\treturn this.pollOptions(poll).reduce((sum, o) => sum + this.optionCount(o), 0)\n\t\t},\n\n\t\tvoterCount(poll) {\n\t\t\tconst n = Number(poll.voterCount ?? poll.voters ?? poll.participants ?? 0)\n\t\t\treturn Number.isFinite(n) && n > 0 ? n : this.totalVotes(poll)\n\t\t},\n\n\t\tvoterMetaLabel(poll) {\n\t\t\tconst voters = this.voterCount(poll)\n\t\t\treturn t('nextcloud-vue', '{n} participants', { n: voters })\n\t\t},\n\n\t\toptionMetaLabel(poll) {\n\t\t\tconst count = this.pollOptions(poll).length\n\t\t\treturn t('nextcloud-vue', '{n} options', { n: count })\n\t\t},\n\n\t\tdeadline(poll) {\n\t\t\treturn poll.deadline ?? poll.expire ?? poll.expiresAt ?? null\n\t\t},\n\n\t\tdeadlineMs(poll) {\n\t\t\tconst v = this.deadline(poll)\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\t// Treat as unix seconds when it's small enough to be a 10-digit epoch.\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\tisClosed(poll) {\n\t\t\tconst ms = this.deadlineMs(poll)\n\t\t\tif (ms === null) {\n\t\t\t\t// Without a deadline, fall back to a `closed` flag if present.\n\t\t\t\treturn poll.closed === true || poll.status === 'closed'\n\t\t\t}\n\t\t\treturn ms <= Date.now()\n\t\t},\n\n\t\tstatusLabel(poll) {\n\t\t\treturn this.isClosed(poll)\n\t\t\t\t? t('nextcloud-vue', 'Closed')\n\t\t\t\t: t('nextcloud-vue', 'Open')\n\t\t},\n\n\t\tstatusVariant(poll) {\n\t\t\treturn this.isClosed(poll) ? 'default' : 'success'\n\t\t},\n\n\t\tasync fetchPolls() {\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(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.polls = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.polls = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.polls = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load polls.')\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('[CnPollsTab] failed to fetch polls', err)\n\t\t\t\tthis.polls = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load polls.')\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-polls-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-polls-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-polls-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-polls-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-polls-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-polls-tab__row {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 10px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tborder-left: 3px solid var(--color-primary-element);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-polls-tab__row--closed {\n\tborder-left-color: var(--color-border-dark, var(--color-border));\n\tbackground: transparent;\n\topacity: 0.78;\n}\n\n.cn-polls-tab__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-polls-tab__row-icon {\n\tdisplay: inline-flex;\n\tcolor: var(--color-primary-element);\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__row--closed .cn-polls-tab__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__title {\n\tflex: 1;\n\tmin-width: 0;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\tfont-weight: 600;\n}\n\na.cn-polls-tab__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-polls-tab__status {\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-polls-tab__meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 28px;\n}\n\n.cn-polls-tab__meta-item {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-polls-tab__meta-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__time {\n\tfont-size: 1em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__options {\n\tlist-style: none;\n\tmargin: 4px 0 0;\n\tpadding: 0 0 0 28px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-polls-tab__option {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-polls-tab__option-label {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n}\n\n.cn-polls-tab__option-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n}\n\n.cn-polls-tab__option-count {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-polls-tab__option-bar {\n\theight: 6px;\n\tborder-radius: 3px;\n\tbackground: var(--color-background-dark);\n\toverflow: hidden;\n}\n\n.cn-polls-tab__option-bar-fill {\n\theight: 100%;\n\tbackground: var(--color-primary-element, #21468B);\n\ttransition: width 0.2s ease;\n}\n\n.cn-polls-tab__description {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 28px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_createTextVNode","_toDisplayString","_normalizeClass","_createBlock","_renderList"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnSharesTab.vue2.js","sources":["../../../../../src/integrations/builtin/shares/CnSharesTab.vue"],"sourcesContent":["<!--\n CnSharesTab — bespoke sidebar tab for the `shares` integration.\n\n Replaces the generic CnIntegrationTab for the `shares` leaf: renders\n a recipient list grouped by share type (user / group / public link\n / federated), with per-row permissions, expiry date, a\n password-protected indicator, and a \"manage in Files\" deep-link.\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/shares`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\SharesProvider`\n (which walks linked files and calls `OCP\\Share\\IManager::getSharesBy()`\n per file).\n\n Surface behaviour:\n - Empty state with \"Open Files\" CTA when no shares exist.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses Shares' four primary signals — recipient, permissions,\n expiry, password-protection — that case handlers need to triage \"who\n has access to this case and how?\" at a glance.\n\n See `openregister/openspec/changes/integration-shares/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-shares-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-shares-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-shares-tab__toolbar\">\n\t\t\t<NcButton variant=\"primary\" data-testid=\"cn-shares-tab-share-file\" @click=\"openCreateDialog\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ shareFileLabel }}\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-shares-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"shares.length === 0\" class=\"cn-sidebar-tab__empty cn-shares-tab__empty\">\n\t\t\t<Share :size=\"32\" class=\"cn-shares-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=\"filesAppUrl\"\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<FolderOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openFilesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else class=\"cn-shares-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedShares\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-shares-tab__group\">\n\t\t\t\t<header class=\"cn-shares-tab__group-header\">\n\t\t\t\t\t<component :is=\"group.icon\" :size=\"18\" />\n\t\t\t\t\t<span class=\"cn-shares-tab__group-label\">{{ group.label }}</span>\n\t\t\t\t\t<span class=\"cn-shares-tab__group-count\">{{ group.rows.length }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-shares-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"share in group.rows\"\n\t\t\t\t\t\t:key=\"shareKey(share)\"\n\t\t\t\t\t\tclass=\"cn-shares-tab__row\"\n\t\t\t\t\t\t:name=\"shareTarget(share)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__avatar\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<component :is=\"iconFor(shareType(share))\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<LockOutline\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__avatar-lock\"\n\t\t\t\t\t\t\t\t\t:size=\"12\"\n\t\t\t\t\t\t\t\t\t:title=\"passwordProtectedLabel\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__permissions\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in permissionBadges(share)\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\t\t\t\t:label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"shareExpiryMs(share)\" #details>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__expiry\" :title=\"expiryLabel\">\n\t\t\t\t\t\t\t\t<ClockOutline :size=\"13\" />\n\t\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\t\t:timestamp=\"shareExpiryMs(share)\"\n\t\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canRevoke(share)\"\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t@click=\"revoke(share)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<CloseCircleOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ revokeLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t\t<div class=\"cn-shares-tab__footer\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<FolderOutline :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnShareCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:files=\"shareableFiles\"\n\t\t\t:filesLoading=\"filesLoading\"\n\t\t\t:principals=\"principals\"\n\t\t\t:principalsLoading=\"principalsLoading\"\n\t\t\t@close=\"showCreate = false\"\n\t\t\t@searchPrincipals=\"searchPrincipals\"\n\t\t\t@create=\"createShare\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountGroupOutline from 'vue-material-design-icons/AccountGroupOutline.vue'\nimport AccountOutline from 'vue-material-design-icons/AccountOutline.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'\nimport Earth from 'vue-material-design-icons/Earth.vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport LockOutline from 'vue-material-design-icons/LockOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Share from 'vue-material-design-icons/Share.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { CnShareCreate } from '../../../components/CnShareCreate/index.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\n// NC core share-type constants (OCP\\Share\\IShare::TYPE_*).\nconst SHARE_TYPE_USER = 0\nconst SHARE_TYPE_GROUP = 1\nconst SHARE_TYPE_LINK = 3\nconst SHARE_TYPE_EMAIL = 4\nconst SHARE_TYPE_REMOTE = 6\nconst SHARE_TYPE_REMOTE_GROUP = 9\n\n// Permission bitmask (OCP\\Constants::PERMISSION_*).\nconst PERMISSION_READ = 1\nconst PERMISSION_UPDATE = 2\nconst PERMISSION_CREATE = 4\nconst PERMISSION_DELETE = 8\nconst PERMISSION_SHARE = 16\n\n/**\n * CnSharesTab — bespoke recipient list for the `shares` integration.\n *\n * Renders shares grouped by type with permissions, expiry, password-\n * protected flag, and a revoke action. Reads from the OR\n * pluggable-integration endpoint and delegates revoke back to the same\n * endpoint via DELETE.\n */\nexport default {\n\tname: 'CnSharesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tAccountOutline,\n\t\tAccountGroupOutline,\n\t\tLinkVariant,\n\t\tEmailOutline,\n\t\tEarth,\n\t\tLockOutline,\n\t\tClockOutline,\n\t\tCloseCircleOutline,\n\t\tFolderOutline,\n\t\tShare,\n\t\tPlus,\n\t\tCnStatusBadge,\n\t\tCnShareCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'shares'`). */\n\t\tintegrationId: { type: String, default: 'shares' },\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 shares on this object yet') },\n\t\t/** Pre-translated label for the \"Open Files\" CTA. */\n\t\topenFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Manage in Files') },\n\t\t/** Pre-translated banner when the share subsystem is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC sharing is currently unavailable.') },\n\t\t/** Pre-translated revoke button label. */\n\t\trevokeLabel: { type: String, default: () => t('nextcloud-vue', 'Revoke share') },\n\t\t/* eslint-disable vue/no-unused-properties -- the row hides the revoke button when canRevoke is false rather than disabling it, so the tooltip has no anchor today */\n\t\t/** Pre-translated tooltip shown when the current user cannot revoke. */\n\t\trevokeDisabledLabel: { type: String, default: () => t('nextcloud-vue', 'Only the share owner can revoke') },\n\t\t/* eslint-enable vue/no-unused-properties */\n\t\t/** Pre-translated label for the password-protected indicator. */\n\t\tpasswordProtectedLabel: { type: String, default: () => t('nextcloud-vue', 'Password protected') },\n\t\t/** Pre-translated label for the expiry row. */\n\t\texpiryLabel: { type: String, default: () => t('nextcloud-vue', 'Expires') },\n\t\t/** URL of the NC Files app entry. */\n\t\tfilesAppUrl: { type: String, default: '/index.php/apps/files' },\n\t\t/** Pre-translated label for the \"Share file\" toolbar button. */\n\t\tshareFileLabel: { type: String, default: () => t('nextcloud-vue', 'Share file') },\n\t},\n\n\temits: ['search-principals', 'share-created', 'share-revoked'],\n\n\tdata() {\n\t\treturn {\n\t\t\tshares: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tshowCreate: false,\n\t\t\tshareableFiles: [],\n\t\t\tfilesLoading: false,\n\t\t\tprincipals: [],\n\t\t\tprincipalsLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tgroupedShares() {\n\t\t\tconst groups = [\n\t\t\t\t{ key: 'user', label: t('nextcloud-vue', 'Users'), icon: 'AccountOutline', match: (s) => this.shareType(s) === SHARE_TYPE_USER },\n\t\t\t\t{ key: 'group', label: t('nextcloud-vue', 'Groups'), icon: 'AccountGroupOutline', match: (s) => this.shareType(s) === SHARE_TYPE_GROUP },\n\t\t\t\t{ key: 'link', label: t('nextcloud-vue', 'Public links'), icon: 'LinkVariant', match: (s) => this.shareType(s) === SHARE_TYPE_LINK },\n\t\t\t\t{ key: 'email', label: t('nextcloud-vue', 'Email'), icon: 'EmailOutline', match: (s) => this.shareType(s) === SHARE_TYPE_EMAIL },\n\t\t\t\t{ key: 'federated', label: t('nextcloud-vue', 'Federated'), icon: 'Earth', match: (s) => this.shareType(s) === SHARE_TYPE_REMOTE || this.shareType(s) === SHARE_TYPE_REMOTE_GROUP },\n\t\t\t]\n\t\t\treturn groups\n\t\t\t\t.map((g) => ({ ...g, rows: this.shares.filter(g.match) }))\n\t\t\t\t.filter((g) => g.rows.length > 0)\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.fetchShares()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchShares()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchShares()\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\t// Tier-2 dedicated endpoints (ShareLinksController) — distinct\n\t\t// from the generic registry `baseUrl()` above. Create/revoke flow\n\t\t// through these so the IManager-backed service owns the write\n\t\t// path (NO cache table).\n\t\tsharesUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/shares`\n\t\t},\n\n\t\tshareableFilesUrl() {\n\t\t\treturn `${this.apiBase}/integrations/shares/files/${this.register}/${this.schema}/${this.objectId}`\n\t\t},\n\n\t\tasync openCreateDialog() {\n\t\t\tthis.showCreate = true\n\t\t\tawait this.fetchShareableFiles()\n\t\t},\n\n\t\tasync fetchShareableFiles() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.filesLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.shareableFilesUrl()), { 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.shareableFiles = data.results || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else {\n\t\t\t\t\tthis.shareableFiles = []\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('[CnSharesTab] failed to fetch shareable files', err)\n\t\t\t\tthis.shareableFiles = []\n\t\t\t} finally {\n\t\t\t\tthis.filesLoading = false\n\t\t\t}\n\t\t},\n\n\t\tsearchPrincipals({ shareType, query }) {\n\t\t\t// Principal lookup is host-supplied: the host app wires NC's\n\t\t\t// share-search OCS endpoint. Emit upward so the host can\n\t\t\t// populate `principals`; default is a no-op empty list.\n\t\t\tthis.$emit('search-principals', { shareType, query })\n\t\t},\n\n\t\tasync createShare(payload) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.sharesUrl()), {\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\tthis.showCreate = false\n\t\t\t\t\tthis.$emit('share-created', payload)\n\t\t\t\t\tawait this.fetchShares()\n\t\t\t\t} else {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.error = data.error || t('nextcloud-vue', 'Could not create share.')\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('[CnSharesTab] failed to create share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create share.')\n\t\t\t}\n\t\t},\n\n\t\tshareKey(share) {\n\t\t\treturn share.id ?? share.shareId ?? share.token ?? ''\n\t\t},\n\n\t\tshareType(share) {\n\t\t\tconst value = share.shareType ?? share.share_type ?? share.type\n\t\t\treturn Number.isFinite(Number(value)) ? Number(value) : -1\n\t\t},\n\n\t\tshareTarget(share) {\n\t\t\tconst type = this.shareType(share)\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\t// Public links surface as a generic \"Share link\" label,\n\t\t\t\t// mirroring NC core's share list (the raw token is never\n\t\t\t\t// shown as a recipient name).\n\t\t\t\treturn share.shareWithDisplayname || share.label || t('nextcloud-vue', 'Share link')\n\t\t\t}\n\t\t\treturn share.shareWithDisplayname || share.shareWith || share.share_with || share.targetDisplayName || ''\n\t\t},\n\n\t\t// Picks the recipient/share-type icon component for a row,\n\t\t// mirroring NC core's share list (user / group / link / email /\n\t\t// federated).\n\t\ticonFor(type) {\n\t\t\tif (type === SHARE_TYPE_GROUP) {\n\t\t\t\treturn 'AccountGroupOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\treturn 'LinkVariant'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_EMAIL) {\n\t\t\t\treturn 'EmailOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_REMOTE || type === SHARE_TYPE_REMOTE_GROUP) {\n\t\t\t\treturn 'Earth'\n\t\t\t}\n\t\t\treturn 'AccountOutline'\n\t\t},\n\n\t\tpermissionLabel(share) {\n\t\t\treturn this.permissionBadges(share).map((b) => b.label).join(' · ')\n\t\t},\n\n\t\t// Decomposes the NC permission bitmask into the badge set the real\n\t\t// share UI shows: \"Can edit\" / \"Read only\" (mutually exclusive),\n\t\t// plus \"Can reshare\" when the share permission bit is set.\n\t\tpermissionBadges(share) {\n\t\t\tconst perms = Number(share.permissions ?? share.permission ?? 0)\n\t\t\tconst canEdit = (perms & PERMISSION_UPDATE) === PERMISSION_UPDATE\n\t\t\t\t|| (perms & PERMISSION_CREATE) === PERMISSION_CREATE\n\t\t\t\t|| (perms & PERMISSION_DELETE) === PERMISSION_DELETE\n\t\t\tconst canRead = (perms & PERMISSION_READ) === PERMISSION_READ\n\t\t\tconst badges = []\n\t\t\tif (canEdit) {\n\t\t\t\tbadges.push({ key: 'edit', variant: 'success', label: t('nextcloud-vue', 'Can edit') })\n\t\t\t} else if (canRead) {\n\t\t\t\tbadges.push({ key: 'read', variant: 'default', label: t('nextcloud-vue', 'Read only') })\n\t\t\t}\n\t\t\tif ((perms & PERMISSION_SHARE) === PERMISSION_SHARE) {\n\t\t\t\tbadges.push({ key: 'reshare', variant: 'info', label: t('nextcloud-vue', 'Can reshare') })\n\t\t\t}\n\t\t\treturn badges\n\t\t},\n\n\t\t// Returns the expiry as epoch-ms for <NcDateTime>, or 0 when there\n\t\t// is no (valid) expiry so the template can `v-if` it away.\n\t\tshareExpiryMs(share) {\n\t\t\tconst value = share.expiration ?? share.expirationDate ?? share.expiry ?? null\n\t\t\tif (!value) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tconst date = new Date(value)\n\t\t\tconst ms = date.getTime()\n\t\t\treturn Number.isNaN(ms) ? 0 : ms\n\t\t},\n\n\t\tisPasswordProtected(share) {\n\t\t\treturn Boolean(share.passwordProtected ?? share.hasPassword ?? share.password)\n\t\t},\n\n\t\tcanRevoke(share) {\n\t\t\t// The current-user-can-revoke flag is provider-supplied. When\n\t\t\t// absent we default to true so the action stays usable; the\n\t\t\t// backend rejects unauthorized revoke attempts.\n\t\t\treturn share.canRevoke !== false\n\t\t},\n\n\t\tasync fetchShares() {\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.shares = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\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('[CnSharesTab] failed to fetch shares', err)\n\t\t\t\tthis.shares = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync revoke(share) {\n\t\t\tconst id = this.shareKey(share)\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.baseUrl()}/${encodeURIComponent(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\tthis.shares = this.shares.filter((row) => this.shareKey(row) !== id)\n\t\t\t\t\tthis.$emit('share-revoked', { id, share })\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\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('[CnSharesTab] failed to revoke share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-shares-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-shares-tab__toolbar {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 10px;\n}\n\n.cn-shares-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-shares-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-shares-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-shares-tab__group {\n\tmargin-bottom: 12px;\n}\n\n.cn-shares-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 0;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-shares-tab__group-label {\n\tflex: 1;\n}\n\n.cn-shares-tab__group-count {\n\tfont-weight: normal;\n\tfont-size: 0.85em;\n\tpadding: 1px 6px;\n\tborder-radius: 9px;\n\tbackground: var(--color-background-hover);\n}\n\n.cn-shares-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Share-type icon tile, mirroring the NcAvatar slot in NC's share list. */\n.cn-shares-tab__avatar {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n}\n\n.cn-shares-tab__avatar-lock {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\tcolor: var(--color-warning, #e9a40f);\n\tbackground: var(--color-main-background);\n\tborder-radius: 50%;\n}\n\n.cn-shares-tab__permissions {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n\n.cn-shares-tab__badge {\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__expiry {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__footer {\n\tmargin-top: 12px;\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["CnStatusBadge","CnShareCreate","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnSharesTab.vue2.js","sources":["../../../../../src/integrations/builtin/shares/CnSharesTab.vue"],"sourcesContent":["<!--\n CnSharesTab — bespoke sidebar tab for the `shares` integration.\n\n Replaces the generic CnIntegrationTab for the `shares` leaf: renders\n a recipient list grouped by share type (user / group / public link\n / federated), with per-row permissions, expiry date, a\n password-protected indicator, and a \"manage in Files\" deep-link.\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/shares`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\SharesProvider`\n (which walks linked files and calls `OCP\\Share\\IManager::getSharesBy()`\n per file).\n\n Surface behaviour:\n - Empty state with \"Open Files\" CTA when no shares exist.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses Shares' four primary signals — recipient, permissions,\n expiry, password-protection — that case handlers need to triage \"who\n has access to this case and how?\" at a glance.\n\n See `openregister/openspec/changes/integration-shares/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-shares-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-shares-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-shares-tab__toolbar\">\n\t\t\t<NcButton variant=\"primary\" data-testid=\"cn-shares-tab-share-file\" @click=\"openCreateDialog\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ shareFileLabel }}\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-shares-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"shares.length === 0\" class=\"cn-sidebar-tab__empty cn-shares-tab__empty\">\n\t\t\t<Share :size=\"32\" class=\"cn-shares-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=\"filesAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openFilesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else class=\"cn-shares-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedShares\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-shares-tab__group\">\n\t\t\t\t<header class=\"cn-shares-tab__group-header\">\n\t\t\t\t\t<component :is=\"group.icon\" :size=\"18\" />\n\t\t\t\t\t<span class=\"cn-shares-tab__group-label\">{{ group.label }}</span>\n\t\t\t\t\t<span class=\"cn-shares-tab__group-count\">{{ group.rows.length }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-shares-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"share in group.rows\"\n\t\t\t\t\t\t:key=\"shareKey(share)\"\n\t\t\t\t\t\tclass=\"cn-shares-tab__row\"\n\t\t\t\t\t\t:name=\"shareTarget(share)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__avatar\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<component :is=\"iconFor(shareType(share))\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<LockOutline\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__avatar-lock\"\n\t\t\t\t\t\t\t\t\t:size=\"12\"\n\t\t\t\t\t\t\t\t\t:title=\"passwordProtectedLabel\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__permissions\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in permissionBadges(share)\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\t\t\t\t:label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"shareExpiryMs(share)\" #details>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__expiry\" :title=\"expiryLabel\">\n\t\t\t\t\t\t\t\t<ClockOutline :size=\"13\" />\n\t\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\t\t:timestamp=\"shareExpiryMs(share)\"\n\t\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canRevoke(share)\"\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t@click=\"revoke(share)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<CloseCircleOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ revokeLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t\t<div class=\"cn-shares-tab__footer\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<FolderOutline :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnShareCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:files=\"shareableFiles\"\n\t\t\t:filesLoading=\"filesLoading\"\n\t\t\t:principals=\"principals\"\n\t\t\t:principalsLoading=\"principalsLoading\"\n\t\t\t@close=\"showCreate = false\"\n\t\t\t@searchPrincipals=\"searchPrincipals\"\n\t\t\t@create=\"createShare\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountGroupOutline from 'vue-material-design-icons/AccountGroupOutline.vue'\nimport AccountOutline from 'vue-material-design-icons/AccountOutline.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'\nimport Earth from 'vue-material-design-icons/Earth.vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport LockOutline from 'vue-material-design-icons/LockOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Share from 'vue-material-design-icons/Share.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { CnShareCreate } from '../../../components/CnShareCreate/index.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\n// NC core share-type constants (OCP\\Share\\IShare::TYPE_*).\nconst SHARE_TYPE_USER = 0\nconst SHARE_TYPE_GROUP = 1\nconst SHARE_TYPE_LINK = 3\nconst SHARE_TYPE_EMAIL = 4\nconst SHARE_TYPE_REMOTE = 6\nconst SHARE_TYPE_REMOTE_GROUP = 9\n\n// Permission bitmask (OCP\\Constants::PERMISSION_*).\nconst PERMISSION_READ = 1\nconst PERMISSION_UPDATE = 2\nconst PERMISSION_CREATE = 4\nconst PERMISSION_DELETE = 8\nconst PERMISSION_SHARE = 16\n\n/**\n * CnSharesTab — bespoke recipient list for the `shares` integration.\n *\n * Renders shares grouped by type with permissions, expiry, password-\n * protected flag, and a revoke action. Reads from the OR\n * pluggable-integration endpoint and delegates revoke back to the same\n * endpoint via DELETE.\n */\nexport default {\n\tname: 'CnSharesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tAccountOutline,\n\t\tAccountGroupOutline,\n\t\tLinkVariant,\n\t\tEmailOutline,\n\t\tEarth,\n\t\tLockOutline,\n\t\tClockOutline,\n\t\tCloseCircleOutline,\n\t\tFolderOutline,\n\t\tShare,\n\t\tPlus,\n\t\tCnStatusBadge,\n\t\tCnShareCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'shares'`). */\n\t\tintegrationId: { type: String, default: 'shares' },\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 shares on this object yet') },\n\t\t/** Pre-translated label for the \"Open Files\" CTA. */\n\t\topenFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Manage in Files') },\n\t\t/** Pre-translated banner when the share subsystem is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC sharing is currently unavailable.') },\n\t\t/** Pre-translated revoke button label. */\n\t\trevokeLabel: { type: String, default: () => t('nextcloud-vue', 'Revoke share') },\n\t\t/* eslint-disable vue/no-unused-properties -- the row hides the revoke button when canRevoke is false rather than disabling it, so the tooltip has no anchor today */\n\t\t/** Pre-translated tooltip shown when the current user cannot revoke. */\n\t\trevokeDisabledLabel: { type: String, default: () => t('nextcloud-vue', 'Only the share owner can revoke') },\n\t\t/* eslint-enable vue/no-unused-properties */\n\t\t/** Pre-translated label for the password-protected indicator. */\n\t\tpasswordProtectedLabel: { type: String, default: () => t('nextcloud-vue', 'Password protected') },\n\t\t/** Pre-translated label for the expiry row. */\n\t\texpiryLabel: { type: String, default: () => t('nextcloud-vue', 'Expires') },\n\t\t/** URL of the NC Files app entry. */\n\t\tfilesAppUrl: { type: String, default: '/index.php/apps/files' },\n\t\t/** Pre-translated label for the \"Share file\" toolbar button. */\n\t\tshareFileLabel: { type: String, default: () => t('nextcloud-vue', 'Share file') },\n\t},\n\n\temits: ['search-principals', 'share-created', 'share-revoked'],\n\n\tdata() {\n\t\treturn {\n\t\t\tshares: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tshowCreate: false,\n\t\t\tshareableFiles: [],\n\t\t\tfilesLoading: false,\n\t\t\tprincipals: [],\n\t\t\tprincipalsLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tgroupedShares() {\n\t\t\tconst groups = [\n\t\t\t\t{ key: 'user', label: t('nextcloud-vue', 'Users'), icon: 'AccountOutline', match: (s) => this.shareType(s) === SHARE_TYPE_USER },\n\t\t\t\t{ key: 'group', label: t('nextcloud-vue', 'Groups'), icon: 'AccountGroupOutline', match: (s) => this.shareType(s) === SHARE_TYPE_GROUP },\n\t\t\t\t{ key: 'link', label: t('nextcloud-vue', 'Public links'), icon: 'LinkVariant', match: (s) => this.shareType(s) === SHARE_TYPE_LINK },\n\t\t\t\t{ key: 'email', label: t('nextcloud-vue', 'Email'), icon: 'EmailOutline', match: (s) => this.shareType(s) === SHARE_TYPE_EMAIL },\n\t\t\t\t{ key: 'federated', label: t('nextcloud-vue', 'Federated'), icon: 'Earth', match: (s) => this.shareType(s) === SHARE_TYPE_REMOTE || this.shareType(s) === SHARE_TYPE_REMOTE_GROUP },\n\t\t\t]\n\t\t\treturn groups\n\t\t\t\t.map((g) => ({ ...g, rows: this.shares.filter(g.match) }))\n\t\t\t\t.filter((g) => g.rows.length > 0)\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.fetchShares()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchShares()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchShares()\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\t// Tier-2 dedicated endpoints (ShareLinksController) — distinct\n\t\t// from the generic registry `baseUrl()` above. Create/revoke flow\n\t\t// through these so the IManager-backed service owns the write\n\t\t// path (NO cache table).\n\t\tsharesUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/shares`\n\t\t},\n\n\t\tshareableFilesUrl() {\n\t\t\treturn `${this.apiBase}/integrations/shares/files/${this.register}/${this.schema}/${this.objectId}`\n\t\t},\n\n\t\tasync openCreateDialog() {\n\t\t\tthis.showCreate = true\n\t\t\tawait this.fetchShareableFiles()\n\t\t},\n\n\t\tasync fetchShareableFiles() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.filesLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.shareableFilesUrl()), { 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.shareableFiles = data.results || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else {\n\t\t\t\t\tthis.shareableFiles = []\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('[CnSharesTab] failed to fetch shareable files', err)\n\t\t\t\tthis.shareableFiles = []\n\t\t\t} finally {\n\t\t\t\tthis.filesLoading = false\n\t\t\t}\n\t\t},\n\n\t\tsearchPrincipals({ shareType, query }) {\n\t\t\t// Principal lookup is host-supplied: the host app wires NC's\n\t\t\t// share-search OCS endpoint. Emit upward so the host can\n\t\t\t// populate `principals`; default is a no-op empty list.\n\t\t\tthis.$emit('search-principals', { shareType, query })\n\t\t},\n\n\t\tasync createShare(payload) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.sharesUrl()), {\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\tthis.showCreate = false\n\t\t\t\t\tthis.$emit('share-created', payload)\n\t\t\t\t\tawait this.fetchShares()\n\t\t\t\t} else {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.error = data.error || t('nextcloud-vue', 'Could not create share.')\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('[CnSharesTab] failed to create share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create share.')\n\t\t\t}\n\t\t},\n\n\t\tshareKey(share) {\n\t\t\treturn share.id ?? share.shareId ?? share.token ?? ''\n\t\t},\n\n\t\tshareType(share) {\n\t\t\tconst value = share.shareType ?? share.share_type ?? share.type\n\t\t\treturn Number.isFinite(Number(value)) ? Number(value) : -1\n\t\t},\n\n\t\tshareTarget(share) {\n\t\t\tconst type = this.shareType(share)\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\t// Public links surface as a generic \"Share link\" label,\n\t\t\t\t// mirroring NC core's share list (the raw token is never\n\t\t\t\t// shown as a recipient name).\n\t\t\t\treturn share.shareWithDisplayname || share.label || t('nextcloud-vue', 'Share link')\n\t\t\t}\n\t\t\treturn share.shareWithDisplayname || share.shareWith || share.share_with || share.targetDisplayName || ''\n\t\t},\n\n\t\t// Picks the recipient/share-type icon component for a row,\n\t\t// mirroring NC core's share list (user / group / link / email /\n\t\t// federated).\n\t\ticonFor(type) {\n\t\t\tif (type === SHARE_TYPE_GROUP) {\n\t\t\t\treturn 'AccountGroupOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\treturn 'LinkVariant'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_EMAIL) {\n\t\t\t\treturn 'EmailOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_REMOTE || type === SHARE_TYPE_REMOTE_GROUP) {\n\t\t\t\treturn 'Earth'\n\t\t\t}\n\t\t\treturn 'AccountOutline'\n\t\t},\n\n\t\tpermissionLabel(share) {\n\t\t\treturn this.permissionBadges(share).map((b) => b.label).join(' · ')\n\t\t},\n\n\t\t// Decomposes the NC permission bitmask into the badge set the real\n\t\t// share UI shows: \"Can edit\" / \"Read only\" (mutually exclusive),\n\t\t// plus \"Can reshare\" when the share permission bit is set.\n\t\tpermissionBadges(share) {\n\t\t\tconst perms = Number(share.permissions ?? share.permission ?? 0)\n\t\t\tconst canEdit = (perms & PERMISSION_UPDATE) === PERMISSION_UPDATE\n\t\t\t\t|| (perms & PERMISSION_CREATE) === PERMISSION_CREATE\n\t\t\t\t|| (perms & PERMISSION_DELETE) === PERMISSION_DELETE\n\t\t\tconst canRead = (perms & PERMISSION_READ) === PERMISSION_READ\n\t\t\tconst badges = []\n\t\t\tif (canEdit) {\n\t\t\t\tbadges.push({ key: 'edit', variant: 'success', label: t('nextcloud-vue', 'Can edit') })\n\t\t\t} else if (canRead) {\n\t\t\t\tbadges.push({ key: 'read', variant: 'default', label: t('nextcloud-vue', 'Read only') })\n\t\t\t}\n\t\t\tif ((perms & PERMISSION_SHARE) === PERMISSION_SHARE) {\n\t\t\t\tbadges.push({ key: 'reshare', variant: 'info', label: t('nextcloud-vue', 'Can reshare') })\n\t\t\t}\n\t\t\treturn badges\n\t\t},\n\n\t\t// Returns the expiry as epoch-ms for <NcDateTime>, or 0 when there\n\t\t// is no (valid) expiry so the template can `v-if` it away.\n\t\tshareExpiryMs(share) {\n\t\t\tconst value = share.expiration ?? share.expirationDate ?? share.expiry ?? null\n\t\t\tif (!value) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tconst date = new Date(value)\n\t\t\tconst ms = date.getTime()\n\t\t\treturn Number.isNaN(ms) ? 0 : ms\n\t\t},\n\n\t\tisPasswordProtected(share) {\n\t\t\treturn Boolean(share.passwordProtected ?? share.hasPassword ?? share.password)\n\t\t},\n\n\t\tcanRevoke(share) {\n\t\t\t// The current-user-can-revoke flag is provider-supplied. When\n\t\t\t// absent we default to true so the action stays usable; the\n\t\t\t// backend rejects unauthorized revoke attempts.\n\t\t\treturn share.canRevoke !== false\n\t\t},\n\n\t\tasync fetchShares() {\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.shares = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\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('[CnSharesTab] failed to fetch shares', err)\n\t\t\t\tthis.shares = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync revoke(share) {\n\t\t\tconst id = this.shareKey(share)\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.baseUrl()}/${encodeURIComponent(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\tthis.shares = this.shares.filter((row) => this.shareKey(row) !== id)\n\t\t\t\t\tthis.$emit('share-revoked', { id, share })\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\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('[CnSharesTab] failed to revoke share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-shares-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-shares-tab__toolbar {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 10px;\n}\n\n.cn-shares-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-shares-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-shares-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-shares-tab__group {\n\tmargin-bottom: 12px;\n}\n\n.cn-shares-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 0;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-shares-tab__group-label {\n\tflex: 1;\n}\n\n.cn-shares-tab__group-count {\n\tfont-weight: normal;\n\tfont-size: 0.85em;\n\tpadding: 1px 6px;\n\tborder-radius: 9px;\n\tbackground: var(--color-background-hover);\n}\n\n.cn-shares-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Share-type icon tile, mirroring the NcAvatar slot in NC's share list. */\n.cn-shares-tab__avatar {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n}\n\n.cn-shares-tab__avatar-lock {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\tcolor: var(--color-warning, #e9a40f);\n\tbackground: var(--color-main-background);\n\tborder-radius: 50%;\n}\n\n.cn-shares-tab__permissions {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n\n.cn-shares-tab__badge {\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__expiry {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__footer {\n\tmargin-top: 12px;\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["CnStatusBadge","CnShareCreate","t"],"mappings":"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"}
@@ -85,8 +85,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
85
85
  createVNode(_component_NcButton, {
86
86
  variant: "primary",
87
87
  href: $props.filesAppUrl,
88
- target: "_blank",
89
- rel: "noopener noreferrer"
88
+ target: "_blank"
90
89
  }, {
91
90
  icon: withCtx(() => [
92
91
  createVNode(_component_FolderOutline, { size: 20 })
@@ -172,8 +171,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
172
171
  createVNode(_component_NcActionLink, {
173
172
  closeAfterClick: true,
174
173
  href: $props.filesAppUrl,
175
- target: "_blank",
176
- rel: "noopener noreferrer"
174
+ target: "_blank"
177
175
  }, {
178
176
  icon: withCtx(() => [
179
177
  createVNode(_component_FolderOutline, { size: 20 })
@@ -213,8 +211,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
213
211
  createVNode(_component_NcButton, {
214
212
  variant: "tertiary",
215
213
  href: $props.filesAppUrl,
216
- target: "_blank",
217
- rel: "noopener noreferrer"
214
+ target: "_blank"
218
215
  }, {
219
216
  icon: withCtx(() => [
220
217
  createVNode(_component_FolderOutline, { size: 18 })
@@ -1 +1 @@
1
- {"version":3,"file":"CnSharesTab.vue3.js","sources":["../../../../../src/integrations/builtin/shares/CnSharesTab.vue?vue&type=template&id=56e70e2e&lang.js"],"sourcesContent":["<!--\n CnSharesTab — bespoke sidebar tab for the `shares` integration.\n\n Replaces the generic CnIntegrationTab for the `shares` leaf: renders\n a recipient list grouped by share type (user / group / public link\n / federated), with per-row permissions, expiry date, a\n password-protected indicator, and a \"manage in Files\" deep-link.\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/shares`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\SharesProvider`\n (which walks linked files and calls `OCP\\Share\\IManager::getSharesBy()`\n per file).\n\n Surface behaviour:\n - Empty state with \"Open Files\" CTA when no shares exist.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses Shares' four primary signals — recipient, permissions,\n expiry, password-protection — that case handlers need to triage \"who\n has access to this case and how?\" at a glance.\n\n See `openregister/openspec/changes/integration-shares/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-shares-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-shares-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-shares-tab__toolbar\">\n\t\t\t<NcButton variant=\"primary\" data-testid=\"cn-shares-tab-share-file\" @click=\"openCreateDialog\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ shareFileLabel }}\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-shares-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"shares.length === 0\" class=\"cn-sidebar-tab__empty cn-shares-tab__empty\">\n\t\t\t<Share :size=\"32\" class=\"cn-shares-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=\"filesAppUrl\"\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<FolderOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openFilesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else class=\"cn-shares-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedShares\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-shares-tab__group\">\n\t\t\t\t<header class=\"cn-shares-tab__group-header\">\n\t\t\t\t\t<component :is=\"group.icon\" :size=\"18\" />\n\t\t\t\t\t<span class=\"cn-shares-tab__group-label\">{{ group.label }}</span>\n\t\t\t\t\t<span class=\"cn-shares-tab__group-count\">{{ group.rows.length }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-shares-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"share in group.rows\"\n\t\t\t\t\t\t:key=\"shareKey(share)\"\n\t\t\t\t\t\tclass=\"cn-shares-tab__row\"\n\t\t\t\t\t\t:name=\"shareTarget(share)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__avatar\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<component :is=\"iconFor(shareType(share))\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<LockOutline\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__avatar-lock\"\n\t\t\t\t\t\t\t\t\t:size=\"12\"\n\t\t\t\t\t\t\t\t\t:title=\"passwordProtectedLabel\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__permissions\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in permissionBadges(share)\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\t\t\t\t:label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"shareExpiryMs(share)\" #details>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__expiry\" :title=\"expiryLabel\">\n\t\t\t\t\t\t\t\t<ClockOutline :size=\"13\" />\n\t\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\t\t:timestamp=\"shareExpiryMs(share)\"\n\t\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canRevoke(share)\"\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t@click=\"revoke(share)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<CloseCircleOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ revokeLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t\t<div class=\"cn-shares-tab__footer\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<FolderOutline :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnShareCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:files=\"shareableFiles\"\n\t\t\t:filesLoading=\"filesLoading\"\n\t\t\t:principals=\"principals\"\n\t\t\t:principalsLoading=\"principalsLoading\"\n\t\t\t@close=\"showCreate = false\"\n\t\t\t@searchPrincipals=\"searchPrincipals\"\n\t\t\t@create=\"createShare\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountGroupOutline from 'vue-material-design-icons/AccountGroupOutline.vue'\nimport AccountOutline from 'vue-material-design-icons/AccountOutline.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'\nimport Earth from 'vue-material-design-icons/Earth.vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport LockOutline from 'vue-material-design-icons/LockOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Share from 'vue-material-design-icons/Share.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { CnShareCreate } from '../../../components/CnShareCreate/index.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\n// NC core share-type constants (OCP\\Share\\IShare::TYPE_*).\nconst SHARE_TYPE_USER = 0\nconst SHARE_TYPE_GROUP = 1\nconst SHARE_TYPE_LINK = 3\nconst SHARE_TYPE_EMAIL = 4\nconst SHARE_TYPE_REMOTE = 6\nconst SHARE_TYPE_REMOTE_GROUP = 9\n\n// Permission bitmask (OCP\\Constants::PERMISSION_*).\nconst PERMISSION_READ = 1\nconst PERMISSION_UPDATE = 2\nconst PERMISSION_CREATE = 4\nconst PERMISSION_DELETE = 8\nconst PERMISSION_SHARE = 16\n\n/**\n * CnSharesTab — bespoke recipient list for the `shares` integration.\n *\n * Renders shares grouped by type with permissions, expiry, password-\n * protected flag, and a revoke action. Reads from the OR\n * pluggable-integration endpoint and delegates revoke back to the same\n * endpoint via DELETE.\n */\nexport default {\n\tname: 'CnSharesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tAccountOutline,\n\t\tAccountGroupOutline,\n\t\tLinkVariant,\n\t\tEmailOutline,\n\t\tEarth,\n\t\tLockOutline,\n\t\tClockOutline,\n\t\tCloseCircleOutline,\n\t\tFolderOutline,\n\t\tShare,\n\t\tPlus,\n\t\tCnStatusBadge,\n\t\tCnShareCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'shares'`). */\n\t\tintegrationId: { type: String, default: 'shares' },\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 shares on this object yet') },\n\t\t/** Pre-translated label for the \"Open Files\" CTA. */\n\t\topenFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Manage in Files') },\n\t\t/** Pre-translated banner when the share subsystem is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC sharing is currently unavailable.') },\n\t\t/** Pre-translated revoke button label. */\n\t\trevokeLabel: { type: String, default: () => t('nextcloud-vue', 'Revoke share') },\n\t\t/* eslint-disable vue/no-unused-properties -- the row hides the revoke button when canRevoke is false rather than disabling it, so the tooltip has no anchor today */\n\t\t/** Pre-translated tooltip shown when the current user cannot revoke. */\n\t\trevokeDisabledLabel: { type: String, default: () => t('nextcloud-vue', 'Only the share owner can revoke') },\n\t\t/* eslint-enable vue/no-unused-properties */\n\t\t/** Pre-translated label for the password-protected indicator. */\n\t\tpasswordProtectedLabel: { type: String, default: () => t('nextcloud-vue', 'Password protected') },\n\t\t/** Pre-translated label for the expiry row. */\n\t\texpiryLabel: { type: String, default: () => t('nextcloud-vue', 'Expires') },\n\t\t/** URL of the NC Files app entry. */\n\t\tfilesAppUrl: { type: String, default: '/index.php/apps/files' },\n\t\t/** Pre-translated label for the \"Share file\" toolbar button. */\n\t\tshareFileLabel: { type: String, default: () => t('nextcloud-vue', 'Share file') },\n\t},\n\n\temits: ['search-principals', 'share-created', 'share-revoked'],\n\n\tdata() {\n\t\treturn {\n\t\t\tshares: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tshowCreate: false,\n\t\t\tshareableFiles: [],\n\t\t\tfilesLoading: false,\n\t\t\tprincipals: [],\n\t\t\tprincipalsLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tgroupedShares() {\n\t\t\tconst groups = [\n\t\t\t\t{ key: 'user', label: t('nextcloud-vue', 'Users'), icon: 'AccountOutline', match: (s) => this.shareType(s) === SHARE_TYPE_USER },\n\t\t\t\t{ key: 'group', label: t('nextcloud-vue', 'Groups'), icon: 'AccountGroupOutline', match: (s) => this.shareType(s) === SHARE_TYPE_GROUP },\n\t\t\t\t{ key: 'link', label: t('nextcloud-vue', 'Public links'), icon: 'LinkVariant', match: (s) => this.shareType(s) === SHARE_TYPE_LINK },\n\t\t\t\t{ key: 'email', label: t('nextcloud-vue', 'Email'), icon: 'EmailOutline', match: (s) => this.shareType(s) === SHARE_TYPE_EMAIL },\n\t\t\t\t{ key: 'federated', label: t('nextcloud-vue', 'Federated'), icon: 'Earth', match: (s) => this.shareType(s) === SHARE_TYPE_REMOTE || this.shareType(s) === SHARE_TYPE_REMOTE_GROUP },\n\t\t\t]\n\t\t\treturn groups\n\t\t\t\t.map((g) => ({ ...g, rows: this.shares.filter(g.match) }))\n\t\t\t\t.filter((g) => g.rows.length > 0)\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.fetchShares()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchShares()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchShares()\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\t// Tier-2 dedicated endpoints (ShareLinksController) — distinct\n\t\t// from the generic registry `baseUrl()` above. Create/revoke flow\n\t\t// through these so the IManager-backed service owns the write\n\t\t// path (NO cache table).\n\t\tsharesUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/shares`\n\t\t},\n\n\t\tshareableFilesUrl() {\n\t\t\treturn `${this.apiBase}/integrations/shares/files/${this.register}/${this.schema}/${this.objectId}`\n\t\t},\n\n\t\tasync openCreateDialog() {\n\t\t\tthis.showCreate = true\n\t\t\tawait this.fetchShareableFiles()\n\t\t},\n\n\t\tasync fetchShareableFiles() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.filesLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.shareableFilesUrl()), { 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.shareableFiles = data.results || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else {\n\t\t\t\t\tthis.shareableFiles = []\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('[CnSharesTab] failed to fetch shareable files', err)\n\t\t\t\tthis.shareableFiles = []\n\t\t\t} finally {\n\t\t\t\tthis.filesLoading = false\n\t\t\t}\n\t\t},\n\n\t\tsearchPrincipals({ shareType, query }) {\n\t\t\t// Principal lookup is host-supplied: the host app wires NC's\n\t\t\t// share-search OCS endpoint. Emit upward so the host can\n\t\t\t// populate `principals`; default is a no-op empty list.\n\t\t\tthis.$emit('search-principals', { shareType, query })\n\t\t},\n\n\t\tasync createShare(payload) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.sharesUrl()), {\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\tthis.showCreate = false\n\t\t\t\t\tthis.$emit('share-created', payload)\n\t\t\t\t\tawait this.fetchShares()\n\t\t\t\t} else {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.error = data.error || t('nextcloud-vue', 'Could not create share.')\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('[CnSharesTab] failed to create share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create share.')\n\t\t\t}\n\t\t},\n\n\t\tshareKey(share) {\n\t\t\treturn share.id ?? share.shareId ?? share.token ?? ''\n\t\t},\n\n\t\tshareType(share) {\n\t\t\tconst value = share.shareType ?? share.share_type ?? share.type\n\t\t\treturn Number.isFinite(Number(value)) ? Number(value) : -1\n\t\t},\n\n\t\tshareTarget(share) {\n\t\t\tconst type = this.shareType(share)\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\t// Public links surface as a generic \"Share link\" label,\n\t\t\t\t// mirroring NC core's share list (the raw token is never\n\t\t\t\t// shown as a recipient name).\n\t\t\t\treturn share.shareWithDisplayname || share.label || t('nextcloud-vue', 'Share link')\n\t\t\t}\n\t\t\treturn share.shareWithDisplayname || share.shareWith || share.share_with || share.targetDisplayName || ''\n\t\t},\n\n\t\t// Picks the recipient/share-type icon component for a row,\n\t\t// mirroring NC core's share list (user / group / link / email /\n\t\t// federated).\n\t\ticonFor(type) {\n\t\t\tif (type === SHARE_TYPE_GROUP) {\n\t\t\t\treturn 'AccountGroupOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\treturn 'LinkVariant'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_EMAIL) {\n\t\t\t\treturn 'EmailOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_REMOTE || type === SHARE_TYPE_REMOTE_GROUP) {\n\t\t\t\treturn 'Earth'\n\t\t\t}\n\t\t\treturn 'AccountOutline'\n\t\t},\n\n\t\tpermissionLabel(share) {\n\t\t\treturn this.permissionBadges(share).map((b) => b.label).join(' · ')\n\t\t},\n\n\t\t// Decomposes the NC permission bitmask into the badge set the real\n\t\t// share UI shows: \"Can edit\" / \"Read only\" (mutually exclusive),\n\t\t// plus \"Can reshare\" when the share permission bit is set.\n\t\tpermissionBadges(share) {\n\t\t\tconst perms = Number(share.permissions ?? share.permission ?? 0)\n\t\t\tconst canEdit = (perms & PERMISSION_UPDATE) === PERMISSION_UPDATE\n\t\t\t\t|| (perms & PERMISSION_CREATE) === PERMISSION_CREATE\n\t\t\t\t|| (perms & PERMISSION_DELETE) === PERMISSION_DELETE\n\t\t\tconst canRead = (perms & PERMISSION_READ) === PERMISSION_READ\n\t\t\tconst badges = []\n\t\t\tif (canEdit) {\n\t\t\t\tbadges.push({ key: 'edit', variant: 'success', label: t('nextcloud-vue', 'Can edit') })\n\t\t\t} else if (canRead) {\n\t\t\t\tbadges.push({ key: 'read', variant: 'default', label: t('nextcloud-vue', 'Read only') })\n\t\t\t}\n\t\t\tif ((perms & PERMISSION_SHARE) === PERMISSION_SHARE) {\n\t\t\t\tbadges.push({ key: 'reshare', variant: 'info', label: t('nextcloud-vue', 'Can reshare') })\n\t\t\t}\n\t\t\treturn badges\n\t\t},\n\n\t\t// Returns the expiry as epoch-ms for <NcDateTime>, or 0 when there\n\t\t// is no (valid) expiry so the template can `v-if` it away.\n\t\tshareExpiryMs(share) {\n\t\t\tconst value = share.expiration ?? share.expirationDate ?? share.expiry ?? null\n\t\t\tif (!value) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tconst date = new Date(value)\n\t\t\tconst ms = date.getTime()\n\t\t\treturn Number.isNaN(ms) ? 0 : ms\n\t\t},\n\n\t\tisPasswordProtected(share) {\n\t\t\treturn Boolean(share.passwordProtected ?? share.hasPassword ?? share.password)\n\t\t},\n\n\t\tcanRevoke(share) {\n\t\t\t// The current-user-can-revoke flag is provider-supplied. When\n\t\t\t// absent we default to true so the action stays usable; the\n\t\t\t// backend rejects unauthorized revoke attempts.\n\t\t\treturn share.canRevoke !== false\n\t\t},\n\n\t\tasync fetchShares() {\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.shares = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\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('[CnSharesTab] failed to fetch shares', err)\n\t\t\t\tthis.shares = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync revoke(share) {\n\t\t\tconst id = this.shareKey(share)\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.baseUrl()}/${encodeURIComponent(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\tthis.shares = this.shares.filter((row) => this.shareKey(row) !== id)\n\t\t\t\t\tthis.$emit('share-revoked', { id, share })\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\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('[CnSharesTab] failed to revoke share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-shares-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-shares-tab__toolbar {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 10px;\n}\n\n.cn-shares-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-shares-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-shares-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-shares-tab__group {\n\tmargin-bottom: 12px;\n}\n\n.cn-shares-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 0;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-shares-tab__group-label {\n\tflex: 1;\n}\n\n.cn-shares-tab__group-count {\n\tfont-weight: normal;\n\tfont-size: 0.85em;\n\tpadding: 1px 6px;\n\tborder-radius: 9px;\n\tbackground: var(--color-background-hover);\n}\n\n.cn-shares-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Share-type icon tile, mirroring the NcAvatar slot in NC's share list. */\n.cn-shares-tab__avatar {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n}\n\n.cn-shares-tab__avatar-lock {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\tcolor: var(--color-warning, #e9a40f);\n\tbackground: var(--color-main-background);\n\tborder-radius: 50%;\n}\n\n.cn-shares-tab__permissions {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n\n.cn-shares-tab__badge {\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__expiry {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__footer {\n\tmargin-top: 12px;\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createTextVNode","_createBlock","_toDisplayString","_resolveDynamicComponent","_Fragment","_renderList"],"mappings":";;AAqDM,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,8BAAiB,GAAA;;;AACV,EAAA,KAAA,EAAA,uBAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;AAKZ,MAAA,UAAA,GAAA,EAAA,KAAA,EAAA,wBAAA,GAAA;;;AAUK,EAAA,KAAA,EAAA,sBAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;;;AAGoB,EAAA,KAAA,EAAA,4CAAA;;;;AAclB,EAAA,KAAK,EAAC,uBAAuB;;AAK/B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,6BAAG,GAAA;AAEV,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,4BAAO,GAAA;AACb,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,4BAAmB,GAAA;2BAEvB,EAAC,qBAAkB,GAAA;;AASnB,EAAA,KAAG,EAAA,uBAAA;AAAA,EAAA,aAAA,EAAA,IAAA;;AAWH,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,4BAAW,GAAA;;;;;;;;;;;;;;;;;;;;;;KA9DlB,KAAO,CAAA,QAAA;AAAf,SAAAA,SAAA,EAAA,EAAAC,kBAAA,CAGI,OAHJ,UAGI,EAAA;qBAFwB,CAAA,6BAAA,EAAA,EAAR,IAAI,EAAC,EAAG,EAAA,CAAA;6BAClB,8BAAF,KAAE,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;AAGZ,IAAAC,kBAAA,CAOM,OAPN,UAOM,EAAA;MANLC,WAKW,CAAA,mBAAA,EAAA;AALA,QAAA,OAAM,EAAC,SAAS;AAAC,QAAA,aAAW,EAAC,0BAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,gBAAA;;AACjC,QAAA,IAAA,UACL,MAAmB;UAAnBA,WAAmB,CAAA,eAAA,EAAA,EAAZ,IAAK,EAAC,EAAE,EAAA,CAAA;;yBACL,MACX;AADW,UAAAC,eAAA,CAAA,GACX,mBAAG,MAAc,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;KAIE,KAAO,CAAA,OAAA;sBAAzBC,WAA6B,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;SACtB,KAAA,CAAA,KAAA;wBAARJ,kBAEI,CAAA,KAAA,EAFJ,UAEI,EAAAK,eAAA,CADF,KAAK,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AAEM,UAAA,CAAA,KAAA,CAAA,MAAO,CAAC,MAAM,KAAA,CAAA;6CAatB,iBAAA,EAAA;cAZHH,WAAqB,CAAA,gBAAA,EAAA;AAAhB,gBAAA,IAAI,EAAE,EAAE;AAAE,gBAAA,KAAK,EAAC,2BAAA;;iCACD,2BAAjB,MAAU,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;yBAUL,CAAA,mBAAA,EAAA;uBARH,EAAC,SAAK;oBACR,EAAE,MAAW,CAAA,WAAA;AAChB,gBAAA,MAAI,EAAC,QAAQ;mBACZ,EAAC,qBAAqB;;AACd,gBAAA,IAAI,gBACA;6BAAA,CAAA,wBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;iCACJ,MACN;AADM,kBAAAC,eAAA,CAAA,GACN,mBAAA,MAAY,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAGZ,aAAAJ,SAAA,EAAA,EAAAC,kBAAA,QAAA;gCACFA,8CACS,QAAA,CAAA,aAAA,EAAA,CAAL,KAAK,KAAA;qCADTA;kBAED,GAAE,EAAE,KAAM,CAAA,GAAG;AACZ,kBAAA,KAAE,EAAC,sBAAsB;;qCAKnB,oBAAA,EAAA;AAHJ,qBAAAD,SAAA,EAAA,EAAAK,WAAA,CAAqCE,wBAAxB,KAAI,CAAC,IAAI,CAAG,EAAA,EAAA,IAAI,EAAE,EAAE,EAAA,CAAA;AACjC,oBAAAL,kBAAA,CAAe,MAAf,EAAA,UAAe,EAAAI,eAAA,CAAA,KAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;uCACY,kBAAA,EAAAA,eAAA,CAAA,KAAA,CAAA,IAAA,CAAA,MAAA,CAAA,EAAA,CAAA,YAAA;;;AAG3B,qBAAAN,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,CAgEHO,QA/De,EAAA,IAAA,EAAAC,UAAA,CAAA,KAAA,CAAA,IAAA,GAAR,KAAK,KAAA;2CADTJ,WAgEH,CAAA,qBAAA,EAAA;wBA9DG,GAAC,EAAE,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAA;6BACf,EAAC,oBAAoB;4BACrB,EAAE,QAAO,CAAA,WAAA,CAAA,KAAA,CAAA;AACX,wBAAA,IAAE,EAAE,IAAI;AACR,wBAAA,mBAAiB,EAAE,IAAI;;AACnB,wBAAA,IAAA,UACN,MAQO;AARP,0BAAAH,kBAAA,CAQO,QARP,WAQO,EAAA;0CAPNG,WAA4C,CAAAE,uBAAA,CAA5B,gBAAO,CAAC,QAAA,CAAA,SAAS,CAAC,KAAK,CAAA,CAAA,CAAA,EAAA,EAAK,IAAA,EAAA,EAAA,EAAA,CAAA;AAErC,4BAAA,CAAA,QAAA,CAAA,mBAAmB,CAAA,KAAA,CAAA;8CAD1BF,WAKK,CAAA,sBAAA,EAAA;;AAHJ,kCAAA,KAAK,EAAC,4BAAG;AACR,kCAAA,IAAI,EAAE,EAAE;AACR,kCAAA,KAAK,EAAE,MAAc,CAAA,sBAAA;AACrB,kCAAA,YAAG,EAAA,MAAA,CAAA,sBAAA;;;;;AAGI,wBAAA,OAAI,gBAeP;6CAAA,mBAAA,EAAA;AAbN,6BAAAL,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,CAMeO,QALE,EAAA,IAAA,EAAAC,UAAA,CAAA,QAAA,CAAA,gBAAK,CAAA,KAAA,IAAd,KAAK,KAAA;mDADbJ,WAMe,CAAA,wBAAA,EAAA;gCAJb,GAAG,EAAE,KAAK,CAAC,GAAE;AACd,gCAAA,KAAK,EAAC,sBAAsB;AAC5B,gCAAA,IAAI,EAAC,OAAI;gCACP,OAAM,EAAE,KAAK,CAAA,OAAA;gCACd,KAAK,EAAE,KAAK,CAAC,KAAA;;;AAER,4BAAA,CAAA,QAAA,CAAA,mBAAe,CAAA,KAAA,CAAA;8CADtBA,WAKe,CAAA,wBAAA,EAAA;;AAHd,kCAAA,KAAK,EAAC,sBAAW;AACjB,kCAAA,IAAI,EAAC,OAAO;AACZ,kCAAA,OAAO,EAAC,SAAS;AAChB,kCAAA,KAAK,EAAC,MAAO,CAAA,sBAAA;;;;;AAWN,wBAAA,OAAK,UACf,MAQC;AAPM,0BAAA,CAAA,QAAA,CAAA,SAAK,CAAA,KAAA,CAAA;4CADZA,WAQC,CAAA,yBAAA,EAAA;;AANC,gCAAA,eAAe,EAAE,IAAI;gCACrB,OAAI,EAAA,MAAA,KAAG,QAAI,CAAA,MAAA,CAAA,KAAA,CAAA,CAAA;;AACD,gCAAA,IAAI,UACd,MAAM;kCAANF,WAAM,CAAA,6BAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;iDACI,MACX;AADW,kCAAAC,eAAA,CAAA,GACX,mBAAG,MAAG,CAAA,WAAA,CAAA,EAAA,CAAA,YAAA;;;;;0BAEPD,WASe,CAAA,uBAAA,EAAA;;AAPb,4BAAA,IAAI,EAAE,MAAA,CAAA,WAAA;AACP,4BAAA,MAAM,EAAC,QAAI;AACX,4BAAA,GAAG,EAAC,qBAAa;;AACN,4BAAA,IAAI,UACd,MAAiB;8BAAjBA,WAAiB,CAAA,wBAAA,EAAA,EAAD,IAAC,EAAA,EAAA,EAAA,CAAA;;6CACP,MACX;AADW,8BAAAC,eAAA,CAAA,GACX,mBAAG,MAAc,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;AA1BH,wBAAA,CAAA,QAAA,CAAA,aAAK,CAAA,KAAA,CAAA;;oCAAA,SAAA;0CACpB,MAKO;gCALPF,kBAKO,CAAA,MAAA,EAAA;AALD,kCAAA,KAAK,EAAC,uBAAE;AAAA,kCAAA,KAAA,EAAA,MAAA,CAAA,WAAA;;kCACbC,WAAQ,CAAA,uBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;kCACRA,WAEI,CAAA,qBAAA,EAAA;oCADJ,SAAA,EAAA,QAAA,CAAA,aAAA,CAAA,KAAA,CAAA;AACC,oCAAA,YAAG,EAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnSharesTab.vue3.js","sources":["../../../../../src/integrations/builtin/shares/CnSharesTab.vue?vue&type=template&id=56e70e2e&lang.js"],"sourcesContent":["<!--\n CnSharesTab — bespoke sidebar tab for the `shares` integration.\n\n Replaces the generic CnIntegrationTab for the `shares` leaf: renders\n a recipient list grouped by share type (user / group / public link\n / federated), with per-row permissions, expiry date, a\n password-protected indicator, and a \"manage in Files\" deep-link.\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/shares`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\SharesProvider`\n (which walks linked files and calls `OCP\\Share\\IManager::getSharesBy()`\n per file).\n\n Surface behaviour:\n - Empty state with \"Open Files\" CTA when no shares exist.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses Shares' four primary signals — recipient, permissions,\n expiry, password-protection — that case handlers need to triage \"who\n has access to this case and how?\" at a glance.\n\n See `openregister/openspec/changes/integration-shares/` for the spec\n delta and ADR-019 (registry mechanism).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-shares-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-shares-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-shares-tab__toolbar\">\n\t\t\t<NcButton variant=\"primary\" data-testid=\"cn-shares-tab-share-file\" @click=\"openCreateDialog\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ shareFileLabel }}\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-shares-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"shares.length === 0\" class=\"cn-sidebar-tab__empty cn-shares-tab__empty\">\n\t\t\t<Share :size=\"32\" class=\"cn-shares-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=\"filesAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openFilesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else class=\"cn-shares-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedShares\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-shares-tab__group\">\n\t\t\t\t<header class=\"cn-shares-tab__group-header\">\n\t\t\t\t\t<component :is=\"group.icon\" :size=\"18\" />\n\t\t\t\t\t<span class=\"cn-shares-tab__group-label\">{{ group.label }}</span>\n\t\t\t\t\t<span class=\"cn-shares-tab__group-count\">{{ group.rows.length }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-shares-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"share in group.rows\"\n\t\t\t\t\t\t:key=\"shareKey(share)\"\n\t\t\t\t\t\tclass=\"cn-shares-tab__row\"\n\t\t\t\t\t\t:name=\"shareTarget(share)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__avatar\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<component :is=\"iconFor(shareType(share))\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<LockOutline\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__avatar-lock\"\n\t\t\t\t\t\t\t\t\t:size=\"12\"\n\t\t\t\t\t\t\t\t\t:title=\"passwordProtectedLabel\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__permissions\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in permissionBadges(share)\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"isPasswordProtected(share)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-shares-tab__badge\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\tvariant=\"warning\"\n\t\t\t\t\t\t\t\t\t:label=\"passwordProtectedLabel\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"shareExpiryMs(share)\" #details>\n\t\t\t\t\t\t\t<span class=\"cn-shares-tab__expiry\" :title=\"expiryLabel\">\n\t\t\t\t\t\t\t\t<ClockOutline :size=\"13\" />\n\t\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\t\t:timestamp=\"shareExpiryMs(share)\"\n\t\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canRevoke(share)\"\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t@click=\"revoke(share)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<CloseCircleOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ revokeLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t\t<div class=\"cn-shares-tab__footer\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:href=\"filesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<FolderOutline :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ openFilesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnShareCreate\n\t\t\tv-if=\"showCreate\"\n\t\t\t:files=\"shareableFiles\"\n\t\t\t:filesLoading=\"filesLoading\"\n\t\t\t:principals=\"principals\"\n\t\t\t:principalsLoading=\"principalsLoading\"\n\t\t\t@close=\"showCreate = false\"\n\t\t\t@searchPrincipals=\"searchPrincipals\"\n\t\t\t@create=\"createShare\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AccountGroupOutline from 'vue-material-design-icons/AccountGroupOutline.vue'\nimport AccountOutline from 'vue-material-design-icons/AccountOutline.vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport ClockOutline from 'vue-material-design-icons/ClockOutline.vue'\nimport CloseCircleOutline from 'vue-material-design-icons/CloseCircleOutline.vue'\nimport Earth from 'vue-material-design-icons/Earth.vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport LockOutline from 'vue-material-design-icons/LockOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport Share from 'vue-material-design-icons/Share.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { CnShareCreate } from '../../../components/CnShareCreate/index.js'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\n// NC core share-type constants (OCP\\Share\\IShare::TYPE_*).\nconst SHARE_TYPE_USER = 0\nconst SHARE_TYPE_GROUP = 1\nconst SHARE_TYPE_LINK = 3\nconst SHARE_TYPE_EMAIL = 4\nconst SHARE_TYPE_REMOTE = 6\nconst SHARE_TYPE_REMOTE_GROUP = 9\n\n// Permission bitmask (OCP\\Constants::PERMISSION_*).\nconst PERMISSION_READ = 1\nconst PERMISSION_UPDATE = 2\nconst PERMISSION_CREATE = 4\nconst PERMISSION_DELETE = 8\nconst PERMISSION_SHARE = 16\n\n/**\n * CnSharesTab — bespoke recipient list for the `shares` integration.\n *\n * Renders shares grouped by type with permissions, expiry, password-\n * protected flag, and a revoke action. Reads from the OR\n * pluggable-integration endpoint and delegates revoke back to the same\n * endpoint via DELETE.\n */\nexport default {\n\tname: 'CnSharesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tAccountOutline,\n\t\tAccountGroupOutline,\n\t\tLinkVariant,\n\t\tEmailOutline,\n\t\tEarth,\n\t\tLockOutline,\n\t\tClockOutline,\n\t\tCloseCircleOutline,\n\t\tFolderOutline,\n\t\tShare,\n\t\tPlus,\n\t\tCnStatusBadge,\n\t\tCnShareCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'shares'`). */\n\t\tintegrationId: { type: String, default: 'shares' },\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 shares on this object yet') },\n\t\t/** Pre-translated label for the \"Open Files\" CTA. */\n\t\topenFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Manage in Files') },\n\t\t/** Pre-translated banner when the share subsystem is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC sharing is currently unavailable.') },\n\t\t/** Pre-translated revoke button label. */\n\t\trevokeLabel: { type: String, default: () => t('nextcloud-vue', 'Revoke share') },\n\t\t/* eslint-disable vue/no-unused-properties -- the row hides the revoke button when canRevoke is false rather than disabling it, so the tooltip has no anchor today */\n\t\t/** Pre-translated tooltip shown when the current user cannot revoke. */\n\t\trevokeDisabledLabel: { type: String, default: () => t('nextcloud-vue', 'Only the share owner can revoke') },\n\t\t/* eslint-enable vue/no-unused-properties */\n\t\t/** Pre-translated label for the password-protected indicator. */\n\t\tpasswordProtectedLabel: { type: String, default: () => t('nextcloud-vue', 'Password protected') },\n\t\t/** Pre-translated label for the expiry row. */\n\t\texpiryLabel: { type: String, default: () => t('nextcloud-vue', 'Expires') },\n\t\t/** URL of the NC Files app entry. */\n\t\tfilesAppUrl: { type: String, default: '/index.php/apps/files' },\n\t\t/** Pre-translated label for the \"Share file\" toolbar button. */\n\t\tshareFileLabel: { type: String, default: () => t('nextcloud-vue', 'Share file') },\n\t},\n\n\temits: ['search-principals', 'share-created', 'share-revoked'],\n\n\tdata() {\n\t\treturn {\n\t\t\tshares: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tshowCreate: false,\n\t\t\tshareableFiles: [],\n\t\t\tfilesLoading: false,\n\t\t\tprincipals: [],\n\t\t\tprincipalsLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tgroupedShares() {\n\t\t\tconst groups = [\n\t\t\t\t{ key: 'user', label: t('nextcloud-vue', 'Users'), icon: 'AccountOutline', match: (s) => this.shareType(s) === SHARE_TYPE_USER },\n\t\t\t\t{ key: 'group', label: t('nextcloud-vue', 'Groups'), icon: 'AccountGroupOutline', match: (s) => this.shareType(s) === SHARE_TYPE_GROUP },\n\t\t\t\t{ key: 'link', label: t('nextcloud-vue', 'Public links'), icon: 'LinkVariant', match: (s) => this.shareType(s) === SHARE_TYPE_LINK },\n\t\t\t\t{ key: 'email', label: t('nextcloud-vue', 'Email'), icon: 'EmailOutline', match: (s) => this.shareType(s) === SHARE_TYPE_EMAIL },\n\t\t\t\t{ key: 'federated', label: t('nextcloud-vue', 'Federated'), icon: 'Earth', match: (s) => this.shareType(s) === SHARE_TYPE_REMOTE || this.shareType(s) === SHARE_TYPE_REMOTE_GROUP },\n\t\t\t]\n\t\t\treturn groups\n\t\t\t\t.map((g) => ({ ...g, rows: this.shares.filter(g.match) }))\n\t\t\t\t.filter((g) => g.rows.length > 0)\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.fetchShares()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchShares()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchShares()\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\t// Tier-2 dedicated endpoints (ShareLinksController) — distinct\n\t\t// from the generic registry `baseUrl()` above. Create/revoke flow\n\t\t// through these so the IManager-backed service owns the write\n\t\t// path (NO cache table).\n\t\tsharesUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/shares`\n\t\t},\n\n\t\tshareableFilesUrl() {\n\t\t\treturn `${this.apiBase}/integrations/shares/files/${this.register}/${this.schema}/${this.objectId}`\n\t\t},\n\n\t\tasync openCreateDialog() {\n\t\t\tthis.showCreate = true\n\t\t\tawait this.fetchShareableFiles()\n\t\t},\n\n\t\tasync fetchShareableFiles() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.filesLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.shareableFilesUrl()), { 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.shareableFiles = data.results || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else {\n\t\t\t\t\tthis.shareableFiles = []\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('[CnSharesTab] failed to fetch shareable files', err)\n\t\t\t\tthis.shareableFiles = []\n\t\t\t} finally {\n\t\t\t\tthis.filesLoading = false\n\t\t\t}\n\t\t},\n\n\t\tsearchPrincipals({ shareType, query }) {\n\t\t\t// Principal lookup is host-supplied: the host app wires NC's\n\t\t\t// share-search OCS endpoint. Emit upward so the host can\n\t\t\t// populate `principals`; default is a no-op empty list.\n\t\t\tthis.$emit('search-principals', { shareType, query })\n\t\t},\n\n\t\tasync createShare(payload) {\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.sharesUrl()), {\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\tthis.showCreate = false\n\t\t\t\t\tthis.$emit('share-created', payload)\n\t\t\t\t\tawait this.fetchShares()\n\t\t\t\t} else {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.error = data.error || t('nextcloud-vue', 'Could not create share.')\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('[CnSharesTab] failed to create share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create share.')\n\t\t\t}\n\t\t},\n\n\t\tshareKey(share) {\n\t\t\treturn share.id ?? share.shareId ?? share.token ?? ''\n\t\t},\n\n\t\tshareType(share) {\n\t\t\tconst value = share.shareType ?? share.share_type ?? share.type\n\t\t\treturn Number.isFinite(Number(value)) ? Number(value) : -1\n\t\t},\n\n\t\tshareTarget(share) {\n\t\t\tconst type = this.shareType(share)\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\t// Public links surface as a generic \"Share link\" label,\n\t\t\t\t// mirroring NC core's share list (the raw token is never\n\t\t\t\t// shown as a recipient name).\n\t\t\t\treturn share.shareWithDisplayname || share.label || t('nextcloud-vue', 'Share link')\n\t\t\t}\n\t\t\treturn share.shareWithDisplayname || share.shareWith || share.share_with || share.targetDisplayName || ''\n\t\t},\n\n\t\t// Picks the recipient/share-type icon component for a row,\n\t\t// mirroring NC core's share list (user / group / link / email /\n\t\t// federated).\n\t\ticonFor(type) {\n\t\t\tif (type === SHARE_TYPE_GROUP) {\n\t\t\t\treturn 'AccountGroupOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_LINK) {\n\t\t\t\treturn 'LinkVariant'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_EMAIL) {\n\t\t\t\treturn 'EmailOutline'\n\t\t\t}\n\t\t\tif (type === SHARE_TYPE_REMOTE || type === SHARE_TYPE_REMOTE_GROUP) {\n\t\t\t\treturn 'Earth'\n\t\t\t}\n\t\t\treturn 'AccountOutline'\n\t\t},\n\n\t\tpermissionLabel(share) {\n\t\t\treturn this.permissionBadges(share).map((b) => b.label).join(' · ')\n\t\t},\n\n\t\t// Decomposes the NC permission bitmask into the badge set the real\n\t\t// share UI shows: \"Can edit\" / \"Read only\" (mutually exclusive),\n\t\t// plus \"Can reshare\" when the share permission bit is set.\n\t\tpermissionBadges(share) {\n\t\t\tconst perms = Number(share.permissions ?? share.permission ?? 0)\n\t\t\tconst canEdit = (perms & PERMISSION_UPDATE) === PERMISSION_UPDATE\n\t\t\t\t|| (perms & PERMISSION_CREATE) === PERMISSION_CREATE\n\t\t\t\t|| (perms & PERMISSION_DELETE) === PERMISSION_DELETE\n\t\t\tconst canRead = (perms & PERMISSION_READ) === PERMISSION_READ\n\t\t\tconst badges = []\n\t\t\tif (canEdit) {\n\t\t\t\tbadges.push({ key: 'edit', variant: 'success', label: t('nextcloud-vue', 'Can edit') })\n\t\t\t} else if (canRead) {\n\t\t\t\tbadges.push({ key: 'read', variant: 'default', label: t('nextcloud-vue', 'Read only') })\n\t\t\t}\n\t\t\tif ((perms & PERMISSION_SHARE) === PERMISSION_SHARE) {\n\t\t\t\tbadges.push({ key: 'reshare', variant: 'info', label: t('nextcloud-vue', 'Can reshare') })\n\t\t\t}\n\t\t\treturn badges\n\t\t},\n\n\t\t// Returns the expiry as epoch-ms for <NcDateTime>, or 0 when there\n\t\t// is no (valid) expiry so the template can `v-if` it away.\n\t\tshareExpiryMs(share) {\n\t\t\tconst value = share.expiration ?? share.expirationDate ?? share.expiry ?? null\n\t\t\tif (!value) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tconst date = new Date(value)\n\t\t\tconst ms = date.getTime()\n\t\t\treturn Number.isNaN(ms) ? 0 : ms\n\t\t},\n\n\t\tisPasswordProtected(share) {\n\t\t\treturn Boolean(share.passwordProtected ?? share.hasPassword ?? share.password)\n\t\t},\n\n\t\tcanRevoke(share) {\n\t\t\t// The current-user-can-revoke flag is provider-supplied. When\n\t\t\t// absent we default to true so the action stays usable; the\n\t\t\t// backend rejects unauthorized revoke attempts.\n\t\t\treturn share.canRevoke !== false\n\t\t},\n\n\t\tasync fetchShares() {\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.shares = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.shares = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\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('[CnSharesTab] failed to fetch shares', err)\n\t\t\t\tthis.shares = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load shares.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync revoke(share) {\n\t\t\tconst id = this.shareKey(share)\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.baseUrl()}/${encodeURIComponent(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\tthis.shares = this.shares.filter((row) => this.shareKey(row) !== id)\n\t\t\t\t\tthis.$emit('share-revoked', { id, share })\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\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('[CnSharesTab] failed to revoke share', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not revoke share.')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-shares-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-shares-tab__toolbar {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tmargin-bottom: 10px;\n}\n\n.cn-shares-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-shares-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-shares-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-shares-tab__group {\n\tmargin-bottom: 12px;\n}\n\n.cn-shares-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 0;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-maxcontrast);\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-shares-tab__group-label {\n\tflex: 1;\n}\n\n.cn-shares-tab__group-count {\n\tfont-weight: normal;\n\tfont-size: 0.85em;\n\tpadding: 1px 6px;\n\tborder-radius: 9px;\n\tbackground: var(--color-background-hover);\n}\n\n.cn-shares-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Share-type icon tile, mirroring the NcAvatar slot in NC's share list. */\n.cn-shares-tab__avatar {\n\tposition: relative;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 34px;\n\theight: 34px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n}\n\n.cn-shares-tab__avatar-lock {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\tcolor: var(--color-warning, #e9a40f);\n\tbackground: var(--color-main-background);\n\tborder-radius: 50%;\n}\n\n.cn-shares-tab__permissions {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n\n.cn-shares-tab__badge {\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__expiry {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n\n.cn-shares-tab__footer {\n\tmargin-top: 12px;\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createTextVNode","_createBlock","_toDisplayString","_resolveDynamicComponent","_renderList","_Fragment"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { NcAvatar, NcCounterBubble, NcLoadingIcon } from '@nextcloud/vue';
3
3
  import ChatOutline from 'vue-material-design-icons/ChatOutline.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'];
@@ -143,8 +144,9 @@ var script = {
143
144
  return stripMarker(raw) || String(this.roomKey(room))
144
145
  },
145
146
 
147
+ // A provider URL is used only when it is a safe scheme; else the app link.
146
148
  roomUrl(room) {
147
- if (room.url) {
149
+ if (room.url && safeHref(room.url) !== '#') {
148
150
  return room.url
149
151
  }
150
152
  const token = room.token ?? room.id ?? '';