mirror of
https://github.com/nextcloud/server.git
synced 2026-02-27 18:37:17 +01:00
feat(unified-search): Use existing min search length config
This setting existed already for the legacy unified search. This commit expose that setting to the new front-end, and also ignore non valid requests in the backend. We also take the opportunity to register the config in the lexicon. Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
@@ -33,6 +33,8 @@ class ConfigLexicon implements ILexicon {
|
||||
public const USER_LOCALE = 'locale';
|
||||
public const USER_TIMEZONE = 'timezone';
|
||||
|
||||
public const UNIFIED_SEARCH_MIN_SEARCH_LENGTH = 'unified_search_min_search_length';
|
||||
|
||||
public const LASTCRON_TIMESTAMP = 'lastcron';
|
||||
|
||||
public function getStrictness(): Strictness {
|
||||
@@ -90,6 +92,7 @@ class ConfigLexicon implements ILexicon {
|
||||
new Entry(self::LASTCRON_TIMESTAMP, ValueType::INT, 0, 'timestamp of last cron execution'),
|
||||
new Entry(self::OCM_DISCOVERY_ENABLED, ValueType::BOOL, true, 'enable/disable OCM', lazy: true),
|
||||
new Entry(self::OCM_INVITE_ACCEPT_DIALOG, ValueType::STRING, '', 'route to local invite accept dialog', lazy: true, note: 'set as empty string to disable feature'),
|
||||
new Entry(self::UNIFIED_SEARCH_MIN_SEARCH_LENGTH, ValueType::INT, 1, 'Minimum search length to trigger the request', lazy: false, rename: 'unified-search.min-search-length'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCSController;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
@@ -37,6 +38,7 @@ class UnifiedSearchController extends OCSController {
|
||||
private SearchComposer $composer,
|
||||
private IRouter $router,
|
||||
private IURLGenerator $urlGenerator,
|
||||
private IL10N $l10n,
|
||||
) {
|
||||
parent::__construct('core', $request);
|
||||
}
|
||||
@@ -101,6 +103,11 @@ class UnifiedSearchController extends OCSController {
|
||||
} catch (UnsupportedFilter|InvalidArgumentException $e) {
|
||||
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($filters->count() === 0) {
|
||||
return new DataResponse($this->l10n->t('No valid filters provided'), Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return new DataResponse(
|
||||
$this->composer->search(
|
||||
$this->userSession->getUser(),
|
||||
|
||||
@@ -181,6 +181,7 @@ import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
|
||||
import NcInputField from '@nextcloud/vue/components/NcInputField'
|
||||
import NcDialog from '@nextcloud/vue/components/NcDialog'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
|
||||
import CustomDateRangeModal from './CustomDateRangeModal.vue'
|
||||
import FilterChip from './SearchFilterChip.vue'
|
||||
@@ -281,6 +282,7 @@ export default defineComponent({
|
||||
internalIsVisible: this.open,
|
||||
initialized: false,
|
||||
searchExternalResources: false,
|
||||
minSearchLength: loadState('unified-search', 'min-search-length', 1),
|
||||
}
|
||||
},
|
||||
|
||||
@@ -293,6 +295,10 @@ export default defineComponent({
|
||||
return !this.isEmptySearch && this.results.length === 0
|
||||
},
|
||||
|
||||
isSearchQueryTooShort() {
|
||||
return this.searchQuery.length < this.minSearchLength
|
||||
},
|
||||
|
||||
showEmptyContentInfo() {
|
||||
return this.isEmptySearch || this.hasNoResults
|
||||
},
|
||||
@@ -301,9 +307,16 @@ export default defineComponent({
|
||||
if (this.searching && this.hasNoResults) {
|
||||
return t('core', 'Searching …')
|
||||
}
|
||||
if (this.isEmptySearch) {
|
||||
return t('core', 'Start typing to search')
|
||||
|
||||
if (this.isSearchQueryTooShort) {
|
||||
switch (this.minSearchLength) {
|
||||
case 1:
|
||||
return t('core', 'Start typing to search')
|
||||
default:
|
||||
return t('core', 'Minimum search length is {minSearchLength} characters', { minSearchLength: this.minSearchLength })
|
||||
}
|
||||
}
|
||||
|
||||
return t('core', 'No matching results')
|
||||
},
|
||||
|
||||
@@ -395,7 +408,7 @@ export default defineComponent({
|
||||
})
|
||||
},
|
||||
find(query: string, providersToSearchOverride = null) {
|
||||
if (query.length === 0) {
|
||||
if (this.isSearchQueryTooShort) {
|
||||
this.results = []
|
||||
this.searching = false
|
||||
return
|
||||
|
||||
@@ -40,4 +40,8 @@ class FilterCollection implements IFilterCollection {
|
||||
yield $k => $v;
|
||||
}
|
||||
}
|
||||
|
||||
public function count(): int {
|
||||
return count($this->filters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace OC\Search;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OC\AppFramework\Bootstrap\Coordinator;
|
||||
use OC\Core\AppInfo\Application;
|
||||
use OC\Core\AppInfo\ConfigLexicon;
|
||||
use OC\Core\ResponseDefinitions;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IURLGenerator;
|
||||
@@ -315,6 +317,12 @@ class SearchComposer {
|
||||
throw new UnsupportedFilter($name, $providerId);
|
||||
}
|
||||
|
||||
$minSearchLength = $this->appConfig->getValueInt(Application::APP_ID, ConfigLexicon::UNIFIED_SEARCH_MIN_SEARCH_LENGTH);
|
||||
if ($filterDefinition->name() === 'term' && mb_strlen(trim($value)) < $minSearchLength) {
|
||||
// Ignore term values that are not long enough
|
||||
return null;
|
||||
}
|
||||
|
||||
return FilterFactory::get($filterDefinition->type(), $value);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace OC;
|
||||
use bantu\IniGetWrapper\IniGetWrapper;
|
||||
use OC\AppFramework\Http\Request;
|
||||
use OC\Authentication\Token\IProvider;
|
||||
use OC\Core\AppInfo\Application;
|
||||
use OC\Core\AppInfo\ConfigLexicon;
|
||||
use OC\Files\FilenameValidator;
|
||||
use OC\Search\SearchQuery;
|
||||
use OC\Template\CSSResourceLocator;
|
||||
@@ -74,9 +76,9 @@ class TemplateLayout {
|
||||
$this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry());
|
||||
$this->initialState->provideInitialState('core', 'apps', array_values($this->navigationManager->getAll()));
|
||||
|
||||
$this->initialState->provideInitialState('unified-search', 'min-search-length', $this->appConfig->getValueInt(Application::APP_ID, ConfigLexicon::UNIFIED_SEARCH_MIN_SEARCH_LENGTH));
|
||||
if ($this->config->getSystemValueBool('unified_search.enabled', false) || !$this->config->getSystemValueBool('enable_non-accessible_features', true)) {
|
||||
$this->initialState->provideInitialState('unified-search', 'limit-default', (int)$this->config->getAppValue('core', 'unified-search.limit-default', (string)SearchQuery::LIMIT_DEFAULT));
|
||||
$this->initialState->provideInitialState('unified-search', 'min-search-length', (int)$this->config->getAppValue('core', 'unified-search.min-search-length', (string)1));
|
||||
$this->initialState->provideInitialState('unified-search', 'live-search', $this->config->getAppValue('core', 'unified-search.live-search', 'yes') === 'yes');
|
||||
Util::addScript('core', 'legacy-unified-search', 'core');
|
||||
} else {
|
||||
|
||||
@@ -36,4 +36,11 @@ interface IFilterCollection extends IteratorAggregate {
|
||||
* @since 28.0.0
|
||||
*/
|
||||
public function getIterator(): \Traversable;
|
||||
|
||||
/**
|
||||
* Return the number of filters
|
||||
*
|
||||
* @since 32.0.1
|
||||
*/
|
||||
public function count(): int;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user