Keep git review state fresh after reconnect (#1491)
This commit is contained in:
@@ -1,48 +1,86 @@
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
import type { CheckoutStatusResponse, CheckoutStatusUpdate } from "@getpaseo/protocol/messages";
|
||||
import { checkoutStatusQueryKey } from "@/git/query-keys";
|
||||
import equal from "fast-deep-equal/es6";
|
||||
import {
|
||||
checkoutPrStatusQueryKey,
|
||||
checkoutStatusQueryKey,
|
||||
invalidatePrPaneTimelineForCheckout,
|
||||
} from "@/git/query-keys";
|
||||
import { expireStaleDiffModeOverrides } from "@/review/store";
|
||||
|
||||
export type CheckoutStatusPayload = CheckoutStatusResponse["payload"];
|
||||
export type CheckoutPrStatusPayload = NonNullable<CheckoutStatusUpdate["payload"]["prStatus"]>;
|
||||
|
||||
export interface CheckoutStatusClient {
|
||||
getCheckoutStatus: (cwd: string) => Promise<CheckoutStatusPayload>;
|
||||
}
|
||||
|
||||
export async function peekOrFetchCheckoutStatus({
|
||||
queryClient,
|
||||
// Checkout status enters the app through exactly two doors: daemon pushes
|
||||
// (applyCheckoutStatusUpdateFromEvent) and query fetches (fetchCheckoutStatus). Both run
|
||||
// the dirty-state reactions, so they hold regardless of which screens are mounted.
|
||||
|
||||
export async function fetchCheckoutStatus({
|
||||
client,
|
||||
serverId,
|
||||
cwd,
|
||||
}: {
|
||||
queryClient: QueryClient;
|
||||
client: CheckoutStatusClient;
|
||||
serverId: string;
|
||||
cwd: string;
|
||||
}): Promise<CheckoutStatusPayload> {
|
||||
const queryKey = checkoutStatusQueryKey(serverId, cwd);
|
||||
const cached = queryClient.getQueryData<CheckoutStatusPayload>(queryKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const snapshot = await client.getCheckoutStatus(cwd);
|
||||
queryClient.setQueryData(queryKey, snapshot);
|
||||
return snapshot;
|
||||
const payload = await client.getCheckoutStatus(cwd);
|
||||
expireStaleDiffModeOverrides({ serverId, cwd, isDirty: payload.isGit && payload.isDirty });
|
||||
return payload;
|
||||
}
|
||||
|
||||
export function applyCheckoutStatusUpdate({
|
||||
export function applyCheckoutStatusUpdateFromEvent({
|
||||
queryClient,
|
||||
serverId,
|
||||
cwd,
|
||||
message,
|
||||
}: {
|
||||
queryClient: QueryClient;
|
||||
serverId: string;
|
||||
cwd: string;
|
||||
message: CheckoutStatusUpdate;
|
||||
}): void {
|
||||
if (message.payload.cwd !== cwd) {
|
||||
const { payload } = message;
|
||||
queryClient.setQueryData(checkoutStatusQueryKey(serverId, payload.cwd), payload);
|
||||
expireStaleDiffModeOverrides({
|
||||
serverId,
|
||||
cwd: payload.cwd,
|
||||
isDirty: payload.isGit && payload.isDirty,
|
||||
});
|
||||
|
||||
const prStatus = payload.prStatus;
|
||||
if (!prStatus) {
|
||||
return;
|
||||
}
|
||||
queryClient.setQueryData(checkoutStatusQueryKey(serverId, cwd), message.payload);
|
||||
|
||||
const previous = queryClient.getQueryData<CheckoutPrStatusPayload>(
|
||||
checkoutPrStatusQueryKey(serverId, prStatus.cwd),
|
||||
);
|
||||
queryClient.setQueryData(checkoutPrStatusQueryKey(serverId, prStatus.cwd), prStatus);
|
||||
|
||||
// The PR activity timeline has no push channel; mark it stale when the pushed PR status
|
||||
// meaningfully changed. Active panes refetch immediately, evicted ones on next mount.
|
||||
if (hasPrStatusChanged(previous, prStatus)) {
|
||||
void invalidatePrPaneTimelineForCheckout(queryClient, { serverId, cwd: prStatus.cwd });
|
||||
}
|
||||
}
|
||||
|
||||
// requestId changes on every emission and carries no PR state.
|
||||
function prStatusWithoutVolatileFields(
|
||||
prStatus: CheckoutPrStatusPayload,
|
||||
): Omit<CheckoutPrStatusPayload, "requestId"> {
|
||||
const { requestId: _requestId, ...rest } = prStatus;
|
||||
return rest;
|
||||
}
|
||||
|
||||
function hasPrStatusChanged(
|
||||
previous: CheckoutPrStatusPayload | undefined,
|
||||
next: CheckoutPrStatusPayload,
|
||||
): boolean {
|
||||
if (!previous) {
|
||||
return true;
|
||||
}
|
||||
return !equal(prStatusWithoutVolatileFields(previous), prStatusWithoutVolatileFields(next));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user