diff --git a/apps/comments/lib/Search/CommentsSearchProvider.php b/apps/comments/lib/Search/CommentsSearchProvider.php index bab10a58eebbb59e6a875fc7570b21e62e25a8ad..e6443c20a2f20730cfa45be03786c8c9ece38982 100644 --- a/apps/comments/lib/Search/CommentsSearchProvider.php +++ b/apps/comments/lib/Search/CommentsSearchProvider.php @@ -77,7 +77,11 @@ class CommentsSearchProvider implements IProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'files.View.index') { + // Files first + return 0; + } return 10; } diff --git a/apps/dav/lib/Search/ContactsSearchProvider.php b/apps/dav/lib/Search/ContactsSearchProvider.php index 82fa44a7a26c794ad257a94fe3a675552be6c9ae..f97ba2cf634c30f767b4231de28cfba0aaf56042 100644 --- a/apps/dav/lib/Search/ContactsSearchProvider.php +++ b/apps/dav/lib/Search/ContactsSearchProvider.php @@ -96,8 +96,11 @@ class ContactsSearchProvider implements IProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { - return 7; + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'contacts.Page.index') { + return -1; + } + return 20; } /** diff --git a/apps/dav/lib/Search/EventsSearchProvider.php b/apps/dav/lib/Search/EventsSearchProvider.php index c9ce11a297db0f4236c1c71997772e7fbb6903bb..619775aa19306b543eb1fc42f8a1e6d2dda8af0c 100644 --- a/apps/dav/lib/Search/EventsSearchProvider.php +++ b/apps/dav/lib/Search/EventsSearchProvider.php @@ -82,7 +82,10 @@ class EventsSearchProvider extends ACalendarSearchProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'calendar.View.index') { + return -1; + } return 10; } diff --git a/apps/dav/lib/Search/TasksSearchProvider.php b/apps/dav/lib/Search/TasksSearchProvider.php index 6c07cfd00f337f1fecaa6003656e3f7abb09bdcb..adc1197aa1867967e8382ae6eba8371c3d1f9aad 100644 --- a/apps/dav/lib/Search/TasksSearchProvider.php +++ b/apps/dav/lib/Search/TasksSearchProvider.php @@ -74,7 +74,10 @@ class TasksSearchProvider extends ACalendarSearchProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'tasks.Page.index') { + return -1; + } return 10; } diff --git a/apps/files/lib/Search/FilesSearchProvider.php b/apps/files/lib/Search/FilesSearchProvider.php index ce6f705f72c53b5211b1c597ea2ffc6f0c027f58..e221dab0ab1078dcf35e1f8dfdb5972d88215301 100644 --- a/apps/files/lib/Search/FilesSearchProvider.php +++ b/apps/files/lib/Search/FilesSearchProvider.php @@ -77,7 +77,11 @@ class FilesSearchProvider implements IProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'files.View.index') { + // Before comments + return -5; + } return 5; } diff --git a/apps/settings/lib/Search/SectionSearch.php b/apps/settings/lib/Search/SectionSearch.php index d949d93fb61fcd7bcbf0442d4536e8147cb3c17b..795b9f7e9f74d5c0a04d0ed5aca5d9962e4afa39 100644 --- a/apps/settings/lib/Search/SectionSearch.php +++ b/apps/settings/lib/Search/SectionSearch.php @@ -75,9 +75,8 @@ class SectionSearch implements IProvider { /** * @inheritDoc */ - public function getOrder(string $from): int { - if (strpos($from, $this->urlGenerator->linkToRoute('settings.PersonalSettings.index') === 0) - || strpos($from, $this->urlGenerator->linkToRoute('settings.AdminSettings.index')) === 0) { + public function getOrder(string $route, array $routeParameters): int { + if ($route === 'settings.PersonalSettings.index' || $route === 'settings.AdminSettings.index') { return -1; } return 20; diff --git a/core/Controller/UnifiedSearchController.php b/core/Controller/UnifiedSearchController.php index 4aaa1b9b067f63a10f8325c9eebf15a337798c5b..839bbde1003b23432c849d47ccfb1db009168b14 100644 --- a/core/Controller/UnifiedSearchController.php +++ b/core/Controller/UnifiedSearchController.php @@ -32,7 +32,9 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; use OCP\IRequest; use OCP\IUserSession; +use OCP\Route\IRouter; use OCP\Search\ISearchQuery; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; class UnifiedSearchController extends Controller { @@ -42,26 +44,33 @@ class UnifiedSearchController extends Controller { /** @var IUserSession */ private $userSession; + /** @var IRouter */ + private $router; + public function __construct(IRequest $request, IUserSession $userSession, - SearchComposer $composer) { + SearchComposer $composer, + IRouter $router) { parent::__construct('core', $request); $this->composer = $composer; $this->userSession = $userSession; + $this->router = $router; } /** * @NoAdminRequired * @NoCSRFRequired - * + * * @param string $from the url the user is currently at - * + * * @return JSONResponse */ - public function getProviders(string $from): JSONResponse { + public function getProviders(string $from = ''): JSONResponse { + [$route, $parameters] = $this->getRouteInformation($from); + return new JSONResponse( - $this->composer->getProviders($from) + $this->composer->getProviders($route, $parameters) ); } @@ -74,6 +83,7 @@ class UnifiedSearchController extends Controller { * @param int|null $sortOrder * @param int|null $limit * @param int|string|null $cursor + * @param string $from * * @return JSONResponse */ @@ -81,10 +91,12 @@ class UnifiedSearchController extends Controller { string $term = '', ?int $sortOrder = null, ?int $limit = null, - $cursor = null): JSONResponse { + $cursor = null, + string $from = ''): JSONResponse { if (empty(trim($term))) { return new JSONResponse(null, Http::STATUS_BAD_REQUEST); } + [$route, $routeParameters] = $this->getRouteInformation($from); return new JSONResponse( $this->composer->search( @@ -94,9 +106,45 @@ class UnifiedSearchController extends Controller { $term, $sortOrder ?? ISearchQuery::SORT_DATE_DESC, $limit ?? SearchQuery::LIMIT_DEFAULT, - $cursor + $cursor, + $route, + $routeParameters ) ) ); } + + protected function getRouteInformation(string $url): array { + $routeStr = ''; + $parameters = []; + + if ($url !== '') { + $urlParts = parse_url($url); + + try { + $parameters = $this->router->findMatchingRoute($urlParts['path']); + + // contacts.PageController.index => contacts.Page.index + $route = $parameters['caller']; + if (substr($route[1], -10) === 'Controller') { + $route[1] = substr($route[1], 0, -10); + } + $routeStr = implode('.', $route); + + // cleanup + unset($parameters['_route'], $parameters['action'], $parameters['caller']); + } catch (ResourceNotFoundException $exception) { + } + + if (isset($urlParts['query'])) { + parse_str($urlParts['query'], $queryParameters); + $parameters = array_merge($parameters, $queryParameters); + } + } + + return [ + $routeStr, + $parameters, + ]; + } } diff --git a/core/js/dist/install.js b/core/js/dist/install.js index a08e3088b2a0c943c8191999a48af38c300f6f8d..9a13d4a9182f220818649bb69ba135f73fc85c3f 100644 Binary files a/core/js/dist/install.js and b/core/js/dist/install.js differ diff --git a/core/js/dist/install.js.map b/core/js/dist/install.js.map index 130525abfb387fe7ff1253dcf61fd109a6f78ab3..1f3b21eda1f7f4a555955f3dc811c5ec12a2a3be 100644 Binary files a/core/js/dist/install.js.map and b/core/js/dist/install.js.map differ diff --git a/core/js/dist/login.js b/core/js/dist/login.js index 4e26c5482d9a6a0e44264eb7a997ca56adea37a5..ed9b24a753b18b50816a0bc31d64026f2637e5f9 100644 Binary files a/core/js/dist/login.js and b/core/js/dist/login.js differ diff --git a/core/js/dist/login.js.map b/core/js/dist/login.js.map index 6af833a9ccd2c8550f243f8735316ab0557bc16e..b97d5c344892bcc4d71f1d933f2a6133ce5b7a53 100644 Binary files a/core/js/dist/login.js.map and b/core/js/dist/login.js.map differ diff --git a/core/js/dist/main.js b/core/js/dist/main.js index 7baabb19e5d50d75429a39ab0fcba068e62446c9..96020a0ae32db6449e539a0c976f85f361c288a6 100644 Binary files a/core/js/dist/main.js and b/core/js/dist/main.js differ diff --git a/core/js/dist/main.js.map b/core/js/dist/main.js.map index c80347ff72c2619e3f0e16166bfb3cd32e315b6d..12c39288474e3d5147b5f05dddf9b3ef2f541f00 100644 Binary files a/core/js/dist/main.js.map and b/core/js/dist/main.js.map differ diff --git a/core/js/dist/maintenance.js b/core/js/dist/maintenance.js index f6c55434406daa1f081df992a664eb9672df9558..eb1ababc9e0e0b618f41056e060b131e6a0355d2 100644 Binary files a/core/js/dist/maintenance.js and b/core/js/dist/maintenance.js differ diff --git a/core/js/dist/maintenance.js.map b/core/js/dist/maintenance.js.map index b0d78a01b9267c7b3c9aaa5dc1fd2083361dd947..855edb44121eee5ff43c34a953bd4ac0a5a28e57 100644 Binary files a/core/js/dist/maintenance.js.map and b/core/js/dist/maintenance.js.map differ diff --git a/core/js/dist/recommendedapps.js b/core/js/dist/recommendedapps.js index db31d1ec8f3837406d9c19ff08c5e639663a43c4..c763081046b41cd409429c04d38c0c7f17edf40c 100644 Binary files a/core/js/dist/recommendedapps.js and b/core/js/dist/recommendedapps.js differ diff --git a/core/js/dist/recommendedapps.js.map b/core/js/dist/recommendedapps.js.map index 864cf8ae121810d4f4f08fc840c02db7c4e2b165..c7cd021446f29b5c4729bcb579f9cbb4d1020557 100644 Binary files a/core/js/dist/recommendedapps.js.map and b/core/js/dist/recommendedapps.js.map differ diff --git a/core/js/dist/unified-search.js b/core/js/dist/unified-search.js index 2a2426a4f6243b43fd1774bd7a43e1c084f4fe9f..d87920694030cf9bcbeb98be819ece5de2b038b7 100644 Binary files a/core/js/dist/unified-search.js and b/core/js/dist/unified-search.js differ diff --git a/core/js/dist/unified-search.js.map b/core/js/dist/unified-search.js.map index 825e8ecb990e2a6791224a511eb10206ff696dbe..02e151de93c22f7fd952d385ed9681046f209805 100644 Binary files a/core/js/dist/unified-search.js.map and b/core/js/dist/unified-search.js.map differ diff --git a/core/src/services/UnifiedSearchService.js b/core/src/services/UnifiedSearchService.js index bc8cca19ce8b8550e0f5eb44e2ca631f29da6049..8e4c4a2a0731b516e819e82acd53d6d0ccf0a148 100644 --- a/core/src/services/UnifiedSearchService.js +++ b/core/src/services/UnifiedSearchService.js @@ -24,8 +24,7 @@ import { loadState } from '@nextcloud/initial-state' import axios from '@nextcloud/axios' export const defaultLimit = loadState('unified-search', 'limit-default') -export const activeApp = loadState('core', 'active-app') - +export const minSearchLength = 2 /** * Get the list of available search providers * diff --git a/core/src/views/UnifiedSearch.vue b/core/src/views/UnifiedSearch.vue index 4e32bdbedd1b08caf127b0b8625b2730912e02bf..4f316866862c93f02abdbce1da356ea93144961b 100644 --- a/core/src/views/UnifiedSearch.vue +++ b/core/src/views/UnifiedSearch.vue @@ -67,7 +67,7 @@ <!-- Grouped search results --> <template v-else> - <ul v-for="(list, type, typesIndex) in orderedResults" + <ul v-for="({list, type}, typesIndex) in orderedResults" :key="type" class="unified-search__results" :class="`unified-search__results-${type}`" @@ -97,7 +97,7 @@ </template> <script> -import { getTypes, search, defaultLimit, activeApp } from '../services/UnifiedSearchService' +import { minSearchLength, getTypes, search, defaultLimit } from '../services/UnifiedSearchService' import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent' import Magnify from 'vue-material-design-icons/Magnify' import debounce from 'debounce' @@ -106,8 +106,6 @@ import HeaderMenu from '../components/HeaderMenu' import SearchResult from '../components/UnifiedSearch/SearchResult' import SearchResultPlaceholder from '../components/UnifiedSearch/SearchResultPlaceholder' -const minSearchLength = 2 - export default { name: 'UnifiedSearch', @@ -132,7 +130,6 @@ export default { query: '', focused: null, - activeApp, defaultLimit, minSearchLength, @@ -163,18 +160,16 @@ export default { }, /** - * Order results by putting the active app first + * Return ordered results * @returns {Object} */ orderedResults() { - const ordered = {} - Object.keys(this.results) - .sort((a, b) => this.typesMap[a].order - this.typesMap[b].order) - .forEach(type => { - ordered[type] = this.results[type] - }) - - return ordered + return Object.values(this.typesIDs) + .filter(type => type in this.results) + .map(type => ({ + type, + list: this.results[type], + })) }, /** @@ -390,10 +385,10 @@ export default { * @returns {Array} */ limitIfAny(list, type) { - if (!this.limits[type]) { - return list + if (type in this.limits) { + return list.slice(0, this.limits[type]) } - return list.slice(0, this.limits[type]) + return list }, getResultsList() { diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php index de7c720f27176f013e0e2e3432603693ee0cccc1..6de581ffa96a42a22f2468d277e6cb1df53e8483 100644 --- a/lib/private/Route/Router.php +++ b/lib/private/Route/Router.php @@ -239,9 +239,9 @@ class Router implements IRouter { * * @param string $url The url to find * @throws \Exception - * @return void + * @return array */ - public function match($url) { + public function findMatchingRoute(string $url): array { if (substr($url, 0, 6) === '/apps/') { // empty string / 'apps' / $app / rest of the route list(, , $app,) = explode('/', $url, 4); @@ -287,6 +287,19 @@ class Router implements IRouter { } } + return $parameters; + } + + /** + * Find and execute the route matching $url + * + * @param string $url The url to find + * @throws \Exception + * @return void + */ + public function match($url) { + $parameters = $this->findMatchingRoute($url); + \OC::$server->getEventLogger()->start('run_route', 'Run route'); if (isset($parameters['caller'])) { $caller = $parameters['caller']; diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php index f86626909c49e9dc411b79910c9d7431226965b8..fdac9c5612aa358c634b79a30ed8090b24fa1ce0 100644 --- a/lib/private/Search/SearchComposer.php +++ b/lib/private/Search/SearchComposer.php @@ -109,19 +109,20 @@ class SearchComposer { * Get a list of all provider IDs & Names for the consecutive calls to `search` * Sort the list by the order property * - * @param string $from the url the user is currently at + * @param string $route the route the user is currently at + * @param array $routeParameters the parameters of the route the user is currently at * * @return array */ - public function getProviders(string $from): array { + public function getProviders(string $route, array $routeParameters): array { $this->loadLazyProviders(); $providers = array_values( - array_map(function (IProvider $provider) use ($from) { + array_map(function (IProvider $provider) use ($route, $routeParameters) { return [ 'id' => $provider->getId(), 'name' => $provider->getName(), - 'order' => $provider->getOrder($from) + 'order' => $provider->getOrder($route, $routeParameters), ]; }, $this->providers) ); diff --git a/lib/private/Search/SearchQuery.php b/lib/private/Search/SearchQuery.php index 186b4ccf18f22a982845898b47984fdc20a25da7..7ba63de90ec5dcf4e432b26890018e421d8e9f64 100644 --- a/lib/private/Search/SearchQuery.php +++ b/lib/private/Search/SearchQuery.php @@ -42,20 +42,32 @@ class SearchQuery implements ISearchQuery { /** @var int|string|null */ private $cursor; + /** @var string */ + private $route; + + /** @var array */ + private $routeParameters; + /** * @param string $term * @param int $sortOrder * @param int $limit * @param int|string|null $cursor + * @param string $route + * @param array $routeParameters */ public function __construct(string $term, int $sortOrder = ISearchQuery::SORT_DATE_DESC, int $limit = self::LIMIT_DEFAULT, - $cursor = null) { + $cursor = null, + string $route = '', + array $routeParameters = []) { $this->term = $term; $this->sortOrder = $sortOrder; $this->limit = $limit; $this->cursor = $cursor; + $this->route = $route; + $this->routeParameters = $routeParameters; } /** @@ -85,4 +97,18 @@ class SearchQuery implements ISearchQuery { public function getCursor() { return $this->cursor; } + + /** + * @inheritDoc + */ + public function getRoute(): string { + return $this->route; + } + + /** + * @inheritDoc + */ + public function getRouteParameters(): array { + return $this->routeParameters; + } } diff --git a/lib/public/Search/IProvider.php b/lib/public/Search/IProvider.php index 5a6cfb3fd03a2087e5f8a1f45cb932ca38eec632..a91efa55fe16db80baab676e83a40c54d5c5cefd 100644 --- a/lib/public/Search/IProvider.php +++ b/lib/public/Search/IProvider.php @@ -68,13 +68,14 @@ interface IProvider { * Get the search provider order * The lower the int, the higher it will be sorted (0 will be before 10) * - * @param string $from the url the user is currently at. (e.g. /apps/files/?dir=/&fileid=982) + * @param string $route the route the user is currently at, e.g. files.view.index + * @param array $routeParameters the parameters of the route the user is currently at, e.g. [fileId = 982, dir = "/"] * * @return int * * @since 20.0.0 */ - public function getOrder(string $from): int; + public function getOrder(string $route, array $routeParameters): int; /** * Find matching search entries in an app diff --git a/lib/public/Search/ISearchQuery.php b/lib/public/Search/ISearchQuery.php index 00d538050d46bdbc9ac960ecc49d22a57fb571ac..f89251dd134bf915647503cdcbbcea122efc25ec 100644 --- a/lib/public/Search/ISearchQuery.php +++ b/lib/public/Search/ISearchQuery.php @@ -76,4 +76,16 @@ interface ISearchQuery { * @since 20.0.0 */ public function getCursor(); + + /** + * @return string + * @since 20.0.0 + */ + public function getRoute(): string; + + /** + * @return array + * @since 20.0.0 + */ + public function getRouteParameters(): array; }