@conduction/nextcloud-vue 2.56.0-beta.3 → 2.56.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +12 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +1 -2
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +0 -3
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -2
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +21 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +12 -5
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +2 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +9 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js +6 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnContextMenu/CnContextMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +116 -15
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +27 -14
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js +13 -6
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue2.js.map +1 -1
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js +2 -0
- package/dist/esm/components/CnDateAxisView/CnDateAxisView.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js +1 -2
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +3 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +17 -17
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js +4 -21
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesWidget/CnFilesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +0 -13
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +8 -8
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js +3 -2
- package/dist/esm/components/CnFlowsPage/CnFlowsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +67 -13
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +15 -8
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/dist/esm/components/CnIndexPage/manifestActionDispatch.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue2.js.map +1 -1
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js +1 -2
- package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue3.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js +0 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js +2 -17
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnLinkButtonWidget/CnLinkButtonWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js +35 -11
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js +3 -2
- package/dist/esm/components/CnLogsPage/CnLogsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +23 -5
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js +19 -3
- package/dist/esm/components/CnObjectList/CnObjectList.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectList/CnObjectList.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +45 -15
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +24 -6
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +0 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js +4 -2
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js +7 -2
- package/dist/esm/components/CnRowActions/CnRowActions.vue2.js.map +1 -1
- package/dist/esm/components/CnRowActions/CnRowActions.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +49 -5
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js +5 -3
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +3 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +1 -0
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js +6 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js +68 -53
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js +17 -0
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js +21 -19
- package/dist/esm/integrations/builtin/bookmarks/CnBookmarksTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/collectives/CnCollectivesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/email/CnEmailTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/flow/CnFlowTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/forms/CnFormsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/maps/CnMapsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/openproject/CnOpenprojectTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/polls/CnPollsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js +3 -6
- package/dist/esm/integrations/builtin/shares/CnSharesTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js +3 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/talk/CnTalkTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js +1 -2
- package/dist/esm/integrations/builtin/time-tracker/CnTimeTrackerTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js +4 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js +6 -3
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js +2 -4
- package/dist/esm/integrations/builtin/xwiki/CnXwikiTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +2 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +78 -7
- package/dist/esm/utils/actionLink.js +5 -0
- package/dist/esm/utils/actionLink.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +16 -1
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/linkNavigation.js +6 -3
- package/dist/esm/utils/linkNavigation.js.map +1 -1
- package/dist/esm/utils/rowAuxClick.js +30 -5
- package/dist/esm/utils/rowAuxClick.js.map +1 -1
- package/dist/esm/utils/safeHref.js +18 -3
- package/dist/esm/utils/safeHref.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +885 -393
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +78 -7
- package/l10n/en.json +2 -0
- package/l10n/nl.json +2 -0
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.vue +14 -5
- package/src/components/CnActionsMenu/CnActionsMenu.vue +0 -3
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -2
- package/src/components/CnAppRoot/CnAppRoot.vue +31 -2
- package/src/components/CnBoardView/CnBoardView.vue +13 -5
- package/src/components/CnCardGrid/CnCardGrid.vue +9 -1
- package/src/components/CnContextMenu/CnContextMenu.vue +6 -1
- package/src/components/CnDataTable/CnDataTable.md +1 -1
- package/src/components/CnDataTable/CnDataTable.vue +131 -17
- package/src/components/CnDateAxisView/CnDateAxisView.vue +15 -6
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +29 -1
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -2
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +5 -3
- package/src/components/CnFilesWidget/CnFilesWidget.vue +4 -21
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +8 -21
- package/src/components/CnFlowsPage/CnFlowsPage.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +75 -14
- package/src/components/CnIndexPage/manifestActionDispatch.js +31 -11
- package/src/components/CnIntegrationWidget/CnIntegrationWidgetEmpty.vue +1 -2
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +0 -1
- package/src/components/CnLinkButtonWidget/CnLinkButtonWidget.vue +2 -17
- package/src/components/CnLogsPage/CnLogsPage.vue +37 -12
- package/src/components/CnObjectCard/CnObjectCard.vue +24 -6
- package/src/components/CnObjectList/CnObjectList.vue +19 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +47 -15
- package/src/components/CnObjectRow/CnObjectRow.vue +25 -7
- package/src/components/CnObjectSidebar/CnFilesTab.vue +0 -1
- package/src/components/CnPageRenderer/CnPageRenderer.vue +2 -0
- package/src/components/CnRowActions/CnRowActions.vue +7 -2
- package/src/components/CnSetupWizard/CnSetupWizard.vue +57 -6
- package/src/components/CnSpendAnalyticsWidget/CnSpendAnalyticsWidget.vue +5 -3
- package/src/components/CnTabs/CnTabs.vue +7 -3
- package/src/components/CnTasksWidget/CnTasksWidget.vue +4 -1
- package/src/css/table.css +26 -0
- package/src/integrations/builtin/analytics/CnAnalyticsCard.vue +3 -2
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +5 -6
- package/src/integrations/builtin/bookmarks/CnBookmarksCard.vue +12 -1
- package/src/integrations/builtin/bookmarks/CnBookmarksTab.vue +23 -6
- package/src/integrations/builtin/bookmarks/__tests__/CnBookmarksTab.spec.js +7 -2
- package/src/integrations/builtin/collectives/CnCollectivesCard.vue +3 -2
- package/src/integrations/builtin/collectives/CnCollectivesTab.vue +5 -6
- package/src/integrations/builtin/cospend/CnCospendCard.vue +2 -2
- package/src/integrations/builtin/cospend/CnCospendTab.vue +3 -4
- package/src/integrations/builtin/deck/CnDeckCard.vue +2 -2
- package/src/integrations/builtin/deck/CnDeckTab.vue +3 -4
- package/src/integrations/builtin/email/CnEmailCard.vue +6 -2
- package/src/integrations/builtin/email/CnEmailTab.vue +7 -4
- package/src/integrations/builtin/flow/CnFlowCard.vue +2 -2
- package/src/integrations/builtin/flow/CnFlowTab.vue +3 -4
- package/src/integrations/builtin/forms/CnFormsCard.vue +3 -2
- package/src/integrations/builtin/forms/CnFormsTab.vue +5 -6
- package/src/integrations/builtin/maps/CnMapsCard.vue +3 -2
- package/src/integrations/builtin/maps/CnMapsTab.vue +5 -6
- package/src/integrations/builtin/maps/__tests__/CnMapsTab.spec.js +9 -0
- package/src/integrations/builtin/openproject/CnOpenprojectCard.vue +3 -2
- package/src/integrations/builtin/openproject/CnOpenprojectTab.vue +5 -6
- package/src/integrations/builtin/photos/CnPhotosCard.vue +2 -2
- package/src/integrations/builtin/photos/CnPhotosTab.vue +3 -4
- package/src/integrations/builtin/polls/CnPollsCard.vue +2 -2
- package/src/integrations/builtin/polls/CnPollsTab.vue +3 -4
- package/src/integrations/builtin/shares/CnSharesTab.vue +3 -6
- package/src/integrations/builtin/talk/CnTalkCard.vue +3 -2
- package/src/integrations/builtin/talk/CnTalkTab.vue +5 -6
- package/src/integrations/builtin/time-tracker/CnTimeTrackerCard.vue +2 -2
- package/src/integrations/builtin/time-tracker/CnTimeTrackerTab.vue +3 -4
- package/src/integrations/builtin/xwiki/CnXwikiCard.vue +4 -2
- package/src/integrations/builtin/xwiki/CnXwikiTab.vue +7 -7
- package/src/integrations/builtin/xwiki/__tests__/CnXwikiTab.spec.js +9 -0
- package/src/schemas/app-manifest-v2.schema.json +2 -1
- package/src/utils/actionLink.js +5 -0
- package/src/utils/actionsDispatcher.js +15 -0
- package/src/utils/linkNavigation.js +6 -3
- package/src/utils/rowAuxClick.js +29 -4
- package/src/utils/safeHref.js +18 -3
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectRow.vue3.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue?vue&type=template&id=25c9f9b1&lang.js"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onPointerDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick } from '../../utils/rowAuxClick.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked or middle-clicked (navigation). Payload: `(object, event)` — the row's object and the native click/auxclick event, for opening it in a new tab on a ctrl/cmd/shift or middle click.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click: emits `click` like a click on a\n\t\t * non-selectable row.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createVNode","_openBlock","_renderSlot","_createBlock","_createElementVNode","_toDisplayString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnObjectRow.vue3.js","sources":["../../../../src/components/CnObjectRow/CnObjectRow.vue?vue&type=template&id=25c9f9b1&lang.js"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-row\"\n\t\t:class=\"{ 'cn-object-row--selected': selected }\"\n\t\t@mousedown=\"onRowMouseDown\"\n\t\t@click=\"onRowClick($event)\"\n\t\t@auxclick=\"onRowAuxClick($event)\">\n\t\t<!-- Selection checkbox -->\n\t\t<div v-if=\"selectable\"\n\t\t\tclass=\"cn-object-row__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Leading icon / image — omitted entirely when nothing is configured\n\t\t (no image, no icon name, no slot). -->\n\t\t<span v-if=\"hasLeadingIcon\" class=\"cn-object-row__icon\">\n\t\t\t<!-- @slot icon Replace the leading icon/image. -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"icon\" :object=\"object\">\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\talt=\"\"\n\t\t\t\t\twidth=\"24\"\n\t\t\t\t\theight=\"24\"\n\t\t\t\t\tclass=\"cn-object-row__image\">\n\t\t\t\t<CnIcon v-else-if=\"iconName\" :name=\"iconName\" :size=\"24\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Main: title + subtitle -->\n\t\t<span class=\"cn-object-row__main\">\n\t\t\t<span class=\"cn-object-row__title\">{{ title }}</span>\n\t\t\t<span v-if=\"subtitle\" class=\"cn-object-row__subtitle\">{{ subtitle }}</span>\n\t\t</span>\n\n\t\t<!-- Badges (default: config-driven status badge) -->\n\t\t<span v-if=\"$slots.badges || badgeLabel\" class=\"cn-object-row__badges\">\n\t\t\t<!-- @slot badges Replace the badge area (overrides the config-driven badge). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"badges\" :object=\"object\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"badgeLabel\"\n\t\t\t\t\t:label=\"badgeLabel\"\n\t\t\t\t\t:variant=\"badgeVariant\"\n\t\t\t\t\t:colorMap=\"badgeColorMap\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</slot>\n\t\t</span>\n\n\t\t<!-- Trailing actions -->\n\t\t<span v-if=\"$slots.actions\"\n\t\t\tclass=\"cn-object-row__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<!-- @slot actions Trailing actions (copy button, menu, …). -->\n\t\t\t<!-- @binding {object} object The row's object. -->\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</span>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * CnObjectRow — Compact single-line list row for object display.\n *\n * The list-mode counterpart to `CnObjectCard`: a leading icon (or image), a\n * name with an optional subtitle, an optional status badge, and a trailing\n * actions area. Which object fields map to each slot is resolved from the\n * `config` prop first, then from `schema.configuration` (so a schema that\n * already declares `objectNameField` / `objectDescriptionField` / `objectImageField`\n * works with zero extra config).\n *\n * ```vue\n * <CnObjectRow\n * :object=\"secret\"\n * :schema=\"secretSchema\"\n * :config=\"{ subtitleField: 'url', iconName: 'Key' }\">\n * <template #actions=\"{ object }\">\n * <NcButton @click=\"copy(object)\">Copy</NcButton>\n * </template>\n * </CnObjectRow>\n * ```\n */\nexport default {\n\tname: 'CnObjectRow',\n\n\tcomponents: {\n\t\tNcCheckboxRadioSwitch,\n\t\tCnIcon,\n\t\tCnStatusBadge,\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition; `schema.configuration` supplies field defaults */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Explicit field mapping. Every key is optional and overrides the\n\t\t * schema-configuration default.\n\t\t *\n\t\t * @type {{ titleField?: string, subtitleField?: string, imageField?: string, iconField?: string, iconName?: string, badgeField?: string, badgeVariantField?: string, badgeVariant?: string, badgeColorMap?: object }}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether this row is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\t// Vue 2 had a separate listener channel, so a consumer's `@click` only ever\n\t// saw `$emit('click')`. In Vue 3 an UNDECLARED event name stays a\n\t// fallthrough attribute: `onClick` lands on the root `<div>` as a native\n\t// handler, so the consumer's handler fires once from the DOM click and\n\t// again from `$emit('click', object)` — twice per click, with different\n\t// payloads. Declaring the names here removes them from `$attrs`, which is\n\t// also what stops VTU v2 recording the native DOM event into `emitted()`.\n\temits: ['select', 'click', 'aux-click'],\n\n\tsetup() {\n\t\t// Tell a deliberate row click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/** Schema-level configuration block (empty when no schema). */\n\t\tschemaConfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.titleField || this.schemaConfig.objectNameField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tsubtitle() {\n\t\t\tconst field = this.config.subtitleField || this.schemaConfig.objectDescriptionField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.imageField || this.schemaConfig.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(String(this.object[field]))\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ticonName() {\n\t\t\tconst field = this.config.iconField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.iconName || ''\n\t\t},\n\n\t\t/** Whether to render the leading icon column at all. */\n\t\thasLeadingIcon() {\n\t\t\treturn Boolean(this.imageUrl || this.iconName || this.$slots.icon)\n\t\t},\n\n\t\tbadgeLabel() {\n\t\t\tconst field = this.config.badgeField\n\t\t\tif (field && this.object[field] !== null && this.object[field] !== undefined && this.object[field] !== '') {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\tbadgeVariant() {\n\t\t\tconst field = this.config.badgeVariantField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.config.badgeVariant || 'default'\n\t\t},\n\n\t\tbadgeColorMap() {\n\t\t\treturn this.config.badgeColorMap || null\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Row-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonRowClick(event) {\n\t\t\tif (this.selectable) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when a selectable row toggles selection (body or checkbox click).\n\t\t\t\t * @type {object} The row's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable row is clicked (navigation). Payload: `(object, event)` — the row's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Row mousedown: record the press for the drag guard, and on a\n\t\t * non-selectable row keep a middle press from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonRowMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Row-body middle click on a non-selectable row: emits `aux-click`, not\n\t\t * `click`, so an existing `click` listener that navigates never moves\n\t\t * the current tab away.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonRowAuxClick(event) {\n\t\t\tif (this.selectable || !isRowMiddleClick(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable row is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the row's object and the native auxclick event.\n\t\t\t * @type {object} The row's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tcursor: pointer;\n}\n\n.cn-object-row:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-row--selected {\n\t/* Inset accent — never border-left (would shift cell content). */\n\tbox-shadow: inset 3px 0 0 0 var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light);\n}\n\n.cn-object-row__checkbox {\n\tflex-shrink: 0;\n}\n\n.cn-object-row__icon {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 24px;\n\theight: 24px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-row__image {\n\twidth: 24px;\n\theight: 24px;\n\tobject-fit: contain;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-object-row__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-object-row__title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__subtitle {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-row__badges {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.cn-object-row__actions {\n\tflex-shrink: 0;\n\tdisplay: flex;\n\talign-items: center;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createVNode","_openBlock","_renderSlot","_createBlock","_createElementVNode","_toDisplayString"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFilesTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnFilesTab.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- The object's folder as a real files browser, on the Files app's own\n\t\t primitives (its actions, its New menu, its breadcrumbs), when the\n\t\t folder resolves for this user. The list below is the fallback for an\n\t\t object with no folder, or a user the folder is not shared with. -->\n\t\t<CnFilesBrowser\n\t\t\tv-if=\"browserRoot !== null\"\n\t\t\t:rootPath=\"browserRoot\"\n\t\t\t:rootLabel=\"browserRootLabel\"\n\t\t\t:rowActions=\"rowActions\"\n\t\t\t:newActions=\"newActions\"\n\t\t\t:linkedItems=\"linkedItems\"\n\t\t\t@changed=\"onBrowserChanged\" />\n\t\t<template v-else>\n\t\t\t<!-- Upload error -->\n\t\t\t<div v-if=\"uploadError\" class=\"cn-sidebar-tab__upload-error\">\n\t\t\t\t{{ uploadError }}\n\t\t\t</div>\n\n\t\t\t<!-- Share toggle — seeds from schema config (defaultAutoShare) or\n\t\t from the `defaultShare` prop. Hidden via `showShareToggle=false`. -->\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-if=\"showShareToggle\"\n\t\t\t\tv-model=\"share\"\n\t\t\t\tclass=\"cn-sidebar-tab__share\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\ttype=\"switch\">\n\t\t\t\t{{ shareLabel }}\n\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t<!-- File drop zone -->\n\t\t\t<div\n\t\t\t\tclass=\"cn-sidebar-tab__dropzone\"\n\t\t\t\t:class=\"{ 'cn-sidebar-tab__dropzone--active': isDragOver }\"\n\t\t\t\t@click=\"triggerFileInput\"\n\t\t\t\t@dragover.prevent=\"onDragOver\"\n\t\t\t\t@dragleave.prevent=\"onDragLeave\"\n\t\t\t\t@drop.prevent=\"onDrop\">\n\t\t\t\t<!--\n\t\t\t\t`:ref` (dynamic), not `ref` (static), and this is load-bearing.\n\n\t\t\t\tEvery other binding on this input is static, and Vue caches the\n\t\t\t\t`@change` handler, so with a STATIC ref the compiler hoists the\n\t\t\t\twhole vnode to module scope. A hoisted vnode is created once,\n\t\t\t\toutside any render, so its ref carries no owner instance\n\t\t\t\t(`rawRef.i === null`).\n\n\t\t\t\t`setRef()` guards that — but the guard AND its early `return`\n\t\t\t\tlive inside `if (process.env.NODE_ENV !== 'production')`. In a\n\t\t\t\tdevelopment build you get the warning \"Missing ref owner\n\t\t\t\tcontext. ref cannot be used on hoisted vnodes.\" and nothing\n\t\t\t\tbreaks. In a PRODUCTION build the guard is compiled out and\n\t\t\t\texecution falls through to `owner.refs`, throwing\n\t\t\t\t`TypeError: Cannot read properties of null (reading 'refs')`\n\t\t\t\t— which aborts the render of whatever mounted this tab.\n\n\t\t\t\tMeasured: hrmq's detail pages (the only pages in the fleet that\n\t\t\t\treach CnIntegrationWidget through a `widgets[]` grid) rendered a\n\t\t\t\tCOMPLETELY BLANK content pane in production while looking fine\n\t\t\t\tin dev. A dynamic ref is compiled as a patchable prop, so the\n\t\t\t\tvnode is created inside the render function and owns a proper\n\t\t\t\tinstance.\n\t\t\t-->\n\t\t\t\t<input\n\t\t\t\t\t:ref=\"fileInputRef\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\tmultiple\n\t\t\t\t\tclass=\"cn-sidebar-tab__file-input\"\n\t\t\t\t\t@change=\"onFileUpload\">\n\t\t\t\t<Upload :size=\"24\" class=\"cn-sidebar-tab__dropzone-icon\" />\n\t\t\t\t<span class=\"cn-sidebar-tab__dropzone-text\">{{ dropZoneLabel }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- File list. Each row borrows what Nextcloud already has on this\n\t\t page: the theme's own mime icon (OC.MimeType), the core preview\n\t\t endpoint for images, the Viewer for opening, and the Files sidebar\n\t\t for details, sharing and versions. Nothing of the Files app is\n\t\t rebuilt here; the row hands over to it. -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t\t<NcEmptyContent\n\t\t\t\tv-else-if=\"files.length === 0\"\n\t\t\t\tclass=\"cn-sidebar-tab__empty\"\n\t\t\t\t:name=\"noFilesLabel\"\n\t\t\t\t:description=\"dropZoneLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Paperclip :size=\"44\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"file in files\"\n\t\t\t\t\t:key=\"file.id\"\n\t\t\t\t\t:name=\"file.name || file.title\"\n\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"openFile(file)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__thumb\"\n\t\t\t\t\t\t\t:src=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t@error=\"onPreviewError(file)\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-else-if=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__mime\"\n\t\t\t\t\t\t\t:src=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<FileOutline v-else :size=\"32\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-sidebar-tab__meta\">\n\t\t\t\t\t\t\t<span>{{ formatFileSize(file.size) }}</span>\n\t\t\t\t\t\t\t<template v-if=\"modifiedAt(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<NcDateTime :timestamp=\"modifiedAt(file)\" :ignoreSeconds=\"true\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t<template v-if=\"labelsOf(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<span>{{ labelsOf(file) }}</span>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"openFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"downloadUrlFor(file)\"\n\t\t\t\t\t\t\t:download=\"file.name || file.title || ''\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ downloadLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\tv-if=\"canShowDetails() && file.path\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t@click=\"showDetails(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<InformationOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ detailsLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"showInFilesUrl(file)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ showInFilesLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton v-if=\"file.id\" :closeAfterClick=\"true\" @click=\"copyLink(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkVariant :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ copyLinkLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"deleteFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"files.length < total\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:wide=\"true\"\n\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t@click=\"loadMore\">\n\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ loadMoreLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport {\n\tNcActionButton,\n\tNcActionLink,\n\tNcActionSeparator,\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcDateTime,\n\tNcEmptyContent,\n\tNcListItem,\n\tNcLoadingIcon,\n} from '@nextcloud/vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport FileOutline from 'vue-material-design-icons/FileOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Paperclip from 'vue-material-design-icons/Paperclip.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnFilesBrowser from '../CnFilesBrowser/CnFilesBrowser.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { resolveObjectFolder } from '../CnFilesBrowser/filesBrowser.js'\n\nexport default {\n\tname: 'CnFilesTab',\n\n\tcomponents: {\n\t\tCnFilesBrowser,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDateTime,\n\t\tNcEmptyContent,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tDelete,\n\t\tDownload,\n\t\tFileOutline,\n\t\tFolderOutline,\n\t\tInformationOutline,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPaperclip,\n\t\tUpload,\n\t},\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown inside the file drop zone */\n\t\tdropZoneLabel: { type: String, default: () => t('nextcloud-vue', 'Drop files here or click to browse') },\n\t\t/** Text shown when no files are attached */\n\t\tnoFilesLabel: { type: String, default: () => t('nextcloud-vue', 'No files attached') },\n\t\t/** Label for the open/view file action */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** What the files browser's root crumb reads; null shows the folder's own name, as the Files app does. */\n\t\tbrowserRootLabel: { type: String, default: null },\n\t\t/**\n\t\t * The host's own actions on each file row of the browser, forwarded\n\t\t * to CnFilesBrowser's `rowActions`: declared like any manifest action\n\t\t * and dispatched with the file's id, name and path merged in.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\trowActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * The host's own entries in the browser's New menu, forwarded to\n\t\t * CnFilesBrowser's `newActions`: declared like a row action and\n\t\t * dispatched with the folder rather than a row, for things like\n\t\t * \"new from template\" or \"request a file from a party\".\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\tnewActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * An app endpoint that answers the object's linked files, rows the\n\t\t * browser shows after the folder's own (files the host joined from\n\t\t * another object's folder). App-relative; `{objectId}` is replaced.\n\t\t * The response is an array (or `{ items: [] }`) of\n\t\t * `{ id, name, mime?, size?, mtime?, href?, downloadHref?, note?, noteHref? }`.\n\t\t * Null fetches nothing.\n\t\t */\n\t\tlinkedItemsUrl: { type: String, default: null },\n\t\t/** Label of the Download action. */\n\t\tdownloadLabel: { type: String, default: () => t('nextcloud-vue', 'Download') },\n\t\t/** Label of the action that opens the Files sidebar on the file. */\n\t\tdetailsLabel: { type: String, default: () => t('nextcloud-vue', 'Details and sharing') },\n\t\t/** Label of the link that opens the file in the Files app. */\n\t\tshowInFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Show in Files') },\n\t\t/** Label of the action that copies the file permalink. */\n\t\tcopyLinkLabel: { type: String, default: () => t('nextcloud-vue', 'Copy link') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Whether to render the \"share uploaded files\" toggle. Off by default;\n\t\t * when false, uploads never set the share flag (no auto-publish).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowShareToggle: { type: Boolean, default: false },\n\t\t/**\n\t\t * Initial state for the share toggle. `true`/`false` wins outright;\n\t\t * `null` (the default) defers to the schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister.\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\tdefaultShare: { type: Boolean, default: null },\n\t\t/** Label for the share toggle */\n\t\tshareLabel: { type: String, default: () => t('nextcloud-vue', 'Share uploaded files') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tfiles: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tisDragOver: false,\n\t\t\tuploadError: '',\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tshare: false,\n\t\t\t/** The object's folder as a user-relative path, or null while unresolved or absent. */\n\t\t\tbrowserRoot: null,\n\t\t\tlinkedItems: [],\n\t\t\t/** File ids whose preview request failed, so the row falls back to the mime icon. */\n\t\t\tpreviewFailed: {},\n\t\t\t/**\n\t\t\t * The file input element, set by the template's function ref.\n\t\t\t *\n\t\t\t * Held here rather than read back through `$refs` so the ref stays\n\t\t\t * DYNAMIC — see the long comment on the input itself for why a\n\t\t\t * static ref on this element is a production crash.\n\t\t\t *\n\t\t\t * @type {HTMLInputElement|null}\n\t\t\t */\n\t\t\tfileInputEl: null,\n\t\t}\n\t},\n\n\twatch: {\n\t\t// Match every other CnObjectSidebar tab — a single immediate\n\t\t// `objectId` watcher drives all initial loads. Folding the\n\t\t// share-toggle seed in here avoids two concurrent GETs of\n\t\t// `schemas/{schema}` on mount (one per immediate watcher).\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchFiles()\n\t\t\t\t}\n\t\t\t\tthis.applyShareDefault()\n\t\t\t\tthis.resolveBrowserRoot()\n\t\t\t\tthis.fetchLinkedItems()\n\t\t\t},\n\t\t},\n\n\t\tlinkedItemsUrl() {\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Function ref for the file input.\n\t\t *\n\t\t * A method (not an inline arrow in the template) so the binding is a\n\t\t * stable reference across renders and Vue does not detach/reattach the\n\t\t * ref on every patch. Being a function ref is what keeps the vnode\n\t\t * dynamic — see the template comment on the input.\n\t\t *\n\t\t * @param {HTMLInputElement|null} el The element, or null on unmount.\n\t\t * @return {void}\n\t\t */\n\t\tfileInputRef(el) {\n\t\t\tthis.fileInputEl = el || null\n\t\t},\n\n\t\t/**\n\t\t * Find the object's folder for the browser, or leave the legacy list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * The browser changed the folder: refresh the object's file list and\n\t\t * the linked rows, since a join or a move can change either.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonBrowserChanged() {\n\t\t\tthis.fetchFiles()\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\n\t\t/**\n\t\t * Read the object's linked files from the host's endpoint, if any.\n\t\t *\n\t\t * A failure leaves the last list in place and logs at debug: the\n\t\t * folder's own rows are the surface, the linked rows a supplement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchLinkedItems() {\n\t\t\tif (!this.linkedItemsUrl || !this.objectId) {\n\t\t\t\tthis.linkedItems = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(this.linkedItemsUrl.replace('{objectId}', encodeURIComponent(this.objectId)))\n\t\t\t\tconst { data } = await axios.get(url)\n\t\t\t\tconst items = Array.isArray(data) ? data : (Array.isArray(data?.items) ? data.items : [])\n\t\t\t\tthis.linkedItems = items.filter((item) => item && typeof item === 'object')\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.debug('[CnFilesTab] linked items not read', error)\n\t\t\t}\n\t\t},\n\n\t\tasync resolveBrowserRoot() {\n\t\t\tthis.browserRoot = null\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet remoteUrl\n\t\t\ttry {\n\t\t\t\tremoteUrl = generateRemoteUrl('dav')\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.browserRoot = await resolveObjectFolder({\n\t\t\t\tapiBase: this.apiBase,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tuid: getCurrentUser()?.uid || '',\n\t\t\t\tremoteUrl,\n\t\t\t})\n\t\t},\n\n\t\tasync fetchFiles(append = false) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (append) {\n\t\t\t\tthis.loadingMore = true\n\t\t\t} else {\n\t\t\t\tthis.loading = true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst params = new URLSearchParams({ limit: this.limit, _page: this.page })\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files?${params}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tthis.files = append ? [...this.files, ...results] : results\n\t\t\t\t\tthis.total = data.total || this.files.length\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('CnFilesTab: Failed to fetch files', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchFiles(true)\n\t\t},\n\n\t\t/**\n\t\t * Seed the `share` toggle. The `defaultShare` prop wins when set\n\t\t * (non-null); otherwise we look up the active schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister and use that.\n\t\t * Network failure or missing key → keep the safe default (false) so\n\t\t * a hiccup never silently flips uploads to \"share\".\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync applyShareDefault() {\n\t\t\tif (this.defaultShare !== null && this.defaultShare !== undefined) {\n\t\t\t\tthis.share = !!this.defaultShare\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.share = false\n\t\t\tif (!this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/schemas/${this.schema}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json().catch(() => null)\n\t\t\t\tif (data?.configuration?.defaultAutoShare === true) {\n\t\t\t\t\tthis.share = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Non-fatal — keep the safe default, but surface the\n\t\t\t\t// failure so a missing toggle default isn't silent.\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to fetch schema default for share toggle', err)\n\t\t\t}\n\t\t},\n\n\t\ttriggerFileInput() {\n\t\t\tthis.fileInputEl?.click()\n\t\t},\n\n\t\tonDragOver() {\n\t\t\tthis.isDragOver = true\n\t\t},\n\n\t\tonDragLeave() {\n\t\t\tthis.isDragOver = false\n\t\t},\n\n\t\tonDrop(event) {\n\t\t\tthis.isDragOver = false\n\t\t\tconst droppedFiles = event.dataTransfer?.files\n\t\t\tif (droppedFiles?.length) {\n\t\t\t\tthis.uploadFiles(droppedFiles)\n\t\t\t}\n\t\t},\n\n\t\tasync onFileUpload(event) {\n\t\t\tconst inputFiles = event.target.files\n\t\t\tif (!inputFiles?.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.uploadFiles(inputFiles)\n\t\t\tif (this.fileInputEl) {\n\t\t\t\tthis.fileInputEl.value = ''\n\t\t\t}\n\t\t},\n\n\t\tasync uploadFiles(fileList) {\n\t\t\tif (!fileList?.length || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.uploadError = ''\n\t\t\tconst formData = new FormData()\n\t\t\tfor (const file of fileList) {\n\t\t\t\tformData.append('files[]', file)\n\t\t\t}\n\t\t\t// Only forward the share flag when the toggle is actually visible.\n\t\t\t// Hiding the toggle (showShareToggle=false) means \"don't auto-publish\".\n\t\t\tif (this.showShareToggle) {\n\t\t\t\tformData.append('share', String(this.share))\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/filesMultipart`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { requesttoken: OC?.requestToken || '', 'OCS-APIREQUEST': 'true' },\n\t\t\t\t\t\tbody: formData,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.uploadError = data.error || `Upload failed (${response.status})`\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.fetchFiles()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to upload file', err)\n\t\t\t\tthis.uploadError = 'Upload failed: could not connect to server'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the Files app's details sidebar is on this page.\n\t\t *\n\t\t * It is when the host page dispatched Nextcloud's `LoadSidebar` event\n\t\t * server-side; then `OCA.Files.Sidebar.open(path)` shows the same\n\t\t * sharing, versions, comments and activity tabs the Files app shows.\n\t\t * Absent, the row offers no details action rather than a dead one. A\n\t\t * method rather than a computed: the global is not reactive, so a\n\t\t * cached answer from before the sidebar script ran would stay wrong.\n\t\t *\n\t\t * @return {boolean} true when the sidebar can be opened.\n\t\t */\n\t\tcanShowDetails() {\n\t\t\treturn typeof window !== 'undefined' && typeof window.OCA?.Files?.Sidebar?.open === 'function'\n\t\t},\n\n\t\t/**\n\t\t * The file's path relative to the user's files root, which is the path\n\t\t * the Viewer and the Files sidebar take. OpenRegister reports the node's\n\t\t * full path (`/{uid}/files/…`), so the first two segments come off.\n\t\t *\n\t\t * @param {string} path The node path as OpenRegister reports it.\n\t\t * @return {string} The user-relative path, `/` at least.\n\t\t */\n\t\tuserRelativePath(path) {\n\t\t\tconst stripped = String(path || '').replace(/^\\/[^/]+\\/files(?=\\/|$)/, '')\n\t\t\treturn stripped === '' ? '/' : stripped\n\t\t},\n\n\t\t/**\n\t\t * The theme's own icon for the file's mime type, the one the Files app\n\t\t * draws, or null on a page without Nextcloud's core script.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The icon url.\n\t\t */\n\t\tmimeIconFor(file) {\n\t\t\tconst getIconUrl = typeof window !== 'undefined' ? window.OC?.MimeType?.getIconUrl : null\n\t\t\tif (typeof getIconUrl !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\ttry {\n\t\t\t\treturn getIconUrl(mime) || null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A small preview for an image, through Nextcloud's core preview\n\t\t * endpoint, or null for anything else or after the preview failed once.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The preview url.\n\t\t */\n\t\tpreviewUrlFor(file) {\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tif (!file.id || !/^image\\//i.test(mime) || /svg/i.test(mime) || this.previewFailed[file.id]) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/core/preview?fileId={fileId}&x=64&y=64&a=1', { fileId: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Remember that a preview did not load, so the row shows the mime icon.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tonPreviewError(file) {\n\t\t\tthis.previewFailed = { ...this.previewFailed, [file.id]: true }\n\t\t},\n\n\t\t/**\n\t\t * The file's modification moment as a Date, or null when unknown.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Date|null} The moment.\n\t\t */\n\t\tmodifiedAt(file) {\n\t\t\tconst raw = file.modified || file.updated || ''\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = new Date(raw)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * The file's labels (Nextcloud tags), joined for the meta line.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The labels, or the empty string.\n\t\t */\n\t\tlabelsOf(file) {\n\t\t\treturn Array.isArray(file.labels) ? file.labels.filter(Boolean).join(', ') : ''\n\t\t},\n\n\t\t/**\n\t\t * The download url for a file, through OpenRegister's file endpoint,\n\t\t * which streams the node the object owns.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tdownloadUrlFor(file) {\n\t\t\treturn `${this.apiBase}/files/${encodeURIComponent(String(file.id))}/download`\n\t\t},\n\n\t\t/**\n\t\t * The Files app's permalink for a file: opens the Files app at the\n\t\t * file's folder with the file selected.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tshowInFilesUrl(file) {\n\t\t\treturn generateUrl('/f/{fileid}', { fileid: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Open the Files sidebar on this file: details, sharing, versions,\n\t\t * comments and activity, exactly as the Files app offers them.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tshowDetails(file) {\n\t\t\tif (!this.canShowDetails() || !file.path) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\twindow.OCA.Files.Sidebar.open(this.userRelativePath(file.path))\n\t\t},\n\n\t\t/**\n\t\t * Put the file's permalink on the clipboard and say so.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync copyLink(file) {\n\t\t\tconst href = new URL(this.showInFilesUrl(file), window.location.origin).href\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(href)\n\t\t\t\tconst { showSuccess } = await import('@nextcloud/dialogs')\n\t\t\t\tshowSuccess(t('nextcloud-vue', 'Link copied'))\n\t\t\t} catch {\n\t\t\t\tconst { showError } = await import('@nextcloud/dialogs')\n\t\t\t\tshowError(t('nextcloud-vue', 'The link could not be copied'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether Nextcloud's Viewer is on this page and handles the file.\n\t\t *\n\t\t * The Viewer is there when the host page dispatched `LoadViewer`\n\t\t * server-side; it lists the mime types it can show, and a type it\n\t\t * cannot falls through to the next way of opening the file.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {boolean} true when the Viewer can open it in place.\n\t\t */\n\t\tviewerHandles(file) {\n\t\t\tconst viewer = typeof window !== 'undefined' ? window.OCA?.Viewer : null\n\t\t\tif (!viewer || typeof viewer.open !== 'function' || !file.path) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tconst mimetypes = Array.isArray(viewer.mimetypes) ? viewer.mimetypes : null\n\t\t\treturn mimetypes === null ? true : mimetypes.includes(mime)\n\t\t},\n\n\t\topenFile(file) {\n\t\t\t// The Viewer first: it opens the file over this page, so the reader\n\t\t\t// stays on the object. A public share link and the Files app come\n\t\t\t// after, in that order, when the Viewer is absent or cannot show\n\t\t\t// the type.\n\t\t\tif (this.viewerHandles(file)) {\n\t\t\t\twindow.OCA.Viewer.open({ path: this.userRelativePath(file.path) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (file.accessUrl) {\n\t\t\t\t// Security: accessUrl originates from the OR files API and may be\n\t\t\t\t// attacker-controlled. Validate the scheme via safeHref before\n\t\t\t\t// opening (C4) — this blocks javascript: / data: payloads. Add\n\t\t\t\t// noopener,noreferrer to prevent the opened tab from accessing\n\t\t\t\t// window.opener (reverse-tabnabbing) and to strip the Referer header.\n\t\t\t\tconst safe = safeHref(file.accessUrl)\n\t\t\t\tif (safe !== '#') {\n\t\t\t\t\twindow.open(safe, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t} else if (file.id) {\n\t\t\t\tconst dirPath = file.path ? file.path.substring(0, file.path.lastIndexOf('/')) : ''\n\t\t\t\tconst cleanPath = dirPath.replace(/^\\/admin\\/files\\//, '/')\n\t\t\t\twindow.open(`/index.php/apps/files/files/${file.id}?dir=${encodeURIComponent(cleanPath)}&openfile=true`, '_blank')\n\t\t\t}\n\t\t},\n\n\t\tasync deleteFile(file) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files/${file.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.files = this.files.filter((f) => f.id !== file.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to delete file', err)\n\t\t\t}\n\t\t},\n\n\t\tformatFileSize(bytes) {\n\t\t\tconst sizes = ['Bytes', 'KB', 'MB', 'GB']\n\t\t\tif (!bytes || bytes === 0) {\n\t\t\t\treturn 'n/a'\n\t\t\t}\n\t\t\tconst i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n\t\t\tif (i === 0) {\n\t\t\t\treturn '< 1 KB'\n\t\t\t}\n\t\t\treturn (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__upload-error {\n\tpadding: 8px 12px;\n\tmargin-bottom: 8px;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground-color: var(--color-error-light, rgba(229, 57, 53, 0.1));\n\tcolor: var(--color-error, #e53935);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__dropzone {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 20px 12px;\n\tmargin-bottom: 16px;\n\tborder: 2px dashed var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tcursor: pointer;\n\ttransition: border-color 0.15s ease, background-color 0.15s ease;\n}\n\n.cn-sidebar-tab__dropzone:hover {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.08));\n}\n\n.cn-sidebar-tab__dropzone--active {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.12));\n}\n\n.cn-sidebar-tab__share { margin-bottom: 12px; }\n\n.cn-sidebar-tab__dropzone-icon { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__dropzone--active .cn-sidebar-tab__dropzone-icon,\n.cn-sidebar-tab__dropzone:hover .cn-sidebar-tab__dropzone-icon { color: var(--color-primary-element); }\n\n.cn-sidebar-tab__dropzone-text { font-size: 13px; color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__file-input { display: none; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-sidebar-tab__mime,\n.cn-sidebar-tab__thumb {\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: block;\n}\n\n.cn-sidebar-tab__thumb {\n\tobject-fit: cover;\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-sidebar-tab__meta { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n</style>\n"],"names":["CnFilesBrowser","t","axios"],"mappings":";;;;;;;;;;;;;;;;;;;AAgOA,aAAe;AACd,CAAA,IAAI,EAAE,YAAY;;CAElB,UAAU,EAAE;AACX,kBAAAA,UAAc;AACd,EAAA,cAAc;EACd,YAAY;AACZ,EAAA,iBAAiB;AACjB,EAAA,QAAQ;AACR,EAAA,qBAAqB;EACrB,UAAU;AACV,EAAA,cAAc;EACd,UAAU;EACV,aAAa;AACb,EAAA,MAAM;AACN,EAAA,QAAQ;EACR,WAAW;EACX,aAAa;AACb,EAAA,kBAAkB;EAClB,WAAW;AACX,EAAA,SAAS;AACT,EAAA,SAAS;AACT,EAAA,MAAM;EACN;;AAED,CAAA,KAAK,EAAE;AACN;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAE1C,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACvC;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACrC;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;AAC5D;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,oCAAoC,GAAG;AACxG;AACA,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,mBAAmB,GAAG;AACtF;EACA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,MAAM,CAAA,EAAG;;AAEtE,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,QAAQ,GAAG;AAC1E;AACA,EAAA,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;AACjD;;;;AAIC;AACA;;AAED,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI;AAC9C;;;;AAIC;AACA;AACA;;AAED,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI;AAC9C;;;;AAIC;AACA;AACA;;AAED,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;AAE/C,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,UAAU,GAAG;;AAE9E,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,qBAAqB,GAAG;;AAExF,EAAA,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,eAAe,GAAG;;AAEtF,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;AAC/E;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;AAC/E;;;AAGC;AACA;;AAED,EAAA,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;AAClD;;AAEC;;AAEA;AACA;;AAED,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM;;AAE9C,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,sBAAsB,GAAG;EACvF;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,KAAK,EAAE,EAAE;GACT,OAAO,EAAE,KAAK;AACd,GAAA,WAAW,EAAE,KAAK;AAClB,GAAA,UAAU,EAAE,KAAK;AACjB,GAAA,WAAW,EAAE,EAAE;AACf,GAAA,IAAI,EAAE,CAAC;AACP,GAAA,KAAK,EAAE,CAAC;AACR,GAAA,KAAK,EAAE,EAAE;GACT,KAAK,EAAE,KAAK;AACZ;AACA,GAAA,WAAW,EAAE,IAAI;AACjB,GAAA,WAAW,EAAE,EAAE;AACf;AACA,GAAA,aAAa,EAAE,EAAE;AACjB;;AAEC;;;AAGA;AACA;;;AAGD,GAAA,WAAW,EAAE,IAAI;AAClB,GAAA;EACA;;AAED,CAAA,KAAK,EAAE;;;;;AAKN,EAAA,QAAQ,EAAE;AACT,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,EAAE,EAAE;AACX,IAAA,IAAI,EAAE,EAAE;AACP,KAAA,IAAI,CAAC,UAAU,GAAC;AACjB,KAAA;IACA,IAAI,CAAC,iBAAiB,GAAC;IACvB,IAAI,CAAC,kBAAkB,GAAC;IACxB,IAAI,CAAC,gBAAgB,GAAC;IACtB;GACD;;AAED,EAAA,cAAc,GAAG;GAChB,IAAI,CAAC,gBAAgB,GAAC;GACtB;EACD;;AAED,CAAA,OAAO,EAAE;AACR;;AAEC;;;;AAIA;AACA;;;;AAID,EAAA,YAAY,CAAC,EAAE,EAAE;GAChB,IAAI,CAAC,cAAc,MAAM,KAAG;GAC5B;;AAED;;AAEC;;;AAGD;;;AAGC;;;AAGD,EAAA,gBAAgB,GAAG;AAClB,GAAA,IAAI,CAAC,UAAU,GAAC;GAChB,IAAI,CAAC,gBAAgB,GAAC;GACtB;;AAED;;AAEC;;;AAGA;;;EAGD,MAAM,gBAAgB,GAAG;AACxB,GAAA,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC3C,IAAA,IAAI,CAAC,WAAU,GAAI,GAAC;IACpB,MAAK;AACN,IAAA;AACA,GAAA,IAAI;IACH,MAAM,GAAE,GAAI,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAA;AACpG,IAAA,MAAM,EAAE,IAAK,EAAA,GAAI,MAAMC,cAAK,CAAC,GAAG,CAAC,GAAG,EAAA;AACpC,IAAA,MAAM,KAAI,GAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAA,GAAI,IAAG,IAAK,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAA,GAAI,IAAI,CAAC,KAAM,GAAE,EAAE,EAAA;AACxF,IAAA,IAAI,CAAC,WAAY,GAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAG,IAAK,OAAO,IAAK,KAAI,QAAQ,EAAA;IACzE,CAAA,OAAO,KAAK,EAAE;AACf;IACA,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,EAAA;AAC1D,IAAA;GACA;;EAED,MAAM,kBAAkB,GAAG;AAC1B,GAAA,IAAI,CAAC,cAAc,KAAG;GACtB,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,MAAM,EAAE;IACrD,MAAK;AACN,IAAA;GACA,IAAI,UAAQ;AACZ,GAAA,IAAI;AACH,IAAA,SAAQ,GAAI,iBAAiB,CAAC,KAAK,EAAA;AACpC,IAAA,CAAE,MAAM;IACP,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,cAAc,MAAM,mBAAmB,CAAC;AAC5C,IAAA,OAAO,EAAE,IAAI,CAAC,OAAO;IACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACvB,IAAA,MAAM,EAAE,IAAI,CAAC,MAAM;IACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;IACvB,GAAG,EAAE,cAAc,EAAE,EAAE,GAAI,IAAG,EAAE;AAChC,IAAA,SAAS;IACT,EAAA;GACD;;EAED,MAAM,UAAU,CAAC,MAAK,GAAI,KAAK,EAAE;AAChC,GAAA,IAAI,CAAC,IAAI,CAAC,QAAS,IAAG,CAAC,IAAI,CAAC,MAAM,EAAE;IACnC,MAAK;AACN,IAAA;GACA,IAAI,MAAM,EAAE;AACX,IAAA,IAAI,CAAC,cAAc,KAAG;IACrB,MAAK;AACN,IAAA,IAAI,CAAC,OAAM,GAAI,KAAG;AACnB,IAAA;AACA,GAAA,IAAI;AACH,IAAA,MAAM,MAAK,GAAI,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAA;IAC1E,MAAM,WAAW,MAAM,KAAK;KAC3B,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;KACrG,EAAE,OAAO,EAAE,YAAY,EAAC,EAAG;AAC5B,MAAA;AACA,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,KAAA,MAAM,OAAM,GAAI,IAAI,CAAC,OAAQ,IAAG,IAAK,IAAG,GAAC;KACzC,IAAI,CAAC,KAAI,GAAI,MAAO,GAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,OAAO,CAAE,GAAE,QAAM;AAC1D,KAAA,IAAI,CAAC,KAAM,GAAE,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,KAAK,CAAC,OAAK;AAC5C,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,EAAA;AACvD,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACnB,IAAA,IAAI,CAAC,WAAU,GAAI,MAAI;AACxB,IAAA;GACA;;EAED,QAAQ,GAAG;GACV,IAAI,CAAC,IAAI,GAAC;AACV,GAAA,IAAI,CAAC,UAAU,CAAC,IAAI,EAAA;GACpB;;AAED;;AAEC;;;AAGA;AACA;;;EAGD,MAAM,iBAAiB,GAAG;GACzB,IAAI,IAAI,CAAC,YAAa,KAAI,IAAG,IAAK,IAAI,CAAC,YAAW,KAAM,SAAS,EAAE;IAClE,IAAI,CAAC,KAAI,GAAI,CAAC,CAAC,IAAI,CAAC,aAAW;IAC/B,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,KAAM,GAAE,MAAI;AACjB,GAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;IACjB,MAAK;AACN,IAAA;AACA,GAAA,IAAI;IACH,MAAM,WAAW,MAAM,KAAK;KAC3B,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;KACnD,EAAE,OAAO,EAAE,YAAY,EAAC,EAAG;AAC5B,MAAA;AACA,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;KACjB,MAAK;AACN,KAAA;AACA,IAAA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,EAAA;IACnD,IAAI,IAAI,EAAE,aAAa,EAAE,qBAAqB,IAAI,EAAE;AACnD,KAAA,IAAI,CAAC,KAAM,GAAE,KAAG;AACjB,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA;AACA;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,6DAA6D,EAAE,GAAG,EAAA;AACjF,IAAA;GACA;;AAED,EAAA,gBAAgB,GAAG;GAClB,IAAI,CAAC,WAAW,EAAE,KAAK,GAAC;GACxB;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;EAED,WAAW,GAAG;AACb,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;GACtB;;EAED,MAAM,CAAC,KAAK,EAAE;AACb,GAAA,IAAI,CAAC,UAAS,GAAI,MAAI;AACtB,GAAA,MAAM,YAAa,GAAE,KAAK,CAAC,YAAY,EAAE,MAAI;GAC7C,IAAI,YAAY,EAAE,MAAM,EAAE;IACzB,IAAI,CAAC,WAAW,CAAC,YAAY,EAAA;AAC9B,IAAA;GACA;;EAED,MAAM,YAAY,CAAC,KAAK,EAAE;AACzB,GAAA,MAAM,UAAW,GAAE,KAAK,CAAC,MAAM,CAAC,MAAI;GACpC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE;IACxB,MAAK;AACN,IAAA;AACA,GAAA,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,EAAA;AACjC,GAAA,IAAI,IAAI,CAAC,WAAW,EAAE;IACrB,IAAI,CAAC,WAAW,CAAC,KAAM,GAAE,GAAC;AAC3B,IAAA;GACA;;EAED,MAAM,WAAW,CAAC,QAAQ,EAAE;GAC3B,IAAI,CAAC,QAAQ,EAAE,MAAO,IAAG,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,MAAM,EAAE;IACxD,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,WAAU,GAAI,GAAC;GACpB,MAAM,QAAO,GAAI,IAAI,QAAQ,GAAC;GAC9B,KAAK,MAAM,QAAQ,QAAQ,EAAE;AAC5B,IAAA,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAA;AAChC,IAAA;;AAEA;GACA,IAAI,IAAI,CAAC,eAAe,EAAE;AACzB,IAAA,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAA;AAC5C,IAAA;;AAEA,GAAA,IAAI,CAAC,OAAM,GAAI,KAAG;AAClB,GAAA,IAAI;IACH,MAAM,WAAW,MAAM,KAAK;KAC3B,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AACpG,KAAA;MACC,MAAM,EAAE,MAAM;AACd,MAAA,OAAO,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,YAAa,IAAG,EAAE,EAAE,gBAAgB,EAAE,QAAQ;MAC3E,IAAI,EAAE,QAAQ;MACd;AACF,MAAA;AACA,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AACjB,KAAA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,EAAA;AACnD,KAAA,IAAI,CAAC,WAAY,GAAE,IAAI,CAAC,KAAI,IAAK,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAA;KACpE,MAAK;AACN,KAAA;AACA,IAAA,MAAM,IAAI,CAAC,UAAU,GAAC;IACrB,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,EAAA;IACtD,IAAI,CAAC,WAAU,GAAI,6CAA2C;AAC/D,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACpB,IAAA;GACA;;AAED;;AAEC;;;;;;;AAOA;;;AAGD,EAAA,cAAc,GAAG;AAChB,GAAA,OAAO,OAAO,WAAW,WAAY,IAAG,OAAO,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,UAAS;GAC7F;;AAED;;;;AAIC;;;;EAID,gBAAgB,CAAC,IAAI,EAAE;AACtB,GAAA,MAAM,QAAO,GAAI,MAAM,CAAC,IAAK,IAAG,EAAE,CAAC,CAAC,OAAO,CAAC,yBAAyB,EAAE,EAAE,EAAA;AACzE,GAAA,OAAO,QAAS,KAAI,EAAC,GAAI,GAAE,GAAI,QAAO;GACtC;;AAED;;;AAGC;;AAEA;;AAED,EAAA,WAAW,CAAC,IAAI,EAAE;AACjB,GAAA,MAAM,UAAW,GAAE,OAAO,MAAO,KAAI,cAAc,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAS,GAAI,KAAG;AACxF,GAAA,IAAI,OAAO,UAAW,KAAI,UAAU,EAAE;AACrC,IAAA,OAAO,IAAG;AACX,IAAA;GACA,MAAM,IAAK,GAAE,IAAI,CAAC,IAAG,IAAK,IAAI,CAAC,QAAS,IAAG,IAAI,CAAC,QAAO,IAAK,GAAC;AAC7D,GAAA,IAAI;IACH,OAAO,UAAU,CAAC,IAAI,CAAA,IAAK,IAAG;AAC/B,IAAA,CAAE,MAAM;AACP,IAAA,OAAO,IAAG;AACX,IAAA;GACA;;AAED;;;AAGC;;AAEA;;AAED,EAAA,aAAa,CAAC,IAAI,EAAE;GACnB,MAAM,IAAK,GAAE,IAAI,CAAC,IAAG,IAAK,IAAI,CAAC,QAAS,IAAG,IAAI,CAAC,QAAO,IAAK,GAAC;AAC7D,GAAA,IAAI,CAAC,IAAI,CAAC,EAAC,IAAK,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAA,IAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAA,IAAK,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AAC5F,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,WAAW,CAAC,6CAA6C,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAA;GACrF;;AAED;;AAEC;;;;AAID,EAAA,cAAc,CAAC,IAAI,EAAE;GACpB,IAAI,CAAC,aAAY,GAAI,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,IAAK,GAAA;GAC9D;;AAED;;AAEC;;;;AAID,EAAA,UAAU,CAAC,IAAI,EAAE;AAChB,GAAA,MAAM,GAAI,GAAE,IAAI,CAAC,YAAY,IAAI,CAAC,OAAQ,IAAG,GAAC;AAC9C,GAAA,IAAI,CAAC,GAAG,EAAE;AACT,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,MAAM,IAAK,GAAE,IAAI,IAAI,CAAC,GAAG,EAAA;AACzB,GAAA,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAE,GAAE,OAAO,IAAG;GAChD;;AAED;;AAEC;;AAEA;;AAED,EAAA,QAAQ,CAAC,IAAI,EAAE;AACd,GAAA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAE,GAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA,GAAI,EAAC;GAC9E;;AAED;;AAEC;AACA;;;;AAID,EAAA,cAAc,CAAC,IAAI,EAAE;AACpB,GAAA,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;GAC7E;;AAED;;AAEC;AACA;;;;AAID,EAAA,cAAc,CAAC,IAAI,EAAE;GACpB,OAAO,WAAW,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAC,EAAG,CAAA;GACrD;;AAED;;;AAGC;;;;AAID,EAAA,WAAW,CAAC,IAAI,EAAE;AACjB,GAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAG,IAAG,CAAC,IAAI,CAAC,IAAI,EAAE;IACzC,MAAK;AACN,IAAA;AACA,GAAA,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAA;GAC9D;;AAED;AACC;AACA;;;;AAID,EAAA,MAAM,QAAQ,CAAC,IAAI,EAAE;AACpB,GAAA,MAAM,IAAK,GAAE,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAG;AAC3E,GAAA,IAAI;AACH,IAAA,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAA;IACxC,MAAM,EAAE,WAAY,EAAA,GAAI,MAAM,OAAO,qDAAoB,EAAA;AACzD,IAAA,WAAW,CAACD,SAAC,CAAC,eAAe,EAAE,aAAa,CAAC,EAAA;AAC9C,IAAA,CAAE,MAAM;IACP,MAAM,EAAE,WAAY,GAAE,MAAM,OAAO,qDAAoB,EAAA;IACvD,SAAS,CAACA,SAAC,CAAC,eAAe,EAAE,8BAA8B,CAAC,EAAA;AAC7D,IAAA;GACA;;AAED;;AAEC;;;;AAIA;;;;AAID,EAAA,aAAa,CAAC,IAAI,EAAE;GACnB,MAAM,MAAO,GAAE,OAAO,MAAK,KAAM,WAAU,GAAI,MAAM,CAAC,GAAG,EAAE,MAAO,GAAE,KAAG;GACvE,IAAI,CAAC,MAAO,IAAG,OAAO,MAAM,CAAC,IAAK,KAAI,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE;IAC/D,OAAO,KAAI;AACZ,IAAA;GACA,MAAM,IAAK,GAAE,IAAI,CAAC,IAAG,IAAK,IAAI,CAAC,QAAS,IAAG,IAAI,CAAC,QAAO,IAAK,GAAC;AAC7D,GAAA,MAAM,YAAY,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAE,GAAE,MAAM,CAAC,SAAQ,GAAI,KAAG;GAC1E,OAAO,SAAQ,KAAM,IAAK,GAAE,IAAK,GAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAA;GAC1D;;AAED,EAAA,QAAQ,CAAC,IAAI,EAAE;;;;AAId;GACA,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;AAC7B,IAAA,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAA,EAAG,EAAA;IACjE,MAAK;AACN,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,SAAS,EAAE;;;;;;AAMnB,IAAA,MAAM,IAAG,GAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAA;AACpC,IAAA,IAAI,IAAG,KAAM,GAAG,EAAE;KACjB,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,qBAAqB,EAAA;AAClD,KAAA;AACD,IAAA,MAAO,IAAI,IAAI,CAAC,EAAE,EAAE;AACnB,IAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,IAAG,GAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA,GAAI,GAAC;IAClF,MAAM,YAAY,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,EAAA;IAC1D,MAAM,CAAC,IAAI,CAAC,CAAC,4BAA4B,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAA;AAClH,IAAA;GACA;;AAED,EAAA,MAAM,UAAU,CAAC,IAAI,EAAE;AACtB,GAAA,IAAI,CAAC,IAAI,CAAC,QAAS,IAAG,CAAC,IAAI,CAAC,MAAM,EAAE;IACnC,MAAK;AACN,IAAA;AACA,GAAA,IAAI;IACH,MAAM,KAAK;KACV,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACtG,KAAA,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,IAAI;AAC9C,MAAA;IACA,IAAI,CAAC,KAAM,GAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAG,KAAI,IAAI,CAAC,EAAE,EAAA;IACrD,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,EAAA;AACvD,IAAA;GACA;;AAED,EAAA,cAAc,CAAC,KAAK,EAAE;AACrB,GAAA,MAAM,KAAI,GAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAA;AACxC,GAAA,IAAI,CAAC,KAAM,IAAG,KAAI,KAAM,CAAC,EAAE;IAC1B,OAAO,KAAI;AACZ,IAAA;GACA,MAAM,CAAA,GAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAA,GAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAA;AAC/D,GAAA,IAAI,CAAA,KAAM,CAAC,EAAE;IACZ,OAAO,QAAO;AACf,IAAA;GACA,OAAO,CAAC,KAAI,GAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAE,GAAE,GAAE,GAAI,KAAK,CAAC,CAAC,CAAA;GAC7D;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnFilesTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnFilesTab.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- The object's folder as a real files browser, on the Files app's own\n\t\t primitives (its actions, its New menu, its breadcrumbs), when the\n\t\t folder resolves for this user. The list below is the fallback for an\n\t\t object with no folder, or a user the folder is not shared with. -->\n\t\t<CnFilesBrowser\n\t\t\tv-if=\"browserRoot !== null\"\n\t\t\t:rootPath=\"browserRoot\"\n\t\t\t:rootLabel=\"browserRootLabel\"\n\t\t\t:rowActions=\"rowActions\"\n\t\t\t:newActions=\"newActions\"\n\t\t\t:linkedItems=\"linkedItems\"\n\t\t\t@changed=\"onBrowserChanged\" />\n\t\t<template v-else>\n\t\t\t<!-- Upload error -->\n\t\t\t<div v-if=\"uploadError\" class=\"cn-sidebar-tab__upload-error\">\n\t\t\t\t{{ uploadError }}\n\t\t\t</div>\n\n\t\t\t<!-- Share toggle — seeds from schema config (defaultAutoShare) or\n\t\t from the `defaultShare` prop. Hidden via `showShareToggle=false`. -->\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-if=\"showShareToggle\"\n\t\t\t\tv-model=\"share\"\n\t\t\t\tclass=\"cn-sidebar-tab__share\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\ttype=\"switch\">\n\t\t\t\t{{ shareLabel }}\n\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t<!-- File drop zone -->\n\t\t\t<div\n\t\t\t\tclass=\"cn-sidebar-tab__dropzone\"\n\t\t\t\t:class=\"{ 'cn-sidebar-tab__dropzone--active': isDragOver }\"\n\t\t\t\t@click=\"triggerFileInput\"\n\t\t\t\t@dragover.prevent=\"onDragOver\"\n\t\t\t\t@dragleave.prevent=\"onDragLeave\"\n\t\t\t\t@drop.prevent=\"onDrop\">\n\t\t\t\t<!--\n\t\t\t\t`:ref` (dynamic), not `ref` (static), and this is load-bearing.\n\n\t\t\t\tEvery other binding on this input is static, and Vue caches the\n\t\t\t\t`@change` handler, so with a STATIC ref the compiler hoists the\n\t\t\t\twhole vnode to module scope. A hoisted vnode is created once,\n\t\t\t\toutside any render, so its ref carries no owner instance\n\t\t\t\t(`rawRef.i === null`).\n\n\t\t\t\t`setRef()` guards that — but the guard AND its early `return`\n\t\t\t\tlive inside `if (process.env.NODE_ENV !== 'production')`. In a\n\t\t\t\tdevelopment build you get the warning \"Missing ref owner\n\t\t\t\tcontext. ref cannot be used on hoisted vnodes.\" and nothing\n\t\t\t\tbreaks. In a PRODUCTION build the guard is compiled out and\n\t\t\t\texecution falls through to `owner.refs`, throwing\n\t\t\t\t`TypeError: Cannot read properties of null (reading 'refs')`\n\t\t\t\t— which aborts the render of whatever mounted this tab.\n\n\t\t\t\tMeasured: hrmq's detail pages (the only pages in the fleet that\n\t\t\t\treach CnIntegrationWidget through a `widgets[]` grid) rendered a\n\t\t\t\tCOMPLETELY BLANK content pane in production while looking fine\n\t\t\t\tin dev. A dynamic ref is compiled as a patchable prop, so the\n\t\t\t\tvnode is created inside the render function and owns a proper\n\t\t\t\tinstance.\n\t\t\t-->\n\t\t\t\t<input\n\t\t\t\t\t:ref=\"fileInputRef\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\tmultiple\n\t\t\t\t\tclass=\"cn-sidebar-tab__file-input\"\n\t\t\t\t\t@change=\"onFileUpload\">\n\t\t\t\t<Upload :size=\"24\" class=\"cn-sidebar-tab__dropzone-icon\" />\n\t\t\t\t<span class=\"cn-sidebar-tab__dropzone-text\">{{ dropZoneLabel }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- File list. Each row borrows what Nextcloud already has on this\n\t\t page: the theme's own mime icon (OC.MimeType), the core preview\n\t\t endpoint for images, the Viewer for opening, and the Files sidebar\n\t\t for details, sharing and versions. Nothing of the Files app is\n\t\t rebuilt here; the row hands over to it. -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t\t<NcEmptyContent\n\t\t\t\tv-else-if=\"files.length === 0\"\n\t\t\t\tclass=\"cn-sidebar-tab__empty\"\n\t\t\t\t:name=\"noFilesLabel\"\n\t\t\t\t:description=\"dropZoneLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Paperclip :size=\"44\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"file in files\"\n\t\t\t\t\t:key=\"file.id\"\n\t\t\t\t\t:name=\"file.name || file.title\"\n\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"openFile(file)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__thumb\"\n\t\t\t\t\t\t\t:src=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t@error=\"onPreviewError(file)\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-else-if=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__mime\"\n\t\t\t\t\t\t\t:src=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<FileOutline v-else :size=\"32\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-sidebar-tab__meta\">\n\t\t\t\t\t\t\t<span>{{ formatFileSize(file.size) }}</span>\n\t\t\t\t\t\t\t<template v-if=\"modifiedAt(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<NcDateTime :timestamp=\"modifiedAt(file)\" :ignoreSeconds=\"true\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t<template v-if=\"labelsOf(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<span>{{ labelsOf(file) }}</span>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"openFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"downloadUrlFor(file)\"\n\t\t\t\t\t\t\t:download=\"file.name || file.title || ''\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ downloadLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\tv-if=\"canShowDetails() && file.path\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t@click=\"showDetails(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<InformationOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ detailsLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"showInFilesUrl(file)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ showInFilesLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton v-if=\"file.id\" :closeAfterClick=\"true\" @click=\"copyLink(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkVariant :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ copyLinkLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"deleteFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"files.length < total\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:wide=\"true\"\n\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t@click=\"loadMore\">\n\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ loadMoreLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport {\n\tNcActionButton,\n\tNcActionLink,\n\tNcActionSeparator,\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcDateTime,\n\tNcEmptyContent,\n\tNcListItem,\n\tNcLoadingIcon,\n} from '@nextcloud/vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport FileOutline from 'vue-material-design-icons/FileOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Paperclip from 'vue-material-design-icons/Paperclip.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnFilesBrowser from '../CnFilesBrowser/CnFilesBrowser.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { resolveObjectFolder } from '../CnFilesBrowser/filesBrowser.js'\n\nexport default {\n\tname: 'CnFilesTab',\n\n\tcomponents: {\n\t\tCnFilesBrowser,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDateTime,\n\t\tNcEmptyContent,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tDelete,\n\t\tDownload,\n\t\tFileOutline,\n\t\tFolderOutline,\n\t\tInformationOutline,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPaperclip,\n\t\tUpload,\n\t},\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown inside the file drop zone */\n\t\tdropZoneLabel: { type: String, default: () => t('nextcloud-vue', 'Drop files here or click to browse') },\n\t\t/** Text shown when no files are attached */\n\t\tnoFilesLabel: { type: String, default: () => t('nextcloud-vue', 'No files attached') },\n\t\t/** Label for the open/view file action */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** What the files browser's root crumb reads; null shows the folder's own name, as the Files app does. */\n\t\tbrowserRootLabel: { type: String, default: null },\n\t\t/**\n\t\t * The host's own actions on each file row of the browser, forwarded\n\t\t * to CnFilesBrowser's `rowActions`: declared like any manifest action\n\t\t * and dispatched with the file's id, name and path merged in.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\trowActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * The host's own entries in the browser's New menu, forwarded to\n\t\t * CnFilesBrowser's `newActions`: declared like a row action and\n\t\t * dispatched with the folder rather than a row, for things like\n\t\t * \"new from template\" or \"request a file from a party\".\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\tnewActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * An app endpoint that answers the object's linked files, rows the\n\t\t * browser shows after the folder's own (files the host joined from\n\t\t * another object's folder). App-relative; `{objectId}` is replaced.\n\t\t * The response is an array (or `{ items: [] }`) of\n\t\t * `{ id, name, mime?, size?, mtime?, href?, downloadHref?, note?, noteHref? }`.\n\t\t * Null fetches nothing.\n\t\t */\n\t\tlinkedItemsUrl: { type: String, default: null },\n\t\t/** Label of the Download action. */\n\t\tdownloadLabel: { type: String, default: () => t('nextcloud-vue', 'Download') },\n\t\t/** Label of the action that opens the Files sidebar on the file. */\n\t\tdetailsLabel: { type: String, default: () => t('nextcloud-vue', 'Details and sharing') },\n\t\t/** Label of the link that opens the file in the Files app. */\n\t\tshowInFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Show in Files') },\n\t\t/** Label of the action that copies the file permalink. */\n\t\tcopyLinkLabel: { type: String, default: () => t('nextcloud-vue', 'Copy link') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Whether to render the \"share uploaded files\" toggle. Off by default;\n\t\t * when false, uploads never set the share flag (no auto-publish).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowShareToggle: { type: Boolean, default: false },\n\t\t/**\n\t\t * Initial state for the share toggle. `true`/`false` wins outright;\n\t\t * `null` (the default) defers to the schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister.\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\tdefaultShare: { type: Boolean, default: null },\n\t\t/** Label for the share toggle */\n\t\tshareLabel: { type: String, default: () => t('nextcloud-vue', 'Share uploaded files') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tfiles: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tisDragOver: false,\n\t\t\tuploadError: '',\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tshare: false,\n\t\t\t/** The object's folder as a user-relative path, or null while unresolved or absent. */\n\t\t\tbrowserRoot: null,\n\t\t\tlinkedItems: [],\n\t\t\t/** File ids whose preview request failed, so the row falls back to the mime icon. */\n\t\t\tpreviewFailed: {},\n\t\t\t/**\n\t\t\t * The file input element, set by the template's function ref.\n\t\t\t *\n\t\t\t * Held here rather than read back through `$refs` so the ref stays\n\t\t\t * DYNAMIC — see the long comment on the input itself for why a\n\t\t\t * static ref on this element is a production crash.\n\t\t\t *\n\t\t\t * @type {HTMLInputElement|null}\n\t\t\t */\n\t\t\tfileInputEl: null,\n\t\t}\n\t},\n\n\twatch: {\n\t\t// Match every other CnObjectSidebar tab — a single immediate\n\t\t// `objectId` watcher drives all initial loads. Folding the\n\t\t// share-toggle seed in here avoids two concurrent GETs of\n\t\t// `schemas/{schema}` on mount (one per immediate watcher).\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchFiles()\n\t\t\t\t}\n\t\t\t\tthis.applyShareDefault()\n\t\t\t\tthis.resolveBrowserRoot()\n\t\t\t\tthis.fetchLinkedItems()\n\t\t\t},\n\t\t},\n\n\t\tlinkedItemsUrl() {\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Function ref for the file input.\n\t\t *\n\t\t * A method (not an inline arrow in the template) so the binding is a\n\t\t * stable reference across renders and Vue does not detach/reattach the\n\t\t * ref on every patch. Being a function ref is what keeps the vnode\n\t\t * dynamic — see the template comment on the input.\n\t\t *\n\t\t * @param {HTMLInputElement|null} el The element, or null on unmount.\n\t\t * @return {void}\n\t\t */\n\t\tfileInputRef(el) {\n\t\t\tthis.fileInputEl = el || null\n\t\t},\n\n\t\t/**\n\t\t * Find the object's folder for the browser, or leave the legacy list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * The browser changed the folder: refresh the object's file list and\n\t\t * the linked rows, since a join or a move can change either.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonBrowserChanged() {\n\t\t\tthis.fetchFiles()\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\n\t\t/**\n\t\t * Read the object's linked files from the host's endpoint, if any.\n\t\t *\n\t\t * A failure leaves the last list in place and logs at debug: the\n\t\t * folder's own rows are the surface, the linked rows a supplement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchLinkedItems() {\n\t\t\tif (!this.linkedItemsUrl || !this.objectId) {\n\t\t\t\tthis.linkedItems = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(this.linkedItemsUrl.replace('{objectId}', encodeURIComponent(this.objectId)))\n\t\t\t\tconst { data } = await axios.get(url)\n\t\t\t\tconst items = Array.isArray(data) ? data : (Array.isArray(data?.items) ? data.items : [])\n\t\t\t\tthis.linkedItems = items.filter((item) => item && typeof item === 'object')\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.debug('[CnFilesTab] linked items not read', error)\n\t\t\t}\n\t\t},\n\n\t\tasync resolveBrowserRoot() {\n\t\t\tthis.browserRoot = null\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet remoteUrl\n\t\t\ttry {\n\t\t\t\tremoteUrl = generateRemoteUrl('dav')\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.browserRoot = await resolveObjectFolder({\n\t\t\t\tapiBase: this.apiBase,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tuid: getCurrentUser()?.uid || '',\n\t\t\t\tremoteUrl,\n\t\t\t})\n\t\t},\n\n\t\tasync fetchFiles(append = false) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (append) {\n\t\t\t\tthis.loadingMore = true\n\t\t\t} else {\n\t\t\t\tthis.loading = true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst params = new URLSearchParams({ limit: this.limit, _page: this.page })\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files?${params}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tthis.files = append ? [...this.files, ...results] : results\n\t\t\t\t\tthis.total = data.total || this.files.length\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('CnFilesTab: Failed to fetch files', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchFiles(true)\n\t\t},\n\n\t\t/**\n\t\t * Seed the `share` toggle. The `defaultShare` prop wins when set\n\t\t * (non-null); otherwise we look up the active schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister and use that.\n\t\t * Network failure or missing key → keep the safe default (false) so\n\t\t * a hiccup never silently flips uploads to \"share\".\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync applyShareDefault() {\n\t\t\tif (this.defaultShare !== null && this.defaultShare !== undefined) {\n\t\t\t\tthis.share = !!this.defaultShare\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.share = false\n\t\t\tif (!this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/schemas/${this.schema}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json().catch(() => null)\n\t\t\t\tif (data?.configuration?.defaultAutoShare === true) {\n\t\t\t\t\tthis.share = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Non-fatal — keep the safe default, but surface the\n\t\t\t\t// failure so a missing toggle default isn't silent.\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to fetch schema default for share toggle', err)\n\t\t\t}\n\t\t},\n\n\t\ttriggerFileInput() {\n\t\t\tthis.fileInputEl?.click()\n\t\t},\n\n\t\tonDragOver() {\n\t\t\tthis.isDragOver = true\n\t\t},\n\n\t\tonDragLeave() {\n\t\t\tthis.isDragOver = false\n\t\t},\n\n\t\tonDrop(event) {\n\t\t\tthis.isDragOver = false\n\t\t\tconst droppedFiles = event.dataTransfer?.files\n\t\t\tif (droppedFiles?.length) {\n\t\t\t\tthis.uploadFiles(droppedFiles)\n\t\t\t}\n\t\t},\n\n\t\tasync onFileUpload(event) {\n\t\t\tconst inputFiles = event.target.files\n\t\t\tif (!inputFiles?.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.uploadFiles(inputFiles)\n\t\t\tif (this.fileInputEl) {\n\t\t\t\tthis.fileInputEl.value = ''\n\t\t\t}\n\t\t},\n\n\t\tasync uploadFiles(fileList) {\n\t\t\tif (!fileList?.length || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.uploadError = ''\n\t\t\tconst formData = new FormData()\n\t\t\tfor (const file of fileList) {\n\t\t\t\tformData.append('files[]', file)\n\t\t\t}\n\t\t\t// Only forward the share flag when the toggle is actually visible.\n\t\t\t// Hiding the toggle (showShareToggle=false) means \"don't auto-publish\".\n\t\t\tif (this.showShareToggle) {\n\t\t\t\tformData.append('share', String(this.share))\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/filesMultipart`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { requesttoken: OC?.requestToken || '', 'OCS-APIREQUEST': 'true' },\n\t\t\t\t\t\tbody: formData,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.uploadError = data.error || `Upload failed (${response.status})`\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.fetchFiles()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to upload file', err)\n\t\t\t\tthis.uploadError = 'Upload failed: could not connect to server'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the Files app's details sidebar is on this page.\n\t\t *\n\t\t * It is when the host page dispatched Nextcloud's `LoadSidebar` event\n\t\t * server-side; then `OCA.Files.Sidebar.open(path)` shows the same\n\t\t * sharing, versions, comments and activity tabs the Files app shows.\n\t\t * Absent, the row offers no details action rather than a dead one. A\n\t\t * method rather than a computed: the global is not reactive, so a\n\t\t * cached answer from before the sidebar script ran would stay wrong.\n\t\t *\n\t\t * @return {boolean} true when the sidebar can be opened.\n\t\t */\n\t\tcanShowDetails() {\n\t\t\treturn typeof window !== 'undefined' && typeof window.OCA?.Files?.Sidebar?.open === 'function'\n\t\t},\n\n\t\t/**\n\t\t * The file's path relative to the user's files root, which is the path\n\t\t * the Viewer and the Files sidebar take. OpenRegister reports the node's\n\t\t * full path (`/{uid}/files/…`), so the first two segments come off.\n\t\t *\n\t\t * @param {string} path The node path as OpenRegister reports it.\n\t\t * @return {string} The user-relative path, `/` at least.\n\t\t */\n\t\tuserRelativePath(path) {\n\t\t\tconst stripped = String(path || '').replace(/^\\/[^/]+\\/files(?=\\/|$)/, '')\n\t\t\treturn stripped === '' ? '/' : stripped\n\t\t},\n\n\t\t/**\n\t\t * The theme's own icon for the file's mime type, the one the Files app\n\t\t * draws, or null on a page without Nextcloud's core script.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The icon url.\n\t\t */\n\t\tmimeIconFor(file) {\n\t\t\tconst getIconUrl = typeof window !== 'undefined' ? window.OC?.MimeType?.getIconUrl : null\n\t\t\tif (typeof getIconUrl !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\ttry {\n\t\t\t\treturn getIconUrl(mime) || null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A small preview for an image, through Nextcloud's core preview\n\t\t * endpoint, or null for anything else or after the preview failed once.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The preview url.\n\t\t */\n\t\tpreviewUrlFor(file) {\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tif (!file.id || !/^image\\//i.test(mime) || /svg/i.test(mime) || this.previewFailed[file.id]) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/core/preview?fileId={fileId}&x=64&y=64&a=1', { fileId: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Remember that a preview did not load, so the row shows the mime icon.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tonPreviewError(file) {\n\t\t\tthis.previewFailed = { ...this.previewFailed, [file.id]: true }\n\t\t},\n\n\t\t/**\n\t\t * The file's modification moment as a Date, or null when unknown.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Date|null} The moment.\n\t\t */\n\t\tmodifiedAt(file) {\n\t\t\tconst raw = file.modified || file.updated || ''\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = new Date(raw)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * The file's labels (Nextcloud tags), joined for the meta line.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The labels, or the empty string.\n\t\t */\n\t\tlabelsOf(file) {\n\t\t\treturn Array.isArray(file.labels) ? file.labels.filter(Boolean).join(', ') : ''\n\t\t},\n\n\t\t/**\n\t\t * The download url for a file, through OpenRegister's file endpoint,\n\t\t * which streams the node the object owns.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tdownloadUrlFor(file) {\n\t\t\treturn `${this.apiBase}/files/${encodeURIComponent(String(file.id))}/download`\n\t\t},\n\n\t\t/**\n\t\t * The Files app's permalink for a file: opens the Files app at the\n\t\t * file's folder with the file selected.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tshowInFilesUrl(file) {\n\t\t\treturn generateUrl('/f/{fileid}', { fileid: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Open the Files sidebar on this file: details, sharing, versions,\n\t\t * comments and activity, exactly as the Files app offers them.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tshowDetails(file) {\n\t\t\tif (!this.canShowDetails() || !file.path) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\twindow.OCA.Files.Sidebar.open(this.userRelativePath(file.path))\n\t\t},\n\n\t\t/**\n\t\t * Put the file's permalink on the clipboard and say so.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync copyLink(file) {\n\t\t\tconst href = new URL(this.showInFilesUrl(file), window.location.origin).href\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(href)\n\t\t\t\tconst { showSuccess } = await import('@nextcloud/dialogs')\n\t\t\t\tshowSuccess(t('nextcloud-vue', 'Link copied'))\n\t\t\t} catch {\n\t\t\t\tconst { showError } = await import('@nextcloud/dialogs')\n\t\t\t\tshowError(t('nextcloud-vue', 'The link could not be copied'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether Nextcloud's Viewer is on this page and handles the file.\n\t\t *\n\t\t * The Viewer is there when the host page dispatched `LoadViewer`\n\t\t * server-side; it lists the mime types it can show, and a type it\n\t\t * cannot falls through to the next way of opening the file.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {boolean} true when the Viewer can open it in place.\n\t\t */\n\t\tviewerHandles(file) {\n\t\t\tconst viewer = typeof window !== 'undefined' ? window.OCA?.Viewer : null\n\t\t\tif (!viewer || typeof viewer.open !== 'function' || !file.path) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tconst mimetypes = Array.isArray(viewer.mimetypes) ? viewer.mimetypes : null\n\t\t\treturn mimetypes === null ? true : mimetypes.includes(mime)\n\t\t},\n\n\t\topenFile(file) {\n\t\t\t// The Viewer first: it opens the file over this page, so the reader\n\t\t\t// stays on the object. A public share link and the Files app come\n\t\t\t// after, in that order, when the Viewer is absent or cannot show\n\t\t\t// the type.\n\t\t\tif (this.viewerHandles(file)) {\n\t\t\t\twindow.OCA.Viewer.open({ path: this.userRelativePath(file.path) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (file.accessUrl) {\n\t\t\t\t// Security: accessUrl originates from the OR files API and may be\n\t\t\t\t// attacker-controlled. Validate the scheme via safeHref before\n\t\t\t\t// opening (C4) — this blocks javascript: / data: payloads. Add\n\t\t\t\t// noopener,noreferrer to prevent the opened tab from accessing\n\t\t\t\t// window.opener (reverse-tabnabbing) and to strip the Referer header.\n\t\t\t\tconst safe = safeHref(file.accessUrl)\n\t\t\t\tif (safe !== '#') {\n\t\t\t\t\twindow.open(safe, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t} else if (file.id) {\n\t\t\t\tconst dirPath = file.path ? file.path.substring(0, file.path.lastIndexOf('/')) : ''\n\t\t\t\tconst cleanPath = dirPath.replace(/^\\/admin\\/files\\//, '/')\n\t\t\t\twindow.open(`/index.php/apps/files/files/${file.id}?dir=${encodeURIComponent(cleanPath)}&openfile=true`, '_blank')\n\t\t\t}\n\t\t},\n\n\t\tasync deleteFile(file) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files/${file.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.files = this.files.filter((f) => f.id !== file.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to delete file', err)\n\t\t\t}\n\t\t},\n\n\t\tformatFileSize(bytes) {\n\t\t\tconst sizes = ['Bytes', 'KB', 'MB', 'GB']\n\t\t\tif (!bytes || bytes === 0) {\n\t\t\t\treturn 'n/a'\n\t\t\t}\n\t\t\tconst i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n\t\t\tif (i === 0) {\n\t\t\t\treturn '< 1 KB'\n\t\t\t}\n\t\t\treturn (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__upload-error {\n\tpadding: 8px 12px;\n\tmargin-bottom: 8px;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground-color: var(--color-error-light, rgba(229, 57, 53, 0.1));\n\tcolor: var(--color-error, #e53935);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__dropzone {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 20px 12px;\n\tmargin-bottom: 16px;\n\tborder: 2px dashed var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tcursor: pointer;\n\ttransition: border-color 0.15s ease, background-color 0.15s ease;\n}\n\n.cn-sidebar-tab__dropzone:hover {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.08));\n}\n\n.cn-sidebar-tab__dropzone--active {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.12));\n}\n\n.cn-sidebar-tab__share { margin-bottom: 12px; }\n\n.cn-sidebar-tab__dropzone-icon { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__dropzone--active .cn-sidebar-tab__dropzone-icon,\n.cn-sidebar-tab__dropzone:hover .cn-sidebar-tab__dropzone-icon { color: var(--color-primary-element); }\n\n.cn-sidebar-tab__dropzone-text { font-size: 13px; color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__file-input { display: none; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-sidebar-tab__mime,\n.cn-sidebar-tab__thumb {\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: block;\n}\n\n.cn-sidebar-tab__thumb {\n\tobject-fit: cover;\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-sidebar-tab__meta { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n</style>\n"],"names":["CnFilesBrowser","t","axios"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFilesTab.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnFilesTab.vue?vue&type=template&id=6b917036&lang.js"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- The object's folder as a real files browser, on the Files app's own\n\t\t primitives (its actions, its New menu, its breadcrumbs), when the\n\t\t folder resolves for this user. The list below is the fallback for an\n\t\t object with no folder, or a user the folder is not shared with. -->\n\t\t<CnFilesBrowser\n\t\t\tv-if=\"browserRoot !== null\"\n\t\t\t:rootPath=\"browserRoot\"\n\t\t\t:rootLabel=\"browserRootLabel\"\n\t\t\t:rowActions=\"rowActions\"\n\t\t\t:newActions=\"newActions\"\n\t\t\t:linkedItems=\"linkedItems\"\n\t\t\t@changed=\"onBrowserChanged\" />\n\t\t<template v-else>\n\t\t\t<!-- Upload error -->\n\t\t\t<div v-if=\"uploadError\" class=\"cn-sidebar-tab__upload-error\">\n\t\t\t\t{{ uploadError }}\n\t\t\t</div>\n\n\t\t\t<!-- Share toggle — seeds from schema config (defaultAutoShare) or\n\t\t from the `defaultShare` prop. Hidden via `showShareToggle=false`. -->\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-if=\"showShareToggle\"\n\t\t\t\tv-model=\"share\"\n\t\t\t\tclass=\"cn-sidebar-tab__share\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\ttype=\"switch\">\n\t\t\t\t{{ shareLabel }}\n\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t<!-- File drop zone -->\n\t\t\t<div\n\t\t\t\tclass=\"cn-sidebar-tab__dropzone\"\n\t\t\t\t:class=\"{ 'cn-sidebar-tab__dropzone--active': isDragOver }\"\n\t\t\t\t@click=\"triggerFileInput\"\n\t\t\t\t@dragover.prevent=\"onDragOver\"\n\t\t\t\t@dragleave.prevent=\"onDragLeave\"\n\t\t\t\t@drop.prevent=\"onDrop\">\n\t\t\t\t<!--\n\t\t\t\t`:ref` (dynamic), not `ref` (static), and this is load-bearing.\n\n\t\t\t\tEvery other binding on this input is static, and Vue caches the\n\t\t\t\t`@change` handler, so with a STATIC ref the compiler hoists the\n\t\t\t\twhole vnode to module scope. A hoisted vnode is created once,\n\t\t\t\toutside any render, so its ref carries no owner instance\n\t\t\t\t(`rawRef.i === null`).\n\n\t\t\t\t`setRef()` guards that — but the guard AND its early `return`\n\t\t\t\tlive inside `if (process.env.NODE_ENV !== 'production')`. In a\n\t\t\t\tdevelopment build you get the warning \"Missing ref owner\n\t\t\t\tcontext. ref cannot be used on hoisted vnodes.\" and nothing\n\t\t\t\tbreaks. In a PRODUCTION build the guard is compiled out and\n\t\t\t\texecution falls through to `owner.refs`, throwing\n\t\t\t\t`TypeError: Cannot read properties of null (reading 'refs')`\n\t\t\t\t— which aborts the render of whatever mounted this tab.\n\n\t\t\t\tMeasured: hrmq's detail pages (the only pages in the fleet that\n\t\t\t\treach CnIntegrationWidget through a `widgets[]` grid) rendered a\n\t\t\t\tCOMPLETELY BLANK content pane in production while looking fine\n\t\t\t\tin dev. A dynamic ref is compiled as a patchable prop, so the\n\t\t\t\tvnode is created inside the render function and owns a proper\n\t\t\t\tinstance.\n\t\t\t-->\n\t\t\t\t<input\n\t\t\t\t\t:ref=\"fileInputRef\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\tmultiple\n\t\t\t\t\tclass=\"cn-sidebar-tab__file-input\"\n\t\t\t\t\t@change=\"onFileUpload\">\n\t\t\t\t<Upload :size=\"24\" class=\"cn-sidebar-tab__dropzone-icon\" />\n\t\t\t\t<span class=\"cn-sidebar-tab__dropzone-text\">{{ dropZoneLabel }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- File list. Each row borrows what Nextcloud already has on this\n\t\t page: the theme's own mime icon (OC.MimeType), the core preview\n\t\t endpoint for images, the Viewer for opening, and the Files sidebar\n\t\t for details, sharing and versions. Nothing of the Files app is\n\t\t rebuilt here; the row hands over to it. -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t\t<NcEmptyContent\n\t\t\t\tv-else-if=\"files.length === 0\"\n\t\t\t\tclass=\"cn-sidebar-tab__empty\"\n\t\t\t\t:name=\"noFilesLabel\"\n\t\t\t\t:description=\"dropZoneLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Paperclip :size=\"44\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"file in files\"\n\t\t\t\t\t:key=\"file.id\"\n\t\t\t\t\t:name=\"file.name || file.title\"\n\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"openFile(file)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__thumb\"\n\t\t\t\t\t\t\t:src=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t@error=\"onPreviewError(file)\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-else-if=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__mime\"\n\t\t\t\t\t\t\t:src=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<FileOutline v-else :size=\"32\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-sidebar-tab__meta\">\n\t\t\t\t\t\t\t<span>{{ formatFileSize(file.size) }}</span>\n\t\t\t\t\t\t\t<template v-if=\"modifiedAt(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<NcDateTime :timestamp=\"modifiedAt(file)\" :ignoreSeconds=\"true\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t<template v-if=\"labelsOf(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<span>{{ labelsOf(file) }}</span>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"openFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"downloadUrlFor(file)\"\n\t\t\t\t\t\t\t:download=\"file.name || file.title || ''\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ downloadLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\tv-if=\"canShowDetails() && file.path\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t@click=\"showDetails(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<InformationOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ detailsLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"showInFilesUrl(file)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ showInFilesLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton v-if=\"file.id\" :closeAfterClick=\"true\" @click=\"copyLink(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkVariant :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ copyLinkLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"deleteFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"files.length < total\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:wide=\"true\"\n\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t@click=\"loadMore\">\n\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ loadMoreLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport {\n\tNcActionButton,\n\tNcActionLink,\n\tNcActionSeparator,\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcDateTime,\n\tNcEmptyContent,\n\tNcListItem,\n\tNcLoadingIcon,\n} from '@nextcloud/vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport FileOutline from 'vue-material-design-icons/FileOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Paperclip from 'vue-material-design-icons/Paperclip.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnFilesBrowser from '../CnFilesBrowser/CnFilesBrowser.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { resolveObjectFolder } from '../CnFilesBrowser/filesBrowser.js'\n\nexport default {\n\tname: 'CnFilesTab',\n\n\tcomponents: {\n\t\tCnFilesBrowser,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDateTime,\n\t\tNcEmptyContent,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tDelete,\n\t\tDownload,\n\t\tFileOutline,\n\t\tFolderOutline,\n\t\tInformationOutline,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPaperclip,\n\t\tUpload,\n\t},\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown inside the file drop zone */\n\t\tdropZoneLabel: { type: String, default: () => t('nextcloud-vue', 'Drop files here or click to browse') },\n\t\t/** Text shown when no files are attached */\n\t\tnoFilesLabel: { type: String, default: () => t('nextcloud-vue', 'No files attached') },\n\t\t/** Label for the open/view file action */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** What the files browser's root crumb reads; null shows the folder's own name, as the Files app does. */\n\t\tbrowserRootLabel: { type: String, default: null },\n\t\t/**\n\t\t * The host's own actions on each file row of the browser, forwarded\n\t\t * to CnFilesBrowser's `rowActions`: declared like any manifest action\n\t\t * and dispatched with the file's id, name and path merged in.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\trowActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * The host's own entries in the browser's New menu, forwarded to\n\t\t * CnFilesBrowser's `newActions`: declared like a row action and\n\t\t * dispatched with the folder rather than a row, for things like\n\t\t * \"new from template\" or \"request a file from a party\".\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\tnewActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * An app endpoint that answers the object's linked files, rows the\n\t\t * browser shows after the folder's own (files the host joined from\n\t\t * another object's folder). App-relative; `{objectId}` is replaced.\n\t\t * The response is an array (or `{ items: [] }`) of\n\t\t * `{ id, name, mime?, size?, mtime?, href?, downloadHref?, note?, noteHref? }`.\n\t\t * Null fetches nothing.\n\t\t */\n\t\tlinkedItemsUrl: { type: String, default: null },\n\t\t/** Label of the Download action. */\n\t\tdownloadLabel: { type: String, default: () => t('nextcloud-vue', 'Download') },\n\t\t/** Label of the action that opens the Files sidebar on the file. */\n\t\tdetailsLabel: { type: String, default: () => t('nextcloud-vue', 'Details and sharing') },\n\t\t/** Label of the link that opens the file in the Files app. */\n\t\tshowInFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Show in Files') },\n\t\t/** Label of the action that copies the file permalink. */\n\t\tcopyLinkLabel: { type: String, default: () => t('nextcloud-vue', 'Copy link') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Whether to render the \"share uploaded files\" toggle. Off by default;\n\t\t * when false, uploads never set the share flag (no auto-publish).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowShareToggle: { type: Boolean, default: false },\n\t\t/**\n\t\t * Initial state for the share toggle. `true`/`false` wins outright;\n\t\t * `null` (the default) defers to the schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister.\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\tdefaultShare: { type: Boolean, default: null },\n\t\t/** Label for the share toggle */\n\t\tshareLabel: { type: String, default: () => t('nextcloud-vue', 'Share uploaded files') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tfiles: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tisDragOver: false,\n\t\t\tuploadError: '',\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tshare: false,\n\t\t\t/** The object's folder as a user-relative path, or null while unresolved or absent. */\n\t\t\tbrowserRoot: null,\n\t\t\tlinkedItems: [],\n\t\t\t/** File ids whose preview request failed, so the row falls back to the mime icon. */\n\t\t\tpreviewFailed: {},\n\t\t\t/**\n\t\t\t * The file input element, set by the template's function ref.\n\t\t\t *\n\t\t\t * Held here rather than read back through `$refs` so the ref stays\n\t\t\t * DYNAMIC — see the long comment on the input itself for why a\n\t\t\t * static ref on this element is a production crash.\n\t\t\t *\n\t\t\t * @type {HTMLInputElement|null}\n\t\t\t */\n\t\t\tfileInputEl: null,\n\t\t}\n\t},\n\n\twatch: {\n\t\t// Match every other CnObjectSidebar tab — a single immediate\n\t\t// `objectId` watcher drives all initial loads. Folding the\n\t\t// share-toggle seed in here avoids two concurrent GETs of\n\t\t// `schemas/{schema}` on mount (one per immediate watcher).\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchFiles()\n\t\t\t\t}\n\t\t\t\tthis.applyShareDefault()\n\t\t\t\tthis.resolveBrowserRoot()\n\t\t\t\tthis.fetchLinkedItems()\n\t\t\t},\n\t\t},\n\n\t\tlinkedItemsUrl() {\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Function ref for the file input.\n\t\t *\n\t\t * A method (not an inline arrow in the template) so the binding is a\n\t\t * stable reference across renders and Vue does not detach/reattach the\n\t\t * ref on every patch. Being a function ref is what keeps the vnode\n\t\t * dynamic — see the template comment on the input.\n\t\t *\n\t\t * @param {HTMLInputElement|null} el The element, or null on unmount.\n\t\t * @return {void}\n\t\t */\n\t\tfileInputRef(el) {\n\t\t\tthis.fileInputEl = el || null\n\t\t},\n\n\t\t/**\n\t\t * Find the object's folder for the browser, or leave the legacy list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * The browser changed the folder: refresh the object's file list and\n\t\t * the linked rows, since a join or a move can change either.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonBrowserChanged() {\n\t\t\tthis.fetchFiles()\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\n\t\t/**\n\t\t * Read the object's linked files from the host's endpoint, if any.\n\t\t *\n\t\t * A failure leaves the last list in place and logs at debug: the\n\t\t * folder's own rows are the surface, the linked rows a supplement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchLinkedItems() {\n\t\t\tif (!this.linkedItemsUrl || !this.objectId) {\n\t\t\t\tthis.linkedItems = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(this.linkedItemsUrl.replace('{objectId}', encodeURIComponent(this.objectId)))\n\t\t\t\tconst { data } = await axios.get(url)\n\t\t\t\tconst items = Array.isArray(data) ? data : (Array.isArray(data?.items) ? data.items : [])\n\t\t\t\tthis.linkedItems = items.filter((item) => item && typeof item === 'object')\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.debug('[CnFilesTab] linked items not read', error)\n\t\t\t}\n\t\t},\n\n\t\tasync resolveBrowserRoot() {\n\t\t\tthis.browserRoot = null\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet remoteUrl\n\t\t\ttry {\n\t\t\t\tremoteUrl = generateRemoteUrl('dav')\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.browserRoot = await resolveObjectFolder({\n\t\t\t\tapiBase: this.apiBase,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tuid: getCurrentUser()?.uid || '',\n\t\t\t\tremoteUrl,\n\t\t\t})\n\t\t},\n\n\t\tasync fetchFiles(append = false) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (append) {\n\t\t\t\tthis.loadingMore = true\n\t\t\t} else {\n\t\t\t\tthis.loading = true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst params = new URLSearchParams({ limit: this.limit, _page: this.page })\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files?${params}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tthis.files = append ? [...this.files, ...results] : results\n\t\t\t\t\tthis.total = data.total || this.files.length\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('CnFilesTab: Failed to fetch files', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchFiles(true)\n\t\t},\n\n\t\t/**\n\t\t * Seed the `share` toggle. The `defaultShare` prop wins when set\n\t\t * (non-null); otherwise we look up the active schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister and use that.\n\t\t * Network failure or missing key → keep the safe default (false) so\n\t\t * a hiccup never silently flips uploads to \"share\".\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync applyShareDefault() {\n\t\t\tif (this.defaultShare !== null && this.defaultShare !== undefined) {\n\t\t\t\tthis.share = !!this.defaultShare\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.share = false\n\t\t\tif (!this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/schemas/${this.schema}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json().catch(() => null)\n\t\t\t\tif (data?.configuration?.defaultAutoShare === true) {\n\t\t\t\t\tthis.share = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Non-fatal — keep the safe default, but surface the\n\t\t\t\t// failure so a missing toggle default isn't silent.\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to fetch schema default for share toggle', err)\n\t\t\t}\n\t\t},\n\n\t\ttriggerFileInput() {\n\t\t\tthis.fileInputEl?.click()\n\t\t},\n\n\t\tonDragOver() {\n\t\t\tthis.isDragOver = true\n\t\t},\n\n\t\tonDragLeave() {\n\t\t\tthis.isDragOver = false\n\t\t},\n\n\t\tonDrop(event) {\n\t\t\tthis.isDragOver = false\n\t\t\tconst droppedFiles = event.dataTransfer?.files\n\t\t\tif (droppedFiles?.length) {\n\t\t\t\tthis.uploadFiles(droppedFiles)\n\t\t\t}\n\t\t},\n\n\t\tasync onFileUpload(event) {\n\t\t\tconst inputFiles = event.target.files\n\t\t\tif (!inputFiles?.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.uploadFiles(inputFiles)\n\t\t\tif (this.fileInputEl) {\n\t\t\t\tthis.fileInputEl.value = ''\n\t\t\t}\n\t\t},\n\n\t\tasync uploadFiles(fileList) {\n\t\t\tif (!fileList?.length || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.uploadError = ''\n\t\t\tconst formData = new FormData()\n\t\t\tfor (const file of fileList) {\n\t\t\t\tformData.append('files[]', file)\n\t\t\t}\n\t\t\t// Only forward the share flag when the toggle is actually visible.\n\t\t\t// Hiding the toggle (showShareToggle=false) means \"don't auto-publish\".\n\t\t\tif (this.showShareToggle) {\n\t\t\t\tformData.append('share', String(this.share))\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/filesMultipart`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { requesttoken: OC?.requestToken || '', 'OCS-APIREQUEST': 'true' },\n\t\t\t\t\t\tbody: formData,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.uploadError = data.error || `Upload failed (${response.status})`\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.fetchFiles()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to upload file', err)\n\t\t\t\tthis.uploadError = 'Upload failed: could not connect to server'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the Files app's details sidebar is on this page.\n\t\t *\n\t\t * It is when the host page dispatched Nextcloud's `LoadSidebar` event\n\t\t * server-side; then `OCA.Files.Sidebar.open(path)` shows the same\n\t\t * sharing, versions, comments and activity tabs the Files app shows.\n\t\t * Absent, the row offers no details action rather than a dead one. A\n\t\t * method rather than a computed: the global is not reactive, so a\n\t\t * cached answer from before the sidebar script ran would stay wrong.\n\t\t *\n\t\t * @return {boolean} true when the sidebar can be opened.\n\t\t */\n\t\tcanShowDetails() {\n\t\t\treturn typeof window !== 'undefined' && typeof window.OCA?.Files?.Sidebar?.open === 'function'\n\t\t},\n\n\t\t/**\n\t\t * The file's path relative to the user's files root, which is the path\n\t\t * the Viewer and the Files sidebar take. OpenRegister reports the node's\n\t\t * full path (`/{uid}/files/…`), so the first two segments come off.\n\t\t *\n\t\t * @param {string} path The node path as OpenRegister reports it.\n\t\t * @return {string} The user-relative path, `/` at least.\n\t\t */\n\t\tuserRelativePath(path) {\n\t\t\tconst stripped = String(path || '').replace(/^\\/[^/]+\\/files(?=\\/|$)/, '')\n\t\t\treturn stripped === '' ? '/' : stripped\n\t\t},\n\n\t\t/**\n\t\t * The theme's own icon for the file's mime type, the one the Files app\n\t\t * draws, or null on a page without Nextcloud's core script.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The icon url.\n\t\t */\n\t\tmimeIconFor(file) {\n\t\t\tconst getIconUrl = typeof window !== 'undefined' ? window.OC?.MimeType?.getIconUrl : null\n\t\t\tif (typeof getIconUrl !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\ttry {\n\t\t\t\treturn getIconUrl(mime) || null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A small preview for an image, through Nextcloud's core preview\n\t\t * endpoint, or null for anything else or after the preview failed once.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The preview url.\n\t\t */\n\t\tpreviewUrlFor(file) {\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tif (!file.id || !/^image\\//i.test(mime) || /svg/i.test(mime) || this.previewFailed[file.id]) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/core/preview?fileId={fileId}&x=64&y=64&a=1', { fileId: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Remember that a preview did not load, so the row shows the mime icon.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tonPreviewError(file) {\n\t\t\tthis.previewFailed = { ...this.previewFailed, [file.id]: true }\n\t\t},\n\n\t\t/**\n\t\t * The file's modification moment as a Date, or null when unknown.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Date|null} The moment.\n\t\t */\n\t\tmodifiedAt(file) {\n\t\t\tconst raw = file.modified || file.updated || ''\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = new Date(raw)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * The file's labels (Nextcloud tags), joined for the meta line.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The labels, or the empty string.\n\t\t */\n\t\tlabelsOf(file) {\n\t\t\treturn Array.isArray(file.labels) ? file.labels.filter(Boolean).join(', ') : ''\n\t\t},\n\n\t\t/**\n\t\t * The download url for a file, through OpenRegister's file endpoint,\n\t\t * which streams the node the object owns.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tdownloadUrlFor(file) {\n\t\t\treturn `${this.apiBase}/files/${encodeURIComponent(String(file.id))}/download`\n\t\t},\n\n\t\t/**\n\t\t * The Files app's permalink for a file: opens the Files app at the\n\t\t * file's folder with the file selected.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tshowInFilesUrl(file) {\n\t\t\treturn generateUrl('/f/{fileid}', { fileid: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Open the Files sidebar on this file: details, sharing, versions,\n\t\t * comments and activity, exactly as the Files app offers them.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tshowDetails(file) {\n\t\t\tif (!this.canShowDetails() || !file.path) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\twindow.OCA.Files.Sidebar.open(this.userRelativePath(file.path))\n\t\t},\n\n\t\t/**\n\t\t * Put the file's permalink on the clipboard and say so.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync copyLink(file) {\n\t\t\tconst href = new URL(this.showInFilesUrl(file), window.location.origin).href\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(href)\n\t\t\t\tconst { showSuccess } = await import('@nextcloud/dialogs')\n\t\t\t\tshowSuccess(t('nextcloud-vue', 'Link copied'))\n\t\t\t} catch {\n\t\t\t\tconst { showError } = await import('@nextcloud/dialogs')\n\t\t\t\tshowError(t('nextcloud-vue', 'The link could not be copied'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether Nextcloud's Viewer is on this page and handles the file.\n\t\t *\n\t\t * The Viewer is there when the host page dispatched `LoadViewer`\n\t\t * server-side; it lists the mime types it can show, and a type it\n\t\t * cannot falls through to the next way of opening the file.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {boolean} true when the Viewer can open it in place.\n\t\t */\n\t\tviewerHandles(file) {\n\t\t\tconst viewer = typeof window !== 'undefined' ? window.OCA?.Viewer : null\n\t\t\tif (!viewer || typeof viewer.open !== 'function' || !file.path) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tconst mimetypes = Array.isArray(viewer.mimetypes) ? viewer.mimetypes : null\n\t\t\treturn mimetypes === null ? true : mimetypes.includes(mime)\n\t\t},\n\n\t\topenFile(file) {\n\t\t\t// The Viewer first: it opens the file over this page, so the reader\n\t\t\t// stays on the object. A public share link and the Files app come\n\t\t\t// after, in that order, when the Viewer is absent or cannot show\n\t\t\t// the type.\n\t\t\tif (this.viewerHandles(file)) {\n\t\t\t\twindow.OCA.Viewer.open({ path: this.userRelativePath(file.path) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (file.accessUrl) {\n\t\t\t\t// Security: accessUrl originates from the OR files API and may be\n\t\t\t\t// attacker-controlled. Validate the scheme via safeHref before\n\t\t\t\t// opening (C4) — this blocks javascript: / data: payloads. Add\n\t\t\t\t// noopener,noreferrer to prevent the opened tab from accessing\n\t\t\t\t// window.opener (reverse-tabnabbing) and to strip the Referer header.\n\t\t\t\tconst safe = safeHref(file.accessUrl)\n\t\t\t\tif (safe !== '#') {\n\t\t\t\t\twindow.open(safe, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t} else if (file.id) {\n\t\t\t\tconst dirPath = file.path ? file.path.substring(0, file.path.lastIndexOf('/')) : ''\n\t\t\t\tconst cleanPath = dirPath.replace(/^\\/admin\\/files\\//, '/')\n\t\t\t\twindow.open(`/index.php/apps/files/files/${file.id}?dir=${encodeURIComponent(cleanPath)}&openfile=true`, '_blank')\n\t\t\t}\n\t\t},\n\n\t\tasync deleteFile(file) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files/${file.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.files = this.files.filter((f) => f.id !== file.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to delete file', err)\n\t\t\t}\n\t\t},\n\n\t\tformatFileSize(bytes) {\n\t\t\tconst sizes = ['Bytes', 'KB', 'MB', 'GB']\n\t\t\tif (!bytes || bytes === 0) {\n\t\t\t\treturn 'n/a'\n\t\t\t}\n\t\t\tconst i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n\t\t\tif (i === 0) {\n\t\t\t\treturn '< 1 KB'\n\t\t\t}\n\t\t\treturn (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__upload-error {\n\tpadding: 8px 12px;\n\tmargin-bottom: 8px;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground-color: var(--color-error-light, rgba(229, 57, 53, 0.1));\n\tcolor: var(--color-error, #e53935);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__dropzone {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 20px 12px;\n\tmargin-bottom: 16px;\n\tborder: 2px dashed var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tcursor: pointer;\n\ttransition: border-color 0.15s ease, background-color 0.15s ease;\n}\n\n.cn-sidebar-tab__dropzone:hover {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.08));\n}\n\n.cn-sidebar-tab__dropzone--active {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.12));\n}\n\n.cn-sidebar-tab__share { margin-bottom: 12px; }\n\n.cn-sidebar-tab__dropzone-icon { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__dropzone--active .cn-sidebar-tab__dropzone-icon,\n.cn-sidebar-tab__dropzone:hover .cn-sidebar-tab__dropzone-icon { color: var(--color-primary-element); }\n\n.cn-sidebar-tab__dropzone-text { font-size: 13px; color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__file-input { display: none; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-sidebar-tab__mime,\n.cn-sidebar-tab__thumb {\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: block;\n}\n\n.cn-sidebar-tab__thumb {\n\tobject-fit: cover;\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-sidebar-tab__meta { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n</style>\n"],"names":["_openBlock","_createElementBlock","_createBlock","_Fragment","_toDisplayString","_createElementVNode","_normalizeClass","_createVNode","_renderList","_createTextVNode"],"mappings":";;AACM,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,gBAAgB,GAAA;;;AAeD,EAAA,KAAK,EAAC,8BAA8B;;AAuDrD,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,+BAA+B,GAAA;;;AAkBhC,EAAA,KAAK,EAAC,sBAAsB;;;;AAwB/B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;;;;;;;;;;;;;;;;;;;;;;AAhHvC,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,CA8LK,OA9LL,UA8LK,EAAA;KAxLG,KAAY,CAAA,WAAA,KAAA,IAAA;sBADnBC,WAO8B,CAAA,yBAAA,EAAA;;AAL5B,UAAA,QAAQ,EAAE,KAAW,CAAA,WAAA;AACrB,UAAA,SAAS,EAAE,MAAgB,CAAA,gBAAA;AAC3B,UAAA,UAAU,EAAE,MAAU,CAAA,UAAA;AACtB,UAAA,UAAU,EAAE,MAAU,CAAA,UAAA;AACtB,UAAA,WAAW,EAAE,KAAW,CAAA,WAAA;AACxB,UAAA,SAAO,EAAE,QAAgB,CAAA,gBAAA;;sBAC3BD,kBAgLU,CAAAE,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;WA9KE,KAAW,CAAA,WAAA;4BAAtBF,kBAEK,CAAA,KAAA,EAFL,UAEK,EAAAG,eAAA,CADD,KAAU,CAAA,WAAA,CAAA,EAAA,CAAA,YAAA;;WAMP,MAAe,CAAA,eAAA;4BADtBF,WAOuB,CAAA,gCAAA,EAAA;;4BALb,KAAK,CAAA,KAAA;6EAAL,KAAK,CAAA,KAAA,IAAA,MAAA,CAAA,CAAA;AACd,gBAAA,KAAK,EAAC,uBAAsB;AAC3B,gBAAA,QAAQ,EAAE,KAAO,CAAA,OAAA;AAClB,gBAAA,IAAI,EAAC,QAAQ;;iCACb,MAAe;kDAAZ,MAAS,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;;;;;UAIbG,kBAwCK,CAAA,KAAA,EAAA;YAvCJ,KAAK,EAAAC,cAAA,CAAA,CAAC,0BAAyB,EAAA,EAAA,kCAAA,EACe,KAAS,CAAA,UAAA,EAAA,CAAA,CAAA;AACtD,YAAA,OAAK,0CAAE,QAAgB,CAAA,gBAAA,IAAA,QAAA,CAAA,gBAAA,CAAA,GAAA,IAAA,CAAA,CAAA,CAAA;AACvB,YAAA,UAAQ,wDAAU,QAAU,CAAA,UAAA,IAAA,QAAA,CAAA,UAAA,CAAA,GAAA,IAAA,CAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AAC5B,YAAA,WAAS,wDAAU,QAAW,CAAA,WAAA,IAAA,QAAA,CAAA,WAAA,CAAA,GAAA,IAAA,CAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AAC9B,YAAA,MAAI,wDAAU,QAAM,CAAA,MAAA,IAAA,QAAA,CAAA,MAAA,CAAA,GAAA,IAAA,CAAA,CAAA,EAAA,CAAA,SAAA,CAAA,CAAA,CAAA;;YA0BrBD,kBAKuB,CAAA,OAAA,EAAA;AAJrB,cAAA,GAAG,EAAE,QAAY,CAAA,YAAA;AAClB,cAAA,IAAI,EAAC,MAAK;AACV,cAAA,QAAO,EAAP,EAAO;AACP,cAAA,KAAK,EAAC,4BAA2B;AAChC,cAAA,QAAM,0CAAE,QAAY,CAAA,YAAA,IAAA,QAAA,CAAA,YAAA,CAAA,GAAA,IAAA,CAAA,CAAA,CAAA;;YACtBE,WAA0D,CAAA,iBAAA,EAAA;AAAjD,cAAA,IAAI,EAAE,EAAE;AAAE,cAAA,KAAK,EAAC,+BAA8B;;YACvDF,kBAAqE,CAAA,MAAA,EAArE,UAAqE,EAAAD,eAAA,CAAtB,MAAY,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;WAQvC,KAAO,CAAA,OAAA;4BAA5BF,WAA+B,CAAA,wBAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,CAAA;AAEnB,cAAA,CAAA,KAAA,CAAA,KAAK,CAAC,MAAO,KAAA,CAAA;8BADzBA,WAQgB,CAAA,yBAAA,EAAA;;AANf,kBAAA,KAAK,EAAC,uBAAsB;AAC3B,kBAAA,IAAI,EAAE,MAAY,CAAA,YAAA;AAClB,kBAAA,WAAW,EAAE,MAAa,CAAA,aAAA;;AAChB,kBAAA,IAAI,UACd,MAAuB;oBAAvBK,WAAuB,CAAA,oBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;;;AAGtB,iBAAAP,SAAA,EAAA,EAAAC,kBAAA,CAwFK,OAxFL,UAwFK,EAAA;oCAvFJA,kBAsFY,CAAAE,QAAA,EAAA,IAAA,EAAAK,UAAA,CArFI,KAAK,CAAA,KAAA,EAAA,CAAb,IAAG,KAAA;yCADXN,WAsFY,CAAA,qBAAA,EAAA;sBApFV,GAAG,EAAE,IAAI,CAAC,EAAE;AACZ,sBAAA,IAAI,EAAE,IAAI,CAAC,IAAK,IAAG,IAAI,CAAC,KAAK;AAC7B,sBAAA,IAAI,EAAE,KAAK;AACX,sBAAA,mBAAmB,EAAE,IAAI;sBACzB,OAAK,EAAA,MAAA,KAAE,QAAQ,CAAA,QAAA,CAAC,IAAI,CAAA,CAAA;;AACV,sBAAA,IAAI,UACd,MAM8B;AALvB,wBAAA,CAAA,QAAA,CAAA,aAAa,CAAC,IAAI,CAAA;0CADzBD,kBAM8B,CAAA,KAAA,EAAA;;AAJ7B,8BAAA,KAAK,EAAC,uBAAsB;8BAC3B,GAAG,EAAE,QAAa,CAAA,aAAA,CAAC,IAAI,CAAA;AACxB,8BAAA,GAAG,EAAC,EAAC;AACL,8BAAA,OAAO,EAAC,MAAK;8BACZ,OAAK,EAAA,MAAA,KAAE,QAAc,CAAA,cAAA,CAAC,IAAI,CAAA,CAAA;;AAEhB,4BAAA,CAAA,QAAA,CAAA,WAAW,CAAC,IAAI,CAAA;4CAD5BA,kBAIO,CAAA,KAAA,EAAA;;AAFN,gCAAA,KAAK,EAAC,sBAAqB;gCAC1B,GAAG,EAAE,QAAW,CAAA,WAAA,CAAC,IAAI,CAAA;AACtB,gCAAA,GAAG,EAAC,EAAE;;4CACPC,WAAgC,CAAA,sBAAA,EAAA;;AAAX,gCAAA,IAAI,EAAE,EAAE;;;AAEnB,sBAAA,OAAO,UACjB,MAUM;AAVN,wBAAAG,kBAAA,CAUM,QAVN,UAUM,EAAA;AATL,0BAAAA,kBAAA,CAA2C,MAAlC,EAAA,IAAA,EAAAD,eAAA,CAAA,QAAA,CAAA,cAAc,CAAC,IAAI,CAAC,IAAI,CAAA,CAAA,EAAA,CAAA,YAAA;AACjB,0BAAA,CAAA,QAAA,CAAA,UAAU,CAAC,IAAI,CAAA;4CAA/BH,kBAGU,CAAAE,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAFT,gCAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAE,kBAAA,CAAkC,MAA5B,EAAA,EAAA,aAAW,EAAC,MAAM,IAAE,KAAE,EAAA,CAAA,CAAA,cAAA,CAAA;gCAC5BE,WAAiE,CAAA,qBAAA,EAAA;kCAApD,SAAS,EAAE,QAAU,CAAA,UAAA,CAAC,IAAI,CAAA;AAAI,kCAAA,aAAa,EAAE,IAAI;;;;AAE/C,0BAAA,CAAA,QAAA,CAAA,QAAQ,CAAC,IAAI,CAAA;4CAA7BN,kBAGU,CAAAE,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAFT,gCAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAAE,kBAAA,CAAkC,MAA5B,EAAA,EAAA,aAAW,EAAC,MAAM,IAAE,KAAE,EAAA,CAAA,CAAA,cAAA,CAAA;gCAC5BA,kBAAgC,CAAA,MAAA,EAAA,IAAA,EAAAD,eAAA,CAAvB,QAAQ,CAAA,QAAA,CAAC,IAAI,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAId,sBAAA,OAAO,UACjB,MAKgB;wBALhBG,WAKgB,CAAA,yBAAA,EAAA;AALC,0BAAA,eAAe,EAAE,IAAI;0BAAG,OAAK,EAAA,MAAA,KAAE,QAAQ,CAAA,QAAA,CAAC,IAAI,CAAA,CAAA;;AACjD,0BAAA,IAAI,UACd,MAAuB;4BAAvBA,WAAuB,CAAA,oBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;2CACX,MACV;AADU,4BAAAE,eAAA,CAAA,GACV,mBAAG,MAAQ,CAAA,SAAA,CAAA,EAAA,CAAA,YAAA;;;;AAGL,wBAAA,CAAA,IAAI,CAAC,EAAE;0CADdP,WASc,CAAA,uBAAA,EAAA;;8BAPZ,IAAI,EAAE,QAAc,CAAA,cAAA,CAAC,IAAI,CAAA;AACzB,8BAAA,QAAQ,EAAE,IAAI,CAAC,IAAG,IAAK,IAAI,CAAC,KAAI,IAAA,EAAA;AAChC,8BAAA,eAAe,EAAE,IAAI;;AACX,8BAAA,IAAI,UACd,MAAsB;gCAAtBK,WAAsB,CAAA,mBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;+CACV,MACV;AADU,gCAAAE,eAAA,CAAA,GACV,mBAAG;;;;;yBAGG,QAAc,CAAA,cAAA,EAAA,IAAM,IAAI,CAAC,IAAI;0CADpCP,WAQgB,CAAA,yBAAA,EAAA;;AANd,8BAAA,eAAe,EAAE,IAAI;8BACrB,OAAK,EAAA,MAAA,KAAE,QAAW,CAAA,WAAA,CAAC,IAAI,CAAA,CAAA;;AACb,8BAAA,IAAI,UACd,MAAgC;gCAAhCK,WAAgC,CAAA,6BAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;+CACpB,MACV;AADU,gCAAAE,eAAA,CAAA,GACV,mBAAG;;;;;AAGG,wBAAA,CAAA,IAAI,CAAC,EAAE;0CADdP,WAUc,CAAA,uBAAA,EAAA;;8BARZ,IAAI,EAAE,QAAc,CAAA,cAAA,CAAC,IAAI,CAAA;AAC1B,8BAAA,MAAM,EAAC,QAAO;AACd,8BAAA,GAAG,EAAC,qBAAoB;AACvB,8BAAA,eAAe,EAAE,IAAI;;AACX,8BAAA,IAAI,UACd,MAA2B;gCAA3BK,WAA2B,CAAA,wBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;+CACf,MACV;AADU,gCAAAE,eAAA,CAAA,GACV,mBAAG;;;;;AAEkB,wBAAA,CAAA,IAAI,CAAC,EAAE;0CAA7BP,WAKgB,CAAA,yBAAA,EAAA;;AALgB,8BAAA,eAAe,EAAE,IAAI;8BAAG,OAAK,EAAA,MAAA,KAAE,QAAQ,CAAA,QAAA,CAAC,IAAI,CAAA,CAAA;;AAChE,8BAAA,IAAI,UACd,MAAyB;gCAAzBK,WAAyB,CAAA,sBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;+CACb,MACV;AADU,gCAAAE,eAAA,CAAA,GACV,mBAAG;;;;;wBAEJF,WAAoB,CAAA,4BAAA,CAAA;wBACpBA,WAKgB,CAAA,yBAAA,EAAA;AALC,0BAAA,eAAe,EAAE,IAAI;0BAAG,OAAK,EAAA,MAAA,KAAE,QAAU,CAAA,UAAA,CAAC,IAAI,CAAA,CAAA;;AACnD,0BAAA,IAAI,UACd,MAAoB;4BAApBA,WAAoB,CAAA,iBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;2CACR,MACV;AADU,4BAAAE,eAAA,CAAA,GACV,mBAAG,MAAU,CAAA,WAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;WAMV,KAAK,CAAA,KAAA,CAAC,MAAK,GAAI,KAAK,CAAA,KAAA;4BAD3BP,WAWU,CAAA,mBAAA,EAAA;;AATT,gBAAA,OAAO,EAAC,UAAS;AAChB,gBAAA,IAAI,EAAE,IAAI;AACV,gBAAA,QAAQ,EAAE,KAAW,CAAA,WAAA;AACtB,gBAAA,KAAK,EAAC,2BAA0B;AAC/B,gBAAA,OAAK,EAAE,QAAQ,CAAA,QAAA;;iCAGN,MACV;AADU,kBAAAO,eAAA,CAAA,GACV,mBAAG;;;;iBAHa,KAAW,CAAA,WAAA;;4BAAG,MAAI;kCACjC,MAA2B;wBAA3BF,WAA2B,CAAA,wBAAA,EAAA,EAAX,IAAI,EAAE,EAAE,EAAA,CAAA;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"CnFilesTab.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnFilesTab.vue?vue&type=template&id=6b917036&lang.js"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- The object's folder as a real files browser, on the Files app's own\n\t\t primitives (its actions, its New menu, its breadcrumbs), when the\n\t\t folder resolves for this user. The list below is the fallback for an\n\t\t object with no folder, or a user the folder is not shared with. -->\n\t\t<CnFilesBrowser\n\t\t\tv-if=\"browserRoot !== null\"\n\t\t\t:rootPath=\"browserRoot\"\n\t\t\t:rootLabel=\"browserRootLabel\"\n\t\t\t:rowActions=\"rowActions\"\n\t\t\t:newActions=\"newActions\"\n\t\t\t:linkedItems=\"linkedItems\"\n\t\t\t@changed=\"onBrowserChanged\" />\n\t\t<template v-else>\n\t\t\t<!-- Upload error -->\n\t\t\t<div v-if=\"uploadError\" class=\"cn-sidebar-tab__upload-error\">\n\t\t\t\t{{ uploadError }}\n\t\t\t</div>\n\n\t\t\t<!-- Share toggle — seeds from schema config (defaultAutoShare) or\n\t\t from the `defaultShare` prop. Hidden via `showShareToggle=false`. -->\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\tv-if=\"showShareToggle\"\n\t\t\t\tv-model=\"share\"\n\t\t\t\tclass=\"cn-sidebar-tab__share\"\n\t\t\t\t:disabled=\"loading\"\n\t\t\t\ttype=\"switch\">\n\t\t\t\t{{ shareLabel }}\n\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t<!-- File drop zone -->\n\t\t\t<div\n\t\t\t\tclass=\"cn-sidebar-tab__dropzone\"\n\t\t\t\t:class=\"{ 'cn-sidebar-tab__dropzone--active': isDragOver }\"\n\t\t\t\t@click=\"triggerFileInput\"\n\t\t\t\t@dragover.prevent=\"onDragOver\"\n\t\t\t\t@dragleave.prevent=\"onDragLeave\"\n\t\t\t\t@drop.prevent=\"onDrop\">\n\t\t\t\t<!--\n\t\t\t\t`:ref` (dynamic), not `ref` (static), and this is load-bearing.\n\n\t\t\t\tEvery other binding on this input is static, and Vue caches the\n\t\t\t\t`@change` handler, so with a STATIC ref the compiler hoists the\n\t\t\t\twhole vnode to module scope. A hoisted vnode is created once,\n\t\t\t\toutside any render, so its ref carries no owner instance\n\t\t\t\t(`rawRef.i === null`).\n\n\t\t\t\t`setRef()` guards that — but the guard AND its early `return`\n\t\t\t\tlive inside `if (process.env.NODE_ENV !== 'production')`. In a\n\t\t\t\tdevelopment build you get the warning \"Missing ref owner\n\t\t\t\tcontext. ref cannot be used on hoisted vnodes.\" and nothing\n\t\t\t\tbreaks. In a PRODUCTION build the guard is compiled out and\n\t\t\t\texecution falls through to `owner.refs`, throwing\n\t\t\t\t`TypeError: Cannot read properties of null (reading 'refs')`\n\t\t\t\t— which aborts the render of whatever mounted this tab.\n\n\t\t\t\tMeasured: hrmq's detail pages (the only pages in the fleet that\n\t\t\t\treach CnIntegrationWidget through a `widgets[]` grid) rendered a\n\t\t\t\tCOMPLETELY BLANK content pane in production while looking fine\n\t\t\t\tin dev. A dynamic ref is compiled as a patchable prop, so the\n\t\t\t\tvnode is created inside the render function and owns a proper\n\t\t\t\tinstance.\n\t\t\t-->\n\t\t\t\t<input\n\t\t\t\t\t:ref=\"fileInputRef\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\tmultiple\n\t\t\t\t\tclass=\"cn-sidebar-tab__file-input\"\n\t\t\t\t\t@change=\"onFileUpload\">\n\t\t\t\t<Upload :size=\"24\" class=\"cn-sidebar-tab__dropzone-icon\" />\n\t\t\t\t<span class=\"cn-sidebar-tab__dropzone-text\">{{ dropZoneLabel }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- File list. Each row borrows what Nextcloud already has on this\n\t\t page: the theme's own mime icon (OC.MimeType), the core preview\n\t\t endpoint for images, the Viewer for opening, and the Files sidebar\n\t\t for details, sharing and versions. Nothing of the Files app is\n\t\t rebuilt here; the row hands over to it. -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t\t<NcEmptyContent\n\t\t\t\tv-else-if=\"files.length === 0\"\n\t\t\t\tclass=\"cn-sidebar-tab__empty\"\n\t\t\t\t:name=\"noFilesLabel\"\n\t\t\t\t:description=\"dropZoneLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Paperclip :size=\"44\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<NcListItem\n\t\t\t\t\tv-for=\"file in files\"\n\t\t\t\t\t:key=\"file.id\"\n\t\t\t\t\t:name=\"file.name || file.title\"\n\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t:forceDisplayActions=\"true\"\n\t\t\t\t\t@click=\"openFile(file)\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__thumb\"\n\t\t\t\t\t\t\t:src=\"previewUrlFor(file)\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tloading=\"lazy\"\n\t\t\t\t\t\t\t@error=\"onPreviewError(file)\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-else-if=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-tab__mime\"\n\t\t\t\t\t\t\t:src=\"mimeIconFor(file)\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<FileOutline v-else :size=\"32\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t<span class=\"cn-sidebar-tab__meta\">\n\t\t\t\t\t\t\t<span>{{ formatFileSize(file.size) }}</span>\n\t\t\t\t\t\t\t<template v-if=\"modifiedAt(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<NcDateTime :timestamp=\"modifiedAt(file)\" :ignoreSeconds=\"true\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t<template v-if=\"labelsOf(file)\">\n\t\t\t\t\t\t\t\t<span aria-hidden=\"true\"> · </span>\n\t\t\t\t\t\t\t\t<span>{{ labelsOf(file) }}</span>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</template>\n\t\t\t\t\t<template #actions>\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"openFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<OpenInNew :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ openLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"downloadUrlFor(file)\"\n\t\t\t\t\t\t\t:download=\"file.name || file.title || ''\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ downloadLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\tv-if=\"canShowDetails() && file.path\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t@click=\"showDetails(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<InformationOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ detailsLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-if=\"file.id\"\n\t\t\t\t\t\t\t:href=\"showInFilesUrl(file)\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t:closeAfterClick=\"true\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<FolderOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ showInFilesLabel }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton v-if=\"file.id\" :closeAfterClick=\"true\" @click=\"copyLink(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<LinkVariant :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ copyLinkLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t<NcActionSeparator />\n\t\t\t\t\t\t<NcActionButton :closeAfterClick=\"true\" @click=\"deleteFile(file)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</template>\n\t\t\t\t</NcListItem>\n\t\t\t</div>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"files.length < total\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:wide=\"true\"\n\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t@click=\"loadMore\">\n\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ loadMoreLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateRemoteUrl, generateUrl } from '@nextcloud/router'\nimport {\n\tNcActionButton,\n\tNcActionLink,\n\tNcActionSeparator,\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcDateTime,\n\tNcEmptyContent,\n\tNcListItem,\n\tNcLoadingIcon,\n} from '@nextcloud/vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport FileOutline from 'vue-material-design-icons/FileOutline.vue'\nimport FolderOutline from 'vue-material-design-icons/FolderOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport OpenInNew from 'vue-material-design-icons/OpenInNew.vue'\nimport Paperclip from 'vue-material-design-icons/Paperclip.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnFilesBrowser from '../CnFilesBrowser/CnFilesBrowser.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { resolveObjectFolder } from '../CnFilesBrowser/filesBrowser.js'\n\nexport default {\n\tname: 'CnFilesTab',\n\n\tcomponents: {\n\t\tCnFilesBrowser,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActionSeparator,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcDateTime,\n\t\tNcEmptyContent,\n\t\tNcListItem,\n\t\tNcLoadingIcon,\n\t\tDelete,\n\t\tDownload,\n\t\tFileOutline,\n\t\tFolderOutline,\n\t\tInformationOutline,\n\t\tLinkVariant,\n\t\tOpenInNew,\n\t\tPaperclip,\n\t\tUpload,\n\t},\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown inside the file drop zone */\n\t\tdropZoneLabel: { type: String, default: () => t('nextcloud-vue', 'Drop files here or click to browse') },\n\t\t/** Text shown when no files are attached */\n\t\tnoFilesLabel: { type: String, default: () => t('nextcloud-vue', 'No files attached') },\n\t\t/** Label for the open/view file action */\n\t\topenLabel: { type: String, default: () => t('nextcloud-vue', 'Open') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** What the files browser's root crumb reads; null shows the folder's own name, as the Files app does. */\n\t\tbrowserRootLabel: { type: String, default: null },\n\t\t/**\n\t\t * The host's own actions on each file row of the browser, forwarded\n\t\t * to CnFilesBrowser's `rowActions`: declared like any manifest action\n\t\t * and dispatched with the file's id, name and path merged in.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\trowActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * The host's own entries in the browser's New menu, forwarded to\n\t\t * CnFilesBrowser's `newActions`: declared like a row action and\n\t\t * dispatched with the folder rather than a row, for things like\n\t\t * \"new from template\" or \"request a file from a party\".\n\t\t *\n\t\t * @type {Array<{id: string, label: string, icon?: string, type?: string, target?: string, props?: object}>}\n\t\t */\n\t\tnewActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * An app endpoint that answers the object's linked files, rows the\n\t\t * browser shows after the folder's own (files the host joined from\n\t\t * another object's folder). App-relative; `{objectId}` is replaced.\n\t\t * The response is an array (or `{ items: [] }`) of\n\t\t * `{ id, name, mime?, size?, mtime?, href?, downloadHref?, note?, noteHref? }`.\n\t\t * Null fetches nothing.\n\t\t */\n\t\tlinkedItemsUrl: { type: String, default: null },\n\t\t/** Label of the Download action. */\n\t\tdownloadLabel: { type: String, default: () => t('nextcloud-vue', 'Download') },\n\t\t/** Label of the action that opens the Files sidebar on the file. */\n\t\tdetailsLabel: { type: String, default: () => t('nextcloud-vue', 'Details and sharing') },\n\t\t/** Label of the link that opens the file in the Files app. */\n\t\tshowInFilesLabel: { type: String, default: () => t('nextcloud-vue', 'Show in Files') },\n\t\t/** Label of the action that copies the file permalink. */\n\t\tcopyLinkLabel: { type: String, default: () => t('nextcloud-vue', 'Copy link') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Whether to render the \"share uploaded files\" toggle. Off by default;\n\t\t * when false, uploads never set the share flag (no auto-publish).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tshowShareToggle: { type: Boolean, default: false },\n\t\t/**\n\t\t * Initial state for the share toggle. `true`/`false` wins outright;\n\t\t * `null` (the default) defers to the schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister.\n\t\t *\n\t\t * @type {boolean|null}\n\t\t */\n\t\tdefaultShare: { type: Boolean, default: null },\n\t\t/** Label for the share toggle */\n\t\tshareLabel: { type: String, default: () => t('nextcloud-vue', 'Share uploaded files') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tfiles: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tisDragOver: false,\n\t\t\tuploadError: '',\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tshare: false,\n\t\t\t/** The object's folder as a user-relative path, or null while unresolved or absent. */\n\t\t\tbrowserRoot: null,\n\t\t\tlinkedItems: [],\n\t\t\t/** File ids whose preview request failed, so the row falls back to the mime icon. */\n\t\t\tpreviewFailed: {},\n\t\t\t/**\n\t\t\t * The file input element, set by the template's function ref.\n\t\t\t *\n\t\t\t * Held here rather than read back through `$refs` so the ref stays\n\t\t\t * DYNAMIC — see the long comment on the input itself for why a\n\t\t\t * static ref on this element is a production crash.\n\t\t\t *\n\t\t\t * @type {HTMLInputElement|null}\n\t\t\t */\n\t\t\tfileInputEl: null,\n\t\t}\n\t},\n\n\twatch: {\n\t\t// Match every other CnObjectSidebar tab — a single immediate\n\t\t// `objectId` watcher drives all initial loads. Folding the\n\t\t// share-toggle seed in here avoids two concurrent GETs of\n\t\t// `schemas/{schema}` on mount (one per immediate watcher).\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchFiles()\n\t\t\t\t}\n\t\t\t\tthis.applyShareDefault()\n\t\t\t\tthis.resolveBrowserRoot()\n\t\t\t\tthis.fetchLinkedItems()\n\t\t\t},\n\t\t},\n\n\t\tlinkedItemsUrl() {\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Function ref for the file input.\n\t\t *\n\t\t * A method (not an inline arrow in the template) so the binding is a\n\t\t * stable reference across renders and Vue does not detach/reattach the\n\t\t * ref on every patch. Being a function ref is what keeps the vnode\n\t\t * dynamic — see the template comment on the input.\n\t\t *\n\t\t * @param {HTMLInputElement|null} el The element, or null on unmount.\n\t\t * @return {void}\n\t\t */\n\t\tfileInputRef(el) {\n\t\t\tthis.fileInputEl = el || null\n\t\t},\n\n\t\t/**\n\t\t * Find the object's folder for the browser, or leave the legacy list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * The browser changed the folder: refresh the object's file list and\n\t\t * the linked rows, since a join or a move can change either.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonBrowserChanged() {\n\t\t\tthis.fetchFiles()\n\t\t\tthis.fetchLinkedItems()\n\t\t},\n\n\t\t/**\n\t\t * Read the object's linked files from the host's endpoint, if any.\n\t\t *\n\t\t * A failure leaves the last list in place and logs at debug: the\n\t\t * folder's own rows are the surface, the linked rows a supplement.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchLinkedItems() {\n\t\t\tif (!this.linkedItemsUrl || !this.objectId) {\n\t\t\t\tthis.linkedItems = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(this.linkedItemsUrl.replace('{objectId}', encodeURIComponent(this.objectId)))\n\t\t\t\tconst { data } = await axios.get(url)\n\t\t\t\tconst items = Array.isArray(data) ? data : (Array.isArray(data?.items) ? data.items : [])\n\t\t\t\tthis.linkedItems = items.filter((item) => item && typeof item === 'object')\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.debug('[CnFilesTab] linked items not read', error)\n\t\t\t}\n\t\t},\n\n\t\tasync resolveBrowserRoot() {\n\t\t\tthis.browserRoot = null\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tlet remoteUrl\n\t\t\ttry {\n\t\t\t\tremoteUrl = generateRemoteUrl('dav')\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.browserRoot = await resolveObjectFolder({\n\t\t\t\tapiBase: this.apiBase,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tuid: getCurrentUser()?.uid || '',\n\t\t\t\tremoteUrl,\n\t\t\t})\n\t\t},\n\n\t\tasync fetchFiles(append = false) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (append) {\n\t\t\t\tthis.loadingMore = true\n\t\t\t} else {\n\t\t\t\tthis.loading = true\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst params = new URLSearchParams({ limit: this.limit, _page: this.page })\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files?${params}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tthis.files = append ? [...this.files, ...results] : results\n\t\t\t\t\tthis.total = data.total || this.files.length\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('CnFilesTab: Failed to fetch files', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchFiles(true)\n\t\t},\n\n\t\t/**\n\t\t * Seed the `share` toggle. The `defaultShare` prop wins when set\n\t\t * (non-null); otherwise we look up the active schema's\n\t\t * `configuration.defaultAutoShare` from OpenRegister and use that.\n\t\t * Network failure or missing key → keep the safe default (false) so\n\t\t * a hiccup never silently flips uploads to \"share\".\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync applyShareDefault() {\n\t\t\tif (this.defaultShare !== null && this.defaultShare !== undefined) {\n\t\t\t\tthis.share = !!this.defaultShare\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.share = false\n\t\t\tif (!this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/schemas/${this.schema}`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json().catch(() => null)\n\t\t\t\tif (data?.configuration?.defaultAutoShare === true) {\n\t\t\t\t\tthis.share = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Non-fatal — keep the safe default, but surface the\n\t\t\t\t// failure so a missing toggle default isn't silent.\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to fetch schema default for share toggle', err)\n\t\t\t}\n\t\t},\n\n\t\ttriggerFileInput() {\n\t\t\tthis.fileInputEl?.click()\n\t\t},\n\n\t\tonDragOver() {\n\t\t\tthis.isDragOver = true\n\t\t},\n\n\t\tonDragLeave() {\n\t\t\tthis.isDragOver = false\n\t\t},\n\n\t\tonDrop(event) {\n\t\t\tthis.isDragOver = false\n\t\t\tconst droppedFiles = event.dataTransfer?.files\n\t\t\tif (droppedFiles?.length) {\n\t\t\t\tthis.uploadFiles(droppedFiles)\n\t\t\t}\n\t\t},\n\n\t\tasync onFileUpload(event) {\n\t\t\tconst inputFiles = event.target.files\n\t\t\tif (!inputFiles?.length) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.uploadFiles(inputFiles)\n\t\t\tif (this.fileInputEl) {\n\t\t\t\tthis.fileInputEl.value = ''\n\t\t\t}\n\t\t},\n\n\t\tasync uploadFiles(fileList) {\n\t\t\tif (!fileList?.length || !this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.uploadError = ''\n\t\t\tconst formData = new FormData()\n\t\t\tfor (const file of fileList) {\n\t\t\t\tformData.append('files[]', file)\n\t\t\t}\n\t\t\t// Only forward the share flag when the toggle is actually visible.\n\t\t\t// Hiding the toggle (showShareToggle=false) means \"don't auto-publish\".\n\t\t\tif (this.showShareToggle) {\n\t\t\t\tformData.append('share', String(this.share))\n\t\t\t}\n\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/filesMultipart`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: { requesttoken: OC?.requestToken || '', 'OCS-APIREQUEST': 'true' },\n\t\t\t\t\t\tbody: formData,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst data = await response.json().catch(() => ({}))\n\t\t\t\t\tthis.uploadError = data.error || `Upload failed (${response.status})`\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.fetchFiles()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to upload file', err)\n\t\t\t\tthis.uploadError = 'Upload failed: could not connect to server'\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the Files app's details sidebar is on this page.\n\t\t *\n\t\t * It is when the host page dispatched Nextcloud's `LoadSidebar` event\n\t\t * server-side; then `OCA.Files.Sidebar.open(path)` shows the same\n\t\t * sharing, versions, comments and activity tabs the Files app shows.\n\t\t * Absent, the row offers no details action rather than a dead one. A\n\t\t * method rather than a computed: the global is not reactive, so a\n\t\t * cached answer from before the sidebar script ran would stay wrong.\n\t\t *\n\t\t * @return {boolean} true when the sidebar can be opened.\n\t\t */\n\t\tcanShowDetails() {\n\t\t\treturn typeof window !== 'undefined' && typeof window.OCA?.Files?.Sidebar?.open === 'function'\n\t\t},\n\n\t\t/**\n\t\t * The file's path relative to the user's files root, which is the path\n\t\t * the Viewer and the Files sidebar take. OpenRegister reports the node's\n\t\t * full path (`/{uid}/files/…`), so the first two segments come off.\n\t\t *\n\t\t * @param {string} path The node path as OpenRegister reports it.\n\t\t * @return {string} The user-relative path, `/` at least.\n\t\t */\n\t\tuserRelativePath(path) {\n\t\t\tconst stripped = String(path || '').replace(/^\\/[^/]+\\/files(?=\\/|$)/, '')\n\t\t\treturn stripped === '' ? '/' : stripped\n\t\t},\n\n\t\t/**\n\t\t * The theme's own icon for the file's mime type, the one the Files app\n\t\t * draws, or null on a page without Nextcloud's core script.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The icon url.\n\t\t */\n\t\tmimeIconFor(file) {\n\t\t\tconst getIconUrl = typeof window !== 'undefined' ? window.OC?.MimeType?.getIconUrl : null\n\t\t\tif (typeof getIconUrl !== 'function') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\ttry {\n\t\t\t\treturn getIconUrl(mime) || null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A small preview for an image, through Nextcloud's core preview\n\t\t * endpoint, or null for anything else or after the preview failed once.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string|null} The preview url.\n\t\t */\n\t\tpreviewUrlFor(file) {\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tif (!file.id || !/^image\\//i.test(mime) || /svg/i.test(mime) || this.previewFailed[file.id]) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/core/preview?fileId={fileId}&x=64&y=64&a=1', { fileId: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Remember that a preview did not load, so the row shows the mime icon.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tonPreviewError(file) {\n\t\t\tthis.previewFailed = { ...this.previewFailed, [file.id]: true }\n\t\t},\n\n\t\t/**\n\t\t * The file's modification moment as a Date, or null when unknown.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Date|null} The moment.\n\t\t */\n\t\tmodifiedAt(file) {\n\t\t\tconst raw = file.modified || file.updated || ''\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst date = new Date(raw)\n\t\t\treturn Number.isNaN(date.getTime()) ? null : date\n\t\t},\n\n\t\t/**\n\t\t * The file's labels (Nextcloud tags), joined for the meta line.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The labels, or the empty string.\n\t\t */\n\t\tlabelsOf(file) {\n\t\t\treturn Array.isArray(file.labels) ? file.labels.filter(Boolean).join(', ') : ''\n\t\t},\n\n\t\t/**\n\t\t * The download url for a file, through OpenRegister's file endpoint,\n\t\t * which streams the node the object owns.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tdownloadUrlFor(file) {\n\t\t\treturn `${this.apiBase}/files/${encodeURIComponent(String(file.id))}/download`\n\t\t},\n\n\t\t/**\n\t\t * The Files app's permalink for a file: opens the Files app at the\n\t\t * file's folder with the file selected.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {string} The url.\n\t\t */\n\t\tshowInFilesUrl(file) {\n\t\t\treturn generateUrl('/f/{fileid}', { fileid: file.id })\n\t\t},\n\n\t\t/**\n\t\t * Open the Files sidebar on this file: details, sharing, versions,\n\t\t * comments and activity, exactly as the Files app offers them.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {void}\n\t\t */\n\t\tshowDetails(file) {\n\t\t\tif (!this.canShowDetails() || !file.path) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\twindow.OCA.Files.Sidebar.open(this.userRelativePath(file.path))\n\t\t},\n\n\t\t/**\n\t\t * Put the file's permalink on the clipboard and say so.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync copyLink(file) {\n\t\t\tconst href = new URL(this.showInFilesUrl(file), window.location.origin).href\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(href)\n\t\t\t\tconst { showSuccess } = await import('@nextcloud/dialogs')\n\t\t\t\tshowSuccess(t('nextcloud-vue', 'Link copied'))\n\t\t\t} catch {\n\t\t\t\tconst { showError } = await import('@nextcloud/dialogs')\n\t\t\t\tshowError(t('nextcloud-vue', 'The link could not be copied'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether Nextcloud's Viewer is on this page and handles the file.\n\t\t *\n\t\t * The Viewer is there when the host page dispatched `LoadViewer`\n\t\t * server-side; it lists the mime types it can show, and a type it\n\t\t * cannot falls through to the next way of opening the file.\n\t\t *\n\t\t * @param {object} file The file row.\n\t\t * @return {boolean} true when the Viewer can open it in place.\n\t\t */\n\t\tviewerHandles(file) {\n\t\t\tconst viewer = typeof window !== 'undefined' ? window.OCA?.Viewer : null\n\t\t\tif (!viewer || typeof viewer.open !== 'function' || !file.path) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst mime = file.type || file.mimetype || file.mimeType || ''\n\t\t\tconst mimetypes = Array.isArray(viewer.mimetypes) ? viewer.mimetypes : null\n\t\t\treturn mimetypes === null ? true : mimetypes.includes(mime)\n\t\t},\n\n\t\topenFile(file) {\n\t\t\t// The Viewer first: it opens the file over this page, so the reader\n\t\t\t// stays on the object. A public share link and the Files app come\n\t\t\t// after, in that order, when the Viewer is absent or cannot show\n\t\t\t// the type.\n\t\t\tif (this.viewerHandles(file)) {\n\t\t\t\twindow.OCA.Viewer.open({ path: this.userRelativePath(file.path) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (file.accessUrl) {\n\t\t\t\t// Security: accessUrl originates from the OR files API and may be\n\t\t\t\t// attacker-controlled. Validate the scheme via safeHref before\n\t\t\t\t// opening (C4) — this blocks javascript: / data: payloads. Add\n\t\t\t\t// noopener,noreferrer to prevent the opened tab from accessing\n\t\t\t\t// window.opener (reverse-tabnabbing) and to strip the Referer header.\n\t\t\t\tconst safe = safeHref(file.accessUrl)\n\t\t\t\tif (safe !== '#') {\n\t\t\t\t\twindow.open(safe, '_blank', 'noopener,noreferrer')\n\t\t\t\t}\n\t\t\t} else if (file.id) {\n\t\t\t\tconst dirPath = file.path ? file.path.substring(0, file.path.lastIndexOf('/')) : ''\n\t\t\t\tconst cleanPath = dirPath.replace(/^\\/admin\\/files\\//, '/')\n\t\t\t\twindow.open(`/index.php/apps/files/files/${file.id}?dir=${encodeURIComponent(cleanPath)}&openfile=true`, '_blank')\n\t\t\t}\n\t\t},\n\n\t\tasync deleteFile(file) {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/files/${file.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.files = this.files.filter((f) => f.id !== file.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnFilesTab: Failed to delete file', err)\n\t\t\t}\n\t\t},\n\n\t\tformatFileSize(bytes) {\n\t\t\tconst sizes = ['Bytes', 'KB', 'MB', 'GB']\n\t\t\tif (!bytes || bytes === 0) {\n\t\t\t\treturn 'n/a'\n\t\t\t}\n\t\t\tconst i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n\t\t\tif (i === 0) {\n\t\t\t\treturn '< 1 KB'\n\t\t\t}\n\t\t\treturn (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__upload-error {\n\tpadding: 8px 12px;\n\tmargin-bottom: 8px;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground-color: var(--color-error-light, rgba(229, 57, 53, 0.1));\n\tcolor: var(--color-error, #e53935);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__dropzone {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 20px 12px;\n\tmargin-bottom: 16px;\n\tborder: 2px dashed var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tcursor: pointer;\n\ttransition: border-color 0.15s ease, background-color 0.15s ease;\n}\n\n.cn-sidebar-tab__dropzone:hover {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.08));\n}\n\n.cn-sidebar-tab__dropzone--active {\n\tborder-color: var(--color-primary-element);\n\tbackground-color: var(--color-primary-element-light, rgba(0, 130, 201, 0.12));\n}\n\n.cn-sidebar-tab__share { margin-bottom: 12px; }\n\n.cn-sidebar-tab__dropzone-icon { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__dropzone--active .cn-sidebar-tab__dropzone-icon,\n.cn-sidebar-tab__dropzone:hover .cn-sidebar-tab__dropzone-icon { color: var(--color-primary-element); }\n\n.cn-sidebar-tab__dropzone-text { font-size: 13px; color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__file-input { display: none; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-sidebar-tab__mime,\n.cn-sidebar-tab__thumb {\n\twidth: 32px;\n\theight: 32px;\n\tdisplay: block;\n}\n\n.cn-sidebar-tab__thumb {\n\tobject-fit: cover;\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-sidebar-tab__meta { color: var(--color-text-maxcontrast); }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n</style>\n"],"names":["_openBlock","_createElementBlock","_createBlock","_Fragment","_toDisplayString","_createElementVNode","_normalizeClass","_createVNode","_renderList","_createTextVNode"],"mappings":"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"}
|