mirror of
https://github.com/nextcloud/server.git
synced 2026-02-20 00:12:30 -05:00
Merge pull request #22104 from nextcloud/enh/search/make-app-handle-the-order-logic
Make apps handle the order logic
This commit is contained in:
commit
55473dd2eb
26 changed files with 181 additions and 86 deletions
|
|
@ -77,7 +77,11 @@ class CommentsSearchProvider implements IProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'files.View.index') {
|
||||
// Files first
|
||||
return 0;
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,8 +96,11 @@ class ContactsSearchProvider implements IProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
return 7;
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'contacts.Page.index') {
|
||||
return -1;
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -82,7 +82,10 @@ class EventsSearchProvider extends ACalendarSearchProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'calendar.View.index') {
|
||||
return -1;
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,10 @@ class TasksSearchProvider extends ACalendarSearchProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'tasks.Page.index') {
|
||||
return -1;
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,11 @@ class FilesSearchProvider implements IProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'files.View.index') {
|
||||
// Before comments
|
||||
return -5;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,10 @@ class SectionSearch implements IProvider {
|
|||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
public function getOrder(string $route, array $routeParameters): int {
|
||||
if ($route === 'settings.PersonalSettings.index' || $route === 'settings.AdminSettings.index') {
|
||||
return -1;
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,22 +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(): JSONResponse {
|
||||
public function getProviders(string $from = ''): JSONResponse {
|
||||
[$route, $parameters] = $this->getRouteInformation($from);
|
||||
|
||||
return new JSONResponse(
|
||||
$this->composer->getProviders()
|
||||
$this->composer->getProviders($route, $parameters)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -70,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
|
||||
*/
|
||||
|
|
@ -77,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(
|
||||
|
|
@ -90,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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
core/js/dist/install.js
vendored
2
core/js/dist/install.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/install.js.map
vendored
2
core/js/dist/install.js.map
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/login.js
vendored
2
core/js/dist/login.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/login.js.map
vendored
2
core/js/dist/login.js.map
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/main.js
vendored
2
core/js/dist/main.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/main.js.map
vendored
2
core/js/dist/main.js.map
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/maintenance.js
vendored
2
core/js/dist/maintenance.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/maintenance.js.map
vendored
2
core/js/dist/maintenance.js.map
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/recommendedapps.js
vendored
2
core/js/dist/recommendedapps.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/recommendedapps.js.map
vendored
2
core/js/dist/recommendedapps.js.map
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/unified-search.js
vendored
2
core/js/dist/unified-search.js
vendored
File diff suppressed because one or more lines are too long
2
core/js/dist/unified-search.js.map
vendored
2
core/js/dist/unified-search.js.map
vendored
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
*
|
||||
|
|
@ -33,9 +32,15 @@ export const activeApp = loadState('core', 'active-app')
|
|||
*/
|
||||
export async function getTypes() {
|
||||
try {
|
||||
const { data } = await axios.get(generateUrl('/search/providers'))
|
||||
const { data } = await axios.get(generateUrl('/search/providers'), {
|
||||
params: {
|
||||
// Sending which location we're currently at
|
||||
from: window.location.pathname.replace('/index.php', '') + window.location.search,
|
||||
},
|
||||
})
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
return sortProviders(data)
|
||||
// Providers are sorted by the api based on their order key
|
||||
return data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
|
@ -43,29 +48,6 @@ export async function getTypes() {
|
|||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the providers by the current active app
|
||||
*
|
||||
* @param {Array} providers the providers list
|
||||
* @returns {Array}
|
||||
*/
|
||||
export function sortProviders(providers) {
|
||||
providers.sort((a, b) => {
|
||||
if (a.id.startsWith(activeApp) && b.id.startsWith(activeApp)) {
|
||||
return a.order - b.order
|
||||
}
|
||||
|
||||
if (a.id.startsWith(activeApp)) {
|
||||
return -1
|
||||
}
|
||||
if (b.id.startsWith(activeApp)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
return providers
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of available search providers
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,29 +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) => {
|
||||
if (a.startsWith(activeApp) && b.startsWith(activeApp)) {
|
||||
return this.typesMap[a].order - this.typesMap[b].order
|
||||
}
|
||||
if (a.startsWith(activeApp)) {
|
||||
return -1
|
||||
}
|
||||
if (b.startsWith(activeApp)) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
.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],
|
||||
}))
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -401,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() {
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
|
|
|
|||
|
|
@ -109,17 +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 $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(): array {
|
||||
public function getProviders(string $route, array $routeParameters): array {
|
||||
$this->loadLazyProviders();
|
||||
|
||||
$providers = array_values(
|
||||
array_map(function (IProvider $provider) {
|
||||
array_map(function (IProvider $provider) use ($route, $routeParameters) {
|
||||
return [
|
||||
'id' => $provider->getId(),
|
||||
'name' => $provider->getName(),
|
||||
'order' => $provider->getOrder()
|
||||
'order' => $provider->getOrder($route, $routeParameters),
|
||||
];
|
||||
}, $this->providers)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,11 +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 $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(): int;
|
||||
public function getOrder(string $route, array $routeParameters): int;
|
||||
|
||||
/**
|
||||
* Find matching search entries in an app
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue