Unverified Commit 50ec1811 authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(panel): 服务器列表无匹配时给出真的清除筛选按钮,清掉搜索和状态筛选并回到第一页

parent f6d586ed
Loading
Loading
Loading
Loading
+59 −2
Changes for panel/src/pages/servers/ServersPage.test.tsx: 59 added lines, 2 removed lines.
Original line number Diff line number Diff line
// @vitest-environment jsdom
import { describe, it, expect, vi, beforeEach, beforeAll } from "vitest";
import { render, screen, within } from "@testing-library/react";
import { describe, it, expect, vi, beforeEach, beforeAll, afterEach } from "vitest";
import { act, render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MemoryRouter } from "react-router-dom";
import type { FleetServer, MyServerView } from "@/lib/types";
@@ -341,3 +341,60 @@ describe("ServersPage order and paging", () => {
    expect(await tableOrder()).toEqual(names.slice(0, 20));
  });
});

describe("ServersPage with nothing matching", () => {
  afterEach(() => {
    vi.useRealTimers();
  });

  it("clears the search and the phase filter from the empty state", async () => {
    tier.isAdmin = false;
    const mine = (name: string): MyServerView => ({
      name,
      subdomain: name,
      owned: true,
      claimable: false,
      phase: "Running",
      playersOnline: 0,
      playersMax: 20,
    });
    calls.myServers.mockResolvedValue([mine("survival"), mine("creative")]);
    const user = renderPage();
    await tableOrder();

    const search = screen.getByPlaceholderText(/Search/) as HTMLInputElement;
    await user.type(search, "zzz");
    await user.click(screen.getByRole("combobox", { name: "Filter by phase" }));
    await user.click(await screen.findByRole("option", { name: "Stopping" }));
    expect(screen.getByText("No matching servers found.")).toBeTruthy();
    expect(screen.getByText("No server matches the current search or filter.")).toBeTruthy();

    await user.click(screen.getByRole("button", { name: "Clear filters" }));
    expect(await tableOrder()).toEqual(["creative", "survival"]);
    expect(search.value).toBe("");
    expect(screen.getByRole("combobox", { name: "Filter by phase" }).textContent).toBe("All phases");
  });

  it("starts the cleared list from its first page", async () => {
    vi.useFakeTimers({ shouldAdvanceTime: true });
    const names = Array.from({ length: 21 }, (_, i) => `srv-${String(i + 1).padStart(2, "0")}`);
    calls.fleet.mockResolvedValue(names.map((n) => row(n, { phase: "Running", ready: true })));
    const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
    render(
      <MemoryRouter>
        <ServersPage />
      </MemoryRouter>,
    );
    await tableOrder();
    await user.click(screen.getByRole("combobox", { name: "Filter by phase" }));
    await user.click(await screen.findByRole("option", { name: "Running" }));
    await user.click(screen.getByRole("button", { name: /Next/ }));
    expect(await tableOrder()).toEqual(["srv-21"]);

    // The next reread finds every server stopped, so the filtered page empties.
    calls.fleet.mockResolvedValue(names.map((n) => row(n, {})));
    await act(() => vi.advanceTimersByTimeAsync(10_000));
    await user.click(await screen.findByRole("button", { name: "Clear filters" }));
    expect(await tableOrder()).toEqual(names.slice(0, 20));
  });
});
+14 −2
Changes for panel/src/pages/servers/ServersPage.tsx: 14 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -402,8 +402,20 @@ export function ServersPage() {
          ) : visible.length === 0 ? (
            <EmptyState
              title={isAdmin ? t("fleet_no_match_title") : t("servers:search_no_match")}
              hint={isAdmin ? t("fleet_no_match_hint") : t("servers:search_clear_btn")}
            />
              hint={t("fleet_no_match_hint")}
            >
              <Button
                variant="outline"
                size="sm"
                onClick={() => {
                  setQuery("");
                  setPhaseFilter("all");
                  setPage(1);
                }}
              >
                {t("servers:search_clear_btn")}
              </Button>
            </EmptyState>
          ) : (
            <>
              {/* Cards until the table fits (two per row from md). The admin