Skip to content

Commit b0f47e1

Browse files
committed
fix: Fix incorrect directory contents when navigating quickly
Signed-off-by: Christopher Ng <[email protected]>
1 parent 24a60e6 commit b0f47e1

File tree

3 files changed

+63
-18
lines changed

3 files changed

+63
-18
lines changed

lib/composables/dav.ts

+56-18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { davGetClient, davGetDefaultPropfind, davGetRecentSearch, davRemoteURL,
2727
import { generateRemoteUrl } from '@nextcloud/router'
2828
import { join } from 'path'
2929
import { computed, onMounted, ref, watch } from 'vue'
30+
import { CancelablePromise } from 'cancelable-promise'
3031

3132
/**
3233
* Handle file loading using WebDAV
@@ -68,6 +69,48 @@ export const useDAVFiles = function(
6869

6970
const resultToNode = (result: FileStat) => davResultToNode(result, defaultRootPath.value, defaultRemoteUrl.value)
7071

72+
const getRecentNodes = (): CancelablePromise<Node[]> => {
73+
const controller = new AbortController()
74+
// unix timestamp in seconds, two weeks ago
75+
const lastTwoWeek = Math.round(Date.now() / 1000) - (60 * 60 * 24 * 14)
76+
return new CancelablePromise(async (resolve, reject, onCancel) => {
77+
onCancel(() => controller.abort())
78+
try {
79+
const { data } = await client.value.search('/', {
80+
signal: controller.signal,
81+
details: true,
82+
data: davGetRecentSearch(lastTwoWeek),
83+
}) as ResponseDataDetailed<SearchResult>
84+
const nodes = data.results.map(resultToNode)
85+
resolve(nodes)
86+
} catch (error) {
87+
reject(error)
88+
}
89+
})
90+
}
91+
92+
const getNodes = (): CancelablePromise<Node[]> => {
93+
const controller = new AbortController()
94+
return new CancelablePromise(async (resolve, reject, onCancel) => {
95+
onCancel(() => controller.abort())
96+
try {
97+
const results = await client.value.getDirectoryContents(`${defaultRootPath.value}${currentPath.value}`, {
98+
signal: controller.signal,
99+
details: true,
100+
data: davGetDefaultPropfind(),
101+
}) as ResponseDataDetailed<FileStat[]>
102+
let nodes = results.data.map(resultToNode)
103+
// Hack for the public endpoint which always returns folder itself
104+
if (isPublicEndpoint.value) {
105+
nodes = nodes.filter((file) => file.path !== currentPath.value)
106+
}
107+
resolve(nodes)
108+
} catch (error) {
109+
reject(error)
110+
}
111+
})
112+
}
113+
71114
/**
72115
* All files in current view and path
73116
*/
@@ -78,6 +121,11 @@ export const useDAVFiles = function(
78121
*/
79122
const isLoading = ref(true)
80123

124+
/**
125+
* The cancelable promise
126+
*/
127+
const promise = ref<null | CancelablePromise<unknown>>(null)
128+
81129
/**
82130
* Create a new directory in the current path
83131
* @param name Name of the new directory
@@ -112,31 +160,21 @@ export const useDAVFiles = function(
112160
* Force reload files using the DAV client
113161
*/
114162
async function loadDAVFiles() {
163+
if (promise.value) {
164+
promise.value.cancel()
165+
}
115166
isLoading.value = true
116167

117168
if (currentView.value === 'favorites') {
118-
files.value = await getFavoriteNodes(client.value, currentPath.value, defaultRootPath.value)
169+
promise.value = getFavoriteNodes(client.value, currentPath.value, defaultRootPath.value)
119170
} else if (currentView.value === 'recent') {
120-
// unix timestamp in seconds, two weeks ago
121-
const lastTwoWeek = Math.round(Date.now() / 1000) - (60 * 60 * 24 * 14)
122-
const { data } = await client.value.search('/', {
123-
details: true,
124-
data: davGetRecentSearch(lastTwoWeek),
125-
}) as ResponseDataDetailed<SearchResult>
126-
files.value = data.results.map(resultToNode)
171+
promise.value = getRecentNodes()
127172
} else {
128-
const results = await client.value.getDirectoryContents(`${defaultRootPath.value}${currentPath.value}`, {
129-
details: true,
130-
data: davGetDefaultPropfind(),
131-
}) as ResponseDataDetailed<FileStat[]>
132-
files.value = results.data.map(resultToNode)
133-
134-
// Hack for the public endpoint which always returns folder itself
135-
if (isPublicEndpoint.value) {
136-
files.value = files.value.filter((file) => file.path !== currentPath.value)
137-
}
173+
promise.value = getNodes()
138174
}
175+
files.value = await promise.value as Node[]
139176

177+
promise.value = null
140178
isLoading.value = false
141179
}
142180

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"@nextcloud/typings": "^1.8.0",
6666
"@types/toastify-js": "^1.12.3",
6767
"@vueuse/core": "^10.9.0",
68+
"cancelable-promise": "^4.3.1",
6869
"toastify-js": "^1.12.0",
6970
"vue-frag": "^1.4.3",
7071
"webdav": "^5.5.0"

0 commit comments

Comments
 (0)