@conduction/nextcloud-vue 2.56.0-beta.4 → 2.56.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +1 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +1 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +71 -7
- package/dist/esm/utils/actionLink.js +5 -0
- package/dist/esm/utils/actionLink.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +16 -1
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/linkNavigation.js +6 -3
- package/dist/esm/utils/linkNavigation.js.map +1 -1
- package/dist/esm/utils/rowAuxClick.js +30 -5
- package/dist/esm/utils/rowAuxClick.js.map +1 -1
- package/dist/esm/utils/safeHref.js +18 -3
- package/dist/esm/utils/safeHref.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +809 -383
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +71 -7
- package/l10n/en.json +1 -0
- package/l10n/nl.json +1 -0
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
- package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
- package/src/components/CnBoardView/CnBoardView.vue +13 -5
- package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
- package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
- package/src/components/CnDataTable/CnDataTable.md +1 -1
- package/src/components/CnDataTable/CnDataTable.vue +131 -17
- package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
- package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
- package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
- package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
- package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
- package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
- package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
- package/src/components/CnObjectList/CnObjectList.vue +19 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
- package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
- package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
- package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
- package/src/components/CnRowActions/CnRowActions.vue +7 -2
- package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
- package/src/components/CnTabs/CnTabs.vue +7 -3
- package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
- package/src/css/table.css +26 -0
- package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
- package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
- package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
- package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
- package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
- package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
- package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
- package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
- package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
- package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
- package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
- package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
- package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
- package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
- package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
- package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
- package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
- package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
- package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
- package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
- package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
- package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
- package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
- package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
- package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
- package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
- package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
- package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
- package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
- package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
- package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
- package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
- package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
- package/src/utils/actionLink.js +5 -0
- package/src/utils/actionsDispatcher.js +15 -0
- package/src/utils/linkNavigation.js +6 -3
- package/src/utils/rowAuxClick.js +29 -4
- package/src/utils/safeHref.js +18 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"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":"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"}
|
|
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
|
@@ -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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nl.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -364,6 +364,32 @@
|
|
|
364
364
|
background-color: var(--color-primary-light);
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
/* A row with a route is a real link (see CnDataTable's row link): the anchor
|
|
368
|
+
in its first cell is stretched over the whole row. The row's own controls
|
|
369
|
+
sit above it so they stay usable; keep the list in step with NESTED_CONTROL
|
|
370
|
+
in utils/rowAuxClick.js. */
|
|
371
|
+
.cn-table-row--linked {
|
|
372
|
+
position: relative;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.cn-table-row__link {
|
|
376
|
+
position: absolute;
|
|
377
|
+
inset: 0;
|
|
378
|
+
cursor: pointer;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.cn-table-row__link:focus-visible {
|
|
382
|
+
outline: 2px solid var(--color-main-text);
|
|
383
|
+
outline-offset: -2px;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.cn-table-row--linked .cn-table-col--checkbox,
|
|
387
|
+
.cn-table-row--linked .cn-table-col--actions,
|
|
388
|
+
.cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
|
|
389
|
+
position: relative;
|
|
390
|
+
z-index: 1;
|
|
391
|
+
}
|
|
392
|
+
|
|
367
393
|
/* Column Types */
|
|
368
394
|
.cn-table-col--checkbox {
|
|
369
395
|
width: 50px;
|
|
@@ -5995,6 +6021,32 @@ svg.leaflet-image-layer.leaflet-interactive path {
|
|
|
5995
6021
|
background-color: var(--color-primary-light);
|
|
5996
6022
|
}
|
|
5997
6023
|
|
|
6024
|
+
/* A row with a route is a real link (see CnDataTable's row link): the anchor
|
|
6025
|
+
in its first cell is stretched over the whole row. The row's own controls
|
|
6026
|
+
sit above it so they stay usable; keep the list in step with NESTED_CONTROL
|
|
6027
|
+
in utils/rowAuxClick.js. */
|
|
6028
|
+
.cn-table-row--linked {
|
|
6029
|
+
position: relative;
|
|
6030
|
+
}
|
|
6031
|
+
|
|
6032
|
+
.cn-table-row__link {
|
|
6033
|
+
position: absolute;
|
|
6034
|
+
inset: 0;
|
|
6035
|
+
cursor: pointer;
|
|
6036
|
+
}
|
|
6037
|
+
|
|
6038
|
+
.cn-table-row__link:focus-visible {
|
|
6039
|
+
outline: 2px solid var(--color-main-text);
|
|
6040
|
+
outline-offset: -2px;
|
|
6041
|
+
}
|
|
6042
|
+
|
|
6043
|
+
.cn-table-row--linked .cn-table-col--checkbox,
|
|
6044
|
+
.cn-table-row--linked .cn-table-col--actions,
|
|
6045
|
+
.cn-table-row--linked td :is(a, button, input, select, textarea, label, summary, [role='button'], [role='checkbox'], [role='link'], [contenteditable='true']):not(.cn-table-row__link) {
|
|
6046
|
+
position: relative;
|
|
6047
|
+
z-index: 1;
|
|
6048
|
+
}
|
|
6049
|
+
|
|
5998
6050
|
/* Column Types */
|
|
5999
6051
|
.cn-table-col--checkbox {
|
|
6000
6052
|
width: 50px;
|
|
@@ -9701,14 +9753,18 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
|
|
|
9701
9753
|
background: none;
|
|
9702
9754
|
border: none;
|
|
9703
9755
|
padding: 6px 0;
|
|
9704
|
-
cursor: pointer;
|
|
9705
9756
|
text-align: left;
|
|
9706
9757
|
color: inherit;
|
|
9707
9758
|
font: inherit;
|
|
9708
9759
|
text-decoration: none;
|
|
9709
9760
|
box-sizing: border-box;
|
|
9710
9761
|
}
|
|
9711
|
-
|
|
9762
|
+
|
|
9763
|
+
/* Only a row with Mail ids is a link; the rest must not look clickable. */
|
|
9764
|
+
a.cn-email-card__open[data-v-fda51a6a] {
|
|
9765
|
+
cursor: pointer;
|
|
9766
|
+
}
|
|
9767
|
+
a.cn-email-card__open:hover .cn-email-card__subject[data-v-fda51a6a] {
|
|
9712
9768
|
color: var(--color-primary-element);
|
|
9713
9769
|
}
|
|
9714
9770
|
.cn-email-card__avatar[data-v-fda51a6a] {
|
|
@@ -9949,10 +10005,14 @@ a.cn-deck-tab__card-title[data-v-3501a864]:hover {
|
|
|
9949
10005
|
border-radius: var(--border-radius-large, 8px);
|
|
9950
10006
|
color: inherit;
|
|
9951
10007
|
text-decoration: none;
|
|
9952
|
-
cursor: pointer;
|
|
9953
10008
|
position: relative;
|
|
9954
10009
|
}
|
|
9955
|
-
|
|
10010
|
+
|
|
10011
|
+
/* Only a row with Mail ids is a link; the rest must not look clickable. */
|
|
10012
|
+
a.cn-email-tab__row[data-v-0bcebbac] {
|
|
10013
|
+
cursor: pointer;
|
|
10014
|
+
}
|
|
10015
|
+
a.cn-email-tab__row[data-v-0bcebbac]:hover {
|
|
9956
10016
|
background-color: var(--color-background-hover);
|
|
9957
10017
|
}
|
|
9958
10018
|
.cn-email-tab__unread-dot[data-v-0bcebbac] {
|
|
@@ -17677,7 +17737,11 @@ to { background-position: -200% 0;
|
|
|
17677
17737
|
}
|
|
17678
17738
|
|
|
17679
17739
|
/* A fade over the clipped edge, only on the side that hides tabs. Stops a
|
|
17680
|
-
pixel above the bar's rule so the rule keeps its full colour.
|
|
17740
|
+
pixel above the bar's rule so the rule keeps its full colour.
|
|
17741
|
+
|
|
17742
|
+
z-index 2 so the fades outrank a lifted tab: CnTabsWidget puts the open tab
|
|
17743
|
+
at 1, and a tie goes to DOM order, which would draw that tab over the start
|
|
17744
|
+
fade (it precedes the tabs) while the end fade still covered it. */
|
|
17681
17745
|
.cn-tabs__strip[data-v-5c1a056f]::before,
|
|
17682
17746
|
.cn-tabs__strip[data-v-5c1a056f]::after {
|
|
17683
17747
|
content: '';
|
|
@@ -17686,7 +17750,7 @@ to { background-position: -200% 0;
|
|
|
17686
17750
|
pointer-events: none;
|
|
17687
17751
|
position: absolute;
|
|
17688
17752
|
width: 56px;
|
|
17689
|
-
z-index:
|
|
17753
|
+
z-index: 2;
|
|
17690
17754
|
}
|
|
17691
17755
|
.cn-tabs__strip[data-v-5c1a056f]::before {
|
|
17692
17756
|
background: linear-gradient(to right, var(--color-main-background) 30%, transparent);
|
|
@@ -17720,7 +17784,7 @@ to { background-position: -200% 0;
|
|
|
17720
17784
|
padding: 0;
|
|
17721
17785
|
position: absolute;
|
|
17722
17786
|
width: 28px;
|
|
17723
|
-
z-index:
|
|
17787
|
+
z-index: 3;
|
|
17724
17788
|
}
|
|
17725
17789
|
|
|
17726
17790
|
/* Nextcloud's `button:hover` rule would otherwise fill the chevron. */
|
|
@@ -63,6 +63,11 @@ function resolveItemActionLink(action, item, router) {
|
|
|
63
63
|
* on an in-app link that opens in place goes through the router; a URL, a
|
|
64
64
|
* new-tab target or a modified click is left to the browser.
|
|
65
65
|
*
|
|
66
|
+
* Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and
|
|
67
|
+
* bars using it must still emit their own events on click, and without an
|
|
68
|
+
* installed router `NcButton :to` falls back to a button that goes nowhere,
|
|
69
|
+
* while an `<a href>` still navigates.
|
|
70
|
+
*
|
|
66
71
|
* @param {MouseEvent} event The click event.
|
|
67
72
|
* @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.
|
|
68
73
|
* @param {object} [router] The app's router.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actionLink.js","sources":["../../../src/utils/actionLink.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n *\n * actionLink — render a menu/bar action that only navigates as a real link.\n *\n * An action descriptor may carry `href` (a URL) or `to` (a vue-router\n * location), each either a value or a function of the item the menu acts on.\n * The rendering component turns it into an `<a href>`; a plain click on an\n * in-app `to` is routed through the router, anything else is the browser's.\n *\n * @module utils/actionLink\n */\n\nimport { followLinkClick } from './linkNavigation.js'\n\n/**\n * The href of an in-app router location. A string is a route PATH and goes\n * through the router as well, so a hash-history app gets its `#`.\n *\n * @param {string|object|null|undefined} to A route path or vue-router location.\n * @param {object} [router] The app's router.\n * @return {string} The href, or '' when there is no router or it cannot resolve.\n */\nexport function routeHref(to, router) {\n\tif (!to || !router || typeof router.resolve !== 'function') {\n\t\treturn ''\n\t}\n\t// A path string, unlike resolveHref's finished URL; resolved as a string so its query survives.\n\ttry {\n\t\treturn router.resolve(to).href || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * The link an action descriptor renders as for one item, or null when it\n * renders as a button: no `href` / `to`, or a `to` the router cannot resolve.\n *\n * @param {object} action The action descriptor (`href`, `to`, `linkTarget`).\n * @param {unknown} item The row / target item a function-valued field is called with.\n * @param {object} [router] The app's router.\n * @return {{href: string, to: (string|object|null), target: (string|undefined)}|null} The link, or null.\n */\nexport function resolveItemActionLink(action, item, router) {\n\tif (!action) {\n\t\treturn null\n\t}\n\tconst target = action.linkTarget || undefined\n\tconst href = typeof action.href === 'function' ? action.href(item) : action.href\n\tif (typeof href === 'string' && href.length > 0) {\n\t\treturn { href, to: null, target }\n\t}\n\tconst to = typeof action.to === 'function' ? action.to(item) : action.to\n\tconst resolved = routeHref(to, router)\n\treturn resolved ? { href: resolved, to, target } : null\n}\n\n/**\n * Click handler for a link from {@link resolveItemActionLink}: a plain click\n * on an in-app link that opens in place goes through the router; a URL, a\n * new-tab target or a modified click is left to the browser.\n *\n * @param {MouseEvent} event The click event.\n * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.\n * @param {object} [router] The app's router.\n * @return {boolean} True when the router navigated.\n */\nexport function followItemActionLink(event, link, router) {\n\tif (!link || !link.to || (link.target && link.target !== '_self')) {\n\t\treturn false\n\t}\n\treturn followLinkClick(event, link.to, router)\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE;AACtC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC7D,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA,CAAC,IAAI;AACL,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,EAAE,CAAC,MAAM;AACT,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;AAC5D,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,IAAI,UAAS;AAC9C,CAAC,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAI;AACjF,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAClD,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AACnC,EAAE;AACF,CAAC,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAE;AACzE,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAC;AACvC,CAAC,OAAO,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAC1D,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE;AACpE,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;AAC/C;;;;"}
|
|
1
|
+
{"version":3,"file":"actionLink.js","sources":["../../../src/utils/actionLink.js"],"sourcesContent":["/**\n * SPDX-License-Identifier: EUPL-1.2\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n *\n * actionLink — render a menu/bar action that only navigates as a real link.\n *\n * An action descriptor may carry `href` (a URL) or `to` (a vue-router\n * location), each either a value or a function of the item the menu acts on.\n * The rendering component turns it into an `<a href>`; a plain click on an\n * in-app `to` is routed through the router, anything else is the browser's.\n *\n * @module utils/actionLink\n */\n\nimport { followLinkClick } from './linkNavigation.js'\n\n/**\n * The href of an in-app router location. A string is a route PATH and goes\n * through the router as well, so a hash-history app gets its `#`.\n *\n * @param {string|object|null|undefined} to A route path or vue-router location.\n * @param {object} [router] The app's router.\n * @return {string} The href, or '' when there is no router or it cannot resolve.\n */\nexport function routeHref(to, router) {\n\tif (!to || !router || typeof router.resolve !== 'function') {\n\t\treturn ''\n\t}\n\t// A path string, unlike resolveHref's finished URL; resolved as a string so its query survives.\n\ttry {\n\t\treturn router.resolve(to).href || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * The link an action descriptor renders as for one item, or null when it\n * renders as a button: no `href` / `to`, or a `to` the router cannot resolve.\n *\n * @param {object} action The action descriptor (`href`, `to`, `linkTarget`).\n * @param {unknown} item The row / target item a function-valued field is called with.\n * @param {object} [router] The app's router.\n * @return {{href: string, to: (string|object|null), target: (string|undefined)}|null} The link, or null.\n */\nexport function resolveItemActionLink(action, item, router) {\n\tif (!action) {\n\t\treturn null\n\t}\n\tconst target = action.linkTarget || undefined\n\tconst href = typeof action.href === 'function' ? action.href(item) : action.href\n\tif (typeof href === 'string' && href.length > 0) {\n\t\treturn { href, to: null, target }\n\t}\n\tconst to = typeof action.to === 'function' ? action.to(item) : action.to\n\tconst resolved = routeHref(to, router)\n\treturn resolved ? { href: resolved, to, target } : null\n}\n\n/**\n * Click handler for a link from {@link resolveItemActionLink}: a plain click\n * on an in-app link that opens in place goes through the router; a URL, a\n * new-tab target or a modified click is left to the browser.\n *\n * Hand-rolled rather than `NcActionRouter` / `NcButton :to`: the menus and\n * bars using it must still emit their own events on click, and without an\n * installed router `NcButton :to` falls back to a button that goes nowhere,\n * while an `<a href>` still navigates.\n *\n * @param {MouseEvent} event The click event.\n * @param {{to: (string|object|null), target: (string|undefined)}} link The resolved link.\n * @param {object} [router] The app's router.\n * @return {boolean} True when the router navigated.\n */\nexport function followItemActionLink(event, link, router) {\n\tif (!link || !link.to || (link.target && link.target !== '_self')) {\n\t\treturn false\n\t}\n\treturn followLinkClick(event, link.to, router)\n}\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE;AACtC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE;AAC7D,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA,CAAC,IAAI;AACL,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,EAAE,CAAC,MAAM;AACT,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;AAC5D,CAAC,IAAI,CAAC,MAAM,EAAE;AACd,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,IAAI,UAAS;AAC9C,CAAC,MAAM,IAAI,GAAG,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAI;AACjF,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAClD,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;AACnC,EAAE;AACF,CAAC,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,GAAE;AACzE,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAC;AACvC,CAAC,OAAO,QAAQ,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI;AACxD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;AAC1D,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE;AACpE,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,OAAO,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC;AAC/C;;;;"}
|
|
@@ -335,6 +335,21 @@ function interpolateActionTarget(target, ctx) {
|
|
|
335
335
|
return interpolateActionString(target || '', ctx || {})
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
// The tokens interpolateActionString resolves; a bare `@` or `{` is not one.
|
|
339
|
+
const ACTION_TARGET_TOKEN = /@(?:objectId|object\.|page\.|workspace\.|config\.|range\.)|\{objectId\}/;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Whether an action target carries a token that interpolation would resolve,
|
|
343
|
+
* so it can only be known once the page context is. A `mailto:` address or a
|
|
344
|
+
* URL with an `@handle` in it has none.
|
|
345
|
+
*
|
|
346
|
+
* @param {string} target The action's raw `target`.
|
|
347
|
+
* @return {boolean}
|
|
348
|
+
*/
|
|
349
|
+
function hasActionTargetTokens(target) {
|
|
350
|
+
return typeof target === 'string' && ACTION_TARGET_TOKEN.test(target)
|
|
351
|
+
}
|
|
352
|
+
|
|
338
353
|
/**
|
|
339
354
|
* The link an action renders as when its only job is to navigate to a target
|
|
340
355
|
* known at render time: `navigate` (token-interpolated like the dispatcher)
|
|
@@ -987,5 +1002,5 @@ function dispatchAction(action, context = {}) {
|
|
|
987
1002
|
}
|
|
988
1003
|
}
|
|
989
1004
|
|
|
990
|
-
export { actionLink, buildOnSuccessRoute, dispatchAction, interpolateActionTarget, isExternalActionTarget, postRunNode, resolveCreateOverrideHandler, resolveObjectOpType, resolveRegisteredHandler, savedObjectId };
|
|
1005
|
+
export { actionLink, buildOnSuccessRoute, dispatchAction, hasActionTargetTokens, interpolateActionTarget, isExternalActionTarget, postRunNode, resolveCreateOverrideHandler, resolveObjectOpType, resolveRegisteredHandler, savedObjectId };
|
|
991
1006
|
//# sourceMappingURL=actionsDispatcher.js.map
|