feat: improve trash empty feedback and selection toolbar refs #21
This commit is contained in:
1 parent
f58f02d4b2
commit
ece135931c
4 files changed
+65
-6
No files matched your search
@@ -130,8 +130,8 @@ export const MemoSelectionActionBar = ({
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="hidden h-full min-h-0 flex-1 items-center justify-center bg-white px-16 py-10 lg:flex xl:px-24">
|
||||
<div className="w-72 -translate-x-20 overflow-hidden rounded-md border border-slate-200 bg-white py-1 shadow-lg xl:-translate-x-28">
|
||||
<div className="hidden h-full min-h-0 flex-1 items-center justify-start bg-white px-16 py-10 lg:flex lg:pl-44 xl:px-24 xl:pl-44">
|
||||
<div className="w-72 overflow-hidden rounded-md border border-slate-200 bg-white py-1 shadow-lg">
|
||||
<div className="flex h-9 items-center gap-2 px-3 text-xs font-semibold text-slate-400">
|
||||
<CheckSquare className="h-4 w-4" />
|
||||
{getSelectionCountLabel(selectedCount, t)}
|
||||
|
||||
@@ -147,6 +147,13 @@ type MemoDeleteOptimisticContext = {
|
||||
previousSelectedMemoId: string | null;
|
||||
};
|
||||
|
||||
type EmptyTrashOptimisticContext = {
|
||||
previousMemoLists: Array<[readonly unknown[], MemoListQueryData | undefined]>;
|
||||
previousMemoDetails: Array<[readonly unknown[], { memo: MemoDetail } | undefined]>;
|
||||
previousActivePane: Pane;
|
||||
previousSelectedMemoId: string | null;
|
||||
};
|
||||
|
||||
const memoToSummary = (memo: MemoDetail): MemoSummary => ({
|
||||
id: memo.id,
|
||||
notebookId: memo.notebookId,
|
||||
@@ -331,6 +338,19 @@ const removeMemoSummariesFromLists = (queryClient: QueryClient, memoIds: Set<str
|
||||
});
|
||||
};
|
||||
|
||||
const clearTrashMemoLists = (queryClient: QueryClient) => {
|
||||
for (const [queryKey, current] of queryClient.getQueriesData<MemoListQueryData>({ queryKey: ["memos", "trash"] })) {
|
||||
if (!current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queryClient.setQueryData(queryKey, {
|
||||
...current,
|
||||
pages: current.pages.map((page) => ({ ...page, memos: [], totalCount: 0, nextCursor: null })),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const decrementNotebookMemoCounts = (queryClient: QueryClient, removedMemos: MemoSummary[]) => {
|
||||
if (removedMemos.length === 0) {
|
||||
return;
|
||||
@@ -1504,16 +1524,51 @@ export const WorkspaceApp = ({
|
||||
|
||||
const emptyTrashMutation = useMutation({
|
||||
mutationFn: api.emptyTrash,
|
||||
onSuccess: async () => {
|
||||
onMutate: async (): Promise<EmptyTrashOptimisticContext> => {
|
||||
setEmptyTrashConfirmationOpen(false);
|
||||
clearMemoSelection();
|
||||
setSelectedMemoId(null);
|
||||
setActivePane("memos");
|
||||
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ["memos"] }),
|
||||
queryClient.invalidateQueries({ queryKey: ["memo"] }),
|
||||
queryClient.invalidateQueries({ queryKey: ["resources"] }),
|
||||
queryClient.cancelQueries({ queryKey: ["memos"] }),
|
||||
queryClient.cancelQueries({ queryKey: ["memo"] }),
|
||||
queryClient.cancelQueries({ queryKey: ["resources"] }),
|
||||
]);
|
||||
|
||||
const previousMemoLists = queryClient.getQueriesData<MemoListQueryData>({ queryKey: ["memos"] });
|
||||
const previousMemoDetails = queryClient.getQueriesData<{ memo: MemoDetail }>({ queryKey: ["memo"] });
|
||||
|
||||
clearTrashMemoLists(queryClient);
|
||||
for (const [queryKey] of previousMemoDetails) {
|
||||
if (queryKey[2] === "trash") {
|
||||
queryClient.removeQueries({ queryKey });
|
||||
}
|
||||
}
|
||||
|
||||
return { previousMemoLists, previousMemoDetails, previousActivePane: activePane, previousSelectedMemoId: selectedMemoId };
|
||||
},
|
||||
onError: (_error, _variables, context) => {
|
||||
context?.previousMemoLists.forEach(([queryKey, data]) => {
|
||||
queryClient.setQueryData(queryKey, data);
|
||||
});
|
||||
context?.previousMemoDetails.forEach(([queryKey, data]) => {
|
||||
queryClient.setQueryData(queryKey, data);
|
||||
});
|
||||
setSelectedMemoId(context?.previousSelectedMemoId ?? null);
|
||||
setActivePane(context?.previousActivePane ?? "memos");
|
||||
setAppNoticeDialog({
|
||||
title: t("workspaceDialogs.emptyTrashFailedTitle"),
|
||||
description: t("workspaceDialogs.emptyTrashFailedDescription"),
|
||||
});
|
||||
},
|
||||
onSettled: (_data, error) => {
|
||||
const refetchType = error ? "active" : "inactive";
|
||||
|
||||
void Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: ["memos"], refetchType }),
|
||||
queryClient.invalidateQueries({ queryKey: ["memo"], refetchType }),
|
||||
queryClient.invalidateQueries({ queryKey: ["resources"], refetchType }),
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -486,6 +486,8 @@ export const enUS = {
|
||||
emptyTrashTitle: "Empty trash",
|
||||
emptyTrashDescription: "All notes in Trash and still-linked attachments will be deleted. This action cannot be undone.",
|
||||
emptyTrashConfirm: "Empty trash",
|
||||
emptyTrashFailedTitle: "Couldn't empty trash",
|
||||
emptyTrashFailedDescription: "Your notes have been restored to Trash. Please try again.",
|
||||
deleteNotebookTitle: "Delete notebook “{{name}}”",
|
||||
deleteNotebookDescription: "Clear its notes and child notebooks first. It cannot be restored from here after deletion.",
|
||||
ok: "OK",
|
||||
|
||||
@@ -486,6 +486,8 @@ export const zhCN = {
|
||||
emptyTrashTitle: "清空回收站",
|
||||
emptyTrashDescription: "回收站中的全部笔记和仍关联的附件都会删除,这个操作不可恢复。",
|
||||
emptyTrashConfirm: "清空回收站",
|
||||
emptyTrashFailedTitle: "清空回收站失败",
|
||||
emptyTrashFailedDescription: "笔记已恢复到回收站,请稍后重试。",
|
||||
deleteNotebookTitle: "删除笔记本「{{name}}」",
|
||||
deleteNotebookDescription: "请先清空其中的笔记和子笔记本。删除后无法从这里恢复。",
|
||||
ok: "知道了",
|
||||
|
||||
Reference in new issue
Block a user