Files
paseo/packages/app/src/git/query-keys.ts
T
Mohamed Boudra 309672c8e5 Show recent commit history in the explorer (#2312)
* feat(app): show recent commit history in explorer

* fix(app): keep recent commit history accurate

* fix(app): include merged commits in recent history

* perf(app): bound recent commit classification

* fix(app): refresh recent commits on Git updates
2026-07-21 22:12:33 +02:00

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",
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"
);
}