fix(panel): 服务器列表的刷新按钮只为自己的点击转圈和禁用,后台轮询时保持可点
This commit is contained in:
2 files changed
+51
-3
No files matched your search
@@ -428,3 +428,41 @@ describe("ServersPage with nothing matching", () => {
|
||||
expect(await tableOrder()).toEqual(names.slice(0, 20));
|
||||
});
|
||||
});
|
||||
|
||||
describe("ServersPage refresh button", () => {
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("stays still and clickable through the background reread, and spins for its own click", async () => {
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
calls.fleet.mockResolvedValue([row("survival", {})]);
|
||||
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<ServersPage />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
await tableOrder();
|
||||
const button = screen.getByRole("button", { name: "Refresh now" }) as HTMLButtonElement;
|
||||
const spinning = () => button.querySelector("svg")?.classList.contains("animate-spin");
|
||||
|
||||
// The background reread hangs; the button does not show it.
|
||||
let finish: (v: FleetServer[]) => void = () => {};
|
||||
calls.fleet.mockReturnValueOnce(new Promise<FleetServer[]>((r) => (finish = r)));
|
||||
await act(() => vi.advanceTimersByTimeAsync(10_000));
|
||||
expect(calls.fleet).toHaveBeenCalledTimes(2);
|
||||
expect(button.disabled).toBe(false);
|
||||
expect(spinning()).toBe(false);
|
||||
|
||||
calls.fleet.mockReturnValueOnce(new Promise<FleetServer[]>((r) => (finish = r)));
|
||||
await user.click(button);
|
||||
expect(calls.fleet).toHaveBeenCalledTimes(3);
|
||||
expect(button.disabled).toBe(true);
|
||||
expect(spinning()).toBe(true);
|
||||
|
||||
await act(async () => finish([row("survival", {})]));
|
||||
expect(button.disabled).toBe(false);
|
||||
expect(spinning()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -148,6 +148,16 @@ export function ServersPage() {
|
||||
|
||||
usePolling(reload, REFRESH_MS);
|
||||
|
||||
// The refresh button answers its own click alone. The background reread every
|
||||
// few seconds leaves it still and clickable; a spin and a disabled button on
|
||||
// each tick read as the page stalling.
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
if (refreshing && !loading) setRefreshing(false);
|
||||
const refresh = () => {
|
||||
setRefreshing(true);
|
||||
reload();
|
||||
};
|
||||
|
||||
const servers = useMemo<UnifiedServer[]>(() => {
|
||||
if (!data) return [];
|
||||
if (isAdmin) {
|
||||
@@ -253,12 +263,12 @@ export function ServersPage() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={reload}
|
||||
disabled={loading}
|
||||
onClick={refresh}
|
||||
disabled={refreshing}
|
||||
aria-label={t("fleet_refresh")}
|
||||
title={t("fleet_refresh")}
|
||||
>
|
||||
<RefreshCw className={cn("h-4 w-4", loading && "animate-spin")} />
|
||||
<RefreshCw className={cn("h-4 w-4", refreshing && "animate-spin")} />
|
||||
</Button>
|
||||
{isAdmin && cfg && <CreateServerDialog cfg={cfg} onCreated={reload} />}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user