diff --git a/__tests__/dav/dav.spec.ts b/__tests__/dav/dav.spec.ts index 321afe1b2..07284bf52 100644 --- a/__tests__/dav/dav.spec.ts +++ b/__tests__/dav/dav.spec.ts @@ -13,7 +13,7 @@ import { resultToNode, } from '../../lib/dav/index' import { File, Folder, NodeStatus } from '../../lib' -import { FileStat } from 'webdav' +import { FileStat, WebDAVClient } from 'webdav' import * as auth from '@nextcloud/auth' // required as default URL will be the DOM URL class which will use the window.location @@ -197,7 +197,7 @@ describe('DAV requests', () => { } // Get the favorite nodes - const nodes = await getFavoriteNodes(client as never) + const nodes = await getFavoriteNodes({ client: client as unknown as WebDAVClient }) // Check client was called correctly expect(client.getDirectoryContents).toBeCalled() @@ -230,7 +230,7 @@ describe('DAV requests', () => { } // Get the favorite nodes - const nodes = await getFavoriteNodes(client as never, '/Neuer Ordner') + const nodes = await getFavoriteNodes({ client: client as unknown as WebDAVClient, path: '/Neuer Ordner' }) // Check client was called correctly expect(client.getDirectoryContents).toBeCalled() diff --git a/lib/dav/dav.ts b/lib/dav/dav.ts index 7f5dff49b..b3f664548 100644 --- a/lib/dav/dav.ts +++ b/lib/dav/dav.ts @@ -9,7 +9,6 @@ import type { Node, NodeData } from '../node/index.ts' import { getCurrentUser, getRequestToken, onRequestTokenUpdate } from '@nextcloud/auth' import { getSharingToken, isPublicShare } from '@nextcloud/sharing/public' import { generateRemoteUrl } from '@nextcloud/router' -import { CancelablePromise } from 'cancelable-promise' import { createClient, getPatcher } from 'webdav' import { parsePermissions } from './davPermissions.ts' import { getFavoritesReport } from './davProperties.ts' @@ -112,44 +111,52 @@ export const getClient = function(remoteURL = defaultRemoteURL, headers: Record< /** * Use WebDAV to query for favorite Nodes * - * @param davClient The WebDAV client to use for performing the request - * @param path Base path for the favorites, if unset all favorites are queried - * @param davRoot The root path for the DAV user (defaults to `defaultRootPath`) + * @param options - Options for the favorite query + * @param options.client - The WebDAV client to use for performing the request + * @param options.path - Base path for the favorites, if unset all favorites are queried + * @param options.davRoot - The root path for the DAV user (defaults to `defaultRootPath`) + * @param options.signal - Optional abort signal to cancel the request + * + * @example + * ```js + * import { getFavoriteNodes } from '@nextcloud/files' + * + * // query favorites for the root + * const favorites = await getFavoriteNodes() + * ``` * @example * ```js + * // Advanced usage with custom client and path * import { getClient, defaultRootPath, getFavoriteNodes } from '@nextcloud/files' * * const client = getClient() - * // query favorites for the root - * const favorites = await getFavoriteNodes(client) - * // which is the same as writing: - * const favorites = await getFavoriteNodes(client, '/', defaultRootPath) + * const controller = new AbortController() + * const favoritesPromise = getFavoriteNodes({ client, path: '/some/folder', signal: controller.signal }) + * // you can abort the request if needed + * controller.abort() + * // or await the result + * const favorites = await favoritesPromise * ``` */ -export const getFavoriteNodes = (davClient: WebDAVClient, path = '/', davRoot = defaultRootPath): CancelablePromise => { - const controller = new AbortController() - return new CancelablePromise(async (resolve, reject, onCancel) => { - onCancel(() => controller.abort()) - try { - const contentsResponse = await davClient.getDirectoryContents(`${davRoot}${path}`, { - signal: controller.signal, - details: true, - data: getFavoritesReport(), - headers: { - // see getClient for patched webdav client - method: 'REPORT', - }, - includeSelf: true, - }) as ResponseDataDetailed - - const nodes = contentsResponse.data - .filter(node => node.filename !== path) // exclude current dir - .map((result) => resultToNode(result, davRoot)) - resolve(nodes) - } catch (error) { - reject(error) - } - }) +export async function getFavoriteNodes(options: { client?: WebDAVClient, path?: string, davRoot?: string, signal?: AbortSignal } = {}): Promise { + const client = options.client ?? getClient() + const path = options.path ?? '/' + const davRoot = options.davRoot ?? defaultRootPath + + const contentsResponse = await client.getDirectoryContents(`${davRoot}${path}`, { + signal: options.signal, + details: true, + data: getFavoritesReport(), + headers: { + // see getClient for patched webdav client + method: 'REPORT', + }, + includeSelf: true, + }) as ResponseDataDetailed + + return contentsResponse.data + .filter(node => node.filename !== path) // exclude current dir + .map((result) => resultToNode(result, davRoot)) } /** diff --git a/lib/navigation/view.ts b/lib/navigation/view.ts index c924750bc..5757461b4 100644 --- a/lib/navigation/view.ts +++ b/lib/navigation/view.ts @@ -37,14 +37,16 @@ export interface IView { emptyView?: (div: HTMLDivElement) => void /** - * Method return the content of the provided path - * This ideally should be a cancellable promise. - * promise.cancel(reason) will be called when the directory - * change and the promise is not resolved yet. - * You _must_ also return the current directory + * Method return the content of the provided path. + * + * This method _must_ also return the current directory * information alongside with its content. + * + * Usually a abort signal is provided to be able to + * cancel the request if the user change directory + * {@see https://developer.mozilla.org/en-US/docs/Web/API/AbortController }. */ - getContents: (path: string) => Promise + getContents(path: string, options: { signal: AbortSignal }): Promise /** * If set then the view will be hidden from the navigation unless its the active view. diff --git a/package-lock.json b/package-lock.json index 219199534..7b0a926a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "@nextcloud/paths": "^2.4.0", "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.3.0", - "cancelable-promise": "^4.3.1", "is-svg": "^6.1.0", "typescript-event-target": "^1.1.1", "webdav": "^5.8.0" @@ -4391,7 +4390,8 @@ "node_modules/cancelable-promise": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/cancelable-promise/-/cancelable-promise-4.3.1.tgz", - "integrity": "sha512-A/8PwLk/T7IJDfUdQ68NR24QHa8rIlnN/stiJEBo6dmVUkD4K14LswG0w3VwdeK/o7qOwRUR1k2MhK5Rpy2m7A==" + "integrity": "sha512-A/8PwLk/T7IJDfUdQ68NR24QHa8rIlnN/stiJEBo6dmVUkD4K14LswG0w3VwdeK/o7qOwRUR1k2MhK5Rpy2m7A==", + "optional": true }, "node_modules/caniuse-lite": { "version": "1.0.30001731", diff --git a/package.json b/package.json index d03399b8c..0ffea3882 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "@nextcloud/paths": "^2.4.0", "@nextcloud/router": "^3.1.0", "@nextcloud/sharing": "^0.3.0", - "cancelable-promise": "^4.3.1", "is-svg": "^6.1.0", "typescript-event-target": "^1.1.1", "webdav": "^5.8.0"