fix: directory table optimistic update

fix optimistic update not working for directory table and trash table
This commit is contained in:
2025-10-18 22:58:23 +00:00
parent efd4eefa49
commit c0f852ad35
5 changed files with 137 additions and 39 deletions

View File

@@ -36,6 +36,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { WithAtom } from "@/components/with-atom"
import { backgroundTaskProgressAtom } from "@/dashboard/state"
import { DirectoryPageContext } from "@/directories/directory-page/context"
import { DirectoryContentTable } from "@/directories/directory-page/directory-content-table"
import { DirectoryPageSkeleton } from "@/directories/directory-page/directory-page-skeleton"
@@ -82,6 +83,16 @@ const itemBeingRenamedAtom = atom<{
name: string
} | null>(null)
const tableFilterAtom = atom((get) => {
const optimisticDeletedItems = get(optimisticDeletedItemsAtom)
console.log("optimisticDeletedItems", optimisticDeletedItems)
return (item: FileSystemItem) => {
const test = !optimisticDeletedItems.has(item.doc._id)
console.log("test", test)
return test
}
})
// MARK: page entry
function RouteComponent() {
const { directoryId } = Route.useParams()
@@ -160,13 +171,17 @@ function RouteComponent() {
{/* DirectoryContentContextMenu must wrap div instead of DirectoryContentTable, otherwise radix will throw "event.preventDefault is not a function" error, idk why */}
<DirectoryContentContextMenu>
<div className="w-full">
<DirectoryContentTable
filterFn={tableFilter}
directoryUrlFn={directoryUrlFn}
fileDragInfoAtom={fileDragInfoAtom}
onContextMenu={handleContextMenuRequest}
onOpenFile={openFile}
/>
<WithAtom atom={optimisticDeletedItemsAtom}>
{(optimisticDeletedItems) => (
<DirectoryContentTable
hiddenItems={optimisticDeletedItems}
directoryUrlFn={directoryUrlFn}
fileDragInfoAtom={fileDragInfoAtom}
onContextMenu={handleContextMenuRequest}
onOpenFile={openFile}
/>
)}
</WithAtom>
</div>
</DirectoryContentContextMenu>
@@ -224,8 +239,9 @@ function RouteComponent() {
}
// ==================================
// MARK: DirectoryContentContextMenu
// MARK: ctx menu
// tags: ctxmenu contextmenu directorycontextmenu
function DirectoryContentContextMenu({
children,
}: {
@@ -234,17 +250,22 @@ function DirectoryContentContextMenu({
const store = useStore()
const [target, setTarget] = useAtom(contextMenuTargetItemsAtom)
const setOptimisticDeletedItems = useSetAtom(optimisticDeletedItemsAtom)
const setBackgroundTaskProgress = useSetAtom(backgroundTaskProgressAtom)
const moveToTrashMutation = useContextMutation(api.filesystem.moveToTrash)
const { mutate: moveToTrash } = useMutation({
mutationFn: moveToTrashMutation,
onMutate: ({ handles }) => {
setBackgroundTaskProgress({
label: "Moving items to trash…",
})
setOptimisticDeletedItems(
(prev) =>
new Set([...prev, ...handles.map((handle) => handle.id)]),
)
},
onSuccess: ({ deleted, errors }, { handles }) => {
setBackgroundTaskProgress(null)
setOptimisticDeletedItems((prev) => {
const newSet = new Set(prev)
for (const handle of handles) {
@@ -262,6 +283,15 @@ function DirectoryContentContextMenu({
)
}
},
onError: (_err, { handles }) => {
setOptimisticDeletedItems((prev) => {
const newSet = new Set(prev)
for (const handle of handles) {
newSet.delete(handle.id)
}
return newSet
})
},
})
const handleDelete = () => {

View File

@@ -14,7 +14,7 @@ import {
} from "convex/react"
import { atom, useAtom, useSetAtom, useStore } from "jotai"
import { ShredderIcon, TrashIcon, UndoIcon } from "lucide-react"
import { useCallback, useContext, useEffect } from "react"
import { useCallback, useContext } from "react"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
import {
@@ -120,13 +120,17 @@ function RouteComponent() {
<TableContextMenu>
<div className="w-full">
<DirectoryContentTable
filterFn={() => true}
directoryUrlFn={directoryUrlFn}
fileDragInfoAtom={fileDragInfoAtom}
onContextMenu={handleContextMenuRequest}
onOpenFile={setOpenedFile}
/>
<WithAtom atom={optimisticRemovedItemsAtom}>
{(optimisticRemovedItems) => (
<DirectoryContentTable
hiddenItems={optimisticRemovedItems}
directoryUrlFn={directoryUrlFn}
fileDragInfoAtom={fileDragInfoAtom}
onContextMenu={handleContextMenuRequest}
onOpenFile={setOpenedFile}
/>
)}
</WithAtom>
</div>
</TableContextMenu>
@@ -174,14 +178,19 @@ function RestoreContextMenuItem() {
const store = useStore()
const setOptimisticRemovedItems = useSetAtom(optimisticRemovedItemsAtom)
const restoreItemsMutation = useConvexMutation(api.filesystem.restoreItems)
const { mutate: restoreItems, isPending: isRestoring } = useMutation({
const { mutate: restoreItems } = useMutation({
mutationFn: restoreItemsMutation,
onMutate: ({ handles }) => {
setBackgroundTaskProgress({
label: "Restoring items…",
})
setOptimisticRemovedItems(
new Set(handles.map((handle) => handle.id)),
)
},
onSuccess: ({ restored, errors }) => {
setBackgroundTaskProgress(null)
if (errors.length === 0) {
if (restored.files > 0 && restored.directories > 0) {
toast.success(
@@ -200,19 +209,18 @@ function RestoreContextMenuItem() {
)
}
},
onError: (_err, { handles }) => {
setOptimisticRemovedItems((prev) => {
const newSet = new Set(prev)
for (const handle of handles) {
newSet.delete(handle.id)
}
return newSet
})
},
})
const setBackgroundTaskProgress = useSetAtom(backgroundTaskProgressAtom)
useEffect(() => {
if (isRestoring) {
setBackgroundTaskProgress({
label: "Restoring items…",
})
} else {
setBackgroundTaskProgress(null)
}
}, [isRestoring, setBackgroundTaskProgress])
const onClick = () => {
const targetItems = store.get(contextMenuTargetItemsAtom)
restoreItems({