diff options
author | Andrey Borysenko <andrey18106x@gmail.com> | 2025-07-17 19:03:09 +0300 |
---|---|---|
committer | Andrey Borysenko <andrey18106x@gmail.com> | 2025-07-17 19:56:38 +0300 |
commit | 393715340e5770f5a3e812c2fd7d562b295ad8ad (patch) | |
tree | 15c47fb12eee36f6ec3892b8a30234a626b56975 | |
parent | 2cbfdcc4932857cc9f335aab86b37cc31cfa863a (diff) | |
download | nextcloud-server-feat/unified_search/online_providers.tar.gz nextcloud-server-feat/unified_search/online_providers.zip |
feat(UnifiedSearch): Online search providers supportfeat/unified_search/online_providers
Signed-off-by: Andrey Borysenko <andrey18106x@gmail.com>
-rw-r--r-- | core/src/components/UnifiedSearch/UnifiedSearchModal.vue | 38 | ||||
-rw-r--r-- | lib/private/Search/SearchComposer.php | 3 | ||||
-rw-r--r-- | lib/public/Search/IOnlineProvider.php | 25 |
3 files changed, 66 insertions, 0 deletions
diff --git a/core/src/components/UnifiedSearch/UnifiedSearchModal.vue b/core/src/components/UnifiedSearch/UnifiedSearchModal.vue index 744c8e604fa..3b89151df3f 100644 --- a/core/src/components/UnifiedSearch/UnifiedSearchModal.vue +++ b/core/src/components/UnifiedSearch/UnifiedSearchModal.vue @@ -86,6 +86,12 @@ <IconFilter :size="20" /> </template> </NcButton> + <NcCheckboxRadioSwitch v-model="searchOnlineResources" + type="switch" + class="unified-search-modal__search-online-resources" + :class="{'unified-search-modal__search-online-resources--aligned': !localSearch}"> + {{ t('core', 'Search online resources') }} + </NcCheckboxRadioSwitch> </div> <div class="unified-search-modal__filters-applied"> <FilterChip v-for="filter in filters" @@ -172,6 +178,7 @@ import NcButton from '@nextcloud/vue/components/NcButton' 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 CustomDateRangeModal from './CustomDateRangeModal.vue' import FilterChip from './SearchFilterChip.vue' @@ -198,6 +205,7 @@ export default defineComponent({ NcEmptyContent, NcDialog, NcInputField, + NcCheckboxRadioSwitch, SearchableList, SearchResult, }, @@ -264,6 +272,7 @@ export default defineComponent({ showDateRangeModal: false, internalIsVisible: this.open, initialized: false, + searchOnlineResources: false, } }, @@ -338,6 +347,12 @@ export default defineComponent({ this.$emit('update:query', this.searchQuery) }, }, + + searchOnlineResources() { + if (this.searchQuery) { + this.find(this.searchQuery) + } + }, }, mounted() { @@ -418,6 +433,14 @@ export default defineComponent({ unifiedSearchLogger.debug('Limiting search to', params.limit) } + const shouldSkipSearch = !this.searchOnlineResources && provider.isOnlineResource + const wasManuallySelected = this.filteredProviders.some(filteredProvider => filteredProvider.id === provider.id) + // if the provider is an online resource and the user has not manually selected it, skip the search + if (shouldSkipSearch && !wasManuallySelected) { + this.searching = false + return + } + const request = unifiedSearch(params).request request().then((response) => { @@ -749,6 +772,21 @@ export default defineComponent({ padding-top: 4px; } + &__search-online-resources { + :deep(span.checkbox-content) { + padding-top: 0; + padding-bottom: 0; + } + + :deep(.checkbox-content__icon) { + margin: auto !important; + } + + &--aligned { + margin-left: auto; + } + } + &__filters-applied { padding-top: 4px; display: flex; diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php index 77d7ca62311..a8c42dcbd33 100644 --- a/lib/private/Search/SearchComposer.php +++ b/lib/private/Search/SearchComposer.php @@ -18,6 +18,7 @@ use OCP\Search\FilterDefinition; use OCP\Search\IFilter; use OCP\Search\IFilteringProvider; use OCP\Search\IInAppSearch; +use OCP\Search\IOnlineProvider; use OCP\Search\IProvider; use OCP\Search\ISearchQuery; use OCP\Search\SearchResult; @@ -178,6 +179,7 @@ class SearchComposer { if ($order === null) { return; } + $isOnlineResource = $provider instanceof IOnlineProvider ? $provider->getIsOnlineResource() : false; $triggers = [$provider->getId()]; if ($provider instanceof IFilteringProvider) { $triggers += $provider->getAlternateIds(); @@ -192,6 +194,7 @@ class SearchComposer { 'name' => $provider->getName(), 'icon' => $this->fetchIcon($appId, $provider->getId()), 'order' => $order, + 'isOnlineResource' => $isOnlineResource, 'triggers' => array_values($triggers), 'filters' => $this->getFiltersType($filters, $provider->getId()), 'inAppSearch' => $provider instanceof IInAppSearch, diff --git a/lib/public/Search/IOnlineProvider.php b/lib/public/Search/IOnlineProvider.php new file mode 100644 index 00000000000..dbe7ecfce68 --- /dev/null +++ b/lib/public/Search/IOnlineProvider.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\Search; + +/** + * Interface for online search providers that forward user queries to external services. + * + * @since 32.0.0 + */ +interface IOnlineProvider { + /** + * Indicates whether this search provider queries online (external) resources. + * This is used by the Unified Search modal filter (toggle switch). By default, searching through online providers is disabled. + * + * @return bool default false + * + * @since 32.0.0 + */ + public function getIsOnlineResource(): bool; +} |