From 87cd9e6e305310bd14941a53689d49e6b92b49d3 Mon Sep 17 00:00:00 2001 From: Andreas Nedbal <andy@pixelde.su> Date: Wed, 12 Jun 2024 10:58:45 +0200 Subject: [PATCH] [FEATURE] Provide backend modules in LiveSearch Backend users can now search for the backend modules they have access to in the LiveSearch. Resolves: #92009 Releases: main Change-Id: I28d9593655989f064b7a7fac0ab80415eee4c6fe Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/84654 Tested-by: core-ci <typo3@b13.com> Reviewed-by: Oliver Bartsch <bo@cedev.de> Tested-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de> Tested-by: Andreas Kienast <a.fernandez@scripting-base.de> --- .../backend-module-result-type.ts | 8 ++ .../AfterBackendPageRenderEventListener.php | 5 + .../LiveSearch/BackendModuleProvider.php | 110 ++++++++++++++++++ .../Resources/Private/Language/locallang.xlf | 9 ++ .../backend-module-result-type.js | 13 +++ ...2009-ProvideBackendModulesInLiveSearch.rst | 23 ++++ 6 files changed, 168 insertions(+) create mode 100644 Build/Sources/TypeScript/backend/live-search/result-types/backend-module-result-type.ts create mode 100644 typo3/sysext/backend/Classes/Search/LiveSearch/BackendModuleProvider.php create mode 100644 typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/backend-module-result-type.js create mode 100644 typo3/sysext/core/Documentation/Changelog/13.2/Feature-92009-ProvideBackendModulesInLiveSearch.rst diff --git a/Build/Sources/TypeScript/backend/live-search/result-types/backend-module-result-type.ts b/Build/Sources/TypeScript/backend/live-search/result-types/backend-module-result-type.ts new file mode 100644 index 000000000000..fe8e2b48ce14 --- /dev/null +++ b/Build/Sources/TypeScript/backend/live-search/result-types/backend-module-result-type.ts @@ -0,0 +1,8 @@ +import LiveSearchConfigurator from '@typo3/backend/live-search/live-search-configurator'; +import { ResultItemInterface } from '@typo3/backend/live-search/element/result/item/item'; + +export function registerType(type: string) { + LiveSearchConfigurator.addInvokeHandler(type, 'open_module', (resultItem: ResultItemInterface): void => { + TYPO3.ModuleMenu.App.showModule(resultItem.extraData.moduleIdentifier); + }); +} diff --git a/typo3/sysext/backend/Classes/EventListener/AfterBackendPageRenderEventListener.php b/typo3/sysext/backend/Classes/EventListener/AfterBackendPageRenderEventListener.php index 07e0d6ebd4b2..0cd3cf648133 100644 --- a/typo3/sysext/backend/Classes/EventListener/AfterBackendPageRenderEventListener.php +++ b/typo3/sysext/backend/Classes/EventListener/AfterBackendPageRenderEventListener.php @@ -18,6 +18,7 @@ declare(strict_types=1); namespace TYPO3\CMS\Backend\EventListener; use TYPO3\CMS\Backend\Controller\Event\AfterBackendPageRenderEvent; +use TYPO3\CMS\Backend\Search\LiveSearch\BackendModuleProvider; use TYPO3\CMS\Backend\Search\LiveSearch\DatabaseRecordProvider; use TYPO3\CMS\Backend\Search\LiveSearch\PageRecordProvider; use TYPO3\CMS\Core\Attribute\AsEventListener; @@ -43,5 +44,9 @@ final readonly class AfterBackendPageRenderEventListener JavaScriptModuleInstruction::create('@typo3/backend/live-search/result-types/page-result-type.js', 'registerRenderer') ->invoke(null, PageRecordProvider::class) ); + $javaScriptRenderer->addJavaScriptModuleInstruction( + JavaScriptModuleInstruction::create('@typo3/backend/live-search/result-types/backend-module-result-type.js', 'registerType') + ->invoke(null, BackendModuleProvider::class) + ); } } diff --git a/typo3/sysext/backend/Classes/Search/LiveSearch/BackendModuleProvider.php b/typo3/sysext/backend/Classes/Search/LiveSearch/BackendModuleProvider.php new file mode 100644 index 000000000000..4f8a6ab66ea7 --- /dev/null +++ b/typo3/sysext/backend/Classes/Search/LiveSearch/BackendModuleProvider.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Backend\Search\LiveSearch; + +use TYPO3\CMS\Backend\Module\ModuleInterface; +use TYPO3\CMS\Backend\Module\ModuleProvider; +use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException; +use TYPO3\CMS\Backend\Routing\UriBuilder; +use TYPO3\CMS\Backend\Search\LiveSearch\SearchDemand\SearchDemand; +use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; +use TYPO3\CMS\Core\Imaging\IconFactory; +use TYPO3\CMS\Core\Imaging\IconSize; +use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Core\Localization\LanguageServiceFactory; + +class BackendModuleProvider implements SearchProviderInterface +{ + private LanguageService $languageService; + + public function __construct( + private readonly LanguageServiceFactory $languageServiceFactory, + private readonly UriBuilder $uriBuilder, + private readonly IconFactory $iconFactory, + private readonly ModuleProvider $moduleProvider + ) { + $this->languageService = $this->languageServiceFactory->createFromUserPreferences($this->getBackendUser()); + } + + public function getFilterLabel(): string + { + return $this->languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:liveSearch.backendModuleProvider.filterLabel'); + } + + public function find(SearchDemand $searchDemand): array + { + $items = []; + + foreach ($this->getFilteredModules($searchDemand) as $module) { + // we can't generate accessible URLs for all modules by their identifier + // if URL generation fails, we don't create an action to open a module + // and if no actions exist, we skip result item creation altogether + try { + $moduleUrl = (string)$this->uriBuilder->buildUriFromRoute($module->getIdentifier()); + } catch (RouteNotFoundException) { + continue; + } + + $action = (new ResultItemAction('open_module')) + ->setLabel($this->languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:resultItem.backendModuleProvider.openModule')) + ->setUrl($moduleUrl); + + $iconIdentifier = $module->getIconIdentifier(); + if ($iconIdentifier === '' && $module->hasParentModule()) { + $iconIdentifier = $module->getParentModule()->getIconIdentifier(); + } + + $items[] = (new ResultItem(self::class)) + ->setItemTitle($this->languageService->sL($module->getTitle())) + ->setTypeLabel($this->languageService->sL('LLL:EXT:backend/Resources/Private/Language/locallang.xlf:liveSearch.backendModuleProvider.typeLabel')) + ->setIcon($this->iconFactory->getIcon($iconIdentifier, IconSize::SMALL)) + ->setActions($action) + ->setExtraData([ + 'moduleIdentifier' => $module->getIdentifier(), + ]); + } + + return $items; + } + + public function count(SearchDemand $searchDemand): int + { + return count($this->getFilteredModules($searchDemand)); + } + + /** + * @return list<ModuleInterface> + */ + private function getFilteredModules(SearchDemand $searchDemand): array + { + $filteredModules = array_filter( + $this->moduleProvider->getModules($this->getBackendUser(), true, false), + fn(ModuleInterface $module) => str_contains(mb_strtolower($this->languageService->sL($module->getTitle())), mb_strtolower($searchDemand->getQuery())) + ); + + $firstResult = $searchDemand->getOffset(); + $remainingItems = $searchDemand->getLimit(); + + return array_slice($filteredModules, $firstResult, $remainingItems, true); + } + + private function getBackendUser(): BackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } +} diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf index de99a6997fa6..9d8405b57ec2 100644 --- a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf +++ b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf @@ -190,6 +190,15 @@ Have a nice day.</source> <trans-unit id="liveSearch.pageRecordProvider.typeLabel" resname="liveSearch.pageRecordProvider.typeLabel"> <source>Page</source> </trans-unit> + <trans-unit id="liveSearch.backendModuleProvider.filterLabel" resname="liveSearch.backendModuleProvider.filterLabel"> + <source>Backend modules</source> + </trans-unit> + <trans-unit id="liveSearch.backendModuleProvider.typeLabel" resname="liveSearch.backendModuleProvider.typeLabel"> + <source>Backend module</source> + </trans-unit> + <trans-unit id="resultItem.backendModuleProvider.openModule" resname="resultItem.backendModuleProvider.openModule"> + <source>Open module</source> + </trans-unit> <trans-unit id="moduleMenu.dropdown.label" resname="moduleMenu.dropdown.label"> <source>Module action</source> </trans-unit> diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/backend-module-result-type.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/backend-module-result-type.js new file mode 100644 index 000000000000..42329614f0d8 --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/backend-module-result-type.js @@ -0,0 +1,13 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +import LiveSearchConfigurator from"@typo3/backend/live-search/live-search-configurator.js";export function registerType(e){LiveSearchConfigurator.addInvokeHandler(e,"open_module",(e=>{TYPO3.ModuleMenu.App.showModule(e.extraData.moduleIdentifier)}))} \ No newline at end of file diff --git a/typo3/sysext/core/Documentation/Changelog/13.2/Feature-92009-ProvideBackendModulesInLiveSearch.rst b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-92009-ProvideBackendModulesInLiveSearch.rst new file mode 100644 index 000000000000..ee92789d3a83 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-92009-ProvideBackendModulesInLiveSearch.rst @@ -0,0 +1,23 @@ +.. include:: /Includes.rst.txt + +.. _feature-92009-1718182575: + +======================================================= +Feature: #92009 - Provide backend modules in LiveSearch +======================================================= + +See :issue:`92009` + +Description +=========== + +The backend LiveSearch is now capable of listing backend modules, a user has +access to, offering the possibility of alternative navigation to different +parts of the backend. + +Impact +====== + +Backend users now have another possibility to quickly access a backend module. + +.. index:: Backend, ext:backend -- GitLab