diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index a005578aa2428..c99011b6a7caf 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -71,10 +71,12 @@ 'OCA\\Files\\Db\\TransferOwnershipMapper' => $baseDir . '/../lib/Db/TransferOwnershipMapper.php', 'OCA\\Files\\DirectEditingCapabilities' => $baseDir . '/../lib/DirectEditingCapabilities.php', 'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => $baseDir . '/../lib/Event/LoadAdditionalScriptsEvent.php', + 'OCA\\Files\\Event\\LoadFilesApp' => $baseDir . '/../lib/Event/LoadFilesApp.php', 'OCA\\Files\\Event\\LoadSearchPlugins' => $baseDir . '/../lib/Event/LoadSearchPlugins.php', 'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php', 'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php', 'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php', + 'OCA\\Files\\Listener\\LoadFilesAppListener' => $baseDir . '/../lib/Listener/LoadFilesAppListener.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => $baseDir . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files\\Listener\\NodeAddedToFavoriteListener' => $baseDir . '/../lib/Listener/NodeAddedToFavoriteListener.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 6f0f0d4cc602f..d7c3e7c43a542 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -86,10 +86,12 @@ class ComposerStaticInitFiles 'OCA\\Files\\Db\\TransferOwnershipMapper' => __DIR__ . '/..' . '/../lib/Db/TransferOwnershipMapper.php', 'OCA\\Files\\DirectEditingCapabilities' => __DIR__ . '/..' . '/../lib/DirectEditingCapabilities.php', 'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => __DIR__ . '/..' . '/../lib/Event/LoadAdditionalScriptsEvent.php', + 'OCA\\Files\\Event\\LoadFilesApp' => __DIR__ . '/..' . '/../lib/Event/LoadFilesApp.php', 'OCA\\Files\\Event\\LoadSearchPlugins' => __DIR__ . '/..' . '/../lib/Event/LoadSearchPlugins.php', 'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php', 'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php', 'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php', + 'OCA\\Files\\Listener\\LoadFilesAppListener' => __DIR__ . '/..' . '/../lib/Listener/LoadFilesAppListener.php', 'OCA\\Files\\Listener\\LoadSearchPluginsListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSearchPluginsListener.php', 'OCA\\Files\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', 'OCA\\Files\\Listener\\NodeAddedToFavoriteListener' => __DIR__ . '/..' . '/../lib/Listener/NodeAddedToFavoriteListener.php', diff --git a/apps/files/lib/AppInfo/Application.php b/apps/files/lib/AppInfo/Application.php index 56fcc6ce2c4aa..4dc4cb0ac9f47 100644 --- a/apps/files/lib/AppInfo/Application.php +++ b/apps/files/lib/AppInfo/Application.php @@ -24,8 +24,10 @@ use OCA\Files\ConfigLexicon; use OCA\Files\Dashboard\FavoriteWidget; use OCA\Files\DirectEditingCapabilities; +use OCA\Files\Event\LoadFilesApp; use OCA\Files\Event\LoadSearchPlugins; use OCA\Files\Event\LoadSidebar; +use OCA\Files\Listener\LoadFilesAppListener; use OCA\Files\Listener\LoadSearchPluginsListener; use OCA\Files\Listener\LoadSidebarListener; use OCA\Files\Listener\NodeAddedToFavoriteListener; @@ -80,6 +82,7 @@ public function register(IRegistrationContext $context): void { $context->registerCapability(AdvancedCapabilities::class); $context->registerCapability(DirectEditingCapabilities::class); + $context->registerEventListener(LoadFilesApp::class, LoadFilesAppListener::class); $context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class); $context->registerEventListener(RenderReferenceEvent::class, RenderReferenceEventListener::class); $context->registerEventListener(BeforeNodeRenamedEvent::class, SyncLivePhotosListener::class); diff --git a/apps/files/lib/Controller/ViewController.php b/apps/files/lib/Controller/ViewController.php index d826f6e8745aa..c76fcc9c6ba73 100644 --- a/apps/files/lib/Controller/ViewController.php +++ b/apps/files/lib/Controller/ViewController.php @@ -8,15 +8,9 @@ namespace OCA\Files\Controller; -use OC\Files\FilenameValidator; use OC\Files\Filesystem; use OCA\Files\AppInfo\Application; -use OCA\Files\ConfigLexicon; -use OCA\Files\Event\LoadAdditionalScriptsEvent; -use OCA\Files\Event\LoadSearchPlugins; -use OCA\Files\Event\LoadSidebar; -use OCA\Files\Service\UserConfig; -use OCA\Files\Service\ViewConfig; +use OCA\Files\Event\LoadFilesApp; use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Attribute\NoAdminRequired; @@ -26,21 +20,15 @@ use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\TemplateResponse; -use OCP\AppFramework\Services\IAppConfig; use OCP\AppFramework\Services\IInitialState; -use OCP\Authentication\TwoFactorAuth\IRegistry; -use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as ResourcesLoadAdditionalScriptsEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; -use OCP\Files\Template\ITemplateManager; -use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; -use OCP\Util; /** * @package OCA\Files\Controller @@ -53,18 +41,11 @@ public function __construct( IRequest $request, private IURLGenerator $urlGenerator, private IL10N $l10n, - private IConfig $config, private IEventDispatcher $eventDispatcher, private IUserSession $userSession, private IAppManager $appManager, private IRootFolder $rootFolder, private IInitialState $initialState, - private ITemplateManager $templateManager, - private UserConfig $userConfig, - private ViewConfig $viewConfig, - private FilenameValidator $filenameValidator, - private IRegistry $twoFactorRegistry, - private IAppConfig $appConfig, ) { parent::__construct($appName, $request); } @@ -142,10 +123,6 @@ public function index($dir = '', $view = '', $fileid = null) { } } - // Load the files we need - Util::addInitScript('files', 'init'); - Util::addScript('files', 'main'); - $user = $this->userSession->getUser(); $userId = $user->getUID(); @@ -174,42 +151,8 @@ public function index($dir = '', $view = '', $fileid = null) { } $this->initialState->provideInitialState('storageStats', $storageInfo); - $this->initialState->provideInitialState('config', $this->userConfig->getConfigs()); - $this->initialState->provideInitialState('viewConfigs', $this->viewConfig->getConfigs()); - $this->initialState->provideInitialState('recent_limit', $this->appConfig->getAppValueInt(ConfigLexicon::RECENT_LIMIT, 100)); - // Not yet consumed by the frontend, provided for future implementation - $this->initialState->provideInitialState('group_recent_files', $this->appConfig->getAppValueBool(ConfigLexicon::GROUP_RECENT_FILES, false)); - $this->initialState->provideInitialState('recent_files_group_mime_types', $this->appConfig->getAppValueArray(ConfigLexicon::RECENT_FILES_GROUP_MIME_TYPES, [])); - $this->initialState->provideInitialState('recent_files_group_timespan_minutes', $this->appConfig->getAppValueInt(ConfigLexicon::RECENT_FILES_GROUP_TIMESPAN_MINUTES, 2)); - - // File sorting user config - $filesSortingConfig = json_decode($this->config->getUserValue($userId, 'files', 'files_sorting_configs', '{}'), true); - $this->initialState->provideInitialState('filesSortingConfig', $filesSortingConfig); - - // Forbidden file characters (deprecated use capabilities) - // TODO: Remove with next release of `@nextcloud/files` - $forbiddenCharacters = $this->filenameValidator->getForbiddenCharacters(); - $this->initialState->provideInitialState('forbiddenCharacters', $forbiddenCharacters); - - $event = new LoadAdditionalScriptsEvent(); - $this->eventDispatcher->dispatchTyped($event); - $this->eventDispatcher->dispatchTyped(new ResourcesLoadAdditionalScriptsEvent()); - $this->eventDispatcher->dispatchTyped(new LoadSidebar()); - $this->eventDispatcher->dispatchTyped(new LoadSearchPlugins()); - - $this->initialState->provideInitialState('templates_enabled', true); - $this->initialState->provideInitialState('templates_path', $this->templateManager->hasTemplateDirectory() ? $this->templateManager->getTemplatePath() : false); - $this->initialState->provideInitialState('templates', $this->templateManager->listCreators()); - $this->initialState->provideInitialState('localClientEnabled', $this->appConfig->getAppValueBool(ConfigLexicon::LOCAL_CLIENT_INTEGRATION)); - - $isTwoFactorEnabled = false; - foreach ($this->twoFactorRegistry->getProviderStates($user) as $providerId => $providerState) { - if ($providerId !== 'backup_codes' && $providerState === true) { - $isTwoFactorEnabled = true; - } - } - $this->initialState->provideInitialState('isTwoFactorEnabled', $isTwoFactorEnabled); + $this->eventDispatcher->dispatchTyped(new LoadFilesApp()); $response = new TemplateResponse( Application::APP_ID, diff --git a/apps/files/lib/Event/LoadFilesApp.php b/apps/files/lib/Event/LoadFilesApp.php new file mode 100644 index 0000000000000..32da6fda6da09 --- /dev/null +++ b/apps/files/lib/Event/LoadFilesApp.php @@ -0,0 +1,21 @@ + + */ +class LoadFilesAppListener implements IEventListener { + public function __construct( + private IEventDispatcher $eventDispatcher, + private IInitialState $initialState, + private IUserConfig $config, + private IUserSession $userSession, + private UserConfig $userConfig, + private ViewConfig $viewConfig, + private FilenameValidator $filenameValidator, + private IRegistry $twoFactorRegistry, + private IAppConfig $appConfig, + private ITemplateManager $templateManager, + ) { + } + + #[\Override] + public function handle(Event $event): void { + if (!($event instanceof LoadFilesApp)) { + return; + } + + Util::addInitScript('files', 'init'); + Util::addScript('files', 'main'); + + $user = $this->userSession->getUser(); + $userId = $user->getUID(); + + $this->initialState->provideInitialState('config', $this->userConfig->getConfigs()); + $this->initialState->provideInitialState('viewConfigs', $this->viewConfig->getConfigs()); + $this->initialState->provideInitialState('recent_limit', $this->appConfig->getAppValueInt(ConfigLexicon::RECENT_LIMIT, 100)); + // Not yet consumed by the frontend, provided for future implementation + $this->initialState->provideInitialState('group_recent_files', $this->appConfig->getAppValueBool(ConfigLexicon::GROUP_RECENT_FILES, false)); + $this->initialState->provideInitialState('recent_files_group_mime_types', $this->appConfig->getAppValueArray(ConfigLexicon::RECENT_FILES_GROUP_MIME_TYPES, [])); + $this->initialState->provideInitialState('recent_files_group_timespan_minutes', $this->appConfig->getAppValueInt(ConfigLexicon::RECENT_FILES_GROUP_TIMESPAN_MINUTES, 2)); + + // File sorting user config + $filesSortingConfig = json_decode($this->config->getValueString($userId, 'files', 'files_sorting_configs', '{}'), true); + $this->initialState->provideInitialState('filesSortingConfig', $filesSortingConfig); + + // Forbidden file characters (deprecated use capabilities) + // TODO: Remove with next release of `@nextcloud/files` + $forbiddenCharacters = $this->filenameValidator->getForbiddenCharacters(); + $this->initialState->provideInitialState('forbiddenCharacters', $forbiddenCharacters); + + $this->eventDispatcher->dispatchTyped(new LoadAdditionalScriptsEvent()); + $this->eventDispatcher->dispatchTyped(new ResourcesLoadAdditionalScriptsEvent()); + $this->eventDispatcher->dispatchTyped(new LoadSidebar()); + $this->eventDispatcher->dispatchTyped(new LoadSearchPlugins()); + + $this->initialState->provideInitialState('templates_enabled', true); + $this->initialState->provideInitialState('templates_path', $this->templateManager->hasTemplateDirectory() ? $this->templateManager->getTemplatePath() : false); + $this->initialState->provideInitialState('templates', $this->templateManager->listCreators()); + $this->initialState->provideInitialState('localClientEnabled', $this->appConfig->getAppValueBool(ConfigLexicon::LOCAL_CLIENT_INTEGRATION)); + + $isTwoFactorEnabled = false; + foreach ($this->twoFactorRegistry->getProviderStates($user) as $providerId => $providerState) { + if ($providerId !== 'backup_codes' && $providerState === true) { + $isTwoFactorEnabled = true; + } + } + + $this->initialState->provideInitialState('isTwoFactorEnabled', $isTwoFactorEnabled); + } +} diff --git a/apps/files/src/components/BreadCrumbs.vue b/apps/files/src/components/BreadCrumbs.vue index 567aecd337981..a2a1a3612d978 100644 --- a/apps/files/src/components/BreadCrumbs.vue +++ b/apps/files/src/components/BreadCrumbs.vue @@ -83,6 +83,7 @@ import { useFilesStore } from '../store/files.ts' import { usePathsStore } from '../store/paths.ts' import { useSelectionStore } from '../store/selection.ts' import { useUploaderStore } from '../store/uploader.ts' +import { getBreadcrumbDirs } from '../utils/breadcrumbs.ts' import { logger } from '../utils/logger.ts' export default defineComponent({ @@ -100,6 +101,12 @@ export default defineComponent({ type: String, default: '/', }, + + /** The directory to start the breadcrumbs with */ + root: { + type: String, + default: '/', + }, }, emits: ['reload'], @@ -159,11 +166,7 @@ export default defineComponent({ computed: { dirs(): string[] { - const cumulativePath = (acc: string) => (value: string) => (acc += `${value}/`) - // Generate a cumulative path for each path segment: ['/', '/foo', '/foo/bar', ...] etc - const paths: string[] = this.path.split('/').filter(Boolean).map(cumulativePath('/')) - // Strip away trailing slash - return ['/', ...paths.map((path: string) => path.replace(/^(.+)\/$/, '$1'))] + return getBreadcrumbDirs(this.path, this.root) }, sections() { diff --git a/apps/files/src/components/FileEntry/FileEntryActions.vue b/apps/files/src/components/FileEntry/FileEntryActions.vue index f6c948789c1b7..82703e12c6193 100644 --- a/apps/files/src/components/FileEntry/FileEntryActions.vue +++ b/apps/files/src/components/FileEntry/FileEntryActions.vue @@ -374,7 +374,7 @@ export default defineComponent({