From 143751c63ba85806602b112c9ea06d357ac54d9e Mon Sep 17 00:00:00 2001 From: NotYuSheng Date: Sun, 26 Jul 2026 13:54:12 +0800 Subject: [PATCH] fix(monitor): compact pagination for narrow drift-panel columns The shared Pagination component was designed for full-width tables. In the monitor Devices / Protocols / IP Addresses drift panels it sits in a ~250px column, where its "Previous"/"Next" text labels wrapped under the chevron and "Next" got clipped at the container edge (the "Page Navigation" nav). Add a `compact` prop: icon-only direction buttons, fewer page numbers (limit 3), and a stacked layout so the whole pager fits on one row. Opt the three drift panels into it. Also make direction buttons nowrap and let the number list wrap defensively so no pager can overflow its container. Co-Authored-By: Claude Opus 4.8 --- .../common/Pagination/Pagination.css | 27 +++++++++++++++++++ .../common/Pagination/Pagination.tsx | 13 ++++++--- .../DeviceDriftPanel/DeviceDriftPanel.tsx | 1 + .../monitor/IpDriftPanel/IpDriftPanel.tsx | 1 + .../ProtocolDriftPanel/ProtocolDriftPanel.tsx | 1 + 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/common/Pagination/Pagination.css b/frontend/src/components/common/Pagination/Pagination.css index cf4a96b4..15e565f9 100644 --- a/frontend/src/components/common/Pagination/Pagination.css +++ b/frontend/src/components/common/Pagination/Pagination.css @@ -53,6 +53,33 @@ border-color: #0056b3; } +/* Keep the Previous/Next direction buttons on a single line. Their icon-text variant + renders an icon + a label; in narrow containers (the monitor drift panels, where the + pager sits in a ~250px column) the label otherwise wraps under the icon — "Previous" + drops to a second row and "Next" gets clipped. */ +.pagination-container .pagination .page-link { + white-space: nowrap; +} + +/* The pager nav must never overflow its container. Let the page-number list wrap onto + another row instead of spilling past the right edge when the column is too narrow. */ +.pagination-container .pagination { + flex-wrap: wrap; +} + +/* Compact mode: the pager lives in a narrow column (monitor drift panels). Stack the + "Showing X of Y" line above the nav and pull the padding in so it fits without wrapping. */ +.pagination-container--compact { + flex-direction: column; + align-items: flex-start; + padding: 0.5rem 0; + gap: 0.5rem; +} + +.pagination-container--compact .pagination-info { + font-size: 0.8rem; +} + /* Responsive adjustments */ @media (width <= 768px) { .pagination-container { diff --git a/frontend/src/components/common/Pagination/Pagination.tsx b/frontend/src/components/common/Pagination/Pagination.tsx index 6db6ca7b..2b8946d5 100644 --- a/frontend/src/components/common/Pagination/Pagination.tsx +++ b/frontend/src/components/common/Pagination/Pagination.tsx @@ -11,6 +11,12 @@ interface PaginationProps { onPageSizeChange?: (pageSize: number) => void; pageSizeOptions?: number[]; showPageSizeSelector?: boolean; + /** + * Compact mode for narrow containers (e.g. the monitor drift panels, where the pager + * sits in a ~250px column). Drops the "Previous"/"Next" text labels for icon-only + * direction buttons and shows fewer page numbers so the whole pager fits on one row. + */ + compact?: boolean; } export const Pagination: React.FC = ({ @@ -22,6 +28,7 @@ export const Pagination: React.FC = ({ onPageSizeChange, pageSizeOptions = [10, 25, 50, 100], showPageSizeSelector = true, + compact = false, }) => { if (totalPages === 0) return null; @@ -42,7 +49,7 @@ export const Pagination: React.FC = ({ }; return ( -
+
Showing {startItem} to {endItem} of {totalItems} items @@ -80,10 +87,10 @@ export const Pagination: React.FC = ({ itemsPerPage={pageSize} setCurrentPage={setCurrentPage} size="sm" - limit={5} + limit={compact ? 3 : 5} ellipsisOn ellipsisJump={2} - directionVariant="icon-text" + directionVariant={compact ? 'icon' : 'icon-text'} />
diff --git a/frontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx b/frontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx index 3ead54d4..7bef6f5e 100644 --- a/frontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx +++ b/frontend/src/components/monitor/DeviceDriftPanel/DeviceDriftPanel.tsx @@ -164,6 +164,7 @@ export const DeviceDriftPanel = ({ snapshots }: DeviceDriftPanelProps) => { pageSize={BADGE_PAGE_SIZE} onPageChange={setPage} showPageSizeSelector={false} + compact /> )} {absentMacs.length > 0 && ( diff --git a/frontend/src/components/monitor/IpDriftPanel/IpDriftPanel.tsx b/frontend/src/components/monitor/IpDriftPanel/IpDriftPanel.tsx index aa13e621..bdaf72e3 100644 --- a/frontend/src/components/monitor/IpDriftPanel/IpDriftPanel.tsx +++ b/frontend/src/components/monitor/IpDriftPanel/IpDriftPanel.tsx @@ -153,6 +153,7 @@ function IpBadgeGroup({ pageSize={BADGE_GROUP_PAGE_SIZE} onPageChange={setPage} showPageSizeSelector={false} + compact /> )} diff --git a/frontend/src/components/monitor/ProtocolDriftPanel/ProtocolDriftPanel.tsx b/frontend/src/components/monitor/ProtocolDriftPanel/ProtocolDriftPanel.tsx index d440d402..ea35fa2e 100644 --- a/frontend/src/components/monitor/ProtocolDriftPanel/ProtocolDriftPanel.tsx +++ b/frontend/src/components/monitor/ProtocolDriftPanel/ProtocolDriftPanel.tsx @@ -103,6 +103,7 @@ function BadgeGroup({ pageSize={BADGE_GROUP_PAGE_SIZE} onPageChange={setPage} showPageSizeSelector={false} + compact /> )}