import { useQueryClient } from '@tanstack/solid-query';
import { useAuth } from './auth';
import {
getRepo,
getRepoBranches,
getRepoDefaultBranch,
getRepoTags,
getRepoForkCount,
getRepoTree,
getRepoLog,
getRepoLanguages,
type RepoContext,
} from './api/repos';
import { getIssue, getRepoIssueCount } from './api/issues';
import { fetchPullRoundPatch, getPull, getRepoPullCount } from './api/pulls';
import { getString } from './api/strings';
import { getRepoStarSummary } from './api/stars';
import { repoQueryKey, issueQueryKey, pullQueryKey, pullPatchQueryKey, issuesQueryKey, pullsQueryKey } from './api/keys';
import { resolveDefaultBranchName } from '../pages/repo/code-helpers';
export const PRELOAD_HOVER_TIME = 30;
export const usePreloader = () => {
const queryClient = useQueryClient();
return (queryKey: readonly unknown[], queryFn: () => Promise<any>, delayMs = PRELOAD_HOVER_TIME) => {
let hoverTimer: ReturnType<typeof setTimeout> | undefined;
const onMouseEnter = () => {
hoverTimer = setTimeout(() => {
queryClient.prefetchQuery({ queryKey, queryFn });
}, delayMs);
};
const onMouseLeave = () => {
clearTimeout(hoverTimer);
};
return { onMouseEnter, onMouseLeave };
};
};
export const useRepoPreloader = () => {
const queryClient = useQueryClient();
const auth = useAuth();
const preload = usePreloader();
return (owner: string, name: string) => {
return preload(
['repo-prefetch', owner, name],
async () => {
const repo = await queryClient.fetchQuery({
queryKey: repoQueryKey(owner, name),
queryFn: () => getRepo(owner, name),
});
if (!repo) {
return repo;
}
const currentDid = auth.currentDid();
// Fetch branches and default-branch, and prefetch counts and tags concurrently
const [branches, defaultBranchRes] = await Promise.all([
queryClient.fetchQuery({
queryKey: ['repo-branches', repo.repoDid],
queryFn: () => getRepoBranches(repo),
}),
queryClient.fetchQuery({
queryKey: ['repo-default-branch', repo.repoDid],
queryFn: () => getRepoDefaultBranch(repo),
}),
queryClient.prefetchQuery({
queryKey: ['repo-star-summary', repo.repoDid, currentDid],
queryFn: () => getRepoStarSummary(repo, currentDid),
}),
queryClient.prefetchQuery({
queryKey: ['repo-fork-count', repo.repoDid],
queryFn: () => getRepoForkCount(repo),
}),
queryClient.prefetchQuery({
queryKey: [...issuesQueryKey(repo.repoDid), 'count'],
queryFn: () => getRepoIssueCount(repo),
}),
queryClient.prefetchQuery({
queryKey: [...pullsQueryKey(repo.repoDid), 'count'],
queryFn: () => getRepoPullCount(repo),
}),
queryClient.prefetchQuery({
queryKey: ['repo-tags', repo.repoDid],
queryFn: () => getRepoTags(repo),
}),
]);
const defaultBranchName =
defaultBranchRes?.name ??
defaultBranchRes?.branch ??
defaultBranchRes?.reference?.name ??
resolveDefaultBranchName(branches?.branches) ??
'main';
// Now that we have the default branch name, prefetch tree, log and languages
await Promise.all([
queryClient.prefetchQuery({
queryKey: ['repo-tree', repo.repoDid, defaultBranchName, ''],
queryFn: async () => ({
tree: await getRepoTree(repo, defaultBranchName, ''),
path: '',
ref: defaultBranchName,
}),
}),
queryClient.prefetchQuery({
queryKey: ['repo-log', repo.repoDid, defaultBranchName],
queryFn: () => getRepoLog(repo, defaultBranchName),
}),
queryClient.prefetchQuery({
queryKey: ['repo-languages', repo.repoDid, defaultBranchName],
queryFn: () => getRepoLanguages(repo, defaultBranchName),
}),
]).catch(() => {
// Ignore background prefetch errors
});
return repo;
}
);
};
};
export const useStringPreloader = () => {
const preload = usePreloader();
return (actor: string, rkey: string) => {
return preload(['string-detail', actor, rkey], () => getString(actor, rkey));
};
};
export const useIssuePreloader = () => {
const queryClient = useQueryClient();
const preload = usePreloader();
return (
repoLabel: string,
kind: 'issue' | 'pull',
uri: string,
number?: string | number,
repoContext?: RepoContext,
) => {
const [owner, slug] = repoLabel.split('/');
const issueRef = String(number || uri.split('/').pop());
return preload(
[kind, uri, 'prefetch'],
async () => {
const repo =
repoContext ||
(await queryClient.fetchQuery({
queryKey: repoQueryKey(owner, slug),
queryFn: () => getRepo(owner, slug),
}));
if (!repo) {
return;
}
if (kind === 'issue') {
await queryClient.prefetchQuery({
queryKey: issueQueryKey(repo.repoDid, issueRef),
queryFn: () => getIssue(repo, issueRef),
});
} else {
const pullDetail = await queryClient.fetchQuery({
queryKey: pullQueryKey(repo.repoDid, issueRef),
queryFn: () => getPull(repo, issueRef),
});
const roundIndex = Math.max(0, pullDetail.pull.value.rounds.length - 1);
await queryClient.prefetchQuery({
queryKey: pullPatchQueryKey(pullDetail.pull.uri, roundIndex),
queryFn: () => fetchPullRoundPatch(pullDetail.pull, roundIndex),
});
}
},
);
};
};