mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 18:15:34 +00:00
feat(ui): persist page size preference across all list pages
Add pageSize to useUiStore (persisted in localStorage). Update PAGE_SIZES default to [20, 50, 100, 200]. All 12 paginated pages now read initial value from store and sync changes back globally.
This commit is contained in:
1 parent
f8a6f9363f
commit
207bc56dbd
9 files changed
+44
-10
No files matched your search
@@ -9,7 +9,7 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
const PAGE_SIZES = [10, 20, 50, 100];
|
||||
const PAGE_SIZES = [20, 50, 100, 200];
|
||||
|
||||
interface PaginationProps {
|
||||
page: number;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useMemo, useCallback } from "react";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
|
||||
export interface PaginationState {
|
||||
page: number;
|
||||
@@ -23,8 +24,11 @@ export function usePagination<T>(
|
||||
items: T[],
|
||||
options: UsePaginationOptions = {},
|
||||
): UsePaginationReturn<T> {
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
|
||||
const [page, setPageRaw] = useState(1);
|
||||
const [pageSize, setPageSizeRaw] = useState(options.defaultPageSize ?? 20);
|
||||
const [pageSize, setPageSizeRaw] = useState(options.defaultPageSize ?? globalPageSize);
|
||||
|
||||
const total = items.length;
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
@@ -45,7 +49,8 @@ export function usePagination<T>(
|
||||
const setPageSize = useCallback((size: number) => {
|
||||
setPageSizeRaw(size);
|
||||
setPageRaw(1);
|
||||
}, []);
|
||||
setGlobalPageSize(size);
|
||||
}, [setGlobalPageSize]);
|
||||
|
||||
const resetPage = useCallback(() => setPageRaw(1), []);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { ClipboardList, RefreshCw } from "lucide-react";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -30,10 +31,13 @@ export function ActivityPage() {
|
||||
const { logs, total, loading, load } = useActivity();
|
||||
const spinning = useMinLoading(loading);
|
||||
const showSkeleton = useDeferredLoading(loading && logs.length === 0);
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const [actionFilter, setActionFilter] = useState("all");
|
||||
const [entityFilter, setEntityFilter] = useState("all");
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ChevronDown, Contact, Info, Merge, RefreshCw, Search, Unlink } from "lucide-react";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
@@ -28,12 +29,15 @@ export function ContactsPage() {
|
||||
const { t } = useTranslation("contacts");
|
||||
const { t: tc } = useTranslation("common");
|
||||
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const [search, setSearch] = useState("");
|
||||
const [appliedSearch, setAppliedSearch] = useState("");
|
||||
const [channelType, setChannelType] = useState("");
|
||||
const [contactType, setContactType] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
|
||||
// Selection state
|
||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useMemo, lazy, Suspense } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Plus, RefreshCw, Search, Database } from "lucide-react";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@@ -38,9 +39,12 @@ export function MemoryPage() {
|
||||
const [deleteLoading, setDeleteLoading] = useState(false);
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
const [indexAllLoading, setIndexAllLoading] = useState(false);
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const [activeTab, setActiveTab] = useState("documents");
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
|
||||
const {
|
||||
documents,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Pagination } from "@/components/shared/pagination";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { TableSkeleton } from "@/components/shared/loading-skeleton";
|
||||
import { useDeferredLoading } from "@/hooks/use-deferred-loading";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
import { useSessions } from "./hooks/use-sessions";
|
||||
import { SessionDetailPage } from "./session-detail-page";
|
||||
import { parseSessionKey } from "@/lib/session-key";
|
||||
@@ -19,9 +20,12 @@ export function SessionsPage() {
|
||||
const { t } = useTranslation("sessions");
|
||||
const { key: detailKey } = useParams<{ key: string }>();
|
||||
const navigate = useNavigate();
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const [search, setSearch] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
|
||||
const { sessions, total, loading, preview, deleteSession, resetSession, patchSession } = useSessions({
|
||||
limit: pageSize,
|
||||
|
||||
@@ -62,11 +62,14 @@ export function TracesPage() {
|
||||
const { t } = useTranslation("traces");
|
||||
const { t: tc } = useTranslation("common");
|
||||
const tz = useUiStore((s) => s.timezone);
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const [agentFilter, setAgentFilter] = useState<string>();
|
||||
const [channelFilter, setChannelFilter] = useState<string>();
|
||||
const [selectedTraceId, setSelectedTraceId] = useState<string | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
|
||||
const ws = useWs();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { BarChart3, RefreshCw } from "lucide-react";
|
||||
import { useUiStore } from "@/stores/use-ui-store";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { PageHeader } from "@/components/shared/page-header";
|
||||
@@ -31,9 +32,12 @@ function AnalyticsDashboard() {
|
||||
useUsageAnalytics(filters);
|
||||
|
||||
// Legacy records table state
|
||||
const globalPageSize = useUiStore((s) => s.pageSize);
|
||||
const setGlobalPageSize = useUiStore((s) => s.setPageSize);
|
||||
const { records, total, loading: recLoading, loadRecords } = useUsage();
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize] = useState(20);
|
||||
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
|
||||
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };
|
||||
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
||||
|
||||
useEffect(() => {
|
||||
@@ -176,7 +180,7 @@ function AnalyticsDashboard() {
|
||||
total={total}
|
||||
totalPages={totalPages}
|
||||
onPageChange={setPage}
|
||||
onPageSizeChange={() => {}}
|
||||
onPageSizeChange={setPageSize}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -11,6 +11,7 @@ interface UiState {
|
||||
timezone: string; // IANA timezone or "auto"
|
||||
sidebarCollapsed: boolean;
|
||||
mobileSidebarOpen: boolean;
|
||||
pageSize: number; // global pagination page size preference
|
||||
|
||||
setTheme: (theme: Theme) => void;
|
||||
setLanguage: (language: Language) => void;
|
||||
@@ -18,6 +19,7 @@ interface UiState {
|
||||
toggleSidebar: () => void;
|
||||
setSidebarCollapsed: (collapsed: boolean) => void;
|
||||
setMobileSidebarOpen: (open: boolean) => void;
|
||||
setPageSize: (size: number) => void;
|
||||
}
|
||||
|
||||
export const useUiStore = create<UiState>()(
|
||||
@@ -28,6 +30,7 @@ export const useUiStore = create<UiState>()(
|
||||
timezone: "auto",
|
||||
sidebarCollapsed: false,
|
||||
mobileSidebarOpen: false,
|
||||
pageSize: 20,
|
||||
|
||||
setTheme: (theme) => {
|
||||
set({ theme });
|
||||
@@ -51,6 +54,8 @@ export const useUiStore = create<UiState>()(
|
||||
},
|
||||
|
||||
setMobileSidebarOpen: (open) => set({ mobileSidebarOpen: open }),
|
||||
|
||||
setPageSize: (size) => set({ pageSize: size }),
|
||||
}),
|
||||
{
|
||||
name: "goclaw:ui", // localStorage key
|
||||
@@ -60,6 +65,7 @@ export const useUiStore = create<UiState>()(
|
||||
language: state.language,
|
||||
timezone: state.timezone,
|
||||
sidebarCollapsed: state.sidebarCollapsed,
|
||||
pageSize: state.pageSize,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user