@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.
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +1 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +1 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +71 -7
- package/dist/esm/utils/actionLink.js +5 -0
- package/dist/esm/utils/actionLink.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +16 -1
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/linkNavigation.js +6 -3
- package/dist/esm/utils/linkNavigation.js.map +1 -1
- package/dist/esm/utils/rowAuxClick.js +30 -5
- package/dist/esm/utils/rowAuxClick.js.map +1 -1
- package/dist/esm/utils/safeHref.js +18 -3
- package/dist/esm/utils/safeHref.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +809 -383
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +71 -7
- package/l10n/en.json +1 -0
- package/l10n/nl.json +1 -0
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
- package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
- package/src/components/CnBoardView/CnBoardView.vue +13 -5
- package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
- package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
- package/src/components/CnDataTable/CnDataTable.md +1 -1
- package/src/components/CnDataTable/CnDataTable.vue +131 -17
- package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
- package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
- package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
- package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
- package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
- package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
- package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
- package/src/components/CnObjectList/CnObjectList.vue +19 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
- package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
- package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
- package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
- package/src/components/CnRowActions/CnRowActions.vue +7 -2
- package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
- package/src/components/CnTabs/CnTabs.vue +7 -3
- package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
- package/src/css/table.css +26 -0
- package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
- package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
- package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
- package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
- package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
- package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
- package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
- package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
- package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
- package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
- package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
- package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
- package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
- package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
- package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
- package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
- package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
- package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
- package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
- package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
- package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
- package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
- package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
- package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
- package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
- package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
- package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
- package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
- package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
- package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
- package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
- package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
- package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
- package/src/utils/actionLink.js +5 -0
- package/src/utils/actionsDispatcher.js +15 -0
- package/src/utils/linkNavigation.js +6 -3
- package/src/utils/rowAuxClick.js +29 -4
- package/src/utils/safeHref.js +18 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnBookmarksTab.vue3.js","sources":["../../../../../src/integrations/builtin/bookmarks/CnBookmarksTab.vue?vue&type=template&id=56da56a8&lang.js"],"sourcesContent":["<!--\n CnBookmarksTab — bespoke sidebar tab for the `bookmarks` integration.\n\n Replaces the generic CnIntegrationTab for the `bookmarks` leaf: renders\n URL preview cards (favicon, title, URL, description snippet, tag chips)\n one per linked bookmark. Talks to the same OpenRegister\n pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/bookmarks`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\BookmarksProvider`\n (which uses NC Bookmarks' own BookmarkMapper filtered by an `or:{uuid}`\n tag). Payload shape: `{ id, title, url, description, tags, added }`.\n\n Surface behaviour:\n - Empty state with \"Open Bookmarks\" CTA when no linked URLs.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n - Tag chips above the list filter the displayed rows client-side per\n the integration-bookmarks spec (Tag-Aware Display).\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses the favicon, the description snippet, and the Bookmarks-side\n tags — three signals case-workers rely on to triage which reference is\n relevant. The bespoke tab surfaces them per row.\n\n See `openregister/openspec/changes/integration-bookmarks/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption principle).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-bookmarks-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-bookmarks-tab__banner\" role=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" />\n\t\t\t<span>{{ degraded }}</span>\n\t\t</div>\n\n\t\t<div class=\"cn-bookmarks-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing bookmark') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new bookmark') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<div v-else-if=\"error\" class=\"cn-bookmarks-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"bookmarks.length === 0\" class=\"cn-sidebar-tab__empty cn-bookmarks-tab__empty\">\n\t\t\t<Bookmark :size=\"32\" class=\"cn-bookmarks-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"bookmarksAppUrl\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openBookmarksLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else>\n\t\t\t<div v-if=\"allTags.length > 0\" class=\"cn-bookmarks-tab__filters\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tag in allTags\"\n\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip\"\n\t\t\t\t\t:class=\"{ 'cn-bookmarks-tab__chip--active': activeTag === tag }\"\n\t\t\t\t\t@click=\"toggleTagFilter(tag)\">\n\t\t\t\t\t{{ tag }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"activeTag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip cn-bookmarks-tab__chip--clear\"\n\t\t\t\t\t@click=\"activeTag = ''\">\n\t\t\t\t\t{{ clearFilterLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<ul class=\"cn-bookmarks-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"bookmark in filteredBookmarks\"\n\t\t\t\t\t:key=\"bookmarkKey(bookmark)\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__row\"\n\t\t\t\t\t:name=\"bookmarkTitle(bookmark)\"\n\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__row-icon\">\n\t\t\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url\" :title=\"bookmark.url\">\n\t\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url-text\">{{ displayUrl(bookmark) }}</span>\n\t\t\t\t\t\t\t<OpenInNew :size=\"12\" class=\"cn-bookmarks-tab__url-ext\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #extra>\n\t\t\t\t\t\t<span v-if=\"bookmark.description\" class=\"cn-bookmarks-tab__description\">\n\t\t\t\t\t\t\t{{ bookmark.description }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"bookmarkTags(bookmark).length > 0\" class=\"cn-bookmarks-tab__tags\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"tag in bookmarkTags(bookmark)\"\n\t\t\t\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\t\t\t\tclass=\"cn-bookmarks-tab__tag\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\t\t\t\t:label=\"tag\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open bookmark') }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkBookmark(bookmark)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink bookmark') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<CnBookmarkPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnBookmarkCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport Bookmark from 'vue-material-design-icons/Bookmark.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnBookmarkCreate from '../../../components/CnBookmarkCreate/CnBookmarkCreate.vue'\nimport CnBookmarkPicker from '../../../components/CnBookmarkPicker/CnBookmarkPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { safeHref } from '../../../utils/safeHref.js'\n\n/**\n * CnBookmarksTab — bespoke URL preview list for the `bookmarks`\n * integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint with\n * favicon, title, URL, description, and Bookmarks-side tag chips. Tag\n * chips at the top filter the visible rows client-side. Tier-2: adds\n * link/create modals and per-row unlink.\n */\nexport default {\n\tname: 'CnBookmarksTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookmark,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnBookmarkPicker,\n\t\tCnBookmarkCreate,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'bookmarks'`). */\n\t\tintegrationId: { type: String, default: 'bookmarks' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No bookmarks linked yet') },\n\t\t/** Pre-translated \"Open Bookmarks\" CTA label. */\n\t\topenBookmarksLabel: { type: String, default: () => t('nextcloud-vue', 'Open Bookmarks') },\n\t\t/** Pre-translated banner when Bookmarks is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Bookmarks is currently unavailable.') },\n\t\t/** Pre-translated \"Clear filter\" chip label. */\n\t\tclearFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Clear filter') },\n\t\t/** URL of the NC Bookmarks app entry. */\n\t\tbookmarksAppUrl: { type: String, default: '/index.php/apps/bookmarks' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tbookmarks: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tactiveTag: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tallTags() {\n\t\t\tconst set = new Set()\n\t\t\tfor (const b of this.bookmarks) {\n\t\t\t\tfor (const tag of this.bookmarkTags(b)) {\n\t\t\t\t\tset.add(tag)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Array.from(set).sort()\n\t\t},\n\n\t\tfilteredBookmarks() {\n\t\t\tif (!this.activeTag) {\n\t\t\t\treturn this.bookmarks\n\t\t\t}\n\t\t\treturn this.bookmarks.filter((b) => this.bookmarkTags(b).includes(this.activeTag))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchBookmarks()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 bookmark endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tbookmarksEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/bookmarks`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tbookmarkId(bookmark) {\n\t\t\treturn bookmark.bookmarkId ?? bookmark.id ?? ''\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.bookmarksEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This bookmark is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkBookmark(bookmark) {\n\t\t\tconst id = this.bookmarkId(bookmark)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/${id}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tbookmarkKey(bookmark) {\n\t\t\treturn bookmark.id ?? bookmark.url ?? ''\n\t\t},\n\n\t\tbookmarkTitle(bookmark) {\n\t\t\treturn bookmark.title || bookmark.url || ''\n\t\t},\n\n\t\t/**\n\t\t * Host (+ path) of the bookmark URL for the subline — drops the\n\t\t * scheme and trailing slash so the row reads like NC Bookmarks\n\t\t * (\"example.com/spec\" rather than \"https://example.com/spec/\").\n\t\t * Falls back to the raw URL when it cannot be parsed.\n\t\t *\n\t\t * @param {object} bookmark Bookmark row.\n\t\t * @return {string} Display URL.\n\t\t */\n\t\tdisplayUrl(bookmark) {\n\t\t\tconst raw = bookmark.url || ''\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw)\n\t\t\t\tconst path = url.pathname === '/' ? '' : url.pathname.replace(/\\/$/, '')\n\t\t\t\treturn `${url.host}${path}${url.search}`\n\t\t\t} catch {\n\t\t\t\treturn raw\n\t\t\t}\n\t\t},\n\n\t\t// Bookmark URLs are user data; block javascript:/data: schemes.\n\t\tbookmarkHref(bookmark) {\n\t\t\treturn safeHref(bookmark.url)\n\t\t},\n\n\t\tbookmarkTags(bookmark) {\n\t\t\tconst tags = bookmark.tags\n\t\t\tif (!Array.isArray(tags)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn tags.filter((tag) => typeof tag === 'string' && tag !== '' && !tag.startsWith('or:'))\n\t\t},\n\n\t\ttoggleTagFilter(tag) {\n\t\t\tthis.activeTag = this.activeTag === tag ? '' : tag\n\t\t},\n\n\t\tasync fetchBookmarks() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.bookmarks = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] failed to fetch bookmarks', err)\n\t\t\t\tthis.bookmarks = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-bookmarks-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-bookmarks-tab__banner {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 10px;\n\tmargin-bottom: 10px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n\tfont-size: 0.9em;\n}\n\n.cn-bookmarks-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-bookmarks-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-bookmarks-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n\tmargin-bottom: 10px;\n}\n\n.cn-bookmarks-tab__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tborder: 1px solid var(--color-border);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tfont-size: 0.8em;\n\tcursor: pointer;\n}\n\n.cn-bookmarks-tab__chip:hover {\n\tbackground: var(--color-background-darker, var(--color-background-hover));\n}\n\n.cn-bookmarks-tab__chip--active {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-bookmarks-tab__chip--clear {\n\tfont-style: italic;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* Favicon / fallback glyph rendered inside NcListItem's #icon slot,\n sized like a real NC Bookmarks site icon. */\n.cn-bookmarks-tab__row-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n/* Truncated URL subline with a trailing external-link affordance. */\n.cn-bookmarks-tab__url {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tmax-width: 100%;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__url-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-bookmarks-tab__url-ext {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__description {\n\tdisplay: -webkit-box;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 1;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-bookmarks-tab__tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tmargin-top: 2px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_createTextVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnBookmarksTab.vue3.js","sources":["../../../../../src/integrations/builtin/bookmarks/CnBookmarksTab.vue?vue&type=template&id=56da56a8&lang.js"],"sourcesContent":["<!--\n CnBookmarksTab — bespoke sidebar tab for the `bookmarks` integration.\n\n Replaces the generic CnIntegrationTab for the `bookmarks` leaf: renders\n URL preview cards (favicon, title, URL, description snippet, tag chips)\n one per linked bookmark. Talks to the same OpenRegister\n pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/bookmarks`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\BookmarksProvider`\n (which uses NC Bookmarks' own BookmarkMapper filtered by an `or:{uuid}`\n tag). Payload shape: `{ id, title, url, description, tags, added }`.\n\n Surface behaviour:\n - Empty state with \"Open Bookmarks\" CTA when no linked URLs.\n - Loading + 503 \"currently unavailable\" + generic error states match\n CnIntegrationTab's behaviour for AD-23 graceful degradation.\n - Tag chips above the list filter the displayed rows client-side per\n the integration-bookmarks spec (Tag-Aware Display).\n\n Bespoke-vs-generic rationale: the generic tab renders a flat link list\n which loses the favicon, the description snippet, and the Bookmarks-side\n tags — three signals case-workers rely on to triage which reference is\n relevant. The bespoke tab surfaces them per row.\n\n See `openregister/openspec/changes/integration-bookmarks/` for the spec\n delta and ADR-019 (registry mechanism), ADR-022 (consumption principle).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-bookmarks-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-bookmarks-tab__banner\" role=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" />\n\t\t\t<span>{{ degraded }}</span>\n\t\t</div>\n\n\t\t<div class=\"cn-bookmarks-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing bookmark') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new bookmark') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<div v-else-if=\"error\" class=\"cn-bookmarks-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\t\t<div v-else-if=\"bookmarks.length === 0\" class=\"cn-sidebar-tab__empty cn-bookmarks-tab__empty\">\n\t\t\t<Bookmark :size=\"32\" class=\"cn-bookmarks-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:href=\"bookmarksAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openBookmarksLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div v-else>\n\t\t\t<div v-if=\"allTags.length > 0\" class=\"cn-bookmarks-tab__filters\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tag in allTags\"\n\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip\"\n\t\t\t\t\t:class=\"{ 'cn-bookmarks-tab__chip--active': activeTag === tag }\"\n\t\t\t\t\t@click=\"toggleTagFilter(tag)\">\n\t\t\t\t\t{{ tag }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"activeTag\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__chip cn-bookmarks-tab__chip--clear\"\n\t\t\t\t\t@click=\"activeTag = ''\">\n\t\t\t\t\t{{ clearFilterLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<ul class=\"cn-bookmarks-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"bookmark in filteredBookmarks\"\n\t\t\t\t\t:key=\"bookmarkKey(bookmark)\"\n\t\t\t\t\tclass=\"cn-bookmarks-tab__row\"\n\t\t\t\t\t:name=\"bookmarkTitle(bookmark)\"\n\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t:target=\"hasSafeUrl(bookmark) ? '_blank' : undefined\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"onBookmarkClick(bookmark, $event)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__row-icon\">\n\t\t\t\t\t\t\t<Bookmark :size=\"20\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url\" :title=\"bookmark.url\">\n\t\t\t\t\t\t\t<span class=\"cn-bookmarks-tab__url-text\">{{ displayUrl(bookmark) }}</span>\n\t\t\t\t\t\t\t<OpenInNew :size=\"12\" class=\"cn-bookmarks-tab__url-ext\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #extra>\n\t\t\t\t\t\t<span v-if=\"bookmark.description\" class=\"cn-bookmarks-tab__description\">\n\t\t\t\t\t\t\t{{ bookmark.description }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"bookmarkTags(bookmark).length > 0\" class=\"cn-bookmarks-tab__tags\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"tag in bookmarkTags(bookmark)\"\n\t\t\t\t\t\t\t\t:key=\"tag\"\n\t\t\t\t\t\t\t\tclass=\"cn-bookmarks-tab__tag\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tvariant=\"info\"\n\t\t\t\t\t\t\t\t:label=\"tag\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"hasSafeUrl(bookmark)\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t:href=\"bookmarkHref(bookmark)\"\n\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open bookmark') }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkBookmark(bookmark)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink bookmark') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<CnBookmarkPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnBookmarkCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport Bookmark from 'vue-material-design-icons/Bookmark.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnBookmarkCreate from '../../../components/CnBookmarkCreate/CnBookmarkCreate.vue'\nimport CnBookmarkPicker from '../../../components/CnBookmarkPicker/CnBookmarkPicker.vue'\nimport CnStatusBadge from '../../../components/CnStatusBadge/CnStatusBadge.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { safeHref } from '../../../utils/safeHref.js'\n\n/**\n * CnBookmarksTab — bespoke URL preview list for the `bookmarks`\n * integration.\n *\n * Renders rows pulled from the OR pluggable-integration endpoint with\n * favicon, title, URL, description, and Bookmarks-side tag chips. Tag\n * chips at the top filter the visible rows client-side. Tier-2: adds\n * link/create modals and per-row unlink.\n */\nexport default {\n\tname: 'CnBookmarksTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookmark,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnBookmarkPicker,\n\t\tCnBookmarkCreate,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'bookmarks'`). */\n\t\tintegrationId: { type: String, default: 'bookmarks' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No bookmarks linked yet') },\n\t\t/** Pre-translated \"Open Bookmarks\" CTA label. */\n\t\topenBookmarksLabel: { type: String, default: () => t('nextcloud-vue', 'Open Bookmarks') },\n\t\t/** Pre-translated banner when Bookmarks is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Bookmarks is currently unavailable.') },\n\t\t/** Pre-translated \"Clear filter\" chip label. */\n\t\tclearFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Clear filter') },\n\t\t/** URL of the NC Bookmarks app entry. */\n\t\tbookmarksAppUrl: { type: String, default: '/index.php/apps/bookmarks' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tbookmarks: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tdegraded: '',\n\t\t\tactiveTag: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tallTags() {\n\t\t\tconst set = new Set()\n\t\t\tfor (const b of this.bookmarks) {\n\t\t\t\tfor (const tag of this.bookmarkTags(b)) {\n\t\t\t\t\tset.add(tag)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Array.from(set).sort()\n\t\t},\n\n\t\tfilteredBookmarks() {\n\t\t\tif (!this.activeTag) {\n\t\t\t\treturn this.bookmarks\n\t\t\t}\n\t\t\treturn this.bookmarks.filter((b) => this.bookmarkTags(b).includes(this.activeTag))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchBookmarks()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchBookmarks()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 bookmark endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tbookmarksEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/bookmarks`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tbookmarkId(bookmark) {\n\t\t\treturn bookmark.bookmarkId ?? bookmark.id ?? ''\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.bookmarksEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This bookmark is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkBookmark(bookmark) {\n\t\t\tconst id = this.bookmarkId(bookmark)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.bookmarksEndpoint()}/${id}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchBookmarks()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink bookmark.')\n\t\t\t}\n\t\t},\n\n\t\tbookmarkKey(bookmark) {\n\t\t\treturn bookmark.id ?? bookmark.url ?? ''\n\t\t},\n\n\t\tbookmarkTitle(bookmark) {\n\t\t\treturn bookmark.title || bookmark.url || ''\n\t\t},\n\n\t\t/**\n\t\t * Host (+ path) of the bookmark URL for the subline — drops the\n\t\t * scheme and trailing slash so the row reads like NC Bookmarks\n\t\t * (\"example.com/spec\" rather than \"https://example.com/spec/\").\n\t\t * Falls back to the raw URL when it cannot be parsed.\n\t\t *\n\t\t * @param {object} bookmark Bookmark row.\n\t\t * @return {string} Display URL.\n\t\t */\n\t\tdisplayUrl(bookmark) {\n\t\t\tconst raw = bookmark.url || ''\n\t\t\ttry {\n\t\t\t\tconst url = new URL(raw)\n\t\t\t\tconst path = url.pathname === '/' ? '' : url.pathname.replace(/\\/$/, '')\n\t\t\t\treturn `${url.host}${path}${url.search}`\n\t\t\t} catch {\n\t\t\t\treturn raw\n\t\t\t}\n\t\t},\n\n\t\t// Bookmark URLs are user data; block javascript:/data: schemes.\n\t\tbookmarkHref(bookmark) {\n\t\t\treturn safeHref(bookmark.url)\n\t\t},\n\n\t\t/**\n\t\t * Whether the bookmark's URL passed `safeHref`, so its row is a link.\n\t\t *\n\t\t * @param {object} bookmark The bookmark row.\n\t\t * @return {boolean}\n\t\t */\n\t\thasSafeUrl(bookmark) {\n\t\t\treturn this.bookmarkHref(bookmark) !== '#'\n\t\t},\n\n\t\t// NcListItem always renders an anchor; one without a safe URL must not follow `#`.\n\t\tonBookmarkClick(bookmark, event) {\n\t\t\tif (!this.hasSafeUrl(bookmark)) {\n\t\t\t\tevent?.preventDefault?.()\n\t\t\t}\n\t\t},\n\n\t\tbookmarkTags(bookmark) {\n\t\t\tconst tags = bookmark.tags\n\t\t\tif (!Array.isArray(tags)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn tags.filter((tag) => typeof tag === 'string' && tag !== '' && !tag.startsWith('or:'))\n\t\t},\n\n\t\ttoggleTagFilter(tag) {\n\t\t\tthis.activeTag = this.activeTag === tag ? '' : tag\n\t\t},\n\n\t\tasync fetchBookmarks() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.bookmarks = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.bookmarks = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnBookmarksTab] failed to fetch bookmarks', err)\n\t\t\t\tthis.bookmarks = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load bookmarks.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-bookmarks-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-bookmarks-tab__banner {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 8px 10px;\n\tmargin-bottom: 10px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n\tfont-size: 0.9em;\n}\n\n.cn-bookmarks-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-bookmarks-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-bookmarks-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__filters {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n\tmargin-bottom: 10px;\n}\n\n.cn-bookmarks-tab__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tborder: 1px solid var(--color-border);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tfont-size: 0.8em;\n\tcursor: pointer;\n}\n\n.cn-bookmarks-tab__chip:hover {\n\tbackground: var(--color-background-darker, var(--color-background-hover));\n}\n\n.cn-bookmarks-tab__chip--active {\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-bookmarks-tab__chip--clear {\n\tfont-style: italic;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* Favicon / fallback glyph rendered inside NcListItem's #icon slot,\n sized like a real NC Bookmarks site icon. */\n.cn-bookmarks-tab__row-icon {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n/* Truncated URL subline with a trailing external-link affordance. */\n.cn-bookmarks-tab__url {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 3px;\n\tmax-width: 100%;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__url-text {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-bookmarks-tab__url-ext {\n\tflex-shrink: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-bookmarks-tab__description {\n\tdisplay: -webkit-box;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\t-webkit-line-clamp: 1;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-bookmarks-tab__tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tmargin-top: 2px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_createTextVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":";;AAuDM,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,iCAAa,GAAA;;;AACd,EAAA,KAAA,EAAA,0BAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;AAKJ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,2BAAc,GAAA;;;AAgBjB,EAAA,KAAA,EAAA,yBAAA;AAAA,EAAA,IAAA,EAAA,OAAA;;;;AAGgC,EAAA,KAAK,EAAC,+CAAgB;;;;;AAcjC,EAAA,KAAA,EAAA,2BAAA;;;AAkBxB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,wBAAO,GAAA;AAYR,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,4BAAW,GAAA;;AAMhB,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,4BAA4B,GAAA;;;AAK9B,EAAA,KAAA,EAAA,+BAAA;;;;AAGF,EAAA,KAAA,EAAA,wBAAA;;;;;;;;;;;;;;;;;;;AAnFZ,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;KACQ,KAAA,CAAA,QAAA;AAAR,SAAAD,SAAA,EAAA,EAAAC,kBAAA,CAGK,OAHL,UAGK,EAAA;UAFJC,WAAgB,CAAA,6BAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;6BACM,8BAAd,KAAQ,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;AAGf,IAAAC,kBAAA,CAaG,OAbH,UAaG,EAAA;iBAPM,CAAA,mBAAA,EAAA;AALD,QAAA,OAAC,EAAA,WAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,UAAA;;AACC,QAAA,IAAI,UACd,MAAQ;UAARD,WAAQ,CAAA,sBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;yBACN,MACH;AADG,UAAAE,eAAA,CAAA,GACH,mBAAG,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,wBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;MAEJF,WAKW,CAAA,mBAAA,EAAA;AALL,QAAA,OAAA,EAAA,SAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,UAAA;;AACM,QAAA,IAAG,UACd,MAAS;UAATA,WAAS,CAAA,eAAA,EAAA,EAAF,IAAE,EAAA,EAAA,EAAA,CAAA;;yBACC;AAAA,UAAAE,eAAA,CAAA,sBACR,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,qBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;KAII,KAAA,CAAA,OAAA;sBAARC,WAAQ,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;SACF,KAAA,CAAA,KAAA;wBAANJ,kBAEI,CAAA,KAAA,EAFJ,UAEI,EAAAK,eAAA,CADF,KAAK,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AAEO,UAAA,CAAA,KAAA,CAAA,SAAS,CAAC,MAAK,KAAA,CAAA;6CAYzB,iBAAA,EAAA;cAXHJ,WAAuB,CAAA,mBAAA,EAAA;AAAd,gBAAA,IAAI,EAAE;AAAK,gBAAA,KAAG,EAAA,8BAAA;;AACvB,cAAAC,kBAAA,CAAqB,2BAAjB,MAAU,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;cACfD,WAQU,CAAA,mBAAA,EAAA;AAPV,gBAAA,OAAI,EAAA,SAAA;AACH,gBAAA,IAAI,EAAE,MAAe,CAAA,eAAA;AACtB,gBAAA,MAAM,EAAC,QAAG;;AACC,gBAAA,IAAI,UACd,MAAuB;kBAAvBA,WAAuB,CAAA,mBAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;;iCACT,MACV;AADU,kBAAAE,eAAA,CAAA,GACV,mBAAE,MAAkB,CAAA,kBAAA,CAAA,EAAA,CAAA,YAAA;;;;;;AAIX,cAAA,CAAA,QAAA,CAAA,OAAO,CAAC,MAAM,GAAA,CAAA;mDAiBnB,iBAAA,EAAA;sCAhBJH,kBAQQ,CAAAM,QAAA,EAAA,IAAA,EAAAC,UAAA,CAPM,QAAC,CAAA,OAAA,EAAA,CAAR,GAAG,KAAA;2CADVP,kBAQQ,CAAA,QAAA,EAAA;AANP,wBAAA,GAAG,EAAG,GAAE;AACP,wBAAA,IAAE,EAAC,QAAQ;AACZ,wBAAA,KAAI,EAACQ,cAAA,CAAA,CAAA,wBAAC,EACG,EAAA,gCAAA,EAAA,KAAA,CAAA,SAAA,KAAA,GAAA,EAAA,CAAA,CAAA;wBACT,OAAK,EAAA,MAAA,KAAE,QAAU,CAAA,eAAA,CAAA,GAAA,CAAA,CAAA;yCACf,GAAI,CAAA,EAAA,EAAA,2BAAA,UAAA,CAAA,CAAA;;qBAGD,KAAC,CAAA,SAAA;wDAKA,CAAA,QAAA,EAAA;;AAJP,0BAAA,IAAI,EAAC,QAAK;AACV,0BAAA,KAAK,EAAC,sDAAU;AACf,0BAAA,OAAI,uCAAG,KAAS,CAAA,SAAA,GAAA,EAAA,CAAA,CAAA;2CACd,MAAgB,CAAA,gBAAA,CAAA,EAAA,CAAA,YAAA;;;;;kCAIhBR,8CACS,QAAA,CAAA,iBAAA,EAAA,CAAL,QAAK,KAAA;uCADTI;uBAEC,EAAE,QAAW,CAAA,WAAA,CAAC,QAAQ,CAAA;yBACrB,EAAC,uBAAQ;wBACT,EAAE,QAAS,CAAA,aAAA,CAAA,QAAA,CAAA;wBACX,EAAE,IAAI;oBACV,IAAI,EAAE,QAAA,CAAA,YAAA,CAAA,QAAA,CAAA;AACN,oBAAA,MAAM,EAAE,QAAA,CAAA,UAAC,CAAA,QAAA,eAAA,SAAA;AACT,oBAAA,mBAAiB,EAAA,IAAA;AACjB,oBAAA,OAAK,EAAE,MAAA,KAAA,QAAA,CAAA,eAAK,CAAA,QAAA,EAAA,MAAA,CAAA,CAAA;;AACF,oBAAA,IAAI,gBAGP;yCAAA,mBAAA,EAAA;wBADNH,WAAuB,CAAA,mBAAA,EAAA,EAAZ,IAAI,EAAE,EAAE,EAAA,CAAA;;;AAGV,oBAAA,OAAO,gBAIV;wCAAA,CAAA,MAAA,EAAA;AAHD,wBAAA,KAAK,EAAA,uBAAA;wBAAA,KAAA,EAAA,QAAA,CAAA,GAAA;;AACV,wBAAAC,kBAAA,CAAwC,MAAxC,EAAA,WAAwC,EAAAG,eAAA,CAAA,QAAA,CAAA,UAAA,CAAA,QAAA,CAAA,CAAA,EAAA,CAAA,YAAA;wBACxCJ,WAAa,CAAA,oBAAA,EAAA;AAAD,0BAAA,IAAC,EAAA,EAAA;AAAA,0BAAA,KAAA,EAAA,2BAAA;;;;AAGH,oBAAA,KAAI,gBAGR;AAFI,sBAAA,CAAA,QAAA,CAAA,WAAA;2DAEJ,mBAAA,EADHI,eAAA,CAAA,QAAQ,CAAC,WAAW,CAAA,EAAA,CAAA,YAAA;;uBAEf,QAAA,CAAA,YAAA,CAAA,QAAA,CAAA,CAAA,MAAA,GAAA,CAAA;AAAT,2BAAAN,SAAA,EAAA,EAAAC,kBAAA,CAQO,QARP,WAQO,EAAA;AAPN,6BAAAD,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,CAMaM,QALb,EAAA,IAAA,EAAAC,UAAA,CAAA,QAAA,CAAA,YAAA,CAAA,QAAA,IAAA,GAAA,KAAA;mDADAH,WAMa,CAAA,wBAAA,EAAA;AAJb,gCAAA,GAAA,EAAA,GAAA;;AAEC,gCAAA,IAAI,EAAC,OAAK;AACV,gCAAA,OAAO,EAAC,MAAG;AACV,gCAAA,KAAK,EAAE,GAAG;;;;;;qCAIb;AACO,sBAAA,CAAA,QAAA,CAAA,UAAM,CAAA,QAAA,CAAA;wCADbA;;AAEE,4BAAA,iBAAiB,IAAI;4BACrB,IAAI,EAAE,QAAY,CAAA,YAAA,CAAC,QAAA,CAAA;AACrB,4BAAA,MAAA,EAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -3,6 +3,7 @@ import { NcLoadingIcon } from '@nextcloud/vue';
|
|
|
3
3
|
import BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue';
|
|
4
4
|
import __sfc_main from '../../../components/CnDetailCard/CnDetailCard.vue.js';
|
|
5
5
|
import { stripMarker } from '../../utils/marker.js';
|
|
6
|
+
import { safeHref } from '../../../utils/safeHref.js';
|
|
6
7
|
import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
|
|
7
8
|
|
|
8
9
|
const VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'];
|
|
@@ -139,8 +140,9 @@ var script = {
|
|
|
139
140
|
return typeof emoji === 'string' ? emoji.trim() : ''
|
|
140
141
|
},
|
|
141
142
|
|
|
143
|
+
// A provider URL is used only when it is a safe scheme; else the app link.
|
|
142
144
|
pageUrl(page) {
|
|
143
|
-
if (typeof page.url === 'string' && page.url !== '') {
|
|
145
|
+
if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
|
|
144
146
|
return page.url
|
|
145
147
|
}
|
|
146
148
|
const d = this.dataOf(page);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnCollectivesCard.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnCollectivesCard.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t","n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnCollectivesCard.vue3.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue?vue&type=template&id=0b91825d&lang.js"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createElementVNode","_createTextVNode","_toDisplayString","_openBlock","_createVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnCollectivesCard.vue3.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesCard.vue?vue&type=template&id=0b91825d&lang.js"],"sourcesContent":["<!--\n CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n integration.\n\n Replaces the generic CnIntegrationCard for the `collectives` leaf.\n Branches on `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N linked pages\" + the\n most-recently-modified page (emoji + title + collective name).\n - detail-page : compact list of linked pages\n (emoji + title + collective name) capped at COMPACT_LIMIT with a\n \"view all\" trail-off pointing at NC Collectives.\n - single-entity : chip with emoji + title for\n reference-property auto-rendering (referenceType: 'collectives').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnCollectivesTab. Provider shape and field-fallback strategy matches\n the tab (see the tab's docblock).\n\n See `openregister/openspec/changes/integration-collectives/` for the\n spec delta and ADR-019 (registry mechanism), AD-19 (surface fallback).\n-->\n<template>\n\t<CnDetailCard :title=\"cardTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span\n\t\t\t\tv-if=\"entity\"\n\t\t\t\tclass=\"cn-collectives-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"pageEmoji(entity)\">{{ pageEmoji(entity) }}</template>\n\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t</span>\n\t\t\t\t<a\n\t\t\t\t\t:href=\"pageUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ pageTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"collectiveLabel(entity)\" class=\"cn-collectives-card__chip-collective\">\n\t\t\t\t\t· {{ collectiveLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-collectives-card__chip cn-collectives-card__chip--fallback\">\n\t\t\t\t<BookOpenPageVariant :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-collectives-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-collectives-card__headline\">\n\t\t\t\t<div class=\"cn-collectives-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-collectives-card__headline-recent\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(mostRecent)\">{{ pageEmoji(mostRecent) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"pageUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ pageTitle(mostRecent) }}</a>\n\t\t\t\t\t<span v-if=\"collectiveLabel(mostRecent)\" class=\"cn-collectives-card__headline-collective\">\n\t\t\t\t\t\t· {{ collectiveLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"pages.length > 1\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: compact list -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-collectives-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<ul v-else class=\"cn-collectives-card__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"page in displayedPages\"\n\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\tclass=\"cn-collectives-card__row\">\n\t\t\t\t\t<span class=\"cn-collectives-card__chip-emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t<BookOpenPageVariant v-else :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<div class=\"cn-collectives-card__row-main\">\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\tclass=\"cn-collectives-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t<span v-if=\"collectiveLabel(page)\" class=\"cn-collectives-card__row-collective\">\n\t\t\t\t\t\t\t{{ collectiveLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div v-if=\"pages.length > COMPACT_LIMIT\" class=\"cn-collectives-card__view-all\">\n\t\t\t\t<a\n\t\t\t\t\t:href=\"collectivesAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ viewAllLabel }}</a>\n\t\t\t</div>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst COMPACT_LIMIT = 5\n\n/**\n * CnCollectivesCard — bespoke surface-aware widget for the `collectives`\n * integration.\n *\n * Renders Collectives-aware metadata across all four AD-19 surfaces. See\n * the file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnCollectivesCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, BookOpenPageVariant },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (page id or slug). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Knowledge') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => BookOpenPageVariant },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No Knowledge pages linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** Pre-translated \"view all\" trail-off link label. */\n\t\tviewAllLabel: { type: String, default: () => t('nextcloud-vue', 'View all in Knowledge') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tCOMPACT_LIMIT,\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tcardTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\tdisplayedPages() {\n\t\t\treturn this.pages.slice(0, COMPACT_LIMIT)\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.pages.length\n\t\t\treturn n('nextcloud-vue', '{count} linked page', '{count} linked pages', total, { count: total })\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.pages].sort((a, b) => this.modifiedMs(b) - this.modifiedMs(a))\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Strip the [or:UUID] marker AND any dangling slug\n\t\t\t// separator (-, _, .) that gets left behind — see\n\t\t\t// CnCollectivesTab.pageTitle for the bug context.\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.collectiveLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? 0 : parsed\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.pages = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (this.value === '' || this.value === undefined || this.value === null || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesCard] failed to fetch single Knowledge page', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-collectives-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-collectives-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-collectives-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__headline-collective {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__chip-emoji {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n\tline-height: 1;\n\tfont-size: 0.95em;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-collectives-card__chip-collective {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-card__chip--fallback {\n\topacity: 0.85;\n}\n\n.cn-collectives-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-collectives-card__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-collectives-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-collectives-card__row-main {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-collectives-card__title {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-collectives-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-collectives-card__row-collective {\n\tfont-size: 0.75em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-collectives-card__view-all {\n\tmargin-top: 6px;\n\tfont-size: 0.8em;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-collectives-card__view-all a {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n\n.cn-collectives-card__view-all a:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_Fragment","_createElementVNode","_createTextVNode","_toDisplayString","_openBlock","_createVNode"],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ import Plus from 'vue-material-design-icons/Plus.vue';
|
|
|
11
11
|
import __sfc_main$1 from '../../../components/CnCollectivePageCreate/CnCollectivePageCreate.vue.js';
|
|
12
12
|
import __sfc_main from '../../../components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js';
|
|
13
13
|
import { stripMarker } from '../../utils/marker.js';
|
|
14
|
+
import { safeHref } from '../../../utils/safeHref.js';
|
|
14
15
|
import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
|
|
15
16
|
|
|
16
17
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
@@ -175,8 +176,9 @@ var script = {
|
|
|
175
176
|
return text
|
|
176
177
|
},
|
|
177
178
|
|
|
179
|
+
// A provider URL is used only when it is a safe scheme; else the app link.
|
|
178
180
|
pageUrl(page) {
|
|
179
|
-
if (typeof page.url === 'string' && page.url !== '') {
|
|
181
|
+
if (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {
|
|
180
182
|
return page.url
|
|
181
183
|
}
|
|
182
184
|
const d = this.dataOf(page);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnCollectivesTab.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesTab.vue"],"sourcesContent":["<!--\n CnCollectivesTab — bespoke sidebar tab for the `collectives` integration.\n\n Replaces the generic CnIntegrationTab for the `collectives` leaf:\n renders linked Knowledge pages grouped by collective (emoji + title +\n optional content snippet + last-modified hint). Each row deep-links to\n the page inside the NC Collectives app via\n /index.php/apps/collectives/{collectiveSlug}/{pageSlug}\n (with a sane fallback to /index.php/apps/collectives/{pageId} when the\n provider only carries an id).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/collectives`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\CollectivesProvider`\n (storage strategy `link-table` — the marker `[or:{uuid}]` lives in the\n Collectives `collectives_pages.slug` column). Provider payload shape\n (verified against `CollectivesProvider::list`):\n { id, title, url, data: { id, slug, emoji, last_user_id, ... } }\n The richer \"spec\" shape (title, slug, emoji, content, fileId,\n lastModified, collectiveId, collectiveName, url) is accepted as well —\n the UI reads both top-level and `data.*` fields defensively so a future\n provider expansion stays drop-in.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the collective grouping, the emoji glyph, and the\n per-page content snippet — three signals that make Knowledge linkage\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Surface behaviour:\n - Empty state (\"No Knowledge pages linked yet\") + \"Open Knowledge\"\n CTA 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-collectives/` for the\n spec delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-collectives-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-collectives-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 v-if=\"!degraded\" class=\"cn-collectives-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 page') }}\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 page') }}\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-collectives-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-collectives-tab__empty\">\n\t\t\t<BookOpenPageVariant :size=\"32\" class=\"cn-collectives-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=\"collectivesAppUrl\"\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<BookOpenPageVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openCollectivesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<div v-else-if=\"pages.length > 0\" class=\"cn-collectives-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedPages\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-collectives-tab__group\">\n\t\t\t\t<header v-if=\"group.label\" class=\"cn-collectives-tab__group-header\">\n\t\t\t\t\t<FolderTextOutline :size=\"14\" />\n\t\t\t\t\t<span>{{ group.label }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-collectives-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"page in group.pages\"\n\t\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\t\tclass=\"cn-collectives-tab__row\"\n\t\t\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-collectives-tab__emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t\t\t<FileDocumentOutline v-else :size=\"22\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-collectives-tab__subname\">\n\t\t\t\t\t\t\t\t<span v-if=\"sublineLabel(page)\" class=\"cn-collectives-tab__subname-line\">{{ sublineLabel(page) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"pageSnippet(page)\" class=\"cn-collectives-tab__snippet\">{{ pageSnippet(page) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"modifiedMs(page)\" #details>\n\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\tclass=\"cn-collectives-tab__time\"\n\t\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in Knowledge') }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPage(page)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</div>\n\n\t\t<CnCollectivePagePicker\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<CnCollectivePageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport FolderTextOutline from 'vue-material-design-icons/FolderTextOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCollectivePageCreate from '../../../components/CnCollectivePageCreate/CnCollectivePageCreate.vue'\nimport CnCollectivePagePicker from '../../../components/CnCollectivePagePicker/CnCollectivePagePicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000\nconst MS_PER_HOUR = 60 * 60 * 1000\nconst SNIPPET_MAX_CHARS = 160\n\n/**\n * CnCollectivesTab — bespoke sidebar list for the `collectives`\n * integration.\n *\n * Renders Knowledge pages grouped by parent collective; each row has\n * emoji + title + content snippet + last-modified hint and deep-links\n * to the page inside NC Collectives.\n */\nexport default {\n\tname: 'CnCollectivesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookOpenPageVariant,\n\t\tFileDocumentOutline,\n\t\tFolderTextOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnCollectivePagePicker,\n\t\tCnCollectivePageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** 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 Knowledge pages linked yet') },\n\t\t/** Pre-translated \"Open Knowledge\" CTA label. */\n\t\topenCollectivesLabel: { type: String, default: () => t('nextcloud-vue', 'Open Knowledge') },\n\t\t/** Pre-translated banner when Collectives is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\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\tcomputed: {\n\t\tgroupedPages() {\n\t\t\tconst buckets = new Map()\n\t\t\tfor (const page of this.pages) {\n\t\t\t\tconst key = String(this.collectiveKey(page) || '__default__')\n\t\t\t\tif (!buckets.has(key)) {\n\t\t\t\t\tbuckets.set(key, { key, label: this.collectiveLabel(page), pages: [] })\n\t\t\t\t}\n\t\t\t\tbuckets.get(key).pages.push(page)\n\t\t\t}\n\t\t\treturn Array.from(buckets.values())\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 collectives endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tcollectivesEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/collectives`\n\t\t},\n\n\t\t/**\n\t\t * Resolve the numeric page id from a row (top-level or `data.*`).\n\t\t *\n\t\t * @param {object} page Provider/link row.\n\t\t *\n\t\t * @return {(number|string)} The page id, or '' when absent.\n\t\t */\n\t\tpageId(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.pageId ?? d.pageId ?? page.id ?? d.id ?? ''\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.pageId ?? d.pageId ?? page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.pageTitle ?? d.pageTitle ?? page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Provider returns the slug (which carries the `[or:{uuid}]`\n\t\t\t// marker) when no real title is available. Strip the marker\n\t\t\t// AND any dangling slug separator (`-`, `_`, `.`) left\n\t\t\t// behind — `phase-d1-page-[or:UUID]` would otherwise render\n\t\t\t// as `phase-d1-page-` with a trailing hyphen (D-1 bug).\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageSnippet(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst raw = page.content ?? d.content ?? ''\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 > SNIPPET_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, SNIPPET_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.collectiveId ?? d.collectiveId ?? d.collective_id ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\tmetaLabel(page) {\n\t\t\tconst ms = this.modifiedMs(page)\n\t\t\tif (ms === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst diff = Date.now() - ms\n\t\t\tif (diff < 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (diff < MS_PER_HOUR) {\n\t\t\t\tconst minutes = Math.max(1, Math.floor(diff / (60 * 1000)))\n\t\t\t\treturn t('nextcloud-vue', 'Updated {n} minutes ago', { n: minutes })\n\t\t\t}\n\t\t\tif (diff < MS_PER_DAY) {\n\t\t\t\tconst hours = Math.max(1, Math.floor(diff / MS_PER_HOUR))\n\t\t\t\treturn t('nextcloud-vue', 'Updated {n} hours ago', { n: hours })\n\t\t\t}\n\t\t\tconst days = Math.max(1, Math.floor(diff / MS_PER_DAY))\n\t\t\treturn t('nextcloud-vue', 'Updated {n} days ago', { n: days })\n\t\t},\n\n\t\t/**\n\t\t * Subname line for a row: the parent collective name. NcDateTime\n\t\t * renders the \"last edited\" moment separately in the row's\n\t\t * #details slot, so the subname carries the collective only.\n\t\t *\n\t\t * @param {object} page Provider/link row.\n\t\t * @return {string} The collective name, or '' when unknown.\n\t\t */\n\t\tsublineLabel(page) {\n\t\t\treturn this.collectiveLabel(page)\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.collectivesEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This page is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link page.')\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('[CnCollectivesTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link page.')\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.collectivesEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create page.')\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('[CnCollectivesTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create page.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst id = this.pageId(page)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.collectivesEndpoint()}/${id}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink page.')\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('[CnCollectivesTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink page.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.collectivesEndpoint()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load Knowledge pages.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesTab] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load Knowledge pages.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-collectives-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-collectives-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-collectives-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-collectives-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-tab__groups {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-collectives-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n\tmargin-bottom: 2px;\n\tpadding: 0 4px;\n}\n\n.cn-collectives-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Emoji glyph stands in for the NcListItem avatar — circular tile\n tinted with the collective accent, mirroring NC Collectives pages. */\n.cn-collectives-tab__emoji {\n\tflex-shrink: 0;\n\twidth: 40px;\n\theight: 40px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tfont-size: 1.25em;\n\tline-height: 1;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-primary-element);\n}\n\n.cn-collectives-tab__subname {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-collectives-tab__subname-line {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-tab__snippet {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tdisplay: -webkit-box;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-collectives-tab__time {\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["CnCollectivePagePicker","CnCollectivePageCreate","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnCollectivesTab.vue2.js","sources":["../../../../../src/integrations/builtin/collectives/CnCollectivesTab.vue"],"sourcesContent":["<!--\n CnCollectivesTab — bespoke sidebar tab for the `collectives` integration.\n\n Replaces the generic CnIntegrationTab for the `collectives` leaf:\n renders linked Knowledge pages grouped by collective (emoji + title +\n optional content snippet + last-modified hint). Each row deep-links to\n the page inside the NC Collectives app via\n /index.php/apps/collectives/{collectiveSlug}/{pageSlug}\n (with a sane fallback to /index.php/apps/collectives/{pageId} when the\n provider only carries an id).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/collectives`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\CollectivesProvider`\n (storage strategy `link-table` — the marker `[or:{uuid}]` lives in the\n Collectives `collectives_pages.slug` column). Provider payload shape\n (verified against `CollectivesProvider::list`):\n { id, title, url, data: { id, slug, emoji, last_user_id, ... } }\n The richer \"spec\" shape (title, slug, emoji, content, fileId,\n lastModified, collectiveId, collectiveName, url) is accepted as well —\n the UI reads both top-level and `data.*` fields defensively so a future\n provider expansion stays drop-in.\n\n Bespoke-vs-generic rationale: the generic tab renders a flat title\n list which loses the collective grouping, the emoji glyph, and the\n per-page content snippet — three signals that make Knowledge linkage\n legible at-a-glance. The bespoke tab surfaces them per row.\n\n Surface behaviour:\n - Empty state (\"No Knowledge pages linked yet\") + \"Open Knowledge\"\n CTA 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-collectives/` for the\n spec delta and ADR-019 (registry mechanism), ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-collectives-tab\">\n\t\t<div v-if=\"degraded\" class=\"cn-collectives-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 v-if=\"!degraded\" class=\"cn-collectives-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 page') }}\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 page') }}\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-collectives-tab__error\" role=\"alert\">\n\t\t\t{{ error }}\n\t\t</div>\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && !degraded\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-collectives-tab__empty\">\n\t\t\t<BookOpenPageVariant :size=\"32\" class=\"cn-collectives-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=\"collectivesAppUrl\"\n\t\t\t\ttarget=\"_blank\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<BookOpenPageVariant :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ openCollectivesLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<div v-else-if=\"pages.length > 0\" class=\"cn-collectives-tab__groups\">\n\t\t\t<section\n\t\t\t\tv-for=\"group in groupedPages\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-collectives-tab__group\">\n\t\t\t\t<header v-if=\"group.label\" class=\"cn-collectives-tab__group-header\">\n\t\t\t\t\t<FolderTextOutline :size=\"14\" />\n\t\t\t\t\t<span>{{ group.label }}</span>\n\t\t\t\t</header>\n\t\t\t\t<ul class=\"cn-collectives-tab__list\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"page in group.pages\"\n\t\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\t\tclass=\"cn-collectives-tab__row\"\n\t\t\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t\t\t:bold=\"true\"\n\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<span class=\"cn-collectives-tab__emoji\" :aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<template v-if=\"pageEmoji(page)\">{{ pageEmoji(page) }}</template>\n\t\t\t\t\t\t\t\t<FileDocumentOutline v-else :size=\"22\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-collectives-tab__subname\">\n\t\t\t\t\t\t\t\t<span v-if=\"sublineLabel(page)\" class=\"cn-collectives-tab__subname-line\">{{ sublineLabel(page) }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"pageSnippet(page)\" class=\"cn-collectives-tab__snippet\">{{ pageSnippet(page) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"modifiedMs(page)\" #details>\n\t\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\t\tclass=\"cn-collectives-tab__time\"\n\t\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t:href=\"pageUrl(page)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in Knowledge') }}\n\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"unlinkPage(page)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</div>\n\n\t\t<CnCollectivePagePicker\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<CnCollectivePageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport BookOpenPageVariant from 'vue-material-design-icons/BookOpenPageVariant.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport FolderTextOutline from 'vue-material-design-icons/FolderTextOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnCollectivePageCreate from '../../../components/CnCollectivePageCreate/CnCollectivePageCreate.vue'\nimport CnCollectivePagePicker from '../../../components/CnCollectivePagePicker/CnCollectivePagePicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { stripMarker } from '../../utils/marker.js'\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000\nconst MS_PER_HOUR = 60 * 60 * 1000\nconst SNIPPET_MAX_CHARS = 160\n\n/**\n * CnCollectivesTab — bespoke sidebar list for the `collectives`\n * integration.\n *\n * Renders Knowledge pages grouped by parent collective; each row has\n * emoji + title + content snippet + last-modified hint and deep-links\n * to the page inside NC Collectives.\n */\nexport default {\n\tname: 'CnCollectivesTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tBookOpenPageVariant,\n\t\tFileDocumentOutline,\n\t\tFolderTextOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnCollectivePagePicker,\n\t\tCnCollectivePageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'collectives'`). */\n\t\tintegrationId: { type: String, default: 'collectives' },\n\t\t/** 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 Knowledge pages linked yet') },\n\t\t/** Pre-translated \"Open Knowledge\" CTA label. */\n\t\topenCollectivesLabel: { type: String, default: () => t('nextcloud-vue', 'Open Knowledge') },\n\t\t/** Pre-translated banner when Collectives is unavailable. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Knowledge is currently unavailable.') },\n\t\t/** URL of the NC Collectives app entry. */\n\t\tcollectivesAppUrl: { type: String, default: '/index.php/apps/collectives' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\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\tcomputed: {\n\t\tgroupedPages() {\n\t\t\tconst buckets = new Map()\n\t\t\tfor (const page of this.pages) {\n\t\t\t\tconst key = String(this.collectiveKey(page) || '__default__')\n\t\t\t\tif (!buckets.has(key)) {\n\t\t\t\t\tbuckets.set(key, { key, label: this.collectiveLabel(page), pages: [] })\n\t\t\t\t}\n\t\t\t\tbuckets.get(key).pages.push(page)\n\t\t\t}\n\t\t\treturn Array.from(buckets.values())\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 collectives endpoints (list/link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\tcollectivesEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/collectives`\n\t\t},\n\n\t\t/**\n\t\t * Resolve the numeric page id from a row (top-level or `data.*`).\n\t\t *\n\t\t * @param {object} page Provider/link row.\n\t\t *\n\t\t * @return {(number|string)} The page id, or '' when absent.\n\t\t */\n\t\tpageId(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.pageId ?? d.pageId ?? page.id ?? d.id ?? ''\n\t\t},\n\n\t\tdataOf(page) {\n\t\t\treturn (page && typeof page.data === 'object' && page.data !== null) ? page.data : {}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.pageId ?? d.pageId ?? page.id ?? d.id ?? page.slug ?? d.slug ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst candidate = page.pageTitle ?? d.pageTitle ?? page.title ?? d.title ?? d.slug ?? page.slug ?? ''\n\t\t\t// Provider returns the slug (which carries the `[or:{uuid}]`\n\t\t\t// marker) when no real title is available. Strip the marker\n\t\t\t// AND any dangling slug separator (`-`, `_`, `.`) left\n\t\t\t// behind — `phase-d1-page-[or:UUID]` would otherwise render\n\t\t\t// as `phase-d1-page-` with a trailing hyphen (D-1 bug).\n\t\t\tconst stripped = stripMarker(candidate).replace(/[-_.]+$/, '').replace(/^[-_.]+/, '').trim()\n\t\t\treturn stripped || String(this.pageKey(page))\n\t\t},\n\n\t\tpageEmoji(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst emoji = page.emoji ?? d.emoji ?? ''\n\t\t\treturn typeof emoji === 'string' ? emoji.trim() : ''\n\t\t},\n\n\t\tpageSnippet(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst raw = page.content ?? d.content ?? ''\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 > SNIPPET_MAX_CHARS) {\n\t\t\t\treturn text.slice(0, SNIPPET_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t// A provider URL is used only when it is a safe scheme; else the app link.\n\t\tpageUrl(page) {\n\t\t\tif (typeof page.url === 'string' && page.url !== '' && safeHref(page.url) !== '#') {\n\t\t\t\treturn page.url\n\t\t\t}\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst collectiveSlug = page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\tconst pageSlug = page.slug ?? d.slug ?? this.pageKey(page)\n\t\t\tif (collectiveSlug !== '' && pageSlug !== '') {\n\t\t\t\treturn `/index.php/apps/collectives/${collectiveSlug}/${pageSlug}`\n\t\t\t}\n\t\t\treturn `/index.php/apps/collectives/${this.pageKey(page)}`\n\t\t},\n\n\t\tcollectiveKey(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\treturn page.collectiveId ?? d.collectiveId ?? d.collective_id ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t},\n\n\t\tcollectiveLabel(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst name = page.collectiveName ?? d.collectiveName ?? d.collective_name ?? page.collectiveSlug ?? d.collectiveSlug ?? d.collective_slug ?? ''\n\t\t\treturn String(name).trim()\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst d = this.dataOf(page)\n\t\t\tconst v = page.lastModified ?? page.modified ?? page.updated ?? d.lastModified ?? d.modified ?? d.last_modified ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\tmetaLabel(page) {\n\t\t\tconst ms = this.modifiedMs(page)\n\t\t\tif (ms === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst diff = Date.now() - ms\n\t\t\tif (diff < 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (diff < MS_PER_HOUR) {\n\t\t\t\tconst minutes = Math.max(1, Math.floor(diff / (60 * 1000)))\n\t\t\t\treturn t('nextcloud-vue', 'Updated {n} minutes ago', { n: minutes })\n\t\t\t}\n\t\t\tif (diff < MS_PER_DAY) {\n\t\t\t\tconst hours = Math.max(1, Math.floor(diff / MS_PER_HOUR))\n\t\t\t\treturn t('nextcloud-vue', 'Updated {n} hours ago', { n: hours })\n\t\t\t}\n\t\t\tconst days = Math.max(1, Math.floor(diff / MS_PER_DAY))\n\t\t\treturn t('nextcloud-vue', 'Updated {n} days ago', { n: days })\n\t\t},\n\n\t\t/**\n\t\t * Subname line for a row: the parent collective name. NcDateTime\n\t\t * renders the \"last edited\" moment separately in the row's\n\t\t * #details slot, so the subname carries the collective only.\n\t\t *\n\t\t * @param {object} page Provider/link row.\n\t\t * @return {string} The collective name, or '' when unknown.\n\t\t */\n\t\tsublineLabel(page) {\n\t\t\treturn this.collectiveLabel(page)\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.collectivesEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'This page is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link page.')\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('[CnCollectivesTab] link failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not link page.')\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.collectivesEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create page.')\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('[CnCollectivesTab] create failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not create page.')\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst id = this.pageId(page)\n\t\t\tif (!id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.collectivesEndpoint()}/${id}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t} else {\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink page.')\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('[CnCollectivesTab] unlink failed', err)\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not unlink page.')\n\t\t\t}\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.collectivesEndpoint()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503 || response.status === 501) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load Knowledge pages.')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnCollectivesTab] failed to fetch Knowledge pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'Could not load Knowledge pages.')\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-collectives-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-collectives-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-collectives-tab__error {\n\tcolor: var(--color-error);\n\tfont-size: 0.9em;\n\tmargin: 4px 0 8px;\n}\n\n.cn-collectives-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-collectives-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-tab__groups {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-collectives-tab__group-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n\tmargin-bottom: 2px;\n\tpadding: 0 4px;\n}\n\n.cn-collectives-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n/* Emoji glyph stands in for the NcListItem avatar — circular tile\n tinted with the collective accent, mirroring NC Collectives pages. */\n.cn-collectives-tab__emoji {\n\tflex-shrink: 0;\n\twidth: 40px;\n\theight: 40px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tfont-size: 1.25em;\n\tline-height: 1;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-primary-element);\n}\n\n.cn-collectives-tab__subname {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-collectives-tab__subname-line {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-collectives-tab__snippet {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tdisplay: -webkit-box;\n\t-webkit-line-clamp: 2;\n\t-webkit-box-orient: vertical;\n}\n\n.cn-collectives-tab__time {\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["CnCollectivePagePicker","CnCollectivePageCreate","t"],"mappings":";;;;;;;;;;;;;;;;AA2KA,MAAM,aAAa,EAAG,GAAE,EAAC,GAAI,EAAG,GAAE,KAAG;AACrC,MAAM,WAAU,GAAI,EAAG,GAAE,EAAG,GAAE,KAAG;AACjC,MAAM,iBAAgB,GAAI,IAAE;;AAE5B;;;AAGC;;;;;AAKD,aAAe;CACd,IAAI,EAAE,kBAAkB;;CAExB,UAAU,EAAE;AACX,EAAA,cAAc;EACd,YAAY;AACZ,EAAA,QAAQ;EACR,UAAU;EACV,UAAU;EACV,aAAa;AACb,EAAA,kBAAkB;AAClB,EAAA,mBAAmB;AACnB,EAAA,mBAAmB;AACnB,EAAA,iBAAiB;AACjB,EAAA,OAAO;EACP,WAAW;AACX,EAAA,SAAS;EACT,IAAI;0BACJA,UAAsB;0BACtBC,YAAsB;EACtB;;AAED,CAAA,KAAK,EAAE;AACN;EACA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAY,EAAG;AACvD;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,+BAA+B,GAAG;AAChG;AACA,EAAA,oBAAoB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,gBAAgB,GAAG;;EAE3F,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,wCAAwC,CAAA,EAAG;AAC/G;AACA,EAAA,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,+BAA+B;EAC3E;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,KAAK,EAAE,EAAE;GACT,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,QAAQ,EAAE;AACT,EAAA,YAAY,GAAG;AACd,GAAA,MAAM,OAAM,GAAI,IAAI,GAAG,GAAC;GACxB,KAAK,MAAM,IAAG,IAAK,IAAI,CAAC,KAAK,EAAE;IAC9B,MAAM,GAAI,GAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAE,IAAG,aAAa,EAAA;AAC5D,IAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACtB,KAAA,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAA;AACvE,KAAA;AACA,IAAA,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAA;AACjC,IAAA;AACA,GAAA,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAA;GAClC;EACD;;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,UAAU,GAAC;AACjB,IAAA;AACD,GAAA,EAAG;;EAEH,QAAQ,GAAG;AACV,GAAA,IAAI,CAAC,UAAU,GAAC;GAChB;;AAED,EAAA,MAAM,GAAG;AACR,GAAA,IAAI,CAAC,UAAU,GAAC;GAChB;EACD;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,OAAO,GAAG;GACT,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,cAAc,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;GACnH;;AAED;;AAEC;AACA;;AAED,EAAA,mBAAmB,GAAG;AACrB,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,YAAY,CAAA;GAC5F;;AAED;;AAEC;AACA;AACA;;;EAGD,MAAM,CAAC,IAAI,EAAE;GACZ,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,MAAO,IAAG,IAAI,CAAC,EAAG,IAAG,CAAC,CAAC,EAAG,IAAG,EAAC;GACtD;;EAED,MAAM,CAAC,IAAI,EAAE;AACZ,GAAA,OAAO,CAAC,IAAK,IAAG,OAAO,IAAI,CAAC,IAAG,KAAM,QAAO,IAAK,IAAI,CAAC,IAAG,KAAM,IAAI,IAAI,IAAI,CAAC,IAAG,GAAI,EAAC;GACpF;;EAED,OAAO,CAAC,IAAI,EAAE;GACb,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,OAAO,IAAI,CAAC,MAAK,IAAK,CAAC,CAAC,MAAK,IAAK,IAAI,CAAC,EAAC,IAAK,CAAC,CAAC,EAAC,IAAK,IAAI,CAAC,IAAK,IAAG,CAAC,CAAC,IAAK,IAAG,EAAC;GAC7E;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;GACf,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,MAAM,SAAQ,GAAI,IAAI,CAAC,aAAa,CAAC,CAAC,SAAQ,IAAK,IAAI,CAAC,KAAM,IAAG,CAAC,CAAC,KAAM,IAAG,CAAC,CAAC,IAAK,IAAG,IAAI,CAAC,IAAK,IAAG,GAAC;;;AAGpG;;;AAGA,GAAA,MAAM,WAAW,WAAW,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,GAAC;AAC3F,GAAA,OAAO,QAAO,IAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;GAC5C;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;GACf,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,MAAM,KAAM,GAAE,IAAI,CAAC,KAAM,IAAG,CAAC,CAAC,KAAM,IAAG,GAAC;AACxC,GAAA,OAAO,OAAO,KAAM,KAAI,QAAS,GAAE,KAAK,CAAC,IAAI,EAAC,GAAI,EAAC;GACnD;;AAED,EAAA,WAAW,CAAC,IAAI,EAAE;GACjB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,MAAM,GAAE,GAAI,IAAI,CAAC,OAAM,IAAK,CAAC,CAAC,OAAQ,IAAG,GAAC;GAC1C,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;;;EAGD,OAAO,CAAC,IAAI,EAAE;AACb,GAAA,IAAI,OAAO,IAAI,CAAC,GAAE,KAAM,QAAO,IAAK,IAAI,CAAC,GAAI,KAAI,EAAG,IAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAE,KAAI,GAAG,EAAE;IAClF,OAAO,IAAI,CAAC,GAAE;AACf,IAAA;GACA,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,MAAM,cAAa,GAAI,IAAI,CAAC,cAAa,IAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,eAAgB,IAAG,GAAC;GACxF,MAAM,WAAW,IAAI,CAAC,IAAG,IAAK,CAAC,CAAC,IAAG,IAAK,IAAI,CAAC,OAAO,CAAC,IAAI,EAAA;AACzD,GAAA,IAAI,mBAAmB,MAAM,aAAa,EAAE,EAAE;AAC7C,IAAA,OAAO,CAAC,4BAA4B,EAAE,cAAc,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;AAClE,IAAA;GACA,OAAO,CAAC,4BAA4B,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;GACzD;;AAED,EAAA,aAAa,CAAC,IAAI,EAAE;GACnB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;GAC1B,OAAO,IAAI,CAAC,YAAa,IAAG,CAAC,CAAC,YAAW,IAAK,CAAC,CAAC,aAAY,IAAK,IAAI,CAAC,cAAe,IAAG,CAAC,CAAC,cAAa,IAAK,CAAC,CAAC,eAAc,IAAK,EAAC;GAClI;;AAED,EAAA,eAAe,CAAC,IAAI,EAAE;GACrB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC1B,GAAA,MAAM,IAAG,GAAI,IAAI,CAAC,cAAa,IAAK,CAAC,CAAC,cAAa,IAAK,CAAC,CAAC,eAAgB,IAAG,IAAI,CAAC,cAAa,IAAK,CAAC,CAAC,cAAa,IAAK,CAAC,CAAC,eAAgB,IAAG,GAAC;GAC9I,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC;GACzB;;AAED,EAAA,UAAU,CAAC,IAAI,EAAE;GAChB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;GAC1B,MAAM,IAAI,IAAI,CAAC,YAAa,IAAG,IAAI,CAAC,YAAY,IAAI,CAAC,OAAQ,IAAG,CAAC,CAAC,YAAa,IAAG,CAAC,CAAC,YAAY,CAAC,CAAC,iBAAiB,KAAG;AACtH,GAAA,IAAI,CAAE,KAAI,IAAK,IAAG,CAAA,KAAM,SAAQ,IAAK,MAAM,EAAE,EAAE;AAC9C,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,OAAO,CAAE,KAAI,QAAQ,EAAE;AAC1B,IAAA,OAAO,CAAA,GAAI,IAAG,GAAI,CAAE,GAAE,OAAO,CAAA;AAC9B,IAAA;AACA,GAAA,MAAM,MAAK,GAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAA;AACnC,GAAA,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAE,KAAI,IAAG,GAAI,IAAK,GAAE,MAAK;GACnD;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;GACf,MAAM,EAAG,GAAE,IAAI,CAAC,UAAU,CAAC,IAAI,EAAA;GAC/B,IAAI,EAAG,KAAI,IAAI,EAAE;AAChB,IAAA,OAAO,EAAC;AACT,IAAA;GACA,MAAM,OAAO,IAAI,CAAC,GAAG,EAAC,GAAI,GAAC;GAC3B,IAAI,IAAK,GAAE,CAAC,EAAE;AACb,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI,IAAG,GAAI,WAAW,EAAE;IACvB,MAAM,OAAM,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAG,GAAE,IAAI,CAAC,CAAC,EAAA;IAC1D,OAAOA,SAAC,CAAC,eAAe,EAAE,yBAAyB,EAAE,EAAE,CAAC,EAAE,OAAM,EAAG,CAAA;AACpE,IAAA;AACA,GAAA,IAAI,OAAO,UAAU,EAAE;IACtB,MAAM,KAAI,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAK,GAAE,WAAW,CAAC,EAAA;IACxD,OAAOA,SAAC,CAAC,eAAe,EAAE,uBAAuB,EAAE,EAAE,CAAC,EAAE,KAAI,EAAG,CAAA;AAChE,IAAA;GACA,MAAM,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAG,GAAI,UAAU,CAAC,EAAA;GACtD,OAAOA,SAAC,CAAC,eAAe,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,IAAG,EAAG,CAAA;GAC7D;;AAED;;;;AAIC;AACA;;;AAGD,EAAA,YAAY,CAAC,IAAI,EAAE;AAClB,GAAA,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,CAAA;GAChC;;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;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE;KACnE,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;AAChB,KAAA,MAAM,IAAI,CAAC,UAAU,GAAC;AACvB,KAAA,MAAO,IAAI,QAAQ,CAAC,MAAK,KAAM,GAAG,EAAE;KACnC,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,8BAA8B,EAAA;KAC7D,MAAK;KACN,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,sBAAsB,EAAA;AACvD,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,EAAA;IACnD,IAAI,CAAC,KAAM,GAAEA,SAAC,CAAC,eAAe,EAAE,sBAAsB,EAAA;AACvD,IAAA;GACA;;EAED,MAAM,YAAY,CAAC,OAAO,EAAE;AAC3B,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,IAAI;AACH,IAAA,MAAM,QAAS,GAAE,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE;KAC5E,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;AAChB,KAAA,MAAM,IAAI,CAAC,UAAU,GAAC;KACrB,MAAK;KACN,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,wBAAwB,EAAA;AACzD,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,EAAA;IACrD,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,wBAAwB,EAAA;AACzD,IAAA;GACA;;AAED,EAAA,MAAM,UAAU,CAAC,IAAI,EAAE;GACtB,MAAM,EAAG,GAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAA;AAC3B,GAAA,IAAI,CAAC,EAAE,EAAE;IACR,MAAK;AACN,IAAA;AACA,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;AAC9E,KAAA,MAAM,EAAE,QAAQ;KAChB,OAAO,EAAE,YAAY,EAAE;KACvB,EAAA;AACD,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;AAChB,KAAA,MAAM,IAAI,CAAC,UAAU,GAAC;KACrB,MAAK;KACN,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,wBAAwB,EAAA;AACzD,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,EAAA;IACrD,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,wBAAwB,EAAA;AACzD,IAAA;GACA;;AAED,EAAA,MAAM,UAAU,GAAG;GAClB,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,WAAW,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AAC/F,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,KAAM,GAAE,KAAG;KACf,MAAK,IAAI,QAAQ,CAAC,MAAO,KAAI,GAAE,IAAK,QAAQ,CAAC,MAAO,KAAI,GAAG,EAAE;KAC9D,IAAI,CAAC,KAAM,GAAE,GAAC;AACd,KAAA,IAAI,CAAC,QAAS,GAAE,IAAI,CAAC,iBAAe;KACnC,MAAK;KACN,IAAI,CAAC,KAAM,GAAE,GAAC;KACd,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,iCAAiC,EAAA;AAClE,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,EAAA;IACvE,IAAI,CAAC,KAAM,GAAE,GAAC;IACd,IAAI,CAAC,KAAI,GAAIA,SAAC,CAAC,eAAe,EAAE,iCAAiC,EAAA;AAClE,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.collectivesAppUrl,
|
|
112
|
-
target: "_blank"
|
|
113
|
-
rel: "noopener noreferrer"
|
|
112
|
+
target: "_blank"
|
|
114
113
|
}, {
|
|
115
114
|
icon: withCtx(() => [
|
|
116
115
|
createVNode(_component_BookOpenPageVariant, { size: 20 })
|
|
@@ -171,8 +170,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
171
170
|
createVNode(_component_NcActionLink, {
|
|
172
171
|
closeAfterClick: true,
|
|
173
172
|
href: $options.pageUrl(page),
|
|
174
|
-
target: "_blank"
|
|
175
|
-
rel: "noopener noreferrer"
|
|
173
|
+
target: "_blank"
|
|
176
174
|
}, {
|
|
177
175
|
icon: withCtx(() => [
|
|
178
176
|
createVNode(_component_OpenInNew, { size: 20 })
|