@conduction/nextcloud-vue 2.56.0-beta.3 → 2.56.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/CnAppRoot/CnAppRoot.vue2.js +21 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.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/CnSetupWizard/CnSetupWizard.vue2.js +49 -5
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.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 +2 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +78 -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/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +885 -393
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +78 -7
- package/l10n/en.json +2 -0
- package/l10n/nl.json +2 -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/CnAppRoot/CnAppRoot.vue +31 -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/CnSetupWizard/CnSetupWizard.vue +57 -6
- 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/schemas/app-manifest-v2.schema.json +2 -1
- 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
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnXwikiCard.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiCard.vue?vue&type=template&id=54e85fe3&lang.js"],"sourcesContent":["<!--\n CnXwikiCard — bespoke surface-aware widget for the `xwiki` integration.\n\n Replaces the generic CnIntegrationCard for the `xwiki` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard: headline count of linked XWiki\n pages + most-recent linked page title + breadcrumb + an auth-\n status badge (configured / not configured / unhealthy).\n - detail-page: linked-pages list with macro-inert text preview of\n the first page (HTML stripped to plain text, `<script>` body\n removed, ~500-char truncation — AD-1) + \"Open in XWiki\" link.\n - single-entity: title + breadcrumb chip resolved from the `value`\n prop (for `referenceType: 'xwiki'` properties); falls back to a\n minimal chip with just the `value` when the lookup fails.\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnXwikiTab; for `single-entity` the optional `value` prop addresses a\n single page by canonical reference (matching the underlying provider\n `get()` contract).\n\n External-fetch latency is normal for XWiki because the OR provider\n hops through Integriq → external HTTP. The card shows a loading\n spinner for the whole round-trip; failure modes (503 +\n `details.cause` per AD-23) collapse to a compact `authStatus` badge\n on the dashboard surfaces instead of a fat banner.\n\n Security note: the text preview NEVER injects HTML into the DOM. The\n `<script>`/`<style>` bodies are stripped first, then all tags are\n removed, and finally the result is bound through `{{ }}` (text\n interpolation) — macros remain inert text.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-1 (text-only preview).\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-xwiki-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<FileDocumentMultiple :size=\"14\" />\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=\"breadcrumbLabel(entity)\" class=\"cn-xwiki-card__chip-breadcrumb\">\n\t\t\t\t\t· {{ breadcrumbLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-xwiki-card__chip cn-xwiki-card__chip--fallback\">\n\t\t\t\t<FileDocumentMultiple :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-xwiki-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent + auth status badge -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div class=\"cn-xwiki-card__dashboard\">\n\t\t\t\t<div class=\"cn-xwiki-card__headline-row\">\n\t\t\t\t\t<strong v-if=\"!degraded\" class=\"cn-xwiki-card__count\">{{ countHeadline }}</strong>\n\t\t\t\t\t<span v-else class=\"cn-xwiki-card__count cn-xwiki-card__count--muted\">\n\t\t\t\t\t\t{{ degradedHeadline }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclass=\"cn-xwiki-card__auth-badge\"\n\t\t\t\t\t\t:class=\"`cn-xwiki-card__auth-badge--${authBadge.kind}`\"\n\t\t\t\t\t\t:title=\"authBadge.title\">\n\t\t\t\t\t\t{{ authBadge.label }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"!degraded && mostRecent\" class=\"cn-xwiki-card__recent\">\n\t\t\t\t\t<FileDocumentMultiple :size=\"14\" />\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=\"breadcrumbLabel(mostRecent)\" class=\"cn-xwiki-card__recent-breadcrumb\">\n\t\t\t\t\t\t· {{ breadcrumbLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-else-if=\"!degraded && pages.length === 0\" class=\"cn-xwiki-card__empty\">\n\t\t\t\t\t{{ emptyLabel }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: list + text preview of first page -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-xwiki-card__banner\" :class=\"`cn-xwiki-card__banner--${bannerKind}`\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-xwiki-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-xwiki-card__detail\">\n\t\t\t\t<ul class=\"cn-xwiki-card__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-card__row\">\n\t\t\t\t\t\t<div class=\"cn-xwiki-card__row-header\">\n\t\t\t\t\t\t\t<FileDocumentMultiple :size=\"16\" class=\"cn-xwiki-card__row-icon\" />\n\t\t\t\t\t\t\t<a\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\"\n\t\t\t\t\t\t\t\tclass=\"cn-xwiki-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-card__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"previewText\" class=\"cn-xwiki-card__preview\">\n\t\t\t\t\t<p>{{ previewText }}</p>\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"firstPageUrl\"\n\t\t\t\t\t\t:href=\"firstPageUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\tclass=\"cn-xwiki-card__open-link\">\n\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t</a>\n\t\t\t\t</div>\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 FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst PREVIEW_MAX_CHARS = 500\n\n/**\n * CnXwikiCard — bespoke surface-aware widget for the `xwiki` integration.\n *\n * Renders XWiki-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnXwikiCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, FileDocumentMultiple },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** 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 canonical reference). */\n\t\tvalue: { type: String, default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Articles') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => FileDocumentMultiple },\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 XWiki pages linked yet') },\n\t\t/** Pre-translated \"Open in XWiki\" label. */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open in XWiki') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\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\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\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\tdegradedHeadline() {\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\treturn t('nextcloud-vue', 'Not configured')\n\t\t\t}\n\t\t\tif (this.bannerKind === 'auth') {\n\t\t\t\treturn t('nextcloud-vue', 'Auth failed')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Unavailable')\n\t\t},\n\n\t\tauthBadge() {\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'missing',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Not configured'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'Add an XWiki source in Integriq to enable this integration.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.bannerKind === 'auth') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'unhealthy',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Auth failed'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.bannerKind === 'upstream' || this.bannerKind === 'error') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'unhealthy',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Unavailable'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'The upstream XWiki host did not respond.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: 'configured',\n\t\t\t\tlabel: t('nextcloud-vue', 'Configured'),\n\t\t\t\ttitle: t('nextcloud-vue', 'Integriq source is configured.'),\n\t\t\t}\n\t\t},\n\n\t\tfirstPageUrl() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.pageUrl(this.pages[0])\n\t\t},\n\n\t\tpreviewText() {\n\t\t\tif (this.surface !== 'detail-page' || this.pages.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst raw = this.pages[0].content ?? this.pages[0].renderedContent ?? ''\n\t\t\treturn this.toSafePreviewText(String(raw))\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\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\tpageUrl(page) {\n\t\t\treturn page.url ?? ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.breadcrumbLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 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\t/**\n\t\t * Reduce a (possibly rendered-HTML) string to safe inert text:\n\t\t * 1. Strip `<script>` and `<style>` blocks entirely (incl. body).\n\t\t * 2. Strip all remaining HTML tags.\n\t\t * 3. Collapse whitespace.\n\t\t * 4. Truncate to PREVIEW_MAX_CHARS.\n\t\t *\n\t\t * Macro markup (e.g. `{{velocity}}…{{/velocity}}`) is preserved as\n\t\t * inert text — it is never executed because the result is bound\n\t\t * via `{{ }}` text interpolation in the template, not v-html.\n\t\t *\n\t\t * @param {string} raw Raw rendered-HTML body or plain text.\n\t\t *\n\t\t * @return {string} Safe preview text (≤ PREVIEW_MAX_CHARS).\n\t\t */\n\t\ttoSafePreviewText(raw) {\n\t\t\tif (raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = raw\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > PREVIEW_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, PREVIEW_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause (`details.cause` per AD-23) to a banner kind.\n\t\t *\n\t\t * @param {string} cause Cause string from the controller envelope.\n\t\t *\n\t\t * @return {string} Banner kind (`unconfigured` / `auth` / `upstream`).\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tapplyDegradedFromCause(cause) {\n\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki connection not configured — add a source in Integriq.')\n\t\t\t} else if (this.bannerKind === 'auth') {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.')\n\t\t\t} else {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki is currently unavailable.')\n\t\t\t}\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\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\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\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.applyDegradedFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t\tthis.degraded = t('nextcloud-vue', 'Could not load XWiki 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('[CnXwikiCard] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'Could not load XWiki 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.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\tthis.bannerKind = 'none'\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 {\n\t\t\t\t\t// On any non-OK (incl. 503) we keep the chip-fallback path\n\t\t\t\t\t// (renders the raw `value` as a minimal chip). The dashboard\n\t\t\t\t\t// surfaces show the badge; single-entity is intentionally\n\t\t\t\t\t// quieter — it's an inline chip in a form/table.\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tif (response.status === 503) {\n\t\t\t\t\t\tlet cause = ''\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tcause = ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t\t}\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('[CnXwikiCard] failed to fetch single XWiki page', err)\n\t\t\t\tthis.entity = null\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-xwiki-card__dashboard {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-xwiki-card__headline-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-xwiki-card__count {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-xwiki-card__count--muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: normal;\n}\n\n.cn-xwiki-card__auth-badge {\n\tflex-shrink: 0;\n\tfont-size: 0.75em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-card__auth-badge--configured {\n\tbackground: var(--color-success, #46ba61);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__auth-badge--missing {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border);\n}\n\n.cn-xwiki-card__auth-badge--unhealthy {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__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-xwiki-card__recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-xwiki-card__recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__recent-breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-card__banner {\n\tpadding: 8px 10px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n\tmargin-bottom: 8px;\n}\n\n.cn-xwiki-card__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-card__banner--auth,\n.cn-xwiki-card__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-xwiki-card__row {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-xwiki-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-xwiki-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-xwiki-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-card__title {\n\tflex: 1;\n\tmin-width: 0;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-xwiki-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__breadcrumb {\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 24px;\n}\n\n.cn-xwiki-card__preview {\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n\tfont-size: 0.9em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-xwiki-card__preview p {\n\tmargin: 0 0 6px;\n}\n\n.cn-xwiki-card__open-link {\n\tcolor: var(--color-primary-element, #21468B);\n\ttext-decoration: none;\n\tfont-weight: 500;\n}\n\n.cn-xwiki-card__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-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-xwiki-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-xwiki-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__chip-breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-card__chip--fallback {\n\topacity: 0.85;\n}\n</style>\n"],"names":["_Fragment","_createVNode","_createElementVNode","_toDisplayString","_openBlock","_createElementBlock","_normalizeClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnXwikiCard.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiCard.vue?vue&type=template&id=54e85fe3&lang.js"],"sourcesContent":["<!--\n CnXwikiCard — bespoke surface-aware widget for the `xwiki` integration.\n\n Replaces the generic CnIntegrationCard for the `xwiki` leaf. Branches\n on `surface` per AD-19:\n - user-dashboard / app-dashboard: headline count of linked XWiki\n pages + most-recent linked page title + breadcrumb + an auth-\n status badge (configured / not configured / unhealthy).\n - detail-page: linked-pages list with macro-inert text preview of\n the first page (HTML stripped to plain text, `<script>` body\n removed, ~500-char truncation — AD-1) + \"Open in XWiki\" link.\n - single-entity: title + breadcrumb chip resolved from the `value`\n prop (for `referenceType: 'xwiki'` properties); falls back to a\n minimal chip with just the `value` when the lookup fails.\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnXwikiTab; for `single-entity` the optional `value` prop addresses a\n single page by canonical reference (matching the underlying provider\n `get()` contract).\n\n External-fetch latency is normal for XWiki because the OR provider\n hops through Integriq → external HTTP. The card shows a loading\n spinner for the whole round-trip; failure modes (503 +\n `details.cause` per AD-23) collapse to a compact `authStatus` badge\n on the dashboard surfaces instead of a fat banner.\n\n Security note: the text preview NEVER injects HTML into the DOM. The\n `<script>`/`<style>` bodies are stripped first, then all tags are\n removed, and finally the result is bound through `{{ }}` (text\n interpolation) — macros remain inert text.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-1 (text-only preview).\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-xwiki-card__chip\"\n\t\t\t\t:title=\"chipSubtitle(entity)\">\n\t\t\t\t<FileDocumentMultiple :size=\"14\" />\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=\"breadcrumbLabel(entity)\" class=\"cn-xwiki-card__chip-breadcrumb\">\n\t\t\t\t\t· {{ breadcrumbLabel(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else-if=\"value\" class=\"cn-xwiki-card__chip cn-xwiki-card__chip--fallback\">\n\t\t\t\t<FileDocumentMultiple :size=\"14\" />\n\t\t\t\t<span>{{ value }}</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-xwiki-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: count + most-recent + auth status badge -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div class=\"cn-xwiki-card__dashboard\">\n\t\t\t\t<div class=\"cn-xwiki-card__headline-row\">\n\t\t\t\t\t<strong v-if=\"!degraded\" class=\"cn-xwiki-card__count\">{{ countHeadline }}</strong>\n\t\t\t\t\t<span v-else class=\"cn-xwiki-card__count cn-xwiki-card__count--muted\">\n\t\t\t\t\t\t{{ degradedHeadline }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclass=\"cn-xwiki-card__auth-badge\"\n\t\t\t\t\t\t:class=\"`cn-xwiki-card__auth-badge--${authBadge.kind}`\"\n\t\t\t\t\t\t:title=\"authBadge.title\">\n\t\t\t\t\t\t{{ authBadge.label }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"!degraded && mostRecent\" class=\"cn-xwiki-card__recent\">\n\t\t\t\t\t<FileDocumentMultiple :size=\"14\" />\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=\"breadcrumbLabel(mostRecent)\" class=\"cn-xwiki-card__recent-breadcrumb\">\n\t\t\t\t\t\t· {{ breadcrumbLabel(mostRecent) }}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-else-if=\"!degraded && pages.length === 0\" class=\"cn-xwiki-card__empty\">\n\t\t\t\t\t{{ emptyLabel }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: list + text preview of first page -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-xwiki-card__banner\" :class=\"`cn-xwiki-card__banner--${bannerKind}`\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"pages.length === 0\" class=\"cn-xwiki-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-xwiki-card__detail\">\n\t\t\t\t<ul class=\"cn-xwiki-card__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-card__row\">\n\t\t\t\t\t\t<div class=\"cn-xwiki-card__row-header\">\n\t\t\t\t\t\t\t<FileDocumentMultiple :size=\"16\" class=\"cn-xwiki-card__row-icon\" />\n\t\t\t\t\t\t\t<a\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\"\n\t\t\t\t\t\t\t\tclass=\"cn-xwiki-card__title\">{{ pageTitle(page) }}</a>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-card__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"previewText\" class=\"cn-xwiki-card__preview\">\n\t\t\t\t\t<p>{{ previewText }}</p>\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"firstPageUrl\"\n\t\t\t\t\t\t:href=\"firstPageUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\tclass=\"cn-xwiki-card__open-link\">\n\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t</a>\n\t\t\t\t</div>\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 FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\nconst PREVIEW_MAX_CHARS = 500\n\n/**\n * CnXwikiCard — bespoke surface-aware widget for the `xwiki` integration.\n *\n * Renders XWiki-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnXwikiCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, FileDocumentMultiple },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** 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 canonical reference). */\n\t\tvalue: { type: String, default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Articles') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => FileDocumentMultiple },\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 XWiki pages linked yet') },\n\t\t/** Pre-translated \"Open in XWiki\" label. */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open in XWiki') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\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\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\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\tdegradedHeadline() {\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\treturn t('nextcloud-vue', 'Not configured')\n\t\t\t}\n\t\t\tif (this.bannerKind === 'auth') {\n\t\t\t\treturn t('nextcloud-vue', 'Auth failed')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Unavailable')\n\t\t},\n\n\t\tauthBadge() {\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'missing',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Not configured'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'Add an XWiki source in Integriq to enable this integration.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.bannerKind === 'auth') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'unhealthy',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Auth failed'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.bannerKind === 'upstream' || this.bannerKind === 'error') {\n\t\t\t\treturn {\n\t\t\t\t\tkind: 'unhealthy',\n\t\t\t\t\tlabel: t('nextcloud-vue', 'Unavailable'),\n\t\t\t\t\ttitle: t('nextcloud-vue', 'The upstream XWiki host did not respond.'),\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkind: 'configured',\n\t\t\t\tlabel: t('nextcloud-vue', 'Configured'),\n\t\t\t\ttitle: t('nextcloud-vue', 'Integriq source is configured.'),\n\t\t\t}\n\t\t},\n\n\t\tfirstPageUrl() {\n\t\t\tif (this.pages.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.pageUrl(this.pages[0])\n\t\t},\n\n\t\tpreviewText() {\n\t\t\tif (this.surface !== 'detail-page' || this.pages.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst raw = this.pages[0].content ?? this.pages[0].renderedContent ?? ''\n\t\t\treturn this.toSafePreviewText(String(raw))\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\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t// An unsafe scheme is treated like a missing URL.\n\t\tpageUrl(page) {\n\t\t\tconst url = page.url ?? ''\n\t\t\treturn url && safeHref(url) !== '#' ? url : ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\tchipSubtitle(page) {\n\t\t\treturn this.breadcrumbLabel(page) || this.pageTitle(page)\n\t\t},\n\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn 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\t/**\n\t\t * Reduce a (possibly rendered-HTML) string to safe inert text:\n\t\t * 1. Strip `<script>` and `<style>` blocks entirely (incl. body).\n\t\t * 2. Strip all remaining HTML tags.\n\t\t * 3. Collapse whitespace.\n\t\t * 4. Truncate to PREVIEW_MAX_CHARS.\n\t\t *\n\t\t * Macro markup (e.g. `{{velocity}}…{{/velocity}}`) is preserved as\n\t\t * inert text — it is never executed because the result is bound\n\t\t * via `{{ }}` text interpolation in the template, not v-html.\n\t\t *\n\t\t * @param {string} raw Raw rendered-HTML body or plain text.\n\t\t *\n\t\t * @return {string} Safe preview text (≤ PREVIEW_MAX_CHARS).\n\t\t */\n\t\ttoSafePreviewText(raw) {\n\t\t\tif (raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = raw\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > PREVIEW_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, PREVIEW_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause (`details.cause` per AD-23) to a banner kind.\n\t\t *\n\t\t * @param {string} cause Cause string from the controller envelope.\n\t\t *\n\t\t * @return {string} Banner kind (`unconfigured` / `auth` / `upstream`).\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tapplyDegradedFromCause(cause) {\n\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\tif (this.bannerKind === 'unconfigured') {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki connection not configured — add a source in Integriq.')\n\t\t\t} else if (this.bannerKind === 'auth') {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.')\n\t\t\t} else {\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'XWiki is currently unavailable.')\n\t\t\t}\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\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\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\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.applyDegradedFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t\tthis.degraded = t('nextcloud-vue', 'Could not load XWiki 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('[CnXwikiCard] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\tthis.degraded = t('nextcloud-vue', 'Could not load XWiki 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.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\tthis.bannerKind = 'none'\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 {\n\t\t\t\t\t// On any non-OK (incl. 503) we keep the chip-fallback path\n\t\t\t\t\t// (renders the raw `value` as a minimal chip). The dashboard\n\t\t\t\t\t// surfaces show the badge; single-entity is intentionally\n\t\t\t\t\t// quieter — it's an inline chip in a form/table.\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tif (response.status === 503) {\n\t\t\t\t\t\tlet cause = ''\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tcause = ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t\t}\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('[CnXwikiCard] failed to fetch single XWiki page', err)\n\t\t\t\tthis.entity = null\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-xwiki-card__dashboard {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-xwiki-card__headline-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-xwiki-card__count {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-xwiki-card__count--muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: normal;\n}\n\n.cn-xwiki-card__auth-badge {\n\tflex-shrink: 0;\n\tfont-size: 0.75em;\n\tpadding: 2px 8px;\n\tborder-radius: 10px;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-card__auth-badge--configured {\n\tbackground: var(--color-success, #46ba61);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__auth-badge--missing {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border);\n}\n\n.cn-xwiki-card__auth-badge--unhealthy {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__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-xwiki-card__recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-xwiki-card__recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__recent-breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-card__banner {\n\tpadding: 8px 10px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n\tmargin-bottom: 8px;\n}\n\n.cn-xwiki-card__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-card__banner--auth,\n.cn-xwiki-card__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-card__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-xwiki-card__row {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-xwiki-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-xwiki-card__row-header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-xwiki-card__row-icon {\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-card__title {\n\tflex: 1;\n\tmin-width: 0;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-xwiki-card__title:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__breadcrumb {\n\tfont-size: 0.8em;\n\tcolor: var(--color-text-maxcontrast);\n\tpadding-left: 24px;\n}\n\n.cn-xwiki-card__preview {\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n\tfont-size: 0.9em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-xwiki-card__preview p {\n\tmargin: 0 0 6px;\n}\n\n.cn-xwiki-card__open-link {\n\tcolor: var(--color-primary-element, #21468B);\n\ttext-decoration: none;\n\tfont-weight: 500;\n}\n\n.cn-xwiki-card__open-link:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-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-xwiki-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-xwiki-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-xwiki-card__chip-breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-card__chip--fallback {\n\topacity: 0.85;\n}\n</style>\n"],"names":["_Fragment","_createVNode","_createElementVNode","_toDisplayString","_openBlock","_createElementBlock","_normalizeClass"],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ import Plus from 'vue-material-design-icons/Plus.vue';
|
|
|
10
10
|
import __sfc_main$1 from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue.js';
|
|
11
11
|
import __sfc_main from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue.js';
|
|
12
12
|
import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
|
|
13
|
+
import { safeHref } from '../../../utils/safeHref.js';
|
|
13
14
|
|
|
14
15
|
const EXCERPT_MAX_CHARS = 140;
|
|
15
16
|
|
|
@@ -214,15 +215,17 @@ var script = {
|
|
|
214
215
|
|
|
215
216
|
/**
|
|
216
217
|
* External XWiki deep-link for the page. Empty string when the
|
|
217
|
-
* provider didn't surface a `url`,
|
|
218
|
-
* (non-anchored) NcListItem rather than a
|
|
218
|
+
* provider didn't surface a `url`, or surfaced an unsafe scheme, so
|
|
219
|
+
* the row renders as a plain (non-anchored) NcListItem rather than a
|
|
220
|
+
* dead link.
|
|
219
221
|
*
|
|
220
222
|
* @param {object} page Provider row.
|
|
221
223
|
*
|
|
222
224
|
* @return {string} Absolute XWiki URL or ''.
|
|
223
225
|
*/
|
|
224
226
|
pageHref(page) {
|
|
225
|
-
|
|
227
|
+
const url = String(page.url ?? '');
|
|
228
|
+
return url && safeHref(url) !== '#' ? url : ''
|
|
226
229
|
},
|
|
227
230
|
|
|
228
231
|
breadcrumbLabel(page) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnXwikiTab.vue2.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t:rel=\"banner.ctaHref ? 'noopener noreferrer' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, so the row renders as a plain\n\t\t * (non-anchored) NcListItem rather than a dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\treturn String(page.url ?? '')\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["CnXwikiPagePicker","CnXwikiPageCreate","t"],"mappings":";;;;;;;;;;;;;AAyLA,MAAM,iBAAgB,GAAI,IAAE;;AAE5B;AACC;AACA;;;;AAIA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,YAAY;;CAElB,UAAU,EAAE;AACX,EAAA,cAAc;EACd,YAAY;AACZ,EAAA,QAAQ;EACR,UAAU;EACV,UAAU;EACV,aAAa;AACb,EAAA,kBAAkB;AAClB,EAAA,oBAAoB;AACpB,EAAA,mBAAmB;AACnB,EAAA,OAAO;EACP,WAAW;AACX,EAAA,SAAS;EACT,IAAI;AACJ,qBAAAA,UAAiB;AACjB,qBAAAC,YAAiB;EACjB;;AAED,CAAA,KAAK,EAAE;AACN;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS;AACjD;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,2BAA2B,GAAG;AAC5F;AACA,EAAA,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,yCAAyC;EAC3F;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,KAAK,EAAE,EAAE;GACT,OAAO,EAAE,KAAK;;AAEd,GAAA,UAAU,EAAE,MAAM;AAClB,GAAA,UAAU,EAAE,KAAK;AACjB,GAAA,UAAU,EAAE,KAAK;AAClB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT,EAAA,MAAM,GAAG;GACR,QAAQ,IAAI,CAAC,UAAU;AACtB,IAAA,KAAK,cAAc;AAClB,KAAA,OAAO;AACN,MAAA,IAAI,EAAE,cAAc;MACpB,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,iCAAiC,CAAC;MAC5D,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,uGAAuG,CAAC;MACpI,QAAQ,EAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,CAAC;AAC1D,MAAA,OAAO,EAAE,IAAI,CAAC,uBAAuB;AACtC,MAAA;IACD,KAAK,MAAM;AACV,KAAA,OAAO;MACN,IAAI,EAAE,MAAM;MACZ,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,6BAA6B,CAAC;AACxD,MAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,6DAA6D,CAAC;AAC1F,MAAA,QAAQ,EAAEA,SAAC,CAAC,eAAe,EAAE,WAAW,CAAC;AACzC,MAAA,OAAO,EAAE,IAAI,CAAC,uBAAuB;AACtC,MAAA;AACD,IAAA,KAAK,UAAU;AACd,KAAA,OAAO;AACN,MAAA,IAAI,EAAE,UAAU;MAChB,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,gCAAgC,CAAC;AAC3D,MAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,iEAAiE,CAAC;AAC9F,MAAA,QAAQ,EAAEA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAC;MACrC,UAAU,EAAE,IAAI,CAAC,UAAU;AAC5B,MAAA;IACD,KAAK,OAAO;AACX,KAAA,OAAO;MACN,IAAI,EAAE,OAAO;MACb,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,CAAC;AACvD,MAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,sDAAsD,CAAC;AACnF,MAAA,QAAQ,EAAEA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAC;MACrC,UAAU,EAAE,IAAI,CAAC,UAAU;AAC5B,MAAA;AACD,IAAA;AACC,KAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAG,EAAA;AACpF,IAAA;GACA;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;KACRA,SAAC;;AAED,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,aAAa,GAAG;AACf,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,MAAM,CAAA;GACtF;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;EAED,MAAM,UAAU,CAAC,OAAO,EAAE;AACzB,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,IAAI;IACH,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE;KAC7D,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;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,EAAA;AAC9C,IAAA;GACA;;EAED,MAAM,YAAY,CAAC,OAAO,EAAE;AAC3B,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE;KACtE,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;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,EAAA;AAChD,IAAA;GACA;;AAED,EAAA,MAAM,UAAU,CAAC,IAAI,EAAE;GACtB,MAAM,GAAI,GAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAA;AAC7B,GAAA,IAAI,CAAC,GAAG,EAAE;IACT,MAAK;AACN,IAAA;AACA,GAAA,IAAI;AACH,IAAA,MAAM,WAAW,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE;AAC7F,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;AACvB,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,EAAA;AAChD,IAAA;GACA;;EAED,OAAO,CAAC,IAAI,EAAE;AACb,GAAA,OAAO,IAAI,CAAC,EAAC,IAAK,IAAI,CAAC,SAAU,IAAG,EAAC;GACrC;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;AACf,GAAA,OAAO,MAAM,CAAC,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,IAAK,IAAG,IAAI,CAAC,SAAQ,IAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;GAC7E;;AAED;;;AAGC;AACA;AACA;AACA;AACA;;AAED,EAAA,QAAQ,CAAC,IAAI,EAAE;GACd,OAAO,MAAM,CAAC,IAAI,CAAC,GAAI,IAAG,EAAE,CAAA;GAC5B;;AAED,EAAA,eAAe,CAAC,IAAI,EAAE;GACrB,MAAM,KAAI,GAAI,IAAI,CAAC,WAAS;GAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAA,KAAM,KAAI,IAAK,KAAK,CAAC,WAAW,CAAC,EAAE;AACzD,IAAA,OAAO,EAAC;AACT,IAAA;;AAEA,GAAA,MAAM,SAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAA;GACnC,IAAI,SAAS,CAAC,WAAW,CAAC,EAAE;;IAE3B,OAAO,MAAM,CAAC,IAAI,CAAC,KAAM,IAAG,EAAE,CAAA;AAC/B,IAAA;;AAEA,GAAA,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAE,KAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAA;GACzE;;AAED;;;;;AAKC;AACA;AACA;;;EAGD,OAAO,CAAC,IAAI,EAAE;GACb,MAAM,GAAE,GAAI,IAAI,CAAC,OAAQ,IAAG,IAAI,CAAC,eAAc,IAAK,IAAI,CAAC,OAAM,IAAK,GAAC;AACrE,GAAA,MAAM,GAAI,GAAE,MAAM,CAAC,GAAG,EAAA;GACtB,IAAI,GAAE,KAAM,EAAE,EAAE;AACf,IAAA,OAAO,EAAC;AACT,IAAA;GACA,IAAI,IAAK,GAAE,GAAE;KACX,OAAO,CAAC,qCAAqC,EAAE,EAAE,CAAA;KACjD,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAA;KAC/C,OAAO,CAAC,UAAU,EAAE,GAAG,CAAA;AACxB,KAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAA;AACpB,KAAC,IAAI,GAAC;AACP,GAAA,IAAI,IAAI,CAAC,SAAS,iBAAiB,EAAE;IACpC,IAAK,GAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,OAAO,EAAC,GAAI,IAAE;AACvD,IAAA;AACA,GAAA,OAAO,IAAG;GACV;;AAED;;;AAGC;AACA;AACA;AACA;;AAED,EAAA,UAAU,CAAC,IAAI,EAAE;GAChB,MAAM,CAAA,GAAI,IAAI,CAAC,QAAS,IAAG,IAAI,CAAC,YAAa,IAAG,IAAI,CAAC,OAAM,IAAK,KAAG;AACnE,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;;;AAGC;;AAEA;;;EAGD,eAAe,CAAC,KAAK,EAAE;AACtB,GAAA,IAAI,KAAI,KAAM,oBAAmB,IAAK,KAAI,KAAM,8BAA8B,EAAE;AAC/E,IAAA,OAAO,cAAa;AACrB,IAAA;GACA,IAAI,KAAM,KAAI,eAAe,EAAE;IAC9B,OAAO,MAAK;AACb,IAAA;AACA,GAAA,OAAO,UAAS;GAChB;;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;AAClB,GAAA,IAAI,CAAC,UAAW,GAAE,OAAK;AACvB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACnF,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;AACjB,KAAA,MAAO,IAAI,QAAQ,CAAC,MAAK,KAAM,GAAG,EAAE;KACnC,IAAI,CAAC,KAAM,GAAE,GAAC;KACd,IAAI,KAAI,GAAI,GAAC;AACb,KAAA,IAAI;MACH,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,MAAA,KAAI,GAAI,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAI,IAAK,EAAE,EAAA;AAC1C,MAAA,CAAE,MAAM;AACP,MAAA,KAAI,GAAI,GAAC;AACV,MAAA;AACA,KAAA,IAAI,CAAC,UAAS,GAAI,IAAI,CAAC,eAAe,CAAC,KAAK,EAAA;KAC3C,MAAK;KACN,IAAI,CAAC,KAAM,GAAE,GAAC;KACd,IAAI,CAAC,aAAa,QAAM;AACzB,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,GAAG,EAAA;IAC7D,IAAI,CAAC,KAAM,GAAE,GAAC;IACd,IAAI,CAAC,aAAa,QAAM;AACzB,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACpB,IAAA;GACA;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnXwikiTab.vue2.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, or surfaced an unsafe scheme, so\n\t\t * the row renders as a plain (non-anchored) NcListItem rather than a\n\t\t * dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\tconst url = String(page.url ?? '')\n\t\t\treturn url && safeHref(url) !== '#' ? url : ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["CnXwikiPagePicker","CnXwikiPageCreate","t"],"mappings":"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"}
|
|
@@ -61,14 +61,13 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
61
61
|
class: "cn-xwiki-tab__banner-cta",
|
|
62
62
|
href: $options.banner.ctaHref || undefined,
|
|
63
63
|
target: $options.banner.ctaHref ? '_blank' : undefined,
|
|
64
|
-
rel: $options.banner.ctaHref ? 'noopener noreferrer' : undefined,
|
|
65
64
|
onClick: $options.banner.ctaHandler
|
|
66
65
|
}, {
|
|
67
66
|
default: withCtx(() => [
|
|
68
67
|
createTextVNode(toDisplayString($options.banner.ctaLabel), 1 /* TEXT */)
|
|
69
68
|
]),
|
|
70
69
|
_: 1 /* STABLE */
|
|
71
|
-
}, 8 /* PROPS */, ["href", "target", "
|
|
70
|
+
}, 8 /* PROPS */, ["href", "target", "onClick"]))
|
|
72
71
|
: createCommentVNode("v-if", true)
|
|
73
72
|
], 2 /* CLASS */))
|
|
74
73
|
: createCommentVNode("v-if", true),
|
|
@@ -151,8 +150,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
151
150
|
class: "cn-xwiki-tab__open",
|
|
152
151
|
closeAfterClick: true,
|
|
153
152
|
href: $options.pageHref(page),
|
|
154
|
-
target: "_blank"
|
|
155
|
-
rel: "noopener noreferrer"
|
|
153
|
+
target: "_blank"
|
|
156
154
|
}, {
|
|
157
155
|
icon: withCtx(() => [
|
|
158
156
|
createVNode(_component_OpenInNew, { size: 20 })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnXwikiTab.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue?vue&type=template&id=4b3fb212&lang.js"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t:rel=\"banner.ctaHref ? 'noopener noreferrer' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, so the row renders as a plain\n\t\t * (non-anchored) NcListItem rather than a dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\treturn String(page.url ?? '')\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createTextVNode","_createVNode","_createBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnXwikiTab.vue3.js","sources":["../../../../../src/integrations/builtin/xwiki/CnXwikiTab.vue?vue&type=template&id=4b3fb212&lang.js"],"sourcesContent":["<!--\n CnXwikiTab — bespoke sidebar tab for the `xwiki` integration.\n\n Replaces the generic CnIntegrationTab for the `xwiki` leaf: renders\n linked XWiki pages as an XWiki-style document list. Each row mirrors\n an XWiki page-index entry — a document icon, the bold page title, a\n space breadcrumb subline (\"Space › Subspace\"), a relative last-\n modified hint (NcDateTime), and a one-line plain-text excerpt of the\n page body. Each row deep-links to the page on the external XWiki host\n (target=_blank rel=noopener).\n\n Talks to the same OpenRegister pluggable-integration sub-resource\n `/api/objects/{register}/{schema}/{objectId}/integrations/xwiki`\n served by `OCA\\OpenRegister\\Service\\Integration\\Providers\\XwikiProvider`\n (storage strategy `external` — routed through `ExternalIntegrationRouter`\n → Integriq `xwiki` source → remote XWiki REST API). Provider\n payload shape per `normalizeRow()`:\n { id, reference, title, space, page, breadcrumb, url, content, ... }\n where `breadcrumb` is an array (the UI joins it with \" › \"), and\n `content` (when present, e.g. on the detail-page surface) is the\n HTML-rendered body — the excerpt strips HTML/macros to inert text and\n is bound via {{ }} interpolation, never injected.\n\n Surface behaviour:\n - Empty state (\"No XWiki pages linked yet\") when the provider\n returns zero rows.\n - **Unconfigured state**: 503 + cause `openconnector-down` or\n `openconnector-source-missing` → prominent \"Configure XWiki\n connection\" CTA pointing at Integriq's source admin page.\n - **Auth-expired state**: 503 + cause `provider-auth` → \"XWiki\n returned 401 — check the Integriq source credentials\" with\n a Reconnect CTA pointing at Integriq.\n - **Upstream-down state**: 503 + cause `upstream-service-down` →\n \"XWiki is currently unavailable\" + Retry CTA.\n - **Generic-error state**: fetch throws or non-OK non-503 → \"Could\n not load XWiki pages\" + Retry CTA.\n - Loading state via NcLoadingIcon for the full-tab spin.\n\n XWiki calls go through Integriq → external HTTP, so latency can\n spike on cold caches. The fetch carries no client-side timeout (the\n router enforces an upstream timeout server-side and surfaces\n upstream-down on expiry), but the loading state is shown for the\n whole round-trip so the sidebar never appears hung.\n\n See `openregister/openspec/changes/integration-xwiki/` for the spec\n delta and ADR-019 (registry mechanism) / ADR-022 (consumption).\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-xwiki-tab\">\n\t\t<!-- Banner state: surface auth + config + upstream failures prominently -->\n\t\t<div\n\t\t\tv-if=\"banner.kind !== 'none'\"\n\t\t\tclass=\"cn-xwiki-tab__banner\"\n\t\t\t:class=\"`cn-xwiki-tab__banner--${banner.kind}`\"\n\t\t\trole=\"alert\">\n\t\t\t<AlertCircleOutline :size=\"18\" class=\"cn-xwiki-tab__banner-icon\" />\n\t\t\t<div class=\"cn-xwiki-tab__banner-body\">\n\t\t\t\t<strong>{{ banner.title }}</strong>\n\t\t\t\t<p>{{ banner.message }}</p>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"banner.ctaLabel\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\tclass=\"cn-xwiki-tab__banner-cta\"\n\t\t\t\t:href=\"banner.ctaHref || undefined\"\n\t\t\t\t:target=\"banner.ctaHref ? '_blank' : undefined\"\n\t\t\t\t@click=\"banner.ctaHandler\">\n\t\t\t\t{{ banner.ctaLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Link / Create actions. Disabled when the source is unconfigured;\n\t\t the banner above already carries the Configure CTA. -->\n\t\t<div v-if=\"banner.kind === 'none' || banner.kind === 'unconfigured'\" class=\"cn-xwiki-tab__actions\">\n\t\t\t<NcButton variant=\"secondary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openPicker\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<LinkVariant :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Link existing page') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton variant=\"primary\" :disabled=\"banner.kind === 'unconfigured'\" @click=\"openCreate\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"18\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Create new page') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<div\n\t\t\tv-else-if=\"pages.length === 0 && banner.kind === 'none'\"\n\t\t\tclass=\"cn-sidebar-tab__empty cn-xwiki-tab__empty\">\n\t\t\t<FileDocumentMultiple :size=\"32\" class=\"cn-xwiki-tab__empty-icon\" />\n\t\t\t<p>{{ emptyLabel }}</p>\n\t\t</div>\n\n\t\t<ul v-else-if=\"pages.length > 0\" class=\"cn-xwiki-tab__list\">\n\t\t\t<NcListItem\n\t\t\t\tv-for=\"page in pages\"\n\t\t\t\t:key=\"pageKey(page)\"\n\t\t\t\tclass=\"cn-xwiki-tab__row\"\n\t\t\t\t:name=\"pageTitle(page)\"\n\t\t\t\t:bold=\"true\"\n\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t:target=\"pageHref(page) ? '_blank' : undefined\"\n\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__row-icon\">\n\t\t\t\t\t\t<FileDocumentOutline :size=\"22\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template #subname>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__subline\">\n\t\t\t\t\t\t<span v-if=\"breadcrumbLabel(page)\" class=\"cn-xwiki-tab__breadcrumb\">\n\t\t\t\t\t\t\t{{ breadcrumbLabel(page) }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcDateTime\n\t\t\t\t\t\t\tv-if=\"modifiedMs(page) !== null\"\n\t\t\t\t\t\t\tclass=\"cn-xwiki-tab__date\"\n\t\t\t\t\t\t\t:timestamp=\"modifiedMs(page)\"\n\t\t\t\t\t\t\trelativeTime=\"short\" />\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\t\t\t\t<template v-if=\"excerpt(page)\" #extra>\n\t\t\t\t\t<span class=\"cn-xwiki-tab__excerpt\">{{ excerpt(page) }}</span>\n\t\t\t\t</template>\n\t\t\t\t<template #actions>\n\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\tv-if=\"pageHref(page)\"\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__open\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t:href=\"pageHref(page)\"\n\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Open in XWiki') }}\n\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\tclass=\"cn-xwiki-tab__unlink\"\n\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t@click=\"unlinkPage(page)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<LinkOff :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Unlink page') }}\n\t\t\t\t\t</NcActionButton>\n\t\t\t\t</template>\n\t\t\t</NcListItem>\n\t\t</ul>\n\n\t\t<CnXwikiPagePicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLinkPick\" />\n\n\t\t<CnXwikiPageCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t:unavailable=\"banner.kind === 'unconfigured'\"\n\t\t\t:openConnectorSourcesUrl=\"openConnectorSourcesUrl\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreatePick\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcButton, NcDateTime, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport FileDocumentMultiple from 'vue-material-design-icons/FileDocumentMultiple.vue'\nimport FileDocumentOutline from 'vue-material-design-icons/FileDocumentOutline.vue'\nimport LinkOff from 'vue-material-design-icons/LinkOff.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport CnXwikiPageCreate from '../../../components/CnXwikiPageCreate/CnXwikiPageCreate.vue'\nimport CnXwikiPagePicker from '../../../components/CnXwikiPagePicker/CnXwikiPagePicker.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst EXCERPT_MAX_CHARS = 140\n\n/**\n * CnXwikiTab — bespoke sidebar list for the `xwiki` external integration.\n *\n * Renders linked XWiki pages as an XWiki-style document index: document\n * icon, bold title, space breadcrumb, relative last-modified, and a\n * one-line plain-text excerpt — plus prominent auth/config banners when\n * the Integriq source is missing/unhealthy.\n */\nexport default {\n\tname: 'CnXwikiTab',\n\n\tcomponents: {\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcButton,\n\t\tNcDateTime,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tAlertCircleOutline,\n\t\tFileDocumentMultiple,\n\t\tFileDocumentOutline,\n\t\tLinkOff,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPlus,\n\t\tCnXwikiPagePicker,\n\t\tCnXwikiPageCreate,\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'xwiki'`). */\n\t\tintegrationId: { type: String, default: 'xwiki' },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No XWiki pages linked yet') },\n\t\t/** URL of Integriq's sources admin page (deep-link target for the configure CTA). */\n\t\topenConnectorSourcesUrl: { type: String, default: '/index.php/apps/openconnector/sources' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpages: [],\n\t\t\tloading: false,\n\t\t\t/** One of: 'none' | 'unconfigured' | 'auth' | 'upstream' | 'error'. */\n\t\t\tbannerKind: 'none',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tbanner() {\n\t\t\tswitch (this.bannerKind) {\n\t\t\t\tcase 'unconfigured':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'unconfigured',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki connection not configured'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Add an XWiki source in Integriq with the upstream URL and credentials so OpenRegister can link pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Configure XWiki connection'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'auth':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'auth',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki authentication failed'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'XWiki returned 401 — check the Integriq source credentials.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Reconnect'),\n\t\t\t\t\t\tctaHref: this.openConnectorSourcesUrl,\n\t\t\t\t\t}\n\t\t\t\tcase 'upstream':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'upstream',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'XWiki is currently unavailable'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'The upstream XWiki host did not respond. Try again in a moment.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tcase 'error':\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'error',\n\t\t\t\t\t\ttitle: t('nextcloud-vue', 'Could not load XWiki pages'),\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Something went wrong while loading the linked pages.'),\n\t\t\t\t\t\tctaLabel: t('nextcloud-vue', 'Retry'),\n\t\t\t\t\t\tctaHandler: this.fetchPages,\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\treturn { kind: 'none', title: '', message: '', ctaLabel: '', ctaHandler: () => {} }\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler(id) {\n\t\t\tif (id) {\n\t\t\t\tthis.fetchPages()\n\t\t\t}\n\t\t} },\n\n\t\tregister() {\n\t\t\tthis.fetchPages()\n\t\t},\n\n\t\tschema() {\n\t\t\tthis.fetchPages()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\t/**\n\t\t * Base for the Tier-2 xwiki endpoints (link/new/destroy).\n\t\t *\n\t\t * @return {string} The endpoint URL.\n\t\t */\n\t\txwikiEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/xwiki`\n\t\t},\n\n\t\topenPicker() {\n\t\t\tthis.pickerOpen = true\n\t\t},\n\n\t\topenCreate() {\n\t\t\tthis.createOpen = true\n\t\t},\n\n\t\tasync onLinkPick(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.xwikiEndpoint()), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] link failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync onCreatePick(payload) {\n\t\t\tthis.createOpen = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/new`), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] create failed', err)\n\t\t\t}\n\t\t},\n\n\t\tasync unlinkPage(page) {\n\t\t\tconst ref = this.pageKey(page)\n\t\t\tif (!ref) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.xwikiEndpoint()}/${encodeURIComponent(ref)}`), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchPages()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] unlink failed', err)\n\t\t\t}\n\t\t},\n\n\t\tpageKey(page) {\n\t\t\treturn page.id ?? page.reference ?? ''\n\t\t},\n\n\t\tpageTitle(page) {\n\t\t\treturn String(page.title ?? page.page ?? page.reference ?? this.pageKey(page))\n\t\t},\n\n\t\t/**\n\t\t * External XWiki deep-link for the page. Empty string when the\n\t\t * provider didn't surface a `url`, or surfaced an unsafe scheme, so\n\t\t * the row renders as a plain (non-anchored) NcListItem rather than a\n\t\t * dead link.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Absolute XWiki URL or ''.\n\t\t */\n\t\tpageHref(page) {\n\t\t\tconst url = String(page.url ?? '')\n\t\t\treturn url && safeHref(url) !== '#' ? url : ''\n\t\t},\n\n\t\tbreadcrumbLabel(page) {\n\t\t\tconst crumb = page.breadcrumb\n\t\t\tif (Array.isArray(crumb) === false || crumb.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// Drop the last element (the title) per AC — show only the ancestor path.\n\t\t\tconst ancestors = crumb.slice(0, -1)\n\t\t\tif (ancestors.length === 0) {\n\t\t\t\t// Single-element breadcrumb (root page) — fall back to the space name.\n\t\t\t\treturn String(page.space ?? '')\n\t\t\t}\n\t\t\t// XWiki renders space paths with a \"›\" chevron separator.\n\t\t\treturn ancestors.map((c) => String(c)).filter((s) => s !== '').join(' › ')\n\t\t},\n\n\t\t/**\n\t\t * One-line plain-text excerpt of the page body for the detail\n\t\t * surface. Strips `<script>`/`<style>` bodies, then all tags,\n\t\t * collapses whitespace and truncates — XWiki macros stay inert\n\t\t * text because the result is bound via {{ }} interpolation.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {string} Safe single-line excerpt (≤ EXCERPT_MAX_CHARS).\n\t\t */\n\t\texcerpt(page) {\n\t\t\tconst raw = page.content ?? page.renderedContent ?? page.excerpt ?? ''\n\t\t\tconst str = String(raw)\n\t\t\tif (str === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet text = str\n\t\t\t\t.replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n\t\t\t\t.replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n\t\t\t\t.replace(/<[^>]+>/g, ' ')\n\t\t\t\t.replace(/\\s+/g, ' ')\n\t\t\t\t.trim()\n\t\t\tif (text.length > EXCERPT_MAX_CHARS) {\n\t\t\t\ttext = text.slice(0, EXCERPT_MAX_CHARS).trimEnd() + '…'\n\t\t\t}\n\t\t\treturn text\n\t\t},\n\n\t\t/**\n\t\t * Last-modified timestamp in milliseconds for the page, suitable\n\t\t * for `NcDateTime`. Returns null when absent or unparseable.\n\t\t *\n\t\t * @param {object} page Provider row.\n\t\t *\n\t\t * @return {number|null} Epoch milliseconds or null.\n\t\t */\n\t\tmodifiedMs(page) {\n\t\t\tconst v = page.modified ?? page.lastModified ?? page.updated ?? null\n\t\t\tif (v === null || v === undefined || v === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof v === 'number') {\n\t\t\t\treturn v < 1e12 ? v * 1000 : v\n\t\t\t}\n\t\t\tconst parsed = Date.parse(String(v))\n\t\t\treturn Number.isNaN(parsed) === true ? null : parsed\n\t\t},\n\n\t\t/**\n\t\t * Map a 503 cause from the controller (`details.cause` per AD-23) to\n\t\t * the matching banner kind. Unknown causes fall through to 'upstream'.\n\t\t *\n\t\t * @param {string} cause One of `openconnector-down` / `openconnector-source-missing` / `provider-auth` / `upstream-service-down`.\n\t\t *\n\t\t * @return {string} Banner kind.\n\t\t */\n\t\tbannerFromCause(cause) {\n\t\t\tif (cause === 'openconnector-down' || cause === 'openconnector-source-missing') {\n\t\t\t\treturn 'unconfigured'\n\t\t\t}\n\t\t\tif (cause === 'provider-auth') {\n\t\t\t\treturn 'auth'\n\t\t\t}\n\t\t\treturn 'upstream'\n\t\t},\n\n\t\tasync fetchPages() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.bannerKind = 'none'\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst rows = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t\tthis.pages = rows\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tlet cause = ''\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst body = await response.json()\n\t\t\t\t\t\tcause = String(body?.details?.cause ?? '')\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcause = ''\n\t\t\t\t\t}\n\t\t\t\t\tthis.bannerKind = this.bannerFromCause(cause)\n\t\t\t\t} else {\n\t\t\t\t\tthis.pages = []\n\t\t\t\t\tthis.bannerKind = 'error'\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnXwikiTab] failed to fetch XWiki pages', err)\n\t\t\t\tthis.pages = []\n\t\t\t\tthis.bannerKind = 'error'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-xwiki-tab__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-bottom: 10px;\n\tflex-wrap: wrap;\n}\n\n.cn-xwiki-tab__unlink {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__banner {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 10px 12px;\n\tmargin-bottom: 12px;\n\tborder-radius: var(--border-radius);\n\tfont-size: 0.9em;\n}\n\n.cn-xwiki-tab__banner--unconfigured {\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\tborder-left: 3px solid var(--color-primary-element, #21468B);\n}\n\n.cn-xwiki-tab__banner--auth,\n.cn-xwiki-tab__banner--error {\n\tbackground: var(--color-error, #e9322d);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner--upstream {\n\tbackground: var(--color-warning, #e9a40f);\n\tcolor: var(--color-main-background);\n}\n\n.cn-xwiki-tab__banner-icon {\n\tflex-shrink: 0;\n\tmargin-top: 2px;\n}\n\n.cn-xwiki-tab__banner-body {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-xwiki-tab__banner-body p {\n\tmargin: 0;\n}\n\n.cn-xwiki-tab__banner-cta {\n\tflex-shrink: 0;\n}\n\n.cn-xwiki-tab__empty {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 16px 8px;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n}\n\n.cn-xwiki-tab__empty-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-xwiki-tab__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* XWiki-style document tile: a tinted square holding the page glyph. */\n.cn-xwiki-tab__row-icon {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--cn-xwiki-accent-soft, rgba(60, 162, 47, 0.12));\n\tcolor: var(--cn-xwiki-accent, #3CA22F);\n}\n\n.cn-xwiki-tab__subline {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\tmin-width: 0;\n}\n\n.cn-xwiki-tab__breadcrumb {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__date {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\twhite-space: nowrap;\n}\n\n.cn-xwiki-tab__excerpt {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tmax-width: 100%;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createBlock","_createTextVNode","_createVNode","_openBlock"],"mappings":"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"}
|
package/dist/esm/l10n/en.json.js
CHANGED
|
@@ -351,6 +351,7 @@ var translations = {
|
|
|
351
351
|
"No widgets configured": "No widgets configured",
|
|
352
352
|
"Not configured": "Not configured",
|
|
353
353
|
"Not set": "Not set",
|
|
354
|
+
"Not run": "Not run",
|
|
354
355
|
Notes: "Notes",
|
|
355
356
|
"Number": "Number",
|
|
356
357
|
"Number configuration": "Number configuration",
|
|
@@ -368,6 +369,7 @@ var translations = {
|
|
|
368
369
|
"One of": "One of",
|
|
369
370
|
Open: "Open",
|
|
370
371
|
"Open access:": "Open access:",
|
|
372
|
+
"Open row": "Open row",
|
|
371
373
|
Operator: "Operator",
|
|
372
374
|
Order: "Order",
|
|
373
375
|
"Owner:": "Owner:",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/esm/l10n/nl.json.js
CHANGED
|
@@ -351,6 +351,7 @@ var translations = {
|
|
|
351
351
|
"No widgets configured": "Geen widgets geconfigureerd",
|
|
352
352
|
"Not configured": "Niet geconfigureerd",
|
|
353
353
|
"Not set": "Niet ingesteld",
|
|
354
|
+
"Not run": "Niet uitgevoerd",
|
|
354
355
|
Notes: "Notities",
|
|
355
356
|
"Number": "Getal",
|
|
356
357
|
"Number configuration": "Nummerconfiguratie",
|
|
@@ -368,6 +369,7 @@ var translations = {
|
|
|
368
369
|
"One of": "Één van",
|
|
369
370
|
Open: "Openen",
|
|
370
371
|
"Open access:": "Openbare toegang:",
|
|
372
|
+
"Open row": "Rij openen",
|
|
371
373
|
Operator: "Operator",
|
|
372
374
|
Order: "Volgorde",
|
|
373
375
|
"Owner:": "Eigenaar:",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|