fix(skills): make the skills.sh retry button actually refetch

After a failed first page the retry handler only reset the page offset,
which was already 0, so the query key never changed and nothing was
requested. Refetch explicitly on the first page; a failed load-more still
restarts from page one.
This commit is contained in:
Jason committed 2026-10-03 23:28:59 +08:00
1 parent 05d70dc32f
commit d6666977a3
2 files changed
+34 -4

No files matched your search

+12 -3
View File
@@ -200,6 +200,7 @@ export function SkillsPage({
isFetching: fetchingSkillsSh,
isPlaceholderData: placeholderSkillsSh,
isError: skillsShError,
refetch: refetchSkillsSh,
} = useSearchSkillsSh(skillsShQuery, SKILLSSH_PAGE_SIZE, skillsShOffset);
const installMutation = useInstallSkill();
const { setRepoEnabled } = useSkillRepoActions();
@@ -231,6 +232,16 @@ export function SkillsPage({
setSkillsShQuery(trimmed);
};
// 第一页失败时 query key 没变,光把 offset 设回 0 什么都不会发生,要显式重新请求
const retrySkillsSh = () => {
setAccumulated([]);
if (skillsShOffset === 0) {
void refetchSkillsSh();
} else {
setSkillsShOffset(0);
}
};
// ─── 已安装 / 目录名占用 ────────────────────────────────────────────
const installedByKey = useMemo(() => {
const map = new Map<string, InstalledSkill>();
@@ -421,9 +432,7 @@ export function SkillsPage({
body = t("skillsPage.discover.skillsShHint");
} else if (skillsShError) {
title = t("skills.skillssh.error");
buttons = [
{ label: t("common.retry"), onClick: () => setSkillsShOffset(0) },
];
buttons = [{ label: t("common.retry"), onClick: retrySkillsSh }];
} else {
title = t("skillsPage.discover.skillsShNone", { query: skillsShQuery });
}
+22 -1
View File
@@ -31,6 +31,8 @@ const searchCache = new Map<
isLoading: boolean;
isFetching: boolean;
isPlaceholderData?: boolean;
isError?: boolean;
refetch?: () => void;
}
>();
@@ -38,7 +40,12 @@ const setSearchResult = (
query: string,
offset: number,
result: SkillsShSearchResult | undefined,
state: Partial<{ isLoading: boolean; isFetching: boolean }> = {},
state: Partial<{
isLoading: boolean;
isFetching: boolean;
isError: boolean;
refetch: () => void;
}> = {},
) => {
searchCache.set(`${query}:${offset}`, {
data: result,
@@ -214,6 +221,20 @@ describe("SkillsPage (Discover)", () => {
expect(screen.getByText("figma-use")).toBeInTheDocument();
});
it("refetches the first skills.sh page when retrying after a failure", async () => {
const refetch = vi.fn();
setSearchResult("boom", 0, undefined, { isError: true, refetch });
renderPage();
await userEvent.type(
screen.getByRole("textbox", { name: "skillsPage.discover.skillsShAria" }),
"boom{Enter}",
);
expect(screen.getByText("skills.skillssh.error")).toBeInTheDocument();
// 第一页失败时 query key 没变,重试必须显式 refetch,不能只把 offset 设回 0
await userEvent.click(screen.getByRole("button", { name: "common.retry" }));
expect(refetch).toHaveBeenCalledTimes(1);
});
it("shows the loading state while a skills.sh query is fetching", async () => {
setSearchResult("x1", 0, undefined, { isLoading: true, isFetching: true });
renderPage();