mirror of
https://github.com/docmost/docmost.git
synced 2026-05-22 18:22:42 +08:00
fix(base): adopt server view state when no local edit is pending
This commit is contained in:
@@ -222,6 +222,12 @@ export function useBaseTable(
|
|||||||
): UseBaseTableResult {
|
): UseBaseTableResult {
|
||||||
const updateViewMutation = useUpdateViewMutation();
|
const updateViewMutation = useUpdateViewMutation();
|
||||||
const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
// While a local edit is pending (debounce scheduled OR mutation in
|
||||||
|
// flight), the reconcile effect preserves local state so we don't
|
||||||
|
// stomp the user's in-flight toggle. When no local edit is pending,
|
||||||
|
// the effect adopts server state — that's what makes remote updates
|
||||||
|
// (another client hiding a column) actually show up on this client.
|
||||||
|
const [hasPendingEdit, setHasPendingEdit] = useState(false);
|
||||||
|
|
||||||
// `base?.properties ?? []` minted a fresh `[]` every render while the
|
// `base?.properties ?? []` minted a fresh `[]` every render while the
|
||||||
// base query was loading, which invalidated every downstream memo and
|
// base query was loading, which invalidated every downstream memo and
|
||||||
@@ -276,14 +282,17 @@ export function useBaseTable(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same view — preserve user toggles, but reconcile the id set:
|
// Same view. If a local edit is pending (user just toggled and
|
||||||
// append properties that were just created, drop properties that
|
// the debounce hasn't flushed yet, or the mutation is in flight),
|
||||||
// were deleted. Without this, creating a new column leaves it
|
// preserve local state — only reconcile the id set so that newly
|
||||||
// invisible to `table.getState().columnOrder` / `gridTemplateColumns`,
|
// created columns show up and deleted columns drop out without
|
||||||
// and the grid's scrollWidth never grows to include it.
|
// stomping the user's toggle. If nothing local is pending, adopt
|
||||||
|
// the server's state — this is what lets remote updates from
|
||||||
|
// other clients show up here.
|
||||||
const validIds = new Set<string>(["__row_number"]);
|
const validIds = new Set<string>(["__row_number"]);
|
||||||
for (const p of properties) validIds.add(p.id);
|
for (const p of properties) validIds.add(p.id);
|
||||||
|
|
||||||
|
if (hasPendingEdit) {
|
||||||
setColumnOrder((prev) => {
|
setColumnOrder((prev) => {
|
||||||
const prevSet = new Set(prev);
|
const prevSet = new Set(prev);
|
||||||
const kept = prev.filter((id) => validIds.has(id));
|
const kept = prev.filter((id) => validIds.has(id));
|
||||||
@@ -312,11 +321,16 @@ export function useBaseTable(
|
|||||||
}
|
}
|
||||||
return changed ? next : prev;
|
return changed ? next : prev;
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setColumnOrder(derivedColumnOrder);
|
||||||
|
setColumnVisibility(derivedColumnVisibility);
|
||||||
|
}
|
||||||
}, [
|
}, [
|
||||||
activeView?.id,
|
activeView?.id,
|
||||||
derivedColumnOrder,
|
derivedColumnOrder,
|
||||||
derivedColumnVisibility,
|
derivedColumnVisibility,
|
||||||
properties,
|
properties,
|
||||||
|
hasPendingEdit,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const columnPinning = useMemo(
|
const columnPinning = useMemo(
|
||||||
@@ -355,9 +369,23 @@ export function useBaseTable(
|
|||||||
clearTimeout(persistTimerRef.current);
|
clearTimeout(persistTimerRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHasPendingEdit(true);
|
||||||
|
|
||||||
persistTimerRef.current = setTimeout(() => {
|
persistTimerRef.current = setTimeout(() => {
|
||||||
|
persistTimerRef.current = null;
|
||||||
const config = buildViewConfigFromTable(table, activeView.config);
|
const config = buildViewConfigFromTable(table, activeView.config);
|
||||||
updateViewMutation.mutate({ viewId: activeView.id, baseId: base.id, config });
|
updateViewMutation.mutate(
|
||||||
|
{ viewId: activeView.id, baseId: base.id, config },
|
||||||
|
{
|
||||||
|
onSettled: () => {
|
||||||
|
// Don't clear if the user has already scheduled another
|
||||||
|
// debounce while this one was in flight.
|
||||||
|
if (persistTimerRef.current === null) {
|
||||||
|
setHasPendingEdit(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
}, 300);
|
}, 300);
|
||||||
}, [activeView, base, table, updateViewMutation]);
|
}, [activeView, base, table, updateViewMutation]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user