mirror of
https://github.com/get-drexa/drive.git
synced 2026-02-02 13:21:17 +00:00
fix: dir content invalidation on move to trash
This commit is contained in:
@@ -49,6 +49,7 @@ import type {
|
||||
DirectoryItem,
|
||||
FileInfo,
|
||||
} from "@/vfs/vfs"
|
||||
import { formatError } from "../../../lib/error"
|
||||
|
||||
export const Route = createFileRoute(
|
||||
"/_authenticated/_sidebar-layout/directories/$directoryId",
|
||||
@@ -86,11 +87,16 @@ const itemBeingRenamedAtom = atom<{
|
||||
// MARK: page entry
|
||||
function RouteComponent() {
|
||||
const { directoryId } = Route.useParams()
|
||||
const { data: directoryInfo, isLoading: isLoadingDirectoryInfo, error: directoryInfoError } = useQuery(
|
||||
useAtomValue(directoryInfoQueryAtom(directoryId)),
|
||||
)
|
||||
const { data: directoryContent, isLoading: isLoadingDirectoryContent, error: directoryContentError } =
|
||||
useQuery(useAtomValue(directoryContentQueryAtom(directoryId)))
|
||||
const {
|
||||
data: directoryInfo,
|
||||
isLoading: isLoadingDirectoryInfo,
|
||||
error: directoryInfoError,
|
||||
} = useQuery(useAtomValue(directoryInfoQueryAtom(directoryId)))
|
||||
const {
|
||||
data: directoryContent,
|
||||
isLoading: isLoadingDirectoryContent,
|
||||
error: directoryContentError,
|
||||
} = useQuery(useAtomValue(directoryContentQueryAtom(directoryId)))
|
||||
|
||||
const directoryUrlById = useCallback(
|
||||
(directoryId: string) => `/directories/${directoryId}`,
|
||||
@@ -236,39 +242,31 @@ function DirectoryContentContextMenu({
|
||||
}) {
|
||||
const store = useStore()
|
||||
const [target, setTarget] = useAtom(contextMenuTargetItemsAtom)
|
||||
const setOptimisticDeletedItems = useSetAtom(optimisticDeletedItemsAtom)
|
||||
const setBackgroundTaskProgress = useSetAtom(backgroundTaskProgressAtom)
|
||||
const setCutItems = useSetAtom(cutItemsAtom)
|
||||
|
||||
const moveToTrashMutation = useAtomValue(moveToTrashMutationAtom)
|
||||
const { mutate: moveToTrash } = useMutation({
|
||||
...useAtomValue(moveToTrashMutationAtom),
|
||||
onMutate: (items) => {
|
||||
...moveToTrashMutation,
|
||||
onMutate: (vars, ctx) => {
|
||||
setBackgroundTaskProgress({
|
||||
label: "Moving items to trash…",
|
||||
})
|
||||
setOptimisticDeletedItems(
|
||||
(prev) => new Set([...prev, ...items.map((item) => item.id)]),
|
||||
return (
|
||||
moveToTrashMutation.onMutate?.(vars, ctx) ?? {
|
||||
prevDirContentMap: new Map(),
|
||||
}
|
||||
)
|
||||
},
|
||||
onSuccess: (trashedItems) => {
|
||||
onSuccess: (data, vars, result, ctx) => {
|
||||
moveToTrashMutation.onSuccess?.(data, vars, result, ctx)
|
||||
setBackgroundTaskProgress(null)
|
||||
setOptimisticDeletedItems((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
for (const item of trashedItems) {
|
||||
newSet.delete(item.id)
|
||||
}
|
||||
return newSet
|
||||
})
|
||||
toast.success(`Moved ${trashedItems.length} items to trash`)
|
||||
toast.success(`Moved ${data.length} items to trash`)
|
||||
},
|
||||
onError: (_err, items) => {
|
||||
setOptimisticDeletedItems((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
for (const item of items) {
|
||||
newSet.delete(item.id)
|
||||
}
|
||||
return newSet
|
||||
})
|
||||
onError: (err, vars, mutateResult, context) => {
|
||||
moveToTrashMutation.onError?.(err, vars, mutateResult, context)
|
||||
toast.error(formatError(err))
|
||||
setBackgroundTaskProgress(null)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ export const moveDirectoryItemsMutationAtom = atom((get) =>
|
||||
if (item.parentId) {
|
||||
const s = movedItems.get(item.parentId)
|
||||
if (!s) {
|
||||
movedItems.set(item.parentId, new Set())
|
||||
movedItems.set(item.parentId, new Set(s))
|
||||
} else {
|
||||
s.add(item.id)
|
||||
}
|
||||
@@ -192,7 +192,6 @@ export const moveDirectoryItemsMutationAtom = atom((get) =>
|
||||
typeof targetDirectory === "string"
|
||||
? targetDirectory
|
||||
: targetDirectory.id
|
||||
console.log(dirId)
|
||||
client.invalidateQueries(get(directoryContentQueryAtom(dirId)))
|
||||
for (const item of items) {
|
||||
if (item.parentId) {
|
||||
@@ -238,36 +237,94 @@ export const moveToTrashMutationAtom = atom((get) =>
|
||||
}
|
||||
}
|
||||
|
||||
const fileDeleteParams = new URLSearchParams()
|
||||
fileDeleteParams.set("id", fileIds.join(","))
|
||||
fileDeleteParams.set("trash", "true")
|
||||
const deleteFilesPromise = fetchApi(
|
||||
"DELETE",
|
||||
`/accounts/${account.id}/files?${fileDeleteParams.toString()}`,
|
||||
{
|
||||
returns: FileInfo.array(),
|
||||
},
|
||||
)
|
||||
let deleteFilesPromise: Promise<FileInfo[]>
|
||||
if (fileIds.length > 0) {
|
||||
const fileDeleteParams = new URLSearchParams()
|
||||
fileDeleteParams.set("id", fileIds.join(","))
|
||||
fileDeleteParams.set("trash", "true")
|
||||
deleteFilesPromise = fetchApi(
|
||||
"DELETE",
|
||||
`/accounts/${account.id}/files?${fileDeleteParams.toString()}`,
|
||||
{
|
||||
returns: FileInfo.array(),
|
||||
},
|
||||
).then(([_, result]) => result)
|
||||
} else {
|
||||
deleteFilesPromise = Promise.resolve([])
|
||||
}
|
||||
|
||||
const directoryDeleteParams = new URLSearchParams()
|
||||
directoryDeleteParams.set("id", directoryIds.join(","))
|
||||
directoryDeleteParams.set("trash", "true")
|
||||
const deleteDirectoriesPromise = fetchApi(
|
||||
"DELETE",
|
||||
`/accounts/${account.id}/directories?${directoryDeleteParams.toString()}`,
|
||||
{
|
||||
returns: DirectoryInfo.array(),
|
||||
},
|
||||
)
|
||||
let deleteDirectoriesPromise: Promise<DirectoryInfo[]>
|
||||
if (directoryIds.length > 0) {
|
||||
const directoryDeleteParams = new URLSearchParams()
|
||||
directoryDeleteParams.set("id", directoryIds.join(","))
|
||||
directoryDeleteParams.set("trash", "true")
|
||||
deleteDirectoriesPromise = fetchApi(
|
||||
"DELETE",
|
||||
`/accounts/${account.id}/directories?${directoryDeleteParams.toString()}`,
|
||||
{
|
||||
returns: DirectoryInfo.array(),
|
||||
},
|
||||
).then(([_, result]) => result)
|
||||
} else {
|
||||
deleteDirectoriesPromise = Promise.resolve([])
|
||||
}
|
||||
|
||||
const [[, deletedFiles], [, deletedDirectories]] =
|
||||
await Promise.all([
|
||||
deleteFilesPromise,
|
||||
deleteDirectoriesPromise,
|
||||
])
|
||||
const [deletedFiles, deletedDirectories] = await Promise.all([
|
||||
deleteFilesPromise,
|
||||
deleteDirectoriesPromise,
|
||||
])
|
||||
|
||||
return [...deletedFiles, ...deletedDirectories]
|
||||
},
|
||||
onMutate: (items, { client }) => {
|
||||
const trashedItems = new Map<string, Set<string>>()
|
||||
for (const item of items) {
|
||||
if (item.parentId) {
|
||||
const s = trashedItems.get(item.parentId)
|
||||
if (!s) {
|
||||
trashedItems.set(item.parentId, new Set(s))
|
||||
} else {
|
||||
s.add(item.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const prevDirContentMap = new Map<
|
||||
string,
|
||||
DirectoryItem[] | undefined
|
||||
>()
|
||||
trashedItems.forEach((s, parentId) => {
|
||||
const query = get(directoryContentQueryAtom(parentId))
|
||||
const prevDirContent = client.getQueryData(query.queryKey)
|
||||
client.setQueryData(
|
||||
query.queryKey,
|
||||
(prev) => prev?.filter((it) => !s.has(it.id)) ?? prev,
|
||||
)
|
||||
prevDirContentMap.set(parentId, prevDirContent)
|
||||
})
|
||||
return { prevDirContentMap }
|
||||
},
|
||||
onSuccess: (_data, items, _result, { client }) => {
|
||||
for (const item of items) {
|
||||
if (item.parentId) {
|
||||
client.invalidateQueries(
|
||||
get(directoryContentQueryAtom(item.parentId)),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (_error, items, context, { client }) => {
|
||||
if (context) {
|
||||
context.prevDirContentMap.forEach(
|
||||
(prevDirContent, parentId) => {
|
||||
client.setQueryData(
|
||||
get(directoryContentQueryAtom(parentId)).queryKey,
|
||||
prevDirContent,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user