@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
@@ -3,6 +3,7 @@ import { NcLoadingIcon } from '@nextcloud/vue';
3
3
  import MapMarker from 'vue-material-design-icons/MapMarker.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'];
@@ -168,8 +169,9 @@ var script = {
168
169
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
169
170
  },
170
171
 
172
+ // A provider URL is used only when it is a safe scheme; else the app link.
171
173
  pointUrl(point) {
172
- if (typeof point.url === 'string' && point.url !== '') {
174
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
173
175
  return point.url
174
176
  }
175
177
  const lat = this.pointLat(point);
@@ -1 +1 @@
1
- {"version":3,"file":"CnMapsCard.vue2.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsCard.vue"],"sourcesContent":["<!--\n CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n\n Replaces the generic CnIntegrationCard for the `maps` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard : map-pin icon + headline\n \"N linked locations\" + the most-recently added POI (name +\n category + coords).\n - detail-page : compact list of linked POIs\n (icon + name + category badge + coords) capped at COMPACT_LIMIT\n with a \"view all\" trail-off pointing at NC Maps.\n - single-entity : pin + name chip for\n reference-property auto-rendering (referenceType: 'maps').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnMapsTab. Provider shape and field-fallback strategy matches the\n tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-maps-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pointUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pointName(entity) }}</a>\n\t\t\t\t<span v-if=\"pointCategory(entity)\" class=\"cn-maps-card__chip-category\">\n\t\t\t\t\t· {{ pointCategory(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-maps-card__chip cn-maps-card__chip--fallback\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-maps-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-maps-card__headline\">\n\t\t\t\t<div class=\"cn-maps-card__headline-line\">\n\t\t\t\t\t<MapMarker :size=\"16\" class=\"cn-maps-card__headline-icon\" />\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-maps-card__headline-recent\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pointUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pointName(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"pointCategory(mostRecent)\" class=\"cn-maps-card__headline-category\">\n\t\t\t\t\t\t· {{ pointCategory(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent && coordsLabel(mostRecent)\" class=\"cn-maps-card__headline-coords\">\n\t\t\t\t\t{{ coordsLabel(mostRecent) }}\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"points.length > 1\" class=\"cn-maps-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-maps-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"point in displayedPoints\"\n\t\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\t\tclass=\"cn-maps-card__row\">\n\t\t\t\t\t<MapMarker :size=\"14\" class=\"cn-maps-card__row-icon\" />\n\t\t\t\t\t<div class=\"cn-maps-card__row-main\">\n\t\t\t\t\t\t<div class=\"cn-maps-card__row-header\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-maps-card__title\">{{ pointName(point) }}</a>\n\t\t\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-card__category\">\n\t\t\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-card__coords\">\n\t\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"points.length > COMPACT_LIMIT\" class=\"cn-maps-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n *\n * Renders Maps-aware metadata across all four AD-19 surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnMapsCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, MapMarker },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (POI id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Locations') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => MapMarker },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No locations linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Locations') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpoints: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPoints() {\n\t\t\treturn this.points.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.points.length\n\t\t\treturn n('nextcloud-vue', '{count} linked location', '{count} linked locations', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.points.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Maps provider has no modified-time column; fall back to id-order\n\t\t\t// (highest id == most recently added). Defensive: also check\n\t\t\t// addedAt / created when present in a future expansion.\n\t\t\tconst sorted = [...this.points].sort((a, b) => {\n\t\t\t\tconst ka = this.recencyKey(a)\n\t\t\t\tconst kb = this.recencyKey(b)\n\t\t\t\treturn kb - ka\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.id ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat !== null && lng !== null) {\n\t\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\tchipSubtitle(point) {\n\t\t\treturn this.coordsLabel(point) || this.pointCategory(point) || this.pointName(point)\n\t\t},\n\n\t\trecencyKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point.addedAt ?? point.added ?? point.created ?? d.addedAt ?? d.added ?? d.created ?? point.id ?? d.id ?? 0\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : 0\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.points = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\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('[CnMapsCard] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnMapsCard] failed to fetch single location', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-maps-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-maps-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-maps-card__headline-line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-maps-card__headline-icon {\n\tcolor: var(--color-primary-element, #21468B);\n\tflex-shrink: 0;\n}\n\n.cn-maps-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__headline-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__headline-coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__chip-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-maps-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-maps-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-maps-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-maps-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tpadding-top: 3px;\n}\n\n.cn-maps-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-maps-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-maps-card__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}\n\na.cn-maps-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__category {\n\tflex-shrink: 0;\n\tfont-size: 0.65em;\n\tpadding: 1px 6px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n}\n\n.cn-maps-card__coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
1
+ {"version":3,"file":"CnMapsCard.vue2.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsCard.vue"],"sourcesContent":["<!--\n CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n\n Replaces the generic CnIntegrationCard for the `maps` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard : map-pin icon + headline\n \"N linked locations\" + the most-recently added POI (name +\n category + coords).\n - detail-page : compact list of linked POIs\n (icon + name + category badge + coords) capped at COMPACT_LIMIT\n with a \"view all\" trail-off pointing at NC Maps.\n - single-entity : pin + name chip for\n reference-property auto-rendering (referenceType: 'maps').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnMapsTab. Provider shape and field-fallback strategy matches the\n tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-maps-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pointUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pointName(entity) }}</a>\n\t\t\t\t<span v-if=\"pointCategory(entity)\" class=\"cn-maps-card__chip-category\">\n\t\t\t\t\t· {{ pointCategory(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-maps-card__chip cn-maps-card__chip--fallback\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-maps-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-maps-card__headline\">\n\t\t\t\t<div class=\"cn-maps-card__headline-line\">\n\t\t\t\t\t<MapMarker :size=\"16\" class=\"cn-maps-card__headline-icon\" />\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-maps-card__headline-recent\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pointUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pointName(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"pointCategory(mostRecent)\" class=\"cn-maps-card__headline-category\">\n\t\t\t\t\t\t· {{ pointCategory(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent && coordsLabel(mostRecent)\" class=\"cn-maps-card__headline-coords\">\n\t\t\t\t\t{{ coordsLabel(mostRecent) }}\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"points.length > 1\" class=\"cn-maps-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-maps-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"point in displayedPoints\"\n\t\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\t\tclass=\"cn-maps-card__row\">\n\t\t\t\t\t<MapMarker :size=\"14\" class=\"cn-maps-card__row-icon\" />\n\t\t\t\t\t<div class=\"cn-maps-card__row-main\">\n\t\t\t\t\t\t<div class=\"cn-maps-card__row-header\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-maps-card__title\">{{ pointName(point) }}</a>\n\t\t\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-card__category\">\n\t\t\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-card__coords\">\n\t\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"points.length > COMPACT_LIMIT\" class=\"cn-maps-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n *\n * Renders Maps-aware metadata across all four AD-19 surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnMapsCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, MapMarker },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (POI id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Locations') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => MapMarker },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No locations linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Locations') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpoints: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPoints() {\n\t\t\treturn this.points.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.points.length\n\t\t\treturn n('nextcloud-vue', '{count} linked location', '{count} linked locations', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.points.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Maps provider has no modified-time column; fall back to id-order\n\t\t\t// (highest id == most recently added). Defensive: also check\n\t\t\t// addedAt / created when present in a future expansion.\n\t\t\tconst sorted = [...this.points].sort((a, b) => {\n\t\t\t\tconst ka = this.recencyKey(a)\n\t\t\t\tconst kb = this.recencyKey(b)\n\t\t\t\treturn kb - ka\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.id ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat !== null && lng !== null) {\n\t\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\tchipSubtitle(point) {\n\t\t\treturn this.coordsLabel(point) || this.pointCategory(point) || this.pointName(point)\n\t\t},\n\n\t\trecencyKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point.addedAt ?? point.added ?? point.created ?? d.addedAt ?? d.added ?? d.created ?? point.id ?? d.id ?? 0\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : 0\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.points = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\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('[CnMapsCard] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnMapsCard] failed to fetch single location', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-maps-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-maps-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-maps-card__headline-line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-maps-card__headline-icon {\n\tcolor: var(--color-primary-element, #21468B);\n\tflex-shrink: 0;\n}\n\n.cn-maps-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__headline-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__headline-coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__chip-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-maps-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-maps-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-maps-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-maps-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tpadding-top: 3px;\n}\n\n.cn-maps-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-maps-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-maps-card__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}\n\na.cn-maps-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__category {\n\tflex-shrink: 0;\n\tfont-size: 0.65em;\n\tpadding: 1px 6px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n}\n\n.cn-maps-card__coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnMapsCard.vue3.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsCard.vue?vue&type=template&id=4c0775e7&lang.js"],"sourcesContent":["<!--\n CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n\n Replaces the generic CnIntegrationCard for the `maps` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard : map-pin icon + headline\n \"N linked locations\" + the most-recently added POI (name +\n category + coords).\n - detail-page : compact list of linked POIs\n (icon + name + category badge + coords) capped at COMPACT_LIMIT\n with a \"view all\" trail-off pointing at NC Maps.\n - single-entity : pin + name chip for\n reference-property auto-rendering (referenceType: 'maps').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnMapsTab. Provider shape and field-fallback strategy matches the\n tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-maps-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pointUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pointName(entity) }}</a>\n\t\t\t\t<span v-if=\"pointCategory(entity)\" class=\"cn-maps-card__chip-category\">\n\t\t\t\t\t· {{ pointCategory(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-maps-card__chip cn-maps-card__chip--fallback\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-maps-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-maps-card__headline\">\n\t\t\t\t<div class=\"cn-maps-card__headline-line\">\n\t\t\t\t\t<MapMarker :size=\"16\" class=\"cn-maps-card__headline-icon\" />\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-maps-card__headline-recent\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pointUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pointName(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"pointCategory(mostRecent)\" class=\"cn-maps-card__headline-category\">\n\t\t\t\t\t\t· {{ pointCategory(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent && coordsLabel(mostRecent)\" class=\"cn-maps-card__headline-coords\">\n\t\t\t\t\t{{ coordsLabel(mostRecent) }}\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"points.length > 1\" class=\"cn-maps-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-maps-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"point in displayedPoints\"\n\t\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\t\tclass=\"cn-maps-card__row\">\n\t\t\t\t\t<MapMarker :size=\"14\" class=\"cn-maps-card__row-icon\" />\n\t\t\t\t\t<div class=\"cn-maps-card__row-main\">\n\t\t\t\t\t\t<div class=\"cn-maps-card__row-header\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-maps-card__title\">{{ pointName(point) }}</a>\n\t\t\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-card__category\">\n\t\t\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-card__coords\">\n\t\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"points.length > COMPACT_LIMIT\" class=\"cn-maps-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n *\n * Renders Maps-aware metadata across all four AD-19 surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnMapsCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, MapMarker },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (POI id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Locations') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => MapMarker },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No locations linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Locations') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpoints: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPoints() {\n\t\t\treturn this.points.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.points.length\n\t\t\treturn n('nextcloud-vue', '{count} linked location', '{count} linked locations', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.points.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Maps provider has no modified-time column; fall back to id-order\n\t\t\t// (highest id == most recently added). Defensive: also check\n\t\t\t// addedAt / created when present in a future expansion.\n\t\t\tconst sorted = [...this.points].sort((a, b) => {\n\t\t\t\tconst ka = this.recencyKey(a)\n\t\t\t\tconst kb = this.recencyKey(b)\n\t\t\t\treturn kb - ka\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.id ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat !== null && lng !== null) {\n\t\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\tchipSubtitle(point) {\n\t\t\treturn this.coordsLabel(point) || this.pointCategory(point) || this.pointName(point)\n\t\t},\n\n\t\trecencyKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point.addedAt ?? point.added ?? point.created ?? d.addedAt ?? d.added ?? d.created ?? point.id ?? d.id ?? 0\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : 0\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.points = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\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('[CnMapsCard] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnMapsCard] failed to fetch single location', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-maps-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-maps-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-maps-card__headline-line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-maps-card__headline-icon {\n\tcolor: var(--color-primary-element, #21468B);\n\tflex-shrink: 0;\n}\n\n.cn-maps-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__headline-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__headline-coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__chip-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-maps-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-maps-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-maps-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-maps-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tpadding-top: 3px;\n}\n\n.cn-maps-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-maps-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-maps-card__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}\n\na.cn-maps-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__category {\n\tflex-shrink: 0;\n\tfont-size: 0.65em;\n\tpadding: 1px 6px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n}\n\n.cn-maps-card__coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createVNode","_createElementVNode","_toDisplayString","_openBlock"],"mappings":"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"}
1
+ {"version":3,"file":"CnMapsCard.vue3.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsCard.vue?vue&type=template&id=4c0775e7&lang.js"],"sourcesContent":["<!--\n CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n\n Replaces the generic CnIntegrationCard for the `maps` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard : map-pin icon + headline\n \"N linked locations\" + the most-recently added POI (name +\n category + coords).\n - detail-page : compact list of linked POIs\n (icon + name + category badge + coords) capped at COMPACT_LIMIT\n with a \"view all\" trail-off pointing at NC Maps.\n - single-entity : pin + name chip for\n reference-property auto-rendering (referenceType: 'maps').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnMapsTab. Provider shape and field-fallback strategy matches the\n tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-maps-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pointUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pointName(entity) }}</a>\n\t\t\t\t<span v-if=\"pointCategory(entity)\" class=\"cn-maps-card__chip-category\">\n\t\t\t\t\t· {{ pointCategory(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-maps-card__chip cn-maps-card__chip--fallback\">\n\t\t\t\t<MapMarker :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-maps-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-maps-card__headline\">\n\t\t\t\t<div class=\"cn-maps-card__headline-line\">\n\t\t\t\t\t<MapMarker :size=\"16\" class=\"cn-maps-card__headline-icon\" />\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-maps-card__headline-recent\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pointUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pointName(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"pointCategory(mostRecent)\" class=\"cn-maps-card__headline-category\">\n\t\t\t\t\t\t· {{ pointCategory(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent && coordsLabel(mostRecent)\" class=\"cn-maps-card__headline-coords\">\n\t\t\t\t\t{{ coordsLabel(mostRecent) }}\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"points.length > 1\" class=\"cn-maps-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"points.length === 0\" class=\"cn-maps-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-maps-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"point in displayedPoints\"\n\t\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\t\tclass=\"cn-maps-card__row\">\n\t\t\t\t\t<MapMarker :size=\"14\" class=\"cn-maps-card__row-icon\" />\n\t\t\t\t\t<div class=\"cn-maps-card__row-main\">\n\t\t\t\t\t\t<div class=\"cn-maps-card__row-header\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-maps-card__title\">{{ pointName(point) }}</a>\n\t\t\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-card__category\">\n\t\t\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-card__coords\">\n\t\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"points.length > COMPACT_LIMIT\" class=\"cn-maps-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"mapsAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnMapsCard — bespoke surface-aware widget for the `maps` integration.\n *\n * Renders Maps-aware metadata across all four AD-19 surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnMapsCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, MapMarker },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (POI id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Locations') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => MapMarker },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No locations linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Locations') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpoints: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPoints() {\n\t\t\treturn this.points.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.points.length\n\t\t\treturn n('nextcloud-vue', '{count} linked location', '{count} linked locations', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.points.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// Maps provider has no modified-time column; fall back to id-order\n\t\t\t// (highest id == most recently added). Defensive: also check\n\t\t\t// addedAt / created when present in a future expansion.\n\t\t\tconst sorted = [...this.points].sort((a, b) => {\n\t\t\t\tconst ka = this.recencyKey(a)\n\t\t\t\tconst kb = this.recencyKey(b)\n\t\t\t\treturn kb - ka\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.id ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat !== null && lng !== null) {\n\t\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\tchipSubtitle(point) {\n\t\t\treturn this.coordsLabel(point) || this.pointCategory(point) || this.pointName(point)\n\t\t},\n\n\t\trecencyKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point.addedAt ?? point.added ?? point.created ?? d.addedAt ?? d.added ?? d.created ?? point.id ?? d.id ?? 0\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : 0\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.points = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\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('[CnMapsCard] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnMapsCard] failed to fetch single location', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-maps-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-maps-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-maps-card__headline-line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-maps-card__headline-icon {\n\tcolor: var(--color-primary-element, #21468B);\n\tflex-shrink: 0;\n}\n\n.cn-maps-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__headline-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__headline-coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__chip-category {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-maps-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-maps-card__row {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-maps-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-maps-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tpadding-top: 3px;\n}\n\n.cn-maps-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-maps-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-maps-card__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}\n\na.cn-maps-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-card__category {\n\tflex-shrink: 0;\n\tfont-size: 0.65em;\n\tpadding: 1px 6px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n}\n\n.cn-maps-card__coords {\n\tfont-family: var(--font-face-monospace, monospace);\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-maps-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createVNode","_createElementVNode","_toDisplayString","_openBlock"],"mappings":"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"}
@@ -10,6 +10,7 @@ import Plus from 'vue-material-design-icons/Plus.vue';
10
10
  import __sfc_main$1 from '../../../components/CnMapPoiCreate/CnMapPoiCreate.vue.js';
11
11
  import __sfc_main from '../../../components/CnMapPoiPicker/CnMapPoiPicker.vue.js';
12
12
  import { stripMarker } from '../../utils/marker.js';
13
+ import { safeHref } from '../../../utils/safeHref.js';
13
14
  import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
14
15
 
15
16
  const COMMENT_MAX_CHARS = 160;
@@ -210,8 +211,9 @@ var script = {
210
211
  return `${lat.toFixed(5)}, ${lng.toFixed(5)}`
211
212
  },
212
213
 
214
+ // A provider URL is used only when it is a safe scheme; else the app link.
213
215
  pointUrl(point) {
214
- if (typeof point.url === 'string' && point.url !== '') {
216
+ if (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {
215
217
  return point.url
216
218
  }
217
219
  if (this.pointHasCoords(point)) {
@@ -1 +1 @@
1
- {"version":3,"file":"CnMapsTab.vue2.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsTab.vue"],"sourcesContent":["<!--\n CnMapsTab — bespoke sidebar tab for the `maps` integration.\n\n Replaces the generic CnIntegrationTab for the `maps` leaf: renders\n linked POIs / favourites with name, category badge, comment snippet,\n and a nicely-formatted lat/lng coordinate pair. Each row deep-links\n into the NC Maps app — the provider already supplies a per-POI URL\n (`/index.php/apps/maps/#/m={id}`); the tab also exposes a separate\n \"Open on map\" link in the format requested by host bundles\n (`/index.php/apps/maps/?point={lat},{lng}` — see the task brief).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/maps`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\MapsProvider`\n (storage strategy `link-table` — marker `[or:{uuid}]` lives in the\n Maps `maps_favorites.name` column). Provider payload shape (verified\n against `MapsProvider::list`):\n { id, title, url, data: { id, name, lat, lng, category, comment, ... } }\n The richer \"spec\" shape (name, category, lat, lng, comment, url) is\n accepted too — the UI reads top-level and `data.*` fields defensively.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the category badge, the human-readable coordinate\n string and the comment snippet — three signals that make a POI\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Visual fidelity: each row mirrors a real NC Maps favourite — an\n offline-safe map-pin tile (no remote tiles / no external images),\n the bold location name, an address subline (falls back to the\n category when no street address is present), a monospace lat/long\n line, and a compact coordinate chip when the row carries coordinates.\n Rows are rendered as `NcListItem`s so the tab matches NC Maps' own\n favourites list look-and-feel. The pin tile is tinted with the leaf\n accent (`--cn-iw-accent`, set from the descriptor's `accentColor`)\n falling back to the theme primary.\n\n Mini-map preview: deliberately skipped — the only inline map\n component in this repo (`CnMapWidget`) is a heavy Leaflet wrapper\n intended for full-page rendering, not for a sidebar row, and would\n pull remote tiles. We surface a static pin tile + formatted\n coordinates + an \"Open on map\" link instead.\n\n Surface behaviour:\n - Empty state (\"No locations linked yet\") + \"Open Locations\" CTA\n when zero rows.\n - Loading state via NcLoadingIcon for the full-tab spin.\n - 503 unavailable banner (matches CnIntegrationTab's AD-23 graceful\n degradation), generic error path on non-OK / fetch throw.\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-maps-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-maps-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-maps-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 location') }}\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 location') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div v-else-if=\"error\" class=\"cn-maps-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"points.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-maps-tab__empty\">\n\t\t\t<MapMarker :size=\"32\" class=\"cn-maps-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=\"mapsAppUrl\"\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<MapMarker :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openMapsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<ul v-else-if=\"points.length > 0\" class=\"cn-maps-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"point in points\"\n\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\tclass=\"cn-maps-tab__row\"\n\t\t\t\t:name=\"pointName(point)\"\n\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-maps-tab__pin\" aria-hidden=\"true\">\n\t\t\t\t\t\t<MapMarker :size=\"22\" class=\"cn-maps-tab__pin-icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #name>\n\t\t\t\t\t<span class=\"cn-maps-tab__title\">{{ pointName(point) }}</span>\n\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-tab__category\">\n\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-maps-tab__subname\">\n\t\t\t\t\t\t<span v-if=\"addressLabel(point)\" class=\"cn-maps-tab__address\">{{ addressLabel(point) }}</span>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-tab__coords\">\n\t\t\t\t\t\t\t<MapMarkerOutline :size=\"13\" class=\"cn-maps-tab__coords-icon\" />\n\t\t\t\t\t\t\t<span class=\"cn-maps-tab__coords-text\">{{ coordsLabel(point) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tv-if=\"pointHasCoords(point)\"\n\t\t\t\t\t\t\t:href=\"openOnMapUrl(point)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-maps-tab__open-link\"\n\t\t\t\t\t\t\t@click.stop>\n\t\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pointComment(point)\" class=\"cn-maps-tab__comment\">\n\t\t\t\t\t\t{{ pointComment(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"pointHasCoords(point)\" #indicator>\n\t\t\t\t\t<span class=\"cn-maps-tab__coord-chip\" :title=\"coordsLabel(point)\">\n\t\t\t\t\t\t<MapMarker :size=\"11\" />\n\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPoint(point)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink location') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnMapPoiPicker\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<CnMapPoiCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport MapMarkerOutline from 'vue-material-design-icons/MapMarkerOutline.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnMapPoiCreate from '../../../components/CnMapPoiCreate/CnMapPoiCreate.vue'\nimport CnMapPoiPicker from '../../../components/CnMapPoiPicker/CnMapPoiPicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst COMMENT_MAX_CHARS = 160\n\n/**\n * CnMapsTab — bespoke sidebar list for the `maps` integration.\n *\n * Renders POIs / favourites pulled from the OR pluggable-integration\n * endpoint with name, category, comment snippet, formatted coordinates,\n * and an \"Open on map\" deep-link.\n */\nexport default {\n\tname: 'CnMapsTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tMapMarker,\n\t\tMapMarkerOutline,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnMapPoiPicker,\n\t\tCnMapPoiCreate,\n\t},\n\n\tprops: {\n\t\t/* eslint-disable vue/no-unused-properties -- the integration dispatch binds integrationId on every integration component (see CnIntegrationWidgetGrid), so declaring it keeps it out of $attrs */\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/* eslint-enable vue/no-unused-properties */\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 locations linked yet') },\n\t\t/** Pre-translated \"Open Locations\" CTA label. */\n\t\topenMapsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Locations') },\n\t\t/** Pre-translated \"Open on map\" inline link label. */\n\t\topenOnMapLabel: { type: String, default: () => t('nextcloud-vue', 'Open on map') },\n\t\t/** Pre-translated banner when Maps is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpoints: [],\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.fetchPoints()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Base for the Tier-2 maps endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tmapsEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/maps`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\t/**\n\t\t * The NC Maps favorite id used for the Tier-2 unlink DELETE.\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {(number|string)} The favorite id.\n\t\t */\n\t\tfavoriteIdOf(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? ''\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\t// Provider returns the name (which carries the `[or:{uuid}]`\n\t\t\t// marker) as title fallback. Strip the marker for display.\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\t// Maps fixtures sometimes land a bare `or:{uuid}` marker in\n\t\t\t// the category column when no real category exists. Strip\n\t\t\t// the marker and suppress the chip when nothing meaningful\n\t\t\t// remains — surfacing the marker as a chip artefact (see\n\t\t\t// phase-d1 maps-tab.png) is the bug we're fixing.\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tpointComment(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.comment ?? d.comment ?? ''\n\t\t\tconst text = String(raw).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (text.length > COMMENT_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, COMMENT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Human-readable address subline for the row.\n\t\t *\n\t\t * NC Maps favourites don't always carry a structured address, so\n\t\t * read a few common fields defensively (top-level + `data.*`) and\n\t\t * fall back to the category when no street address exists — that\n\t\t * keeps the subline informative without surfacing the bare coords\n\t\t * twice (coords have their own line).\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {string} The address subline (may be empty).\n\t\t */\n\t\taddressLabel(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.address ?? point.formattedAddress ?? d.address ?? d.formattedAddress ?? d.street ?? ''\n\t\t\tconst text = stripMarker(String(raw)).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') {\n\t\t\t\treturn text\n\t\t\t}\n\t\t\treturn this.pointCategory(point)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tpointHasCoords(point) {\n\t\t\treturn this.pointLat(point) !== null && this.pointLng(point) !== null\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tif (this.pointHasCoords(point)) {\n\t\t\t\treturn this.openOnMapUrl(point)\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\topenOnMapUrl(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn this.mapsAppUrl\n\t\t\t}\n\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.mapsEndpoint()), {\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.fetchPoints()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This location is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\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('[CnMapsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\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('[CnMapsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoint(point) {\n\t\t\tconst favoriteId = this.favoriteIdOf(point)\n\t\t\tif (!favoriteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/${favoriteId}`), {\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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\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('[CnMapsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPoints() {\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.mapsEndpoint()), { 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.points = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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('[CnMapsTab] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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-maps-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-maps-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-maps-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-maps-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-maps-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Offline-safe static pin tile — a tinted rounded square with a marker\n glyph, mirroring a Maps favourite thumbnail without loading any tiles. */\n.cn-maps-tab__pin {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--cn-iw-accent, var(--color-primary-element, #0082c9));\n\tcolor: var(--color-primary-element-text, #fff);\n\tflex-shrink: 0;\n}\n\n.cn-maps-tab__pin-icon {\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-maps-tab__title {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__category {\n\tflex-shrink: 0;\n\tmargin-inline-start: 6px;\n\tfont-size: 0.7em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n\tvertical-align: middle;\n}\n\n.cn-maps-tab__subname {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px 10px;\n}\n\n.cn-maps-tab__address {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__coords {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__coords-icon {\n\tcolor: var(--cn-iw-accent, var(--color-primary-element));\n}\n\n.cn-maps-tab__coords-text {\n\tfont-family: var(--font-face-monospace, monospace);\n}\n\n.cn-maps-tab__open-link {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-tab__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-tab__comment {\n\tdisplay: -webkit-box;\n\tmargin-top: 2px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n/* Compact coordinate chip in the row indicator slot. */\n.cn-maps-tab__coord-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tpadding: 1px 6px;\n\tborder-radius: 10px;\n\tfont-size: 0.7em;\n\tfont-family: var(--font-face-monospace, monospace);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnMapPoiPicker","CnMapPoiCreate","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnMapsTab.vue2.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsTab.vue"],"sourcesContent":["<!--\n CnMapsTab — bespoke sidebar tab for the `maps` integration.\n\n Replaces the generic CnIntegrationTab for the `maps` leaf: renders\n linked POIs / favourites with name, category badge, comment snippet,\n and a nicely-formatted lat/lng coordinate pair. Each row deep-links\n into the NC Maps app — the provider already supplies a per-POI URL\n (`/index.php/apps/maps/#/m={id}`); the tab also exposes a separate\n \"Open on map\" link in the format requested by host bundles\n (`/index.php/apps/maps/?point={lat},{lng}` — see the task brief).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/maps`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\MapsProvider`\n (storage strategy `link-table` — marker `[or:{uuid}]` lives in the\n Maps `maps_favorites.name` column). Provider payload shape (verified\n against `MapsProvider::list`):\n { id, title, url, data: { id, name, lat, lng, category, comment, ... } }\n The richer \"spec\" shape (name, category, lat, lng, comment, url) is\n accepted too — the UI reads top-level and `data.*` fields defensively.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the category badge, the human-readable coordinate\n string and the comment snippet — three signals that make a POI\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Visual fidelity: each row mirrors a real NC Maps favourite — an\n offline-safe map-pin tile (no remote tiles / no external images),\n the bold location name, an address subline (falls back to the\n category when no street address is present), a monospace lat/long\n line, and a compact coordinate chip when the row carries coordinates.\n Rows are rendered as `NcListItem`s so the tab matches NC Maps' own\n favourites list look-and-feel. The pin tile is tinted with the leaf\n accent (`--cn-iw-accent`, set from the descriptor's `accentColor`)\n falling back to the theme primary.\n\n Mini-map preview: deliberately skipped — the only inline map\n component in this repo (`CnMapWidget`) is a heavy Leaflet wrapper\n intended for full-page rendering, not for a sidebar row, and would\n pull remote tiles. We surface a static pin tile + formatted\n coordinates + an \"Open on map\" link instead.\n\n Surface behaviour:\n - Empty state (\"No locations linked yet\") + \"Open Locations\" CTA\n when zero rows.\n - Loading state via NcLoadingIcon for the full-tab spin.\n - 503 unavailable banner (matches CnIntegrationTab's AD-23 graceful\n degradation), generic error path on non-OK / fetch throw.\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-maps-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-maps-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-maps-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 location') }}\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 location') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div v-else-if=\"error\" class=\"cn-maps-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"points.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-maps-tab__empty\">\n\t\t\t<MapMarker :size=\"32\" class=\"cn-maps-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=\"mapsAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<MapMarker :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openMapsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<ul v-else-if=\"points.length > 0\" class=\"cn-maps-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"point in points\"\n\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\tclass=\"cn-maps-tab__row\"\n\t\t\t\t:name=\"pointName(point)\"\n\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-maps-tab__pin\" aria-hidden=\"true\">\n\t\t\t\t\t\t<MapMarker :size=\"22\" class=\"cn-maps-tab__pin-icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #name>\n\t\t\t\t\t<span class=\"cn-maps-tab__title\">{{ pointName(point) }}</span>\n\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-tab__category\">\n\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-maps-tab__subname\">\n\t\t\t\t\t\t<span v-if=\"addressLabel(point)\" class=\"cn-maps-tab__address\">{{ addressLabel(point) }}</span>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-tab__coords\">\n\t\t\t\t\t\t\t<MapMarkerOutline :size=\"13\" class=\"cn-maps-tab__coords-icon\" />\n\t\t\t\t\t\t\t<span class=\"cn-maps-tab__coords-text\">{{ coordsLabel(point) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tv-if=\"pointHasCoords(point)\"\n\t\t\t\t\t\t\t:href=\"openOnMapUrl(point)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-maps-tab__open-link\"\n\t\t\t\t\t\t\t@click.stop>\n\t\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pointComment(point)\" class=\"cn-maps-tab__comment\">\n\t\t\t\t\t\t{{ pointComment(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"pointHasCoords(point)\" #indicator>\n\t\t\t\t\t<span class=\"cn-maps-tab__coord-chip\" :title=\"coordsLabel(point)\">\n\t\t\t\t\t\t<MapMarker :size=\"11\" />\n\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPoint(point)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink location') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnMapPoiPicker\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<CnMapPoiCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport MapMarkerOutline from 'vue-material-design-icons/MapMarkerOutline.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnMapPoiCreate from '../../../components/CnMapPoiCreate/CnMapPoiCreate.vue'\nimport CnMapPoiPicker from '../../../components/CnMapPoiPicker/CnMapPoiPicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst COMMENT_MAX_CHARS = 160\n\n/**\n * CnMapsTab — bespoke sidebar list for the `maps` integration.\n *\n * Renders POIs / favourites pulled from the OR pluggable-integration\n * endpoint with name, category, comment snippet, formatted coordinates,\n * and an \"Open on map\" deep-link.\n */\nexport default {\n\tname: 'CnMapsTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tMapMarker,\n\t\tMapMarkerOutline,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnMapPoiPicker,\n\t\tCnMapPoiCreate,\n\t},\n\n\tprops: {\n\t\t/* eslint-disable vue/no-unused-properties -- the integration dispatch binds integrationId on every integration component (see CnIntegrationWidgetGrid), so declaring it keeps it out of $attrs */\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/* eslint-enable vue/no-unused-properties */\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 locations linked yet') },\n\t\t/** Pre-translated \"Open Locations\" CTA label. */\n\t\topenMapsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Locations') },\n\t\t/** Pre-translated \"Open on map\" inline link label. */\n\t\topenOnMapLabel: { type: String, default: () => t('nextcloud-vue', 'Open on map') },\n\t\t/** Pre-translated banner when Maps is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpoints: [],\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.fetchPoints()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Base for the Tier-2 maps endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tmapsEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/maps`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\t/**\n\t\t * The NC Maps favorite id used for the Tier-2 unlink DELETE.\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {(number|string)} The favorite id.\n\t\t */\n\t\tfavoriteIdOf(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? ''\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\t// Provider returns the name (which carries the `[or:{uuid}]`\n\t\t\t// marker) as title fallback. Strip the marker for display.\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\t// Maps fixtures sometimes land a bare `or:{uuid}` marker in\n\t\t\t// the category column when no real category exists. Strip\n\t\t\t// the marker and suppress the chip when nothing meaningful\n\t\t\t// remains — surfacing the marker as a chip artefact (see\n\t\t\t// phase-d1 maps-tab.png) is the bug we're fixing.\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tpointComment(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.comment ?? d.comment ?? ''\n\t\t\tconst text = String(raw).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (text.length > COMMENT_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, COMMENT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Human-readable address subline for the row.\n\t\t *\n\t\t * NC Maps favourites don't always carry a structured address, so\n\t\t * read a few common fields defensively (top-level + `data.*`) and\n\t\t * fall back to the category when no street address exists — that\n\t\t * keeps the subline informative without surfacing the bare coords\n\t\t * twice (coords have their own line).\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {string} The address subline (may be empty).\n\t\t */\n\t\taddressLabel(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.address ?? point.formattedAddress ?? d.address ?? d.formattedAddress ?? d.street ?? ''\n\t\t\tconst text = stripMarker(String(raw)).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') {\n\t\t\t\treturn text\n\t\t\t}\n\t\t\treturn this.pointCategory(point)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tpointHasCoords(point) {\n\t\t\treturn this.pointLat(point) !== null && this.pointLng(point) !== null\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tif (this.pointHasCoords(point)) {\n\t\t\t\treturn this.openOnMapUrl(point)\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\topenOnMapUrl(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn this.mapsAppUrl\n\t\t\t}\n\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.mapsEndpoint()), {\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.fetchPoints()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This location is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\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('[CnMapsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\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('[CnMapsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoint(point) {\n\t\t\tconst favoriteId = this.favoriteIdOf(point)\n\t\t\tif (!favoriteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/${favoriteId}`), {\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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\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('[CnMapsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPoints() {\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.mapsEndpoint()), { 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.points = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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('[CnMapsTab] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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-maps-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-maps-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-maps-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-maps-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-maps-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Offline-safe static pin tile — a tinted rounded square with a marker\n glyph, mirroring a Maps favourite thumbnail without loading any tiles. */\n.cn-maps-tab__pin {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--cn-iw-accent, var(--color-primary-element, #0082c9));\n\tcolor: var(--color-primary-element-text, #fff);\n\tflex-shrink: 0;\n}\n\n.cn-maps-tab__pin-icon {\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-maps-tab__title {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__category {\n\tflex-shrink: 0;\n\tmargin-inline-start: 6px;\n\tfont-size: 0.7em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n\tvertical-align: middle;\n}\n\n.cn-maps-tab__subname {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px 10px;\n}\n\n.cn-maps-tab__address {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__coords {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__coords-icon {\n\tcolor: var(--cn-iw-accent, var(--color-primary-element));\n}\n\n.cn-maps-tab__coords-text {\n\tfont-family: var(--font-face-monospace, monospace);\n}\n\n.cn-maps-tab__open-link {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-tab__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-tab__comment {\n\tdisplay: -webkit-box;\n\tmargin-top: 2px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n/* Compact coordinate chip in the row indicator slot. */\n.cn-maps-tab__coord-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tpadding: 1px 6px;\n\tborder-radius: 10px;\n\tfont-size: 0.7em;\n\tfont-family: var(--font-face-monospace, monospace);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["CnMapPoiPicker","CnMapPoiCreate","t"],"mappings":";;;;;;;;;;;;;;;AA+LA,MAAM,iBAAgB,GAAI,IAAE;;AAE5B;;AAEC;;AAEA;;;AAGD,aAAe;AACd,CAAA,IAAI,EAAE,WAAW;;CAEjB,UAAU,EAAE;AACX,EAAA,cAAc;EACd,YAAY;AACZ,EAAA,QAAQ;EACR,UAAU;EACV,aAAa;AACb,EAAA,kBAAkB;AAClB,EAAA,OAAO;EACP,WAAW;AACX,EAAA,SAAS;AACT,EAAA,gBAAgB;AAChB,EAAA,SAAS;EACT,IAAI;AACJ,kBAAAA,UAAc;AACd,kBAAAC,YAAc;EACd;;AAED,CAAA,KAAK,EAAE;AACN;AACA;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;AAChD;AACA;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;AAC1C;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACvC;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACrC;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;AAC5D;AACA,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,yBAAyB,GAAG;AAC1F;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,gBAAgB,GAAG;AACpF;AACA,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,aAAa,GAAG;;EAElF,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,uCAAuC,CAAA,EAAG;;EAE9G,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAqB,EAAG;EAC7D;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,MAAM,EAAE,EAAE;GACV,OAAO,EAAE,KAAK;AACd,GAAA,KAAK,EAAE,EAAE;GACT,QAAQ,EAAE,EAAE;AACZ,GAAA,UAAU,EAAE,KAAK;AACjB,GAAA,UAAU,EAAE,KAAK;AAClB,GAAA;EACA;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE;AACxC,GAAA,IAAI,EAAE,EAAE;AACP,IAAA,IAAI,CAAC,WAAW,GAAC;AAClB,IAAA;AACD,GAAA,EAAG;;EAEH,QAAQ,GAAG;AACV,GAAA,IAAI,CAAC,WAAW,GAAC;GACjB;;AAED,EAAA,MAAM,GAAG;AACR,GAAA,IAAI,CAAC,WAAW,GAAC;GACjB;EACD;;AAED,CAAA,OAAO,EAAE;AACR;;AAEC;AACA;;AAED,EAAA,YAAY,GAAG;AACd,GAAA,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAA;GACrF;;EAED,MAAM,CAAC,KAAK,EAAE;AACb,GAAA,OAAO,CAAC,KAAM,IAAG,OAAO,KAAK,CAAC,SAAS,QAAO,IAAK,KAAK,CAAC,IAAG,KAAM,IAAI,IAAI,KAAK,CAAC,IAAG,GAAI,EAAC;GACxF;;AAED,EAAA,QAAQ,CAAC,KAAK,EAAE;GACf,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;AAC3B,GAAA,OAAO,KAAK,CAAC,UAAS,IAAK,KAAK,CAAC,EAAC,IAAK,CAAC,CAAC,UAAS,IAAK,CAAC,CAAC,EAAG,IAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;GACnF;;AAED;;AAEC;AACA;AACA;AACA;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;GAC3B,OAAO,KAAK,CAAC,UAAW,IAAG,KAAK,CAAC,EAAC,IAAK,CAAC,CAAC,UAAS,IAAK,CAAC,CAAC,EAAC,IAAK,EAAC;GAChE;;AAED,EAAA,SAAS,CAAC,KAAK,EAAE;GAChB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;GAC3B,MAAM,SAAQ,GAAI,KAAK,CAAC,IAAG,IAAK,KAAK,CAAC,KAAI,IAAK,CAAC,CAAC,IAAK,IAAG,CAAC,CAAC,KAAI,IAAK,GAAC;;;GAGrE,OAAO,WAAW,CAAC,SAAS,CAAA,IAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;GAC5D;;AAED,EAAA,aAAa,CAAC,KAAK,EAAE;GACpB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;AAC3B,GAAA,MAAM,IAAI,KAAK,CAAC,QAAS,IAAG,CAAC,CAAC,QAAS,IAAG,GAAC;;;;;AAK3C;AACA,GAAA,OAAO,WAAW,CAAC,CAAC,CAAA;GACpB;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;AAC3B,GAAA,MAAM,GAAE,GAAI,KAAK,CAAC,OAAM,IAAK,CAAC,CAAC,OAAQ,IAAG,GAAC;GAC3C,MAAM,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAC;GACnD,IAAI,IAAK,KAAI,EAAE,EAAE;AAChB,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,SAAS,iBAAiB,EAAE;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,OAAO,EAAC,GAAI,GAAE;AACvD,IAAA;AACA,GAAA,OAAO,IAAG;GACV;;AAED;AACC;AACA;;;;;AAKA;AACA;AACA;AACA;AACA;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;AAC3B,GAAA,MAAM,MAAM,KAAK,CAAC,OAAM,IAAK,KAAK,CAAC,gBAAiB,IAAG,CAAC,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,CAAC,MAAO,IAAG,GAAC;GACvG,MAAM,IAAK,GAAE,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAC;GAChE,IAAI,IAAK,KAAI,EAAE,EAAE;AAChB,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,CAAA;GAC/B;;AAED,EAAA,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE;GACnB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAA;AAC3B,GAAA,MAAM,CAAE,GAAE,KAAK,CAAC,GAAG,CAAA,IAAK,CAAC,CAAC,GAAG,CAAA,IAAK,KAAG;AACrC,GAAA,IAAI,CAAE,KAAI,IAAK,IAAG,CAAA,KAAM,SAAQ,IAAK,MAAM,EAAE,EAAE;AAC9C,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,MAAM,GAAI,GAAE,OAAO,CAAA,KAAM,WAAW,CAAA,GAAI,MAAM,CAAC,CAAC,EAAA;AAChD,GAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,IAAG,GAAI,MAAM,IAAG;GAChD;;AAED,EAAA,QAAQ,CAAC,KAAK,EAAE;AACf,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAA;GAChC;;AAED,EAAA,QAAQ,CAAC,KAAK,EAAE;AACf,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAA;GAChC;;AAED,EAAA,cAAc,CAAC,KAAK,EAAE;GACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAA,KAAM,IAAK,IAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAE,KAAI,IAAG;GACpE;;AAED,EAAA,WAAW,CAAC,KAAK,EAAE;GAClB,MAAM,GAAE,GAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAA;GAC/B,MAAM,GAAE,GAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAA;GAC/B,IAAI,GAAE,KAAM,IAAG,IAAK,GAAE,KAAM,IAAI,EAAE;AACjC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;GAC5C;;;AAGD,EAAA,QAAQ,CAAC,KAAK,EAAE;AACf,GAAA,IAAI,OAAO,KAAK,CAAC,GAAI,KAAI,YAAY,KAAK,CAAC,GAAE,KAAM,EAAC,IAAK,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAA,KAAM,GAAG,EAAE;AACrF,IAAA,OAAO,KAAK,CAAC,GAAE;AAChB,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE;IAC/B,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAA;AAC/B,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,UAAS;GACrB;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,MAAM,GAAE,GAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAA;GAC/B,MAAM,GAAE,GAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAA;GAC/B,IAAI,GAAE,KAAM,IAAG,IAAK,GAAE,KAAM,IAAI,EAAE;AACjC,IAAA,OAAO,IAAI,CAAC,UAAS;AACtB,IAAA;GACA,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;GAC/C;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;EAED,MAAM,UAAU,CAAC,OAAO,EAAE;AACzB,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,IAAI;IACH,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE;KAC5D,MAAM,EAAE,MAAM;KACd,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,EAAE,cAAc,EAAE,kBAAiB,EAAG;KAClE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC7B,EAAA;AACD,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAI,CAAC,WAAW,GAAC;AACxB,KAAA,MAAO,IAAI,QAAQ,CAAC,MAAK,KAAM,GAAG,EAAE;KACnC,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,kCAAkC,EAAA;KACjE,MAAK;KACN,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,0BAA0B,EAAA;AAC3D,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,EAAA;IAC5C,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,0BAA0B,EAAA;AAC3D,IAAA;GACA;;EAED,MAAM,YAAY,CAAC,OAAO,EAAE;AAC3B,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE;KACrE,MAAM,EAAE,MAAM;KACd,OAAO,EAAE,EAAE,GAAG,YAAY,EAAE,EAAE,cAAc,EAAE,kBAAiB,EAAG;KAClE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC7B,EAAA;AACD,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAI,CAAC,WAAW,GAAC;KACtB,MAAK;KACN,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,EAAA;AAC7D,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,EAAA;IAC9C,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,EAAA;AAC7D,IAAA;GACA;;EAED,MAAM,WAAW,CAAC,KAAK,EAAE;AACxB,GAAA,MAAM,UAAW,GAAE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAA;AAC1C,GAAA,IAAI,CAAC,UAAU,EAAE;IAChB,MAAK;AACN,IAAA;AACA,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE;AAC/E,KAAA,MAAM,EAAE,QAAQ;KAChB,OAAO,EAAE,YAAY,EAAE;KACvB,EAAA;AACD,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAI,CAAC,WAAW,GAAC;KACtB,MAAK;KACN,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,EAAA;AAC7D,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,EAAA;IAC9C,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,EAAA;AAC7D,IAAA;GACA;;AAED,EAAA,MAAM,WAAW,GAAG;GACnB,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE;IACrD,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,OAAM,GAAI,KAAG;GAClB,IAAI,CAAC,KAAM,GAAE,GAAC;AACd,GAAA,IAAI,CAAC,QAAO,GAAI,GAAC;AACjB,GAAA,IAAI;AACH,IAAA,MAAM,QAAS,GAAE,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACxF,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,KAAA,MAAM,IAAG,GAAI,IAAI,CAAC,OAAM,IAAK,IAAI,CAAC,KAAI,KAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAK,GAAE,EAAE,CAAE,IAAG,GAAC;AACjF,KAAA,IAAI,CAAC,MAAK,GAAI,KAAG;KAChB,MAAK,IAAI,QAAQ,CAAC,MAAO,KAAI,GAAE,IAAK,QAAQ,CAAC,MAAO,KAAI,GAAG,EAAE;KAC9D,IAAI,CAAC,MAAO,GAAE,GAAC;AACf,KAAA,IAAI,CAAC,QAAS,GAAE,IAAI,CAAC,iBAAe;KACnC,MAAK;KACN,IAAI,CAAC,MAAO,GAAE,GAAC;KACf,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,2BAA2B,EAAA;AAC5D,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,EAAA;IAC1D,IAAI,CAAC,MAAO,GAAE,GAAC;IACf,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,2BAA2B,EAAA;AAC5D,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACpB,IAAA;GACA;EACD;AACF;;;;"}
@@ -109,8 +109,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
109
109
  createVNode(_component_NcButton, {
110
110
  variant: "primary",
111
111
  href: $props.mapsAppUrl,
112
- target: "_blank",
113
- rel: "noopener noreferrer"
112
+ target: "_blank"
114
113
  }, {
115
114
  icon: withCtx(() => [
116
115
  createVNode(_component_MapMarker, { size: 20 })
@@ -179,8 +178,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
179
178
  createVNode(_component_NcActionLink, {
180
179
  closeAfterClick: true,
181
180
  href: $options.pointUrl(point),
182
- target: "_blank",
183
- rel: "noopener noreferrer"
181
+ target: "_blank"
184
182
  }, {
185
183
  icon: withCtx(() => [
186
184
  createVNode(_component_OpenInNew, { size: 20 })
@@ -1 +1 @@
1
- {"version":3,"file":"CnMapsTab.vue3.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsTab.vue?vue&type=template&id=00a3cb8e&lang.js"],"sourcesContent":["<!--\n CnMapsTab — bespoke sidebar tab for the `maps` integration.\n\n Replaces the generic CnIntegrationTab for the `maps` leaf: renders\n linked POIs / favourites with name, category badge, comment snippet,\n and a nicely-formatted lat/lng coordinate pair. Each row deep-links\n into the NC Maps app — the provider already supplies a per-POI URL\n (`/index.php/apps/maps/#/m={id}`); the tab also exposes a separate\n \"Open on map\" link in the format requested by host bundles\n (`/index.php/apps/maps/?point={lat},{lng}` — see the task brief).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/maps`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\MapsProvider`\n (storage strategy `link-table` — marker `[or:{uuid}]` lives in the\n Maps `maps_favorites.name` column). Provider payload shape (verified\n against `MapsProvider::list`):\n { id, title, url, data: { id, name, lat, lng, category, comment, ... } }\n The richer \"spec\" shape (name, category, lat, lng, comment, url) is\n accepted too — the UI reads top-level and `data.*` fields defensively.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the category badge, the human-readable coordinate\n string and the comment snippet — three signals that make a POI\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Visual fidelity: each row mirrors a real NC Maps favourite — an\n offline-safe map-pin tile (no remote tiles / no external images),\n the bold location name, an address subline (falls back to the\n category when no street address is present), a monospace lat/long\n line, and a compact coordinate chip when the row carries coordinates.\n Rows are rendered as `NcListItem`s so the tab matches NC Maps' own\n favourites list look-and-feel. The pin tile is tinted with the leaf\n accent (`--cn-iw-accent`, set from the descriptor's `accentColor`)\n falling back to the theme primary.\n\n Mini-map preview: deliberately skipped — the only inline map\n component in this repo (`CnMapWidget`) is a heavy Leaflet wrapper\n intended for full-page rendering, not for a sidebar row, and would\n pull remote tiles. We surface a static pin tile + formatted\n coordinates + an \"Open on map\" link instead.\n\n Surface behaviour:\n - Empty state (\"No locations linked yet\") + \"Open Locations\" CTA\n when zero rows.\n - Loading state via NcLoadingIcon for the full-tab spin.\n - 503 unavailable banner (matches CnIntegrationTab's AD-23 graceful\n degradation), generic error path on non-OK / fetch throw.\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-maps-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-maps-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-maps-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 location') }}\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 location') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div v-else-if=\"error\" class=\"cn-maps-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"points.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-maps-tab__empty\">\n\t\t\t<MapMarker :size=\"32\" class=\"cn-maps-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=\"mapsAppUrl\"\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<MapMarker :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openMapsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<ul v-else-if=\"points.length > 0\" class=\"cn-maps-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"point in points\"\n\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\tclass=\"cn-maps-tab__row\"\n\t\t\t\t:name=\"pointName(point)\"\n\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-maps-tab__pin\" aria-hidden=\"true\">\n\t\t\t\t\t\t<MapMarker :size=\"22\" class=\"cn-maps-tab__pin-icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #name>\n\t\t\t\t\t<span class=\"cn-maps-tab__title\">{{ pointName(point) }}</span>\n\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-tab__category\">\n\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-maps-tab__subname\">\n\t\t\t\t\t\t<span v-if=\"addressLabel(point)\" class=\"cn-maps-tab__address\">{{ addressLabel(point) }}</span>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-tab__coords\">\n\t\t\t\t\t\t\t<MapMarkerOutline :size=\"13\" class=\"cn-maps-tab__coords-icon\" />\n\t\t\t\t\t\t\t<span class=\"cn-maps-tab__coords-text\">{{ coordsLabel(point) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tv-if=\"pointHasCoords(point)\"\n\t\t\t\t\t\t\t:href=\"openOnMapUrl(point)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-maps-tab__open-link\"\n\t\t\t\t\t\t\t@click.stop>\n\t\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pointComment(point)\" class=\"cn-maps-tab__comment\">\n\t\t\t\t\t\t{{ pointComment(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"pointHasCoords(point)\" #indicator>\n\t\t\t\t\t<span class=\"cn-maps-tab__coord-chip\" :title=\"coordsLabel(point)\">\n\t\t\t\t\t\t<MapMarker :size=\"11\" />\n\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPoint(point)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink location') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnMapPoiPicker\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<CnMapPoiCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport MapMarkerOutline from 'vue-material-design-icons/MapMarkerOutline.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnMapPoiCreate from '../../../components/CnMapPoiCreate/CnMapPoiCreate.vue'\nimport CnMapPoiPicker from '../../../components/CnMapPoiPicker/CnMapPoiPicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst COMMENT_MAX_CHARS = 160\n\n/**\n * CnMapsTab — bespoke sidebar list for the `maps` integration.\n *\n * Renders POIs / favourites pulled from the OR pluggable-integration\n * endpoint with name, category, comment snippet, formatted coordinates,\n * and an \"Open on map\" deep-link.\n */\nexport default {\n\tname: 'CnMapsTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tMapMarker,\n\t\tMapMarkerOutline,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnMapPoiPicker,\n\t\tCnMapPoiCreate,\n\t},\n\n\tprops: {\n\t\t/* eslint-disable vue/no-unused-properties -- the integration dispatch binds integrationId on every integration component (see CnIntegrationWidgetGrid), so declaring it keeps it out of $attrs */\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/* eslint-enable vue/no-unused-properties */\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 locations linked yet') },\n\t\t/** Pre-translated \"Open Locations\" CTA label. */\n\t\topenMapsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Locations') },\n\t\t/** Pre-translated \"Open on map\" inline link label. */\n\t\topenOnMapLabel: { type: String, default: () => t('nextcloud-vue', 'Open on map') },\n\t\t/** Pre-translated banner when Maps is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpoints: [],\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.fetchPoints()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Base for the Tier-2 maps endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tmapsEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/maps`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\t/**\n\t\t * The NC Maps favorite id used for the Tier-2 unlink DELETE.\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {(number|string)} The favorite id.\n\t\t */\n\t\tfavoriteIdOf(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? ''\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\t// Provider returns the name (which carries the `[or:{uuid}]`\n\t\t\t// marker) as title fallback. Strip the marker for display.\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\t// Maps fixtures sometimes land a bare `or:{uuid}` marker in\n\t\t\t// the category column when no real category exists. Strip\n\t\t\t// the marker and suppress the chip when nothing meaningful\n\t\t\t// remains — surfacing the marker as a chip artefact (see\n\t\t\t// phase-d1 maps-tab.png) is the bug we're fixing.\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tpointComment(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.comment ?? d.comment ?? ''\n\t\t\tconst text = String(raw).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (text.length > COMMENT_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, COMMENT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Human-readable address subline for the row.\n\t\t *\n\t\t * NC Maps favourites don't always carry a structured address, so\n\t\t * read a few common fields defensively (top-level + `data.*`) and\n\t\t * fall back to the category when no street address exists — that\n\t\t * keeps the subline informative without surfacing the bare coords\n\t\t * twice (coords have their own line).\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {string} The address subline (may be empty).\n\t\t */\n\t\taddressLabel(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.address ?? point.formattedAddress ?? d.address ?? d.formattedAddress ?? d.street ?? ''\n\t\t\tconst text = stripMarker(String(raw)).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') {\n\t\t\t\treturn text\n\t\t\t}\n\t\t\treturn this.pointCategory(point)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tpointHasCoords(point) {\n\t\t\treturn this.pointLat(point) !== null && this.pointLng(point) !== null\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tif (this.pointHasCoords(point)) {\n\t\t\t\treturn this.openOnMapUrl(point)\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\topenOnMapUrl(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn this.mapsAppUrl\n\t\t\t}\n\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.mapsEndpoint()), {\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.fetchPoints()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This location is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\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('[CnMapsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\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('[CnMapsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoint(point) {\n\t\t\tconst favoriteId = this.favoriteIdOf(point)\n\t\t\tif (!favoriteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/${favoriteId}`), {\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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\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('[CnMapsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPoints() {\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.mapsEndpoint()), { 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.points = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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('[CnMapsTab] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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-maps-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-maps-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-maps-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-maps-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-maps-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Offline-safe static pin tile — a tinted rounded square with a marker\n glyph, mirroring a Maps favourite thumbnail without loading any tiles. */\n.cn-maps-tab__pin {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--cn-iw-accent, var(--color-primary-element, #0082c9));\n\tcolor: var(--color-primary-element-text, #fff);\n\tflex-shrink: 0;\n}\n\n.cn-maps-tab__pin-icon {\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-maps-tab__title {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__category {\n\tflex-shrink: 0;\n\tmargin-inline-start: 6px;\n\tfont-size: 0.7em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n\tvertical-align: middle;\n}\n\n.cn-maps-tab__subname {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px 10px;\n}\n\n.cn-maps-tab__address {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__coords {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__coords-icon {\n\tcolor: var(--cn-iw-accent, var(--color-primary-element));\n}\n\n.cn-maps-tab__coords-text {\n\tfont-family: var(--font-face-monospace, monospace);\n}\n\n.cn-maps-tab__open-link {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-tab__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-tab__comment {\n\tdisplay: -webkit-box;\n\tmargin-top: 2px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n/* Compact coordinate chip in the row indicator slot. */\n.cn-maps-tab__coord-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tpadding: 1px 6px;\n\tborder-radius: 10px;\n\tfont-size: 0.7em;\n\tfont-family: var(--font-face-monospace, monospace);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createTextVNode","_createVNode","_toDisplayString","_createBlock"],"mappings":"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"}
1
+ {"version":3,"file":"CnMapsTab.vue3.js","sources":["../../../../../src/integrations/builtin/maps/CnMapsTab.vue?vue&type=template&id=00a3cb8e&lang.js"],"sourcesContent":["<!--\n CnMapsTab — bespoke sidebar tab for the `maps` integration.\n\n Replaces the generic CnIntegrationTab for the `maps` leaf: renders\n linked POIs / favourites with name, category badge, comment snippet,\n and a nicely-formatted lat/lng coordinate pair. Each row deep-links\n into the NC Maps app — the provider already supplies a per-POI URL\n (`/index.php/apps/maps/#/m={id}`); the tab also exposes a separate\n \"Open on map\" link in the format requested by host bundles\n (`/index.php/apps/maps/?point={lat},{lng}` — see the task brief).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/maps`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\MapsProvider`\n (storage strategy `link-table` — marker `[or:{uuid}]` lives in the\n Maps `maps_favorites.name` column). Provider payload shape (verified\n against `MapsProvider::list`):\n { id, title, url, data: { id, name, lat, lng, category, comment, ... } }\n The richer \"spec\" shape (name, category, lat, lng, comment, url) is\n accepted too — the UI reads top-level and `data.*` fields defensively.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the category badge, the human-readable coordinate\n string and the comment snippet — three signals that make a POI\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Visual fidelity: each row mirrors a real NC Maps favourite — an\n offline-safe map-pin tile (no remote tiles / no external images),\n the bold location name, an address subline (falls back to the\n category when no street address is present), a monospace lat/long\n line, and a compact coordinate chip when the row carries coordinates.\n Rows are rendered as `NcListItem`s so the tab matches NC Maps' own\n favourites list look-and-feel. The pin tile is tinted with the leaf\n accent (`--cn-iw-accent`, set from the descriptor's `accentColor`)\n falling back to the theme primary.\n\n Mini-map preview: deliberately skipped — the only inline map\n component in this repo (`CnMapWidget`) is a heavy Leaflet wrapper\n intended for full-page rendering, not for a sidebar row, and would\n pull remote tiles. We surface a static pin tile + formatted\n coordinates + an \"Open on map\" link instead.\n\n Surface behaviour:\n - Empty state (\"No locations linked yet\") + \"Open Locations\" CTA\n when zero rows.\n - Loading state via NcLoadingIcon for the full-tab spin.\n - 503 unavailable banner (matches CnIntegrationTab's AD-23 graceful\n degradation), generic error path on non-OK / fetch throw.\n\n See `openregister/openspec/changes/integration-maps/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-maps-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-maps-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-maps-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 location') }}\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 location') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div v-else-if=\"error\" class=\"cn-maps-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"points.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-maps-tab__empty\">\n\t\t\t<MapMarker :size=\"32\" class=\"cn-maps-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=\"mapsAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<MapMarker :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openMapsLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<ul v-else-if=\"points.length > 0\" class=\"cn-maps-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"point in points\"\n\t\t\t\t:key=\"pointKey(point)\"\n\t\t\t\tclass=\"cn-maps-tab__row\"\n\t\t\t\t:name=\"pointName(point)\"\n\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-maps-tab__pin\" aria-hidden=\"true\">\n\t\t\t\t\t\t<MapMarker :size=\"22\" class=\"cn-maps-tab__pin-icon\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #name>\n\t\t\t\t\t<span class=\"cn-maps-tab__title\">{{ pointName(point) }}</span>\n\t\t\t\t\t<span v-if=\"pointCategory(point)\" class=\"cn-maps-tab__category\">\n\t\t\t\t\t\t{{ pointCategory(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-maps-tab__subname\">\n\t\t\t\t\t\t<span v-if=\"addressLabel(point)\" class=\"cn-maps-tab__address\">{{ addressLabel(point) }}</span>\n\t\t\t\t\t\t<span v-if=\"coordsLabel(point)\" class=\"cn-maps-tab__coords\">\n\t\t\t\t\t\t\t<MapMarkerOutline :size=\"13\" class=\"cn-maps-tab__coords-icon\" />\n\t\t\t\t\t\t\t<span class=\"cn-maps-tab__coords-text\">{{ coordsLabel(point) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tv-if=\"pointHasCoords(point)\"\n\t\t\t\t\t\t\t:href=\"openOnMapUrl(point)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-maps-tab__open-link\"\n\t\t\t\t\t\t\t@click.stop>\n\t\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"pointComment(point)\" class=\"cn-maps-tab__comment\">\n\t\t\t\t\t\t{{ pointComment(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"pointHasCoords(point)\" #indicator>\n\t\t\t\t\t<span class=\"cn-maps-tab__coord-chip\" :title=\"coordsLabel(point)\">\n\t\t\t\t\t\t<MapMarker :size=\"11\" />\n\t\t\t\t\t\t{{ coordsLabel(point) }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pointUrl(point)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ openOnMapLabel }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPoint(point)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink location') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnMapPoiPicker\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<CnMapPoiCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport MapMarker from 'vue-material-design-icons/MapMarker.vue'\nimport MapMarkerOutline from 'vue-material-design-icons/MapMarkerOutline.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnMapPoiCreate from '../../../components/CnMapPoiCreate/CnMapPoiCreate.vue'\nimport CnMapPoiPicker from '../../../components/CnMapPoiPicker/CnMapPoiPicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst COMMENT_MAX_CHARS = 160\n\n/**\n * CnMapsTab — bespoke sidebar list for the `maps` integration.\n *\n * Renders POIs / favourites pulled from the OR pluggable-integration\n * endpoint with name, category, comment snippet, formatted coordinates,\n * and an \"Open on map\" deep-link.\n */\nexport default {\n\tname: 'CnMapsTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tMapMarker,\n\t\tMapMarkerOutline,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnMapPoiPicker,\n\t\tCnMapPoiCreate,\n\t},\n\n\tprops: {\n\t\t/* eslint-disable vue/no-unused-properties -- the integration dispatch binds integrationId on every integration component (see CnIntegrationWidgetGrid), so declaring it keeps it out of $attrs */\n\t\t/** Stable integration id (forwarded from the registry — always `'maps'`). */\n\t\tintegrationId: { type: String, default: 'maps' },\n\t\t/* eslint-enable vue/no-unused-properties */\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 locations linked yet') },\n\t\t/** Pre-translated \"Open Locations\" CTA label. */\n\t\topenMapsLabel: { type: String, default: () => t('nextcloud-vue', 'Open Locations') },\n\t\t/** Pre-translated \"Open on map\" inline link label. */\n\t\topenOnMapLabel: { type: String, default: () => t('nextcloud-vue', 'Open on map') },\n\t\t/** Pre-translated banner when Maps is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Location is currently unavailable.') },\n\t\t/** URL of the NC Maps app entry. */\n\t\tmapsAppUrl: { type: String, default: '/index.php/apps/maps' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpoints: [],\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.fetchPoints()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPoints()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Base for the Tier-2 maps endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tmapsEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/maps`\n\t\t},\n\n\t\tdataOf(point) {\n\t\t\treturn (point && typeof point.data === 'object' && point.data !== null) ? point.data : {}\n\t\t},\n\n\t\tpointKey(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? this.pointName(point)\n\t\t},\n\n\t\t/**\n\t\t * The NC Maps favorite id used for the Tier-2 unlink DELETE.\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {(number|string)} The favorite id.\n\t\t */\n\t\tfavoriteIdOf(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\treturn point.favoriteId ?? point.id ?? d.favoriteId ?? d.id ?? ''\n\t\t},\n\n\t\tpointName(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst candidate = point.name ?? point.title ?? d.name ?? d.title ?? ''\n\t\t\t// Provider returns the name (which carries the `[or:{uuid}]`\n\t\t\t// marker) as title fallback. Strip the marker for display.\n\t\t\treturn stripMarker(candidate) || String(this.pointKey(point))\n\t\t},\n\n\t\tpointCategory(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst c = point.category ?? d.category ?? ''\n\t\t\t// Maps fixtures sometimes land a bare `or:{uuid}` marker in\n\t\t\t// the category column when no real category exists. Strip\n\t\t\t// the marker and suppress the chip when nothing meaningful\n\t\t\t// remains — surfacing the marker as a chip artefact (see\n\t\t\t// phase-d1 maps-tab.png) is the bug we're fixing.\n\t\t\treturn stripMarker(c)\n\t\t},\n\n\t\tpointComment(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.comment ?? d.comment ?? ''\n\t\t\tconst text = String(raw).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (text.length > COMMENT_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, COMMENT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Human-readable address subline for the row.\n\t\t *\n\t\t * NC Maps favourites don't always carry a structured address, so\n\t\t * read a few common fields defensively (top-level + `data.*`) and\n\t\t * fall back to the category when no street address exists — that\n\t\t * keeps the subline informative without surfacing the bare coords\n\t\t * twice (coords have their own line).\n\t\t *\n\t\t * @param {object} point Provider row.\n\t\t *\n\t\t * @return {string} The address subline (may be empty).\n\t\t */\n\t\taddressLabel(point) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst raw = point.address ?? point.formattedAddress ?? d.address ?? d.formattedAddress ?? d.street ?? ''\n\t\t\tconst text = stripMarker(String(raw)).replace(/\\s+/g, ' ').trim()\n\t\t\tif (text !== '') {\n\t\t\t\treturn text\n\t\t\t}\n\t\t\treturn this.pointCategory(point)\n\t\t},\n\n\t\tcoordOf(point, key) {\n\t\t\tconst d = this.dataOf(point)\n\t\t\tconst v = point[key] ?? d[key] ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst num = typeof v === 'number' ? v : Number(v)\n\t\t\treturn Number.isFinite(num) === true ? num : null\n\t\t},\n\n\t\tpointLat(point) {\n\t\t\treturn this.coordOf(point, 'lat')\n\t\t},\n\n\t\tpointLng(point) {\n\t\t\treturn this.coordOf(point, 'lng')\n\t\t},\n\n\t\tpointHasCoords(point) {\n\t\t\treturn this.pointLat(point) !== null && this.pointLng(point) !== null\n\t\t},\n\n\t\tcoordsLabel(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${lat.toFixed(5)}, ${lng.toFixed(5)}`\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpointUrl(point) {\n\t\t\tif (typeof point.url === 'string' && point.url !== '' && safeHref(point.url) !== '#') {\n\t\t\t\treturn point.url\n\t\t\t}\n\t\t\tif (this.pointHasCoords(point)) {\n\t\t\t\treturn this.openOnMapUrl(point)\n\t\t\t}\n\t\t\treturn this.mapsAppUrl\n\t\t},\n\n\t\topenOnMapUrl(point) {\n\t\t\tconst lat = this.pointLat(point)\n\t\t\tconst lng = this.pointLng(point)\n\t\t\tif (lat === null || lng === null) {\n\t\t\t\treturn this.mapsAppUrl\n\t\t\t}\n\t\t\treturn `${this.mapsAppUrl}/?point=${lat},${lng}`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.mapsEndpoint()), {\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.fetchPoints()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This location is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\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('[CnMapsTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link location.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\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('[CnMapsTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create location.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPoint(point) {\n\t\t\tconst favoriteId = this.favoriteIdOf(point)\n\t\t\tif (!favoriteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.mapsEndpoint()}/${favoriteId}`), {\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.fetchPoints()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\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('[CnMapsTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink location.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPoints() {\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.mapsEndpoint()), { 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.points = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.points = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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('[CnMapsTab] failed to fetch locations', err)\n\t\t\t\tthis.points = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load locations.')\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-maps-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-maps-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-maps-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-maps-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-maps-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Offline-safe static pin tile — a tinted rounded square with a marker\n glyph, mirroring a Maps favourite thumbnail without loading any tiles. */\n.cn-maps-tab__pin {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--cn-iw-accent, var(--color-primary-element, #0082c9));\n\tcolor: var(--color-primary-element-text, #fff);\n\tflex-shrink: 0;\n}\n\n.cn-maps-tab__pin-icon {\n\tcolor: var(--color-primary-element-text, #fff);\n}\n\n.cn-maps-tab__title {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__category {\n\tflex-shrink: 0;\n\tmargin-inline-start: 6px;\n\tfont-size: 0.7em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.03em;\n\tvertical-align: middle;\n}\n\n.cn-maps-tab__subname {\n\tdisplay: flex;\n\talign-items: center;\n\tflex-wrap: wrap;\n\tgap: 4px 10px;\n}\n\n.cn-maps-tab__address {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-maps-tab__coords {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-maps-tab__coords-icon {\n\tcolor: var(--cn-iw-accent, var(--color-primary-element));\n}\n\n.cn-maps-tab__coords-text {\n\tfont-family: var(--font-face-monospace, monospace);\n}\n\n.cn-maps-tab__open-link {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-maps-tab__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-maps-tab__comment {\n\tdisplay: -webkit-box;\n\tmargin-top: 2px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n/* Compact coordinate chip in the row indicator slot. */\n.cn-maps-tab__coord-chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tpadding: 1px 6px;\n\tborder-radius: 10px;\n\tfont-size: 0.7em;\n\tfont-family: var(--font-face-monospace, monospace);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createTextVNode","_createBlock","_toDisplayString"],"mappings":";;AAyGM,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,4BAAO,GAAA;;;AACI,EAAA,KAAK,EAAC,qBAAqB;AAAC,EAAA,IAAG,EAAA,OAAA;;AAK/C,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;;AAiBV,EAAA,KAAK,EAAC,oBAAK;AAAA,EAAA,IAAA,EAAA,OAAA;;;;OAM7B,EAAE,0CAAqB;;;;AAcT,EAAA,KAAA,EAAA,mBAAA;;;AAUV,EAAA,KAAK,EAAC,kBAAI;AAAA,EAAA,aAAA,EAAA,MAAA;;AAKV,MAAA,UAAA,GAAA,EAAA,KAAK,EAAA,oBAAA,GAAA;;;AACG,EAAA,KAAA,EAAA,uBAAA;;AAKR,MAAA,WAAA,GAAA,EAAA,KAAK,EAAA,sBAAA,GAAA;;;AACG,EAAA,KAAA,EAAA,sBAAA;;;;AACU,EAAA,KAAA,EAAA,qBAAA;;AAEvB,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,0BAAA,GAAA;;;;;;;;;;;;;;;;;;;;;;;;AApEF,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;KACS,KAAQ,CAAA,QAAA;yCAGb,iBAAA,EAAA;qBAF4B,CAAA,6BAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;AAC3B,UAAAC,kBAAA,CAAM,8BAAA,KAAA,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;uBAgBH,iBAAA,EAAA;iBAPM,CAAA,mBAAA,EAAA;AALD,QAAA,OAAO,EAAC,WAAW;AAAE,QAAA,OAAK,EAAE,QAAU,CAAA,UAAA;;AACpC,QAAA,IAAI,UACd,MAAM;UAANC,WAAM,CAAA,sBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;yBACG,MACV;AADU,UAAAC,eAAA,CAAA,GACV,mBAAG,IAAC,CAAA,CAAA,CAAA,eAAA,EAAA,wBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;MAEFD,WAKC,CAAA,mBAAA,EAAA;AALM,QAAA,OAAO,EAAC,SAAS;AAAE,QAAA,OAAK,EAAE,QAAU,CAAA,UAAA;;AAClC,QAAA,IAAI,gBACM;qBAAA,CAAA,eAAA,EAAA,EAAb,IAAI,EAAE,EAAE,EAAA,CAAA;;yBACL,MACT;AADS,UAAAC,eAAA,CAAA,GACT,mBAAC,IAAC,CAAA,CAAA,CAAA,eAAA,EAAA,qBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;KAIa,KAAA,CAAA,OAAA;sBAAdC,WAAc,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;SAEH,KAAK,CAAA,KAAA;0CAEf,CAAA,KAAA,YAAA,EAAAC,eAAA,MADG,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;WAIG,KAAM,CAAA,MAAA,CAAC,MAAM,KAAA,CAAA,IAAA,CAAW,KAAQ,CAAA,QAAA;AADzC,aAAAN,SAAA,EAAA,EAAAC,kBAAA,CAcG,OAdH,UAcG,EAAA;cAXHE,WAAM,CAAA,oBAAA,EAAA;AAAA,gBAAA,IAAA,EAAA,EAAA;AAAA,gBAAA,KAAA,EAAA,yBAAA;;iCACG,2BAAL,MAAK,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;yBASA,CAAA,mBAAA,EAAA;AAPT,gBAAA,OAAM,EAAC,SAAS;AACf,gBAAA,IAAG,EAAE,MAAU,CAAA,UAAA;AACf,gBAAA,MAAI,EAAC,QAAQ;;AACR,gBAAA,IAAA,UACN,MAAS;kBAATA,WAAS,CAAA,oBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;iCACC;AAAA,kBAAAC,eAAA,CAAA,sBACR,MAAU,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAIA,YAAA,CAAA,KAAA,CAAA,MAAI,CAAA,MAAA,GAAA,CAAA;AAAf,eAAAJ,SAAA,EAAA,EAAAC,kBAAA,OAAA;kCACCA,8CACS,KAAA,CAAA,MAAA,EAAA,CAAL,KAAK,KAAA;uCADTI;oBAED,GAAG,EAAC,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAA;AACnB,oBAAA,KAAI,EAAC,kBAAS;oBACd,IAAI,EAAE,QAAQ,CAAA,SAAA,CAAE,KAAK,CAAA;oBACpB,IAAG,EAAE,QAAQ,CAAA,QAAA,CAAC,KAAC,CAAA;AACd,oBAAA,MAAG,EAAC,QAAQ;uCACH,EAAA,IAAA;;AACD,oBAAA,IAAI,UACd,MAEO;AAFP,sBAAAH,kBAAA,CAEO,QAFP,UAEO,EAAA;wBADNC,WAAQ,CAAA,oBAAA,EAAA;AAAA,0BAAA,IAAA,EAAA,EAAA;AAAA,0BAAA,KAAA,EAAA,uBAAA;;;;kCAIT,MAAW;AAAX,sBAAAD,kBAAA,CAAW,MAAX,EAAA,UAAW,EAAAI,eAAA,CAAA,QAAA,CAAA,SAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;AACC,sBAAA,CAAA,QAAA,CAAA,aAAE,CAAA,KAAA,CAAA;AAAd,2BAAAN,SAAA,EAAA,EAAAC,kBAAA,CAEO,MAFP,EAAA,UAEO,EADHK,eAAA,CAAA,QAAA,CAAA,aAAW,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;qCAIf;AAAA,sBAAAJ,kBAAA,SAAA;AACa,wBAAA,CAAA,QAAA,CAAA,YAAC,CAAA,KAAA,CAAA;AAAb,6BAAAF,SAAA,EAAA,EAAAC,kBAAA,CAAa,MAAb,EAAA,WAAa,EAAAK,eAAA,CAAA,QAAA,CAAA,YAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;AACD,wBAAA,CAAA,QAAA,CAAA,WAAW,CAAA,KAAA,CAAA;AAAvB,6BAAAN,SAAA,EAAA,EAAAC,kBAAA,SAAA;8BACCE,WAAoB,CAAA,2BAAA,EAAA;AAAD,gCAAA,IAAC,EAAA,EAAA;AAAA,gCAAA,KAAA,EAAA,0BAAA;;AACrB,8BAAAD,kBAAA,CAAA,MAAA,EAAA,WAAA,EAAAI,eAAA,CAAA,QAAA,CAAA,WAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}