From 0f1b143cb555edfbbc56bacb4932fc4272a92f79 Mon Sep 17 00:00:00 2001 From: Hebi Li Date: Tue, 27 Jun 2023 17:25:58 -0700 Subject: [PATCH] fix: content loss caused by `dirty` status override (#344) --- ui/src/components/Sidebar.tsx | 6 +++++- ui/src/lib/store/index.tsx | 3 +++ ui/src/lib/store/repoStateSlice.tsx | 12 +++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index a7be7896..76637c42 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -320,7 +320,11 @@ function SyncStatus() { let res: string[] = []; if (state.repoLoaded) { for (const id in state.pods) { - if (state.pods[id].dirty || state.pods[id].isSyncing) { + if ( + state.pods[id].dirty || + state.pods[id].dirtyPending || + state.pods[id].isSyncing + ) { res.push(id); } } diff --git a/ui/src/lib/store/index.tsx b/ui/src/lib/store/index.tsx index cc968e24..ca276e9a 100644 --- a/ui/src/lib/store/index.tsx +++ b/ui/src/lib/store/index.tsx @@ -20,6 +20,9 @@ export type Pod = { type: "CODE" | "SCOPE" | "RICH"; content?: string; dirty?: boolean; + // A temporary dirty status used during remote API syncing, so that new dirty + // status is not cleared by API returns. + dirtyPending?: boolean; isSyncing?: boolean; children: { id: string; type: string }[]; parent: string; diff --git a/ui/src/lib/store/repoStateSlice.tsx b/ui/src/lib/store/repoStateSlice.tsx index 99354d0d..70d3c0b4 100644 --- a/ui/src/lib/store/repoStateSlice.tsx +++ b/ui/src/lib/store/repoStateSlice.tsx @@ -113,7 +113,7 @@ export const createRepoStateSlice: StateCreator< remoteUpdateAllPods: async (client) => { // The pods that haven't been inserted to the database yet const pendingPods = Object.values(get().pods).filter( - (pod) => pod.dirty && pod.pending + (pod) => (pod.dirty || pod.dirtyPending) && pod.pending ); // First insert all pending pods and ignore their relationship for now @@ -139,11 +139,17 @@ export const createRepoStateSlice: StateCreator< if (!pod) return; pod.children?.map(({ id }) => helper(id)); if (id !== "ROOT") { - if (pod.dirty && !pod.isSyncing) { + if ((pod.dirty || pod.dirtyPending) && !pod.isSyncing) { set( produce((state) => { // FIXME when doRemoteUpdatePod fails, this will be stuck. state.pods[id].isSyncing = true; + // Transfer the dirty status from dirty to dirtyPending. This is + // because pod may be updated during remote syncing, and the flag + // might be cleared by a successful return, causing unsaved + // content. + state.pods[id].dirty = false; + state.pods[id].dirtyPending = true; }) ); try { @@ -156,7 +162,7 @@ export const createRepoStateSlice: StateCreator< state.pods[id].isSyncing = false; // pod may be updated during remote syncing // clear dirty flag only when remote update is successful - if (res) state.pods[id].dirty = false; + if (res) state.pods[id].dirtyPending = false; }) ); } catch (e) {