fix: retain uncertain optimistic mutations

This commit is contained in:
DongHyeonka
2026-08-02 02:42:56 +09:00
parent 15645541b7
commit d9afccdd60
15 changed files with 2172 additions and 124 deletions
+40 -9
View File
@@ -11,6 +11,7 @@ export const ASYNC_OVERLAYS = Object.freeze([
"refreshing",
"stale-degraded",
"mutation-pending",
"mutation-effect-unknown",
"mutation-conflict",
] as const);
@@ -19,30 +20,42 @@ export type AsyncOverlay =
refreshing: false;
staleDegraded: false;
mutationPending: false;
mutationEffectUnknown: false;
mutationConflict: false;
}>
| Readonly<{
refreshing: true;
staleDegraded: false;
mutationPending: false;
mutationEffectUnknown: false;
mutationConflict: false;
}>
| Readonly<{
refreshing: false;
staleDegraded: true;
mutationPending: false;
mutationEffectUnknown: false;
mutationConflict: false;
}>
| Readonly<{
refreshing: false;
staleDegraded: false;
mutationPending: true;
mutationEffectUnknown: false;
mutationConflict: false;
}>
| Readonly<{
refreshing: false;
staleDegraded: false;
mutationPending: false;
mutationEffectUnknown: true;
mutationConflict: false;
}>
| Readonly<{
refreshing: false;
staleDegraded: false;
mutationPending: false;
mutationEffectUnknown: false;
mutationConflict: true;
}>;
@@ -54,6 +67,7 @@ export type AsyncSignals = Readonly<{
isStale?: boolean;
isDegraded?: boolean;
isMutationPending?: boolean;
hasMutationEffectUnknown?: boolean;
hasMutationConflict?: boolean;
}>;
@@ -84,15 +98,17 @@ export function deriveAsyncState(signals: AsyncSignals): AsyncState {
: "initial-loading";
const indicator =
signals.hasMutationConflict && hasData
? "mutation-conflict"
: signals.isMutationPending && hasData
? "mutation-pending"
: signals.isStale && signals.isDegraded && hasData
? "stale-degraded"
: signals.isFetching && hasData
? "refreshing"
: null;
signals.hasMutationEffectUnknown && hasData
? "mutation-effect-unknown"
: signals.hasMutationConflict && hasData
? "mutation-conflict"
: signals.isMutationPending && hasData
? "mutation-pending"
: signals.isStale && signals.isDegraded && hasData
? "stale-degraded"
: signals.isFetching && hasData
? "refreshing"
: null;
const overlay = overlayFor(indicator);
return Object.freeze({
@@ -107,6 +123,7 @@ export function deriveAsyncState(signals: AsyncSignals): AsyncState {
export function selectOverlayIndicator(
overlay: AsyncOverlay,
): AsyncState["indicator"] {
if (overlay.mutationEffectUnknown) return "mutation-effect-unknown";
if (overlay.mutationConflict) return "mutation-conflict";
if (overlay.mutationPending) return "mutation-pending";
if (overlay.staleDegraded) return "stale-degraded";
@@ -120,6 +137,7 @@ function overlayFor(indicator: AsyncState["indicator"]): AsyncOverlay {
refreshing: true,
staleDegraded: false,
mutationPending: false,
mutationEffectUnknown: false,
mutationConflict: false,
});
}
@@ -128,6 +146,7 @@ function overlayFor(indicator: AsyncState["indicator"]): AsyncOverlay {
refreshing: false,
staleDegraded: true,
mutationPending: false,
mutationEffectUnknown: false,
mutationConflict: false,
});
}
@@ -136,6 +155,16 @@ function overlayFor(indicator: AsyncState["indicator"]): AsyncOverlay {
refreshing: false,
staleDegraded: false,
mutationPending: true,
mutationEffectUnknown: false,
mutationConflict: false,
});
}
if (indicator === "mutation-effect-unknown") {
return Object.freeze({
refreshing: false,
staleDegraded: false,
mutationPending: false,
mutationEffectUnknown: true,
mutationConflict: false,
});
}
@@ -144,6 +173,7 @@ function overlayFor(indicator: AsyncState["indicator"]): AsyncOverlay {
refreshing: false,
staleDegraded: false,
mutationPending: false,
mutationEffectUnknown: false,
mutationConflict: true,
});
}
@@ -151,6 +181,7 @@ function overlayFor(indicator: AsyncState["indicator"]): AsyncOverlay {
refreshing: false,
staleDegraded: false,
mutationPending: false,
mutationEffectUnknown: false,
mutationConflict: false,
});
}