Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nextcloud-libraries/nextcloud-dialogs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v5.3.4
Choose a base ref
...
head repository: nextcloud-libraries/nextcloud-dialogs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v5.3.5
Choose a head ref
  • 14 commits
  • 9 files changed
  • 4 contributors

Commits on Jun 29, 2024

  1. chore(deps): Bump @nextcloud/typings from 1.8.0 to 1.9.0

    Bumps [@nextcloud/typings](https://github.com/nextcloud/nextcloud-typings) from 1.8.0 to 1.9.0.
    - [Release notes](https://github.com/nextcloud/nextcloud-typings/releases)
    - [Changelog](https://github.com/nextcloud-libraries/nextcloud-typings/blob/master/CHANGELOG.md)
    - [Commits](nextcloud-libraries/nextcloud-typings@v1.8.0...v1.9.0)
    
    ---
    updated-dependencies:
    - dependency-name: "@nextcloud/typings"
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    3830ad1 View commit details
  2. chore(deps-dev): Bump typedoc from 0.26.0 to 0.26.3

    Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.0 to 0.26.3.
    - [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
    - [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
    - [Commits](TypeStrong/typedoc@v0.26.0...v0.26.3)
    
    ---
    updated-dependencies:
    - dependency-name: typedoc
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    9129186 View commit details
  3. chore(deps-dev): Bump @zamiell/typedoc-plugin-not-exported

    Bumps [@zamiell/typedoc-plugin-not-exported](https://github.com/Zamiell/typedoc-plugin-not-exported) from 0.2.0 to 0.3.0.
    - [Commits](https://github.com/Zamiell/typedoc-plugin-not-exported/commits)
    
    ---
    updated-dependencies:
    - dependency-name: "@zamiell/typedoc-plugin-not-exported"
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    7ab5af7 View commit details
  4. Merge pull request #1373 from nextcloud-libraries/dependabot/npm_and_…

    …yarn/nextcloud/typings-1.9.0
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    c39a847 View commit details
  5. Merge pull request #1374 from nextcloud-libraries/dependabot/npm_and_…

    …yarn/typedoc-0.26.3
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    15defab View commit details
  6. Merge pull request #1375 from nextcloud-libraries/dependabot/npm_and_…

    …yarn/zamiell/typedoc-plugin-not-exported-0.3.0
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    573e938 View commit details
  7. chore(deps-dev): Bump vite from 5.3.1 to 5.3.2

    Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.3.1 to 5.3.2.
    - [Release notes](https://github.com/vitejs/vite/releases)
    - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
    - [Commits](https://github.com/vitejs/vite/commits/v5.3.2/packages/vite)
    
    ---
    updated-dependencies:
    - dependency-name: vite
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    b363600 View commit details
  8. Merge pull request #1376 from nextcloud-libraries/dependabot/npm_and_…

    …yarn/vite-5.3.2
    dependabot[bot] authored Jun 29, 2024
    Copy the full SHA
    e0907de View commit details

Commits on Jul 1, 2024

  1. Translate l10n/messages.pot in fi_FI

    100% translated source file: 'l10n/messages.pot'
    on 'fi_FI'.
    transifex-integration[bot] authored Jul 1, 2024
    Copy the full SHA
    2a64e3c View commit details
  2. Copy the full SHA
    00e605d View commit details

Commits on Jul 2, 2024

  1. fix(FilePicker): Cleanup DAV handling and properly handle `currentFol…

    …der`
    
    Instead of fetching the directory in a second request we simply do it like the file app
    and always request the content together with its root.
    This also allows to remove some functions by refactoring.
    
    Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
    susnux committed Jul 2, 2024
    Copy the full SHA
    b3c0fc6 View commit details
  2. Merge pull request #1378 from nextcloud-libraries/fix/current-folder

    fix(FilePicker): Cleanup DAV handling and properly handle `currentFolder`
    susnux authored Jul 2, 2024
    Copy the full SHA
    4033659 View commit details

Commits on Jul 3, 2024

  1. chore: Prepare 5.3.5

    Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
    susnux committed Jul 3, 2024
    Copy the full SHA
    33d4b2b View commit details
  2. Merge pull request #1379 from nextcloud-libraries/chore/prepare-5-3-5

    chore: Prepare 5.3.5
    susnux authored Jul 3, 2024
    Copy the full SHA
    f5fac57 View commit details
Showing with 313 additions and 145 deletions.
  1. +13 −0 CHANGELOG.md
  2. +114 −3 l10n/fi_FI.pot
  3. +9 −3 lib/components/FilePicker/FilePicker.vue
  4. +5 −22 lib/composables/dav.spec.ts
  5. +20 −72 lib/composables/dav.ts
  6. +34 −0 lib/utils/dav.spec.ts
  7. +76 −0 lib/utils/dav.ts
  8. +37 −40 package-lock.json
  9. +5 −5 package.json
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,19 @@

All notable changes to this project will be documented in this file.

## 5.3.5
[Full Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v5.3.4...v5.3.5)

### Fixed
* fix(FilePicker): Cleanup DAV handling and properly handle `currentFolder` [\#1378](https://github.com/nextcloud-libraries/nextcloud-dialogs/pull/1378) \([susnux](https://github.com/susnux)\)

### Changed
* Updated translations
* chore(deps): Bump @nextcloud/typings from 1.8.0 to 1.9.0
* chore(deps-dev): Bump typedoc from 0.26.0 to 0.26.3
* chore(deps-dev): Bump @zamiell/typedoc-plugin-not-exported from 0.2.0 to 0.3.0
* chore(deps-dev): Bump vite from 5.3.1 to 5.3.2

## 5.3.4
[Full Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v5.3.3...v5.3.4)

117 changes: 114 additions & 3 deletions l10n/fi_FI.pot
Original file line number Diff line number Diff line change
@@ -1,15 +1,126 @@
#
# Translators:
# Joas Schilling, 2023
# John Molakvoæ <skjnldsv@protonmail.com>, 2023
# Jiri Grönroos <jiri.gronroos@iki.fi>, 2024
# thingumy, 2024
#
msgid ""
msgstr ""
"Last-Translator: Joas Schilling, 2023\n"
"Last-Translator: thingumy, 2024\n"
"Language-Team: Finnish (Finland) (https://app.transifex.com/nextcloud/teams/64236/fi_FI/)\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Language: fi_FI\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: lib/toast.ts:223
msgid "\"{name}\" is an invalid folder name."
msgstr "\"{name}\" on virheellinen kansion nimi."

msgid "\"{name}\" is not an allowed folder name"
msgstr "\"{name}\" ei ole sallittu kansion nimi"

msgid "\"/\" is not allowed inside a folder name."
msgstr "\"/\" ei ole sallittu kansion nimessä."

msgid "All files"
msgstr "Kaikki tiedostot"

msgid "Choose"
msgstr "Valitse"

msgid "Choose {file}"
msgstr "Valitse {file}"

msgid "Choose %n file"
msgid_plural "Choose %n files"
msgstr[0] "Valitse %n tiedosto"
msgstr[1] "Valitse %n tiedostoa"

msgid "Copy"
msgstr "Kopioi"

msgid "Copy to {target}"
msgstr "Kopioi sijaintiin {target}"

msgid "Could not create the new folder"
msgstr "Uutta kansiota ei voitu luoda"

msgid "Could not load files settings"
msgstr "Tiedoston asetuksia ei saa ladattua"

msgid "Could not load files views"
msgstr "Tiedoston näkymiä ei saa ladattua"

msgid "Create directory"
msgstr "Luo kansio"

msgid "Current view selector"
msgstr "Nykyisen näkymän valinta"

msgid "Favorites"
msgstr "Suosikit"

msgid "Files and folders you mark as favorite will show up here."
msgstr "Tiedostot ja kansiot, jotka merkitset suosikkeihisi, näkyvät täällä."

msgid "Files and folders you recently modified will show up here."
msgstr "Tiedostot ja kansiot, joita muokkasit äskettäin, näkyvät täällä."

msgid "Filter file list"
msgstr "Suodata tiedostolistaa"

msgid "Folder name cannot be empty."
msgstr "Kansion nimi ei voi olla tyhjä."

msgid "Home"
msgstr "Koti"

msgid "Modified"
msgstr "Muokattu"

msgid "Move"
msgstr "Siirrä"

msgid "Move to {target}"
msgstr "Siirrä sijaintiin {target}"

msgid "Name"
msgstr "Nimi"

msgid "New"
msgstr "Uusi"

msgid "New folder"
msgstr "Uusi kansio"

msgid "New folder name"
msgstr "Uuden kansion nimi"

msgid "No files in here"
msgstr "Täällä ei ole tiedostoja"

msgid "No files matching your filter were found."
msgstr "Suodatinta vastaavia tiedostoja ei löytynyt."

msgid "No matching files"
msgstr "Ei vastaavia tiedostoja"

msgid "Recent"
msgstr "Viimeisimmät"

msgid "Select all entries"
msgstr "Valitse kaikki tietueet"

msgid "Select entry"
msgstr "Valitse tietue"

msgid "Select the row for {nodename}"
msgstr "Valitse rivi {nodename}:lle"

msgid "Size"
msgstr "Koko"

msgid "Undo"
msgstr "Kumoa"

msgid "Upload some content or sync with your devices!"
msgstr "Lähetä jotain sisältöä tai synkronoi laitteidesi kanssa!"
12 changes: 9 additions & 3 deletions lib/components/FilePicker/FilePicker.vue
Original file line number Diff line number Diff line change
@@ -146,13 +146,19 @@ 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.value.length === 0 && props.allowPickDirectory && currentFolder.value ? [currentFolder.value] : selectedFiles.value
const nodes = selectedFiles.value.length === 0
&& props.allowPickDirectory
&& currentFolder.value
? [currentFolder.value]
: selectedFiles.value

const buttons = typeof props.buttons === 'function'
? props.buttons(nodes, currentPath.value, currentView.value)
: props.buttons

return buttons.map((button) => ({
...button,
disabled: button.disabled || isLoading.value,
callback: () => {
// lock default close handling
isHandlingCallback = true
@@ -203,9 +209,9 @@ const navigatedPath = ref('')
watch([navigatedPath], () => {
if (props.path === undefined && navigatedPath.value) {
window.sessionStorage.setItem('NC.FilePicker.LastPath', navigatedPath.value)
// Reset selected files
selectedFiles.value = []
}
// Reset selected files
selectedFiles.value = []
})

/**
27 changes: 5 additions & 22 deletions lib/composables/dav.spec.ts
Original file line number Diff line number Diff line change
@@ -71,7 +71,6 @@ describe('dav composable', () => {
expect(Array.isArray(vue.vm.files)).toBe(true)
expect(vue.vm.files.length).toBe(0)
// functions
expect(typeof vue.vm.getFile === 'function').toBe(true)
expect(typeof vue.vm.loadFiles === 'function').toBe(true)
})

@@ -153,23 +152,6 @@ describe('dav composable', () => {
expect(client.search).toBeCalledTimes(1)
})

it('getFile works', async () => {
const client = {
stat: vi.fn((v) => ({ data: { path: v } })),
getDirectoryContents: vi.fn(() => ({ data: [] })),
}
nextcloudFiles.davGetClient.mockImplementation(() => client)
nextcloudFiles.davResultToNode.mockImplementation((v) => v)

const { getFile } = useDAVFiles(ref('files'), ref('/'))

const node = await getFile('/some/path/file.ext')
expect(node).toEqual({ path: `${nextcloudFiles.davRootPath}/some/path/file.ext` })
// Check mock usage
expect(client.stat).toBeCalledWith(`${nextcloudFiles.davRootPath}/some/path/file.ext`, { details: true })
expect(nextcloudFiles.davResultToNode).toBeCalledWith({ path: `${nextcloudFiles.davRootPath}/some/path/file.ext` })
})

it('createDirectory works', async () => {
const client = {
stat: vi.fn((v) => ({ data: { path: v } })),
@@ -189,11 +171,12 @@ describe('dav composable', () => {
it('loadFiles work', async () => {
const client = {
stat: vi.fn((v) => ({ data: { path: v } })),
getDirectoryContents: vi.fn((p, o) => ({ data: [] })),
search: vi.fn((p, o) => ({ data: { results: [], truncated: false } })),
getDirectoryContents: vi.fn((_p, _o) => ({ data: [] })),
search: vi.fn((_p, _o) => ({ data: { results: [], truncated: false } })),
}
nextcloudFiles.davGetClient.mockImplementationOnce(() => client)
nextcloudFiles.davResultToNode.mockImplementationOnce((v) => v)
nextcloudFiles.getFavoriteNodes.mockImplementationOnce(() => Promise.resolve([]))

const view = ref<'files' | 'recent' | 'favorites'>('files')
const path = ref('/')
@@ -216,8 +199,8 @@ describe('dav composable', () => {
it('request cancelation works', async () => {
const client = {
stat: vi.fn((v) => ({ data: { path: v } })),
getDirectoryContents: vi.fn((p, o) => ({ data: [] })),
search: vi.fn((p, o) => ({ data: { results: [], truncated: false } })),
getDirectoryContents: vi.fn((_p, _o) => ({ data: [] })),
search: vi.fn((_p, _o) => ({ data: { results: [], truncated: false } })),
}
nextcloudFiles.davGetClient.mockImplementationOnce(() => client)
nextcloudFiles.davResultToNode.mockImplementationOnce((v) => v)
92 changes: 20 additions & 72 deletions lib/composables/dav.ts
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Folder, Node } from '@nextcloud/files'
import type { ContentsWithRoot, Folder, Node } from '@nextcloud/files'
import type { ComputedRef, Ref } from 'vue'
import type { FileStat, ResponseDataDetailed, SearchResult } from 'webdav'

import { davGetClient, davGetDefaultPropfind, davGetRecentSearch, davResultToNode, davRootPath, getFavoriteNodes } from '@nextcloud/files'
import { join } from 'path'
import { onMounted, ref, shallowRef, watch } from 'vue'
import { davGetClient, davRootPath, getFavoriteNodes } from '@nextcloud/files'
import { CancelablePromise } from 'cancelable-promise'
import { join } from 'node:path'
import { onMounted, ref, shallowRef, watch } from 'vue'
import { getFile, getNodes, getRecentNodes } from '../utils/dav'

/**
* Handle file loading using WebDAV
@@ -27,48 +27,6 @@ export const useDAVFiles = function(
*/
const client = davGetClient()

const resultToNode = (result: FileStat) => davResultToNode(result)

const getRecentNodes = (): CancelablePromise<Node[]> => {
const controller = new AbortController()
// unix timestamp in seconds, two weeks ago
const lastTwoWeek = Math.round(Date.now() / 1000) - (60 * 60 * 24 * 14)
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
try {
const { data } = await client.search('/', {
signal: controller.signal,
details: true,
data: davGetRecentSearch(lastTwoWeek),
}) as ResponseDataDetailed<SearchResult>
const nodes = data.results.map(resultToNode)
resolve(nodes)
} catch (error) {
reject(error)
}
})
}

const getNodes = (): CancelablePromise<Node[]> => {
const controller = new AbortController()
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
try {
const results = await client.getDirectoryContents(join(davRootPath, currentPath.value), {
signal: controller.signal,
details: true,
data: davGetDefaultPropfind(),
}) as ResponseDataDetailed<FileStat[]>
let nodes = results.data.map(resultToNode)
// Hack for the public endpoint which always returns folder itself
nodes = nodes.filter((file) => file.path !== currentPath.value)
resolve(nodes)
} catch (error) {
reject(error)
}
})
}

/**
* All files in current view and path
*/
@@ -77,49 +35,33 @@ export const useDAVFiles = function(
/**
* The current folder
*/
const folder = shallowRef<Folder>()
watch([currentPath], async () => {
folder.value = (files.value.find(({ path }) => path === currentPath.value) ?? await getFile(currentPath.value)) as Folder
}, { immediate: true })
const folder = shallowRef<Folder|null>(null)

/**
* Loading state of the files
*/
const isLoading = ref(true)

/**
* The cancelable promise
* The cancelable promise used internally to cancel on fast navigation
*/
const promise = ref<null | CancelablePromise<unknown>>(null)
const promise = ref<null | CancelablePromise<Node[] | ContentsWithRoot>>(null)

/**
* Create a new directory in the current path
* The directory will be added to the current file list
* @param name Name of the new directory
* @return {Promise<Folder>} The created directory
*/
async function createDirectory(name: string): Promise<Folder> {
const path = join(currentPath.value, name)

await client.createDirectory(join(davRootPath, path))
const directory = await getFile(path) as Folder
const directory = await getFile(client, path) as Folder
files.value = [...files.value, directory]
return directory
}

/**
* Get information for one file
*
* @param path The path of the file or folder
* @param rootPath DAV root path, defaults to '/files/USERID'
*/
async function getFile(path: string, rootPath: string = davRootPath) {
const { data } = await client.stat(join(rootPath, path), {
details: true,
data: davGetDefaultPropfind(),
}) as ResponseDataDetailed<FileStat>
return resultToNode(data)
}

/**
* Force reload files using the DAV client
*/
@@ -132,11 +74,18 @@ export const useDAVFiles = function(
if (currentView.value === 'favorites') {
promise.value = getFavoriteNodes(client, currentPath.value)
} else if (currentView.value === 'recent') {
promise.value = getRecentNodes()
promise.value = getRecentNodes(client)
} else {
promise.value = getNodes(client, currentPath.value)
}
const content = await promise.value
if ('folder' in content) {
folder.value = content.folder
files.value = content.contents
} else {
promise.value = getNodes()
folder.value = null
files.value = content
}
files.value = await promise.value as Node[]

promise.value = null
isLoading.value = false
@@ -157,7 +106,6 @@ export const useDAVFiles = function(
files,
folder,
loadFiles: loadDAVFiles,
getFile,
createDirectory,
}
}
Loading