aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Borysenko <andrey18106x@gmail.com>2025-07-17 19:03:09 +0300
committerAndrey Borysenko <andrey18106x@gmail.com>2025-07-17 19:56:38 +0300
commit393715340e5770f5a3e812c2fd7d562b295ad8ad (patch)
tree15c47fb12eee36f6ec3892b8a30234a626b56975
parent2cbfdcc4932857cc9f335aab86b37cc31cfa863a (diff)
downloadnextcloud-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.vue38
-rw-r--r--lib/private/Search/SearchComposer.php3
-rw-r--r--lib/public/Search/IOnlineProvider.php25
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;
+}