diff --git a/lib/components/FilePicker/FilePicker.vue b/lib/components/FilePicker/FilePicker.vue index 86da7f62..d6b7f6e2 100644 --- a/lib/components/FilePicker/FilePicker.vue +++ b/lib/components/FilePicker/FilePicker.vue @@ -18,9 +18,10 @@
+ @create-node="onCreateFolder" + @update:path="navigatedPath = $event" />

{{ viewHeadline }}

@@ -67,7 +68,7 @@ import FilePickerNavigation from './FilePickerNavigation.vue' import { emit as emitOnEventBus } from '@nextcloud/event-bus' import { NcDialog, NcEmptyContent } from '@nextcloud/vue' -import { computed, onMounted, ref, toRef } from 'vue' +import { computed, onMounted, ref, shallowReactive, toRef, watch } from 'vue' import { showError } from '../../toast' import { useDAVFiles } from '../../composables/dav' import { useMimeFilter } from '../../composables/mime' @@ -148,8 +149,9 @@ const isOpen = ref(true) * Map buttons to Dialog buttons by wrapping the callback function to pass the selected files */ const dialogButtons = computed(() => { + const nodes = selectedFiles.length === 0 && props.allowPickDirectory && currentFolder.value ? [currentFolder.value] : selectedFiles const buttons = typeof props.buttons === 'function' - ? props.buttons(selectedFiles.value as Node[], currentPath.value, currentView.value) + ? props.buttons(nodes, currentPath.value, currentView.value) : props.buttons return buttons.map((button) => ({ @@ -157,7 +159,7 @@ const dialogButtons = computed(() => { callback: () => { // lock default close handling isHandlingCallback = true - handleButtonClick(button.callback) + handleButtonClick(button.callback, nodes) }, } as IFilePickerButton)) }) @@ -168,8 +170,7 @@ const dialogButtons = computed(() => { */ let isHandlingCallback = false -const handleButtonClick = async (callback: IFilePickerButton['callback']) => { - const nodes = selectedFiles.value.length === 0 && props.allowPickDirectory ? [await getFile(currentPath.value)] : selectedFiles.value as Node[] +const handleButtonClick = async (callback: IFilePickerButton['callback'], nodes: Node[]) => { callback(nodes) emit('close', nodes) // Unlock close @@ -189,7 +190,7 @@ const viewHeadline = computed(() => currentView.value === 'favorites' ? t('Favor /** * All currently selected files */ -const selectedFiles = ref([]) +const selectedFiles = shallowReactive([]) /** * Last path navigated to using the file picker @@ -200,28 +201,23 @@ const savedPath = ref(window?.sessionStorage.getItem('NC.FilePicker.LastPath') | /** * The path the user manually navigated to using this filepicker instance */ -const navigatedPath = ref() +const navigatedPath = ref('') +// Save the navigated path to the session storage on change +watch([navigatedPath], () => { + if (props.path === undefined && navigatedPath.value) { + window.sessionStorage.setItem('NC.FilePicker.LastPath', navigatedPath.value) + // Reset selected files + selectedFiles.splice(0, selectedFiles.length) + } +}) /** * The current path that should be picked from */ -const currentPath = computed({ +const currentPath = computed(() => // Only use the path for the files view as favorites and recent only works on the root - get: () => currentView.value === 'files' ? navigatedPath.value || props.path || savedPath.value : '/', - /** - * Navigate to the new path and save it to the session storage - * - * @param path The new path - */ - set: (path: string) => { - if (props.path === undefined) { - window.sessionStorage.setItem('NC.FilePicker.LastPath', path) - } - navigatedPath.value = path - // Reset selected files - selectedFiles.value = [] - }, -}) + currentView.value === 'files' ? navigatedPath.value || props.path || savedPath.value : '/', +) /** * A string used to filter files in current view @@ -230,7 +226,13 @@ const filterString = ref('') const { isSupportedMimeType } = useMimeFilter(toRef(props, 'mimetypeFilter')) // vue 3.3 will allow cleaner syntax of toRef(() => props.mimetypeFilter) -const { files, isLoading, loadFiles, getFile, createDirectory } = useDAVFiles(currentView, currentPath, isPublic) +const { + files, + folder: currentFolder, + isLoading, + loadFiles, + createDirectory, +} = useDAVFiles(currentView, currentPath, isPublic) onMounted(() => loadFiles()) @@ -281,7 +283,7 @@ const noFilesDescription = computed(() => { const onCreateFolder = async (name: string) => { try { const folder = await createDirectory(name) - currentPath.value = folder.path + navigatedPath.value = folder.path // emit event bus to force files app to reload that file if needed emitOnEventBus('files:node:created', files.value.filter((file) => file.basename === name)[0]) } catch (error) { diff --git a/lib/composables/dav.ts b/lib/composables/dav.ts index e1417c00..47d8095f 100644 --- a/lib/composables/dav.ts +++ b/lib/composables/dav.ts @@ -26,7 +26,7 @@ import type { FileStat, ResponseDataDetailed, SearchResult } from 'webdav' import { davGetClient, davGetDefaultPropfind, davGetRecentSearch, davRemoteURL, davResultToNode, davRootPath, getFavoriteNodes } from '@nextcloud/files' import { generateRemoteUrl } from '@nextcloud/router' import { join } from 'path' -import { computed, onMounted, ref, watch } from 'vue' +import { computed, onMounted, ref, shallowRef, watch } from 'vue' import { CancelablePromise } from 'cancelable-promise' /** @@ -39,8 +39,8 @@ import { CancelablePromise } from 'cancelable-promise' export const useDAVFiles = function( currentView: Ref<'files'|'recent'|'favorites'> | ComputedRef<'files'|'recent'|'favorites'>, currentPath: Ref | ComputedRef, - isPublicEndpoint: Ref | ComputedRef -): { isLoading: Ref, createDirectory: (name: string) => Promise, files: Ref, loadFiles: () => Promise, getFile: (path: string) => Promise } { + isPublicEndpoint: Ref | ComputedRef, +) { const defaultRootPath = computed(() => isPublicEndpoint.value ? '/' : davRootPath) @@ -114,7 +114,15 @@ export const useDAVFiles = function( /** * All files in current view and path */ - const files = ref([] as Node[]) as Ref + const files = shallowRef([] as Node[]) as Ref + + /** + * The current folder + */ + const folder = shallowRef() + watch([currentPath], async () => { + folder.value = (files.value.find(({ path }) => path === currentPath.value) ?? await getFile(currentPath.value)) as Folder + }, { immediate: true }) /** * Loading state of the files @@ -136,7 +144,7 @@ export const useDAVFiles = function( await client.value.createDirectory(join(defaultRootPath.value, path)) const directory = await getFile(path) as Folder - files.value.push(directory) + files.value = [...files.value, directory] return directory } @@ -191,6 +199,7 @@ export const useDAVFiles = function( return { isLoading, files, + folder, loadFiles: loadDAVFiles, getFile, createDirectory,