mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 20:22:45 +00:00
* feat(git): default review to all branch changes Keep the selected comparison stable while agents edit and commit so reviewing the complete result does not require switching scopes or interrupt unfinished comments. * test(git): release Windows checkout handles during cleanup Allow transient filesystem handles from subscription teardown to close before removing the test repository.
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import type { Query, QueryClient } from "@tanstack/react-query";
|
|
import { prPanePipelineQueryKind, prPaneTimelineQueryKind } from "./pull-request-panel/query-keys";
|
|
|
|
interface CheckoutQueryIdentity {
|
|
serverId: string;
|
|
cwd: string;
|
|
}
|
|
|
|
interface CheckoutQueryScope {
|
|
serverId: string;
|
|
cwd?: string;
|
|
}
|
|
|
|
type CheckoutQueryKey = readonly unknown[];
|
|
|
|
// A commit's file diff is immutable for a given sha+path, so every consumer
|
|
// can share the same long-lived cache policy.
|
|
export const COMMIT_FILE_DIFF_STALE_TIME = 5 * 60_000;
|
|
|
|
export function checkoutStatusQueryKey(serverId: string, cwd: string) {
|
|
return ["checkoutStatus", serverId, cwd] as const;
|
|
}
|
|
|
|
export function checkoutDiffQueryKey(
|
|
serverId: string,
|
|
cwd: string,
|
|
mode: "uncommitted" | "base" | "all",
|
|
baseRef?: string,
|
|
ignoreWhitespace?: boolean,
|
|
) {
|
|
return ["checkoutDiff", serverId, cwd, mode, baseRef ?? "", ignoreWhitespace === true] as const;
|
|
}
|
|
|
|
export function checkoutPrStatusQueryKey(serverId: string, cwd: string) {
|
|
return ["checkoutPrStatus", serverId, cwd] as const;
|
|
}
|
|
|
|
export function checkoutCommitsQueryKey(serverId: string, cwd: string) {
|
|
return ["checkoutCommits", serverId, cwd] as const;
|
|
}
|
|
|
|
export function checkoutCommitFileDiffQueryKey(
|
|
serverId: string,
|
|
cwd: string,
|
|
sha: string,
|
|
path: string,
|
|
) {
|
|
return ["checkoutCommitFileDiff", serverId, cwd, sha, path] as const;
|
|
}
|
|
|
|
export async function invalidateCheckoutGitQueriesForClient(
|
|
queryClient: QueryClient,
|
|
identity: CheckoutQueryIdentity,
|
|
) {
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
queryKey: checkoutStatusQueryKey(identity.serverId, identity.cwd),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate("checkoutDiff", identity),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate("checkoutPrStatus", identity),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
queryKey: checkoutCommitsQueryKey(identity.serverId, identity.cwd),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate(prPaneTimelineQueryKind, identity),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate(prPanePipelineQueryKind, identity),
|
|
}),
|
|
]);
|
|
}
|
|
|
|
// checkoutDiff is excluded: diff queries are subscription-fed (queryFn: skipToken) and
|
|
// receive a fresh snapshot on every resubscribe, so invalidation cannot and need not
|
|
// refetch them.
|
|
export async function invalidateCheckoutGitQueriesForServer(
|
|
queryClient: QueryClient,
|
|
serverId: string,
|
|
) {
|
|
const kinds = [
|
|
"checkoutStatus",
|
|
"checkoutPrStatus",
|
|
"checkoutCommits",
|
|
prPaneTimelineQueryKind,
|
|
prPanePipelineQueryKind,
|
|
];
|
|
await Promise.all(
|
|
kinds.map((kind) =>
|
|
queryClient.invalidateQueries({ predicate: checkoutQueryPredicate(kind, { serverId }) }),
|
|
),
|
|
);
|
|
}
|
|
|
|
export async function invalidatePrPaneTimelineForCheckout(
|
|
queryClient: QueryClient,
|
|
identity: CheckoutQueryIdentity,
|
|
) {
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate(prPaneTimelineQueryKind, identity),
|
|
}),
|
|
queryClient.invalidateQueries({
|
|
predicate: checkoutQueryPredicate(prPanePipelineQueryKind, identity),
|
|
}),
|
|
]);
|
|
}
|
|
|
|
function checkoutQueryPredicate(
|
|
queryKind: CheckoutQueryKey[0],
|
|
scope: CheckoutQueryScope,
|
|
): (query: Query) => boolean {
|
|
return (query) => {
|
|
const key = query.queryKey;
|
|
return (
|
|
isCheckoutQueryKey(key) &&
|
|
key[0] === queryKind &&
|
|
key[1] === scope.serverId &&
|
|
(scope.cwd === undefined || key[2] === scope.cwd)
|
|
);
|
|
};
|
|
}
|
|
|
|
function isCheckoutQueryKey(key: readonly unknown[]): key is CheckoutQueryKey {
|
|
return (
|
|
key.length >= 3 &&
|
|
typeof key[0] === "string" &&
|
|
typeof key[1] === "string" &&
|
|
typeof key[2] === "string"
|
|
);
|
|
}
|