diff options
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/components/PublicPageMenu/PublicPageMenuLinkEntry.vue | 2 | ||||
-rw-r--r-- | core/src/components/UnifiedSearch/UnifiedSearchModal.vue | 60 | ||||
-rw-r--r-- | core/src/views/UnifiedSearch.vue | 63 |
3 files changed, 69 insertions, 56 deletions
diff --git a/core/src/components/PublicPageMenu/PublicPageMenuLinkEntry.vue b/core/src/components/PublicPageMenu/PublicPageMenuLinkEntry.vue index 54645e9ce48..5f3a4883d6d 100644 --- a/core/src/components/PublicPageMenu/PublicPageMenuLinkEntry.vue +++ b/core/src/components/PublicPageMenu/PublicPageMenuLinkEntry.vue @@ -33,7 +33,7 @@ const emit = defineEmits<{ async function copyLink() { try { await window.navigator.clipboard.writeText(props.href) - showSuccess(t('core', 'Direct link copied to clipboard')) + showSuccess(t('core', 'Direct link copied')) } catch { // No secure context -> fallback to dialog window.prompt(t('core', 'Please copy the link manually:'), props.href) diff --git a/core/src/components/UnifiedSearch/UnifiedSearchModal.vue b/core/src/components/UnifiedSearch/UnifiedSearchModal.vue index 002606f058b..e59058bc0f0 100644 --- a/core/src/components/UnifiedSearch/UnifiedSearchModal.vue +++ b/core/src/components/UnifiedSearch/UnifiedSearchModal.vue @@ -86,6 +86,13 @@ <IconFilter :size="20" /> </template> </NcButton> + <NcCheckboxRadioSwitch v-if="hasExternalResources" + v-model="searchExternalResources" + type="switch" + class="unified-search-modal__search-external-resources" + :class="{'unified-search-modal__search-external-resources--aligned': localSearch}"> + {{ t('core', 'Search connected services') }} + </NcCheckboxRadioSwitch> </div> <div class="unified-search-modal__filters-applied"> <FilterChip v-for="filter in filters" @@ -129,7 +136,7 @@ v-bind="result" /> </ul> <div class="result-footer"> - <NcButton type="tertiary-no-background" @click="loadMoreResultsForProvider(providerResult)"> + <NcButton v-if="providerResult.results.length === providerResult.limit" type="tertiary-no-background" @click="loadMoreResultsForProvider(providerResult)"> {{ t('core', 'Load more results') }} <template #icon> <IconDotsHorizontal :size="20" /> @@ -172,6 +179,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 +206,7 @@ export default defineComponent({ NcEmptyContent, NcDialog, NcInputField, + NcCheckboxRadioSwitch, SearchableList, SearchResult, }, @@ -264,6 +273,7 @@ export default defineComponent({ showDateRangeModal: false, internalIsVisible: this.open, initialized: false, + searchExternalResources: false, } }, @@ -301,6 +311,10 @@ export default defineComponent({ debouncedFilterContacts() { return debounce(this.filterContacts, 300) }, + + hasExternalResources() { + return this.providers.some(provider => provider.isExternalProvider) + }, }, watch: { @@ -338,6 +352,12 @@ export default defineComponent({ this.$emit('update:query', this.searchQuery) }, }, + + searchExternalResources() { + if (this.searchQuery) { + this.find(this.searchQuery) + } + }, }, mounted() { @@ -367,7 +387,7 @@ export default defineComponent({ this.$refs.searchInput?.focus() }) }, - find(query: string) { + find(query: string, providersToSearchOverride = null) { if (query.length === 0) { this.results = [] this.searching = false @@ -382,7 +402,7 @@ export default defineComponent({ this.searching = true const newResults = [] - const providersToSearch = this.filteredProviders.length > 0 ? this.filteredProviders : this.providers + const providersToSearch = providersToSearchOverride || (this.filteredProviders.length > 0 ? this.filteredProviders : this.providers) const searchProvider = (provider) => { const params = { type: provider.searchFrom ?? provider.id, @@ -418,12 +438,21 @@ export default defineComponent({ unifiedSearchLogger.debug('Limiting search to', params.limit) } + const shouldSkipSearch = !this.searchExternalResources && provider.isExternalProvider + const wasManuallySelected = this.filteredProviders.some(filteredProvider => filteredProvider.id === provider.id) + // if the provider is an external 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) => { newResults.push({ ...provider, results: response.data.ocs.data.entries, + limit: params.limit ?? 5, }) unifiedSearchLogger.debug('Unified search results:', { results: this.results, newResults }) @@ -513,15 +542,7 @@ export default defineComponent({ }, async loadMoreResultsForProvider(provider) { this.providerResultLimit += 5 - // Remove all other providers from filteredProviders except the current "loadmore" provider - this.filteredProviders = this.filteredProviders.filter(filteredProvider => filteredProvider.id === provider.id) - // Plugin filters may have extra parameters, so we need to keep them - // See method handlePluginFilter for more details - if (this.filteredProviders.length > 0 && this.filteredProviders[0].isPluginFilter) { - provider = this.filteredProviders[0] - } - this.addProviderFilter(provider, true) - this.find(this.searchQuery) + this.find(this.searchQuery, [provider]) }, addProviderFilter(providerFilter, loadMoreResultsForProvider = false) { unifiedSearchLogger.debug('Applying provider filter', { providerFilter, loadMoreResultsForProvider }) @@ -749,6 +770,21 @@ export default defineComponent({ padding-top: 4px; } + &__search-external-resources { + :deep(span.checkbox-content) { + padding-top: 0; + padding-bottom: 0; + } + + :deep(.checkbox-content__icon) { + margin: auto !important; + } + + &--aligned { + margin-inline-start: auto; + } + } + &__filters-applied { padding-top: 4px; display: flex; diff --git a/core/src/views/UnifiedSearch.vue b/core/src/views/UnifiedSearch.vue index 0dec6d5fb6e..103e47b0425 100644 --- a/core/src/views/UnifiedSearch.vue +++ b/core/src/views/UnifiedSearch.vue @@ -3,16 +3,14 @@ - SPDX-License-Identifier: AGPL-3.0-or-later --> <template> - <div class="header-menu unified-search-menu"> - <NcButton v-show="!showLocalSearch" - class="header-menu__trigger" + <div class="unified-search-menu"> + <NcHeaderButton v-show="!showLocalSearch" :aria-label="t('core', 'Unified search')" - type="tertiary-no-background" @click="toggleUnifiedSearch"> <template #icon> - <Magnify class="header-menu__trigger-icon" :size="20" /> + <NcIconSvgWrapper :path="mdiMagnify" /> </template> - </NcButton> + </NcHeaderButton> <UnifiedSearchLocalSearchBar v-if="supportsLocalSearch" :open.sync="showLocalSearch" :query.sync="queryText" @@ -24,25 +22,24 @@ </template> <script lang="ts"> +import { mdiMagnify } from '@mdi/js' import { emit, subscribe } from '@nextcloud/event-bus' -import { translate } from '@nextcloud/l10n' +import { t } from '@nextcloud/l10n' import { useBrowserLocation } from '@vueuse/core' +import debounce from 'debounce' import { defineComponent } from 'vue' - -import NcButton from '@nextcloud/vue/components/NcButton' -import Magnify from 'vue-material-design-icons/Magnify.vue' +import NcHeaderButton from '@nextcloud/vue/components/NcHeaderButton' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import UnifiedSearchModal from '../components/UnifiedSearch/UnifiedSearchModal.vue' import UnifiedSearchLocalSearchBar from '../components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue' - -import debounce from 'debounce' -import logger from '../logger' +import logger from '../logger.js' export default defineComponent({ name: 'UnifiedSearch', components: { - NcButton, - Magnify, + NcHeaderButton, + NcIconSvgWrapper, UnifiedSearchModal, UnifiedSearchLocalSearchBar, }, @@ -52,7 +49,9 @@ export default defineComponent({ return { currentLocation, - t: translate, + + mdiMagnify, + t, } }, @@ -130,7 +129,7 @@ export default defineComponent({ * @param event The keyboard event */ onKeyDown(event: KeyboardEvent) { - if (event.ctrlKey && event.code === 'KeyF') { + if (event.ctrlKey && event.key === 'f') { // only handle search if not already open - in this case the browser native search should be used if (!this.showLocalSearch && !this.showUnifiedSearch) { event.preventDefault() @@ -175,31 +174,9 @@ export default defineComponent({ <style lang="scss" scoped> // this is needed to allow us overriding component styles (focus-visible) -#header { - .header-menu { - display: flex; - align-items: center; - justify-content: center; - - &__trigger { - height: var(--header-height); - width: var(--header-height) !important; - - &:focus-visible { - // align with other header menu entries - outline: none !important; - box-shadow: none !important; - } - - &:not(:hover,:focus,:focus-visible) { - opacity: .85; - } - - &-icon { - // ensure the icon has the correct color - color: var(--color-background-plain-text) !important; - } - } - } +.unified-search-menu { + display: flex; + align-items: center; + justify-content: center; } </style> |