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

feat(panel): pagination for server lists

parent e1892659
Loading
Loading
Loading
Loading
+2 −2
Changes for panel/src/components/AppShell.tsx: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -121,8 +121,8 @@ export function AppShell() {
            <ThemeToggle />
          </div>
        </header>
        <main className="flex-1 p-6">
          <div className="mx-auto max-w-7xl space-y-7">
        <main className="flex flex-1 flex-col p-6">
          <div className="mx-auto flex w-full max-w-6xl flex-1 flex-col gap-6">
            <Outlet />
          </div>
        </main>
+41 −0
Changes for panel/src/components/Pagination.tsx: 41 added lines, 0 removed lines.
Original line number Diff line number Diff line
import { ChevronLeft, ChevronRight } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";

interface Props {
  page: number;
  pageSize: number;
  total: number;
  onChange: (page: number) => void;
}

export function Pagination({ page, pageSize, total, onChange }: Props) {
  const { t } = useTranslation("common");
  const totalPages = Math.max(1, Math.ceil(total / pageSize));

  return (
    <div className="flex items-center justify-center gap-2 mt-auto">
      <Button
        variant="outline"
        size="sm"
        disabled={page <= 1}
        onClick={() => onChange(page - 1)}
      >
        <ChevronLeft />
        {t("pagination_prev")}
      </Button>
      <span className="text-xs text-muted-foreground min-w-[6rem] text-center">
        {t("pagination_of", { current: page, total: totalPages })}
      </span>
      <Button
        variant="outline"
        size="sm"
        disabled={page >= totalPages}
        onClick={() => onChange(page + 1)}
      >
        {t("pagination_next")}
        <ChevronRight />
      </Button>
    </div>
  );
}
+4 −1
Changes for panel/src/i18n/resources/en-US/common.json: 4 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -19,5 +19,8 @@
  "lang_en": "EN",
  "lang_zh": "中文",
  "lang_toggle_hint": "Switch to {{lang}}",
  "toggle_theme": "Toggle theme"
  "toggle_theme": "Toggle theme",
  "pagination_prev": "Previous",
  "pagination_next": "Next",
  "pagination_of": "Page {{current}} of {{total}}"
}
+4 −1
Changes for panel/src/i18n/resources/zh-CN/common.json: 4 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -19,5 +19,8 @@
  "lang_en": "EN",
  "lang_zh": "中文",
  "lang_toggle_hint": "切换至 {{lang}}",
  "toggle_theme": "切换主题"
  "toggle_theme": "切换主题",
  "pagination_prev": "上一页",
  "pagination_next": "下一页",
  "pagination_of": "第 {{current}} / {{total}} 页"
}
+17 −4
Changes for panel/src/pages/MyServers.tsx: 17 added lines, 4 removed lines.
Original line number Diff line number Diff line
import { useState } from "react";
import { Server } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Card, CardContent } from "@/components/ui/card";
import { ServerCard } from "@/components/ServerCard";
import { Pagination } from "@/components/Pagination";
import { Loading, ErrorState, EmptyState } from "@/components/States";
import { api } from "@/lib/api";
import { useAsync, useConfig } from "@/lib/hooks";

// MyServers is the User-Side fleet: list / wake / stop / claim the servers the
// caller owns or may claim. Creation lives on Admin-Side now (POST /servers is
// admin-tier) — the platform provisions servers; users claim and operate them.
const PAGE_SIZE = 12;

export function MyServers() {
  const cfg = useConfig();
  const { data, error, loading, reload } = useAsync(() => api.myServers(), []);
  const { t } = useTranslation("servers");
  const servers = data ?? [];
  const [page, setPage] = useState(1);
  const totalPages = Math.max(1, Math.ceil(servers.length / PAGE_SIZE));
  const paged = servers.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);

  return (
    <>
@@ -40,7 +44,7 @@ export function MyServers() {
        />
      ) : (
        <div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
          {servers.map((s) => (
          {paged.map((s) => (
            <ServerCard key={s.name} server={s} cfg={cfg} onChanged={reload} />
          ))}
        </div>
@@ -51,6 +55,15 @@ export function MyServers() {
          {t("my_servers_footer")}
        </CardContent>
      </Card>

      {servers.length > 0 && (
        <Pagination
          page={page}
          pageSize={PAGE_SIZE}
          total={servers.length}
          onChange={(p) => { setPage(p); if (p > totalPages) setPage(totalPages); }}
        />
      )}
    </>
  );
}
Loading