diff options
Diffstat (limited to 'apps/files/src/components')
4 files changed, 134 insertions, 3 deletions
diff --git a/apps/files/src/components/FilesListTableHeaderActions.vue b/apps/files/src/components/FilesListTableHeaderActions.vue index 4d2f2f361e6..53b7e7ef21b 100644 --- a/apps/files/src/components/FilesListTableHeaderActions.vue +++ b/apps/files/src/components/FilesListTableHeaderActions.vue @@ -6,6 +6,7 @@ <div class="files-list__column files-list__row-actions-batch" data-cy-files-list-selection-actions> <NcActions ref="actionsMenu" container="#app-content-vue" + :boundaries-element="boundariesElement" :disabled="!!loading || areSomeNodesLoading" :force-name="true" :inline="enabledInlineActions.length" @@ -123,6 +124,8 @@ export default defineComponent({ const fileListWidth = useFileListWidth() const { directory } = useRouteParameters() + const boundariesElement = document.getElementById('app-content-vue') + return { directory, fileListWidth, @@ -130,6 +133,8 @@ export default defineComponent({ actionsMenuStore, filesStore, selectionStore, + + boundariesElement, } }, diff --git a/apps/files/src/components/FilesNavigationItem.vue b/apps/files/src/components/FilesNavigationItem.vue index 372a83e1441..c29bc00c67f 100644 --- a/apps/files/src/components/FilesNavigationItem.vue +++ b/apps/files/src/components/FilesNavigationItem.vue @@ -89,7 +89,7 @@ export default defineComponent({ return (Object.values(this.views).reduce((acc, views) => [...acc, ...views], []) as View[]) .filter(view => view.params?.dir.startsWith(this.parent.params?.dir)) } - return this.views[this.parent.id] ?? [] // Root level views have `undefined` parent ids + return this.filterVisible(this.views[this.parent.id] ?? []) }, style() { @@ -103,11 +103,15 @@ export default defineComponent({ }, methods: { + filterVisible(views: View[]) { + return views.filter(({ id, hidden }) => id === this.currentView?.id || hidden !== true) + }, + hasChildViews(view: View): boolean { if (this.level >= maxLevel) { return false } - return this.views[view.id]?.length > 0 + return this.filterVisible(this.views[view.id] ?? []).length > 0 }, /** diff --git a/apps/files/src/components/FilesNavigationSearch.vue b/apps/files/src/components/FilesNavigationSearch.vue new file mode 100644 index 00000000000..85dc5534e5e --- /dev/null +++ b/apps/files/src/components/FilesNavigationSearch.vue @@ -0,0 +1,122 @@ +<!-- + - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> + +<script setup lang="ts"> +import { mdiMagnify, mdiSearchWeb } from '@mdi/js' +import { t } from '@nextcloud/l10n' +import { computed } from 'vue' +import NcActions from '@nextcloud/vue/components/NcActions' +import NcActionButton from '@nextcloud/vue/components/NcActionButton' +import NcAppNavigationSearch from '@nextcloud/vue/components/NcAppNavigationSearch' +import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' +import { onBeforeNavigation } from '../composables/useBeforeNavigation.ts' +import { useNavigation } from '../composables/useNavigation.ts' +import { useRouteParameters } from '../composables/useRouteParameters.ts' +import { useFilesStore } from '../store/files.ts' +import { useSearchStore } from '../store/search.ts' +import { VIEW_ID } from '../views/search.ts' + +const { currentView } = useNavigation(true) +const { directory } = useRouteParameters() + +const filesStore = useFilesStore() +const searchStore = useSearchStore() + +/** + * When the route is changed from search view to something different + * we need to clear the search box. + */ +onBeforeNavigation((to, from, next) => { + if (to.params.view !== VIEW_ID && from.params.view === VIEW_ID) { + // we are leaving the search view so unset the query + searchStore.query = '' + searchStore.scope = 'filter' + } else if (to.params.view === VIEW_ID && from.params.view === VIEW_ID) { + // fix the query if the user refreshed the view + if (searchStore.query && !to.query.query) { + // @ts-expect-error This is a weird issue with vue-router v4 and will be fixed in v5 (vue 3) + return next({ + ...to, + query: { + ...to.query, + query: searchStore.query, + }, + }) + } + } + next() +}) + +/** + * Are we currently on the search view. + * Needed to disable the action menu (we cannot change the search mode there) + */ +const isSearchView = computed(() => currentView.value.id === VIEW_ID) + +/** + * Local search is only possible on real DAV resources within the files root + */ +const canSearchLocally = computed(() => { + if (searchStore.base) { + return true + } + + const folder = filesStore.getDirectoryByPath(currentView.value.id, directory.value) + return folder?.isDavResource && folder?.root?.startsWith('/files/') +}) + +/** + * Different searchbox label depending if filtering or searching + */ +const searchLabel = computed(() => { + if (searchStore.scope === 'globally') { + return t('files', 'Search globally by filename …') + } else if (searchStore.scope === 'locally') { + return t('files', 'Search here by filename …') + } + return t('files', 'Filter file names …') +}) + +/** + * Update the search value and set the base if needed + * @param value - The new value + */ +function onUpdateSearch(value: string) { + if (searchStore.scope === 'locally' && currentView.value.id !== VIEW_ID) { + searchStore.base = filesStore.getDirectoryByPath(currentView.value.id, directory.value) + } + searchStore.query = value +} +</script> + +<template> + <NcAppNavigationSearch :label="searchLabel" :model-value="searchStore.query" @update:modelValue="onUpdateSearch"> + <template #actions> + <NcActions :aria-label="t('files', 'Search scope options')" :disabled="isSearchView"> + <template #icon> + <NcIconSvgWrapper :path="searchStore.scope === 'globally' ? mdiSearchWeb : mdiMagnify" /> + </template> + <NcActionButton close-after-click @click="searchStore.scope = 'filter'"> + <template #icon> + <NcIconSvgWrapper :path="mdiMagnify" /> + </template> + {{ t('files', 'Filter in current view') }} + </NcActionButton> + <NcActionButton v-if="canSearchLocally" close-after-click @click="searchStore.scope = 'locally'"> + <template #icon> + <NcIconSvgWrapper :path="mdiMagnify" /> + </template> + {{ t('files', 'Search from this location') }} + </NcActionButton> + <NcActionButton close-after-click @click="searchStore.scope = 'globally'"> + <template #icon> + <NcIconSvgWrapper :path="mdiSearchWeb" /> + </template> + {{ t('files', 'Search globally') }} + </NcActionButton> + </NcActions> + </template> + </NcAppNavigationSearch> +</template> diff --git a/apps/files/src/components/NavigationQuota.vue b/apps/files/src/components/NavigationQuota.vue index f1d2738e81d..fd10af1c495 100644 --- a/apps/files/src/components/NavigationQuota.vue +++ b/apps/files/src/components/NavigationQuota.vue @@ -58,7 +58,7 @@ export default { computed: { storageStatsTitle() { const usedQuotaByte = formatFileSize(this.storageStats?.used, false, false) - const quotaByte = formatFileSize(this.storageStats?.quota, false, false) + const quotaByte = formatFileSize(this.storageStats?.total, false, false) // If no quota set if (this.storageStats?.quota < 0) { |