- No sessions found matching your search.
+ {loadingMore ? (
+
+
+ Loading sessions...
+
+ ) : (
+ "No sessions found matching your search."
+ )}
) : (
@@ -752,75 +760,39 @@ export function SessionTable({
- {/* Pagination Controls */}
- {totalPages > 1 && (
+ {/* Pagination Controls — single Prev/Next surface that transparently fetches
+ the next server batch when the user pages past locally-loaded sessions.
+ Renders whenever there's somewhere to navigate (more local pages OR more
+ on the server). */}
+ {(totalPages > 1 || hasMore) && (
- Page {currentPage} of {totalPages} ({sortedSessions.length}{hasMore ? '+' : ''} total sessions)
+ Page {currentPage} of {totalPages}{hasMore ? '+' : ''} ({sortedSessions.length}{hasMore ? '+' : ''} total sessions)
)}
-
- {/* Load More Button */}
- {hasMore && (
-
- {searchQuery.trim() ? (
- // Search active: offer to load all remaining sessions
-
- ) : (
- // No search: standard load-more (100 at a time)
-
- )}
-
- )}
);
}
diff --git a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardFilters.ts b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardFilters.ts
index 92fd53f8..4dbb2de2 100644
--- a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardFilters.ts
+++ b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardFilters.ts
@@ -13,6 +13,8 @@ interface UseDashboardFiltersParams {
tenantId: string | null | undefined;
globalAdminMode: boolean;
tenantIdFilter: string;
+ hasMore: boolean;
+ loadingMore: boolean;
}
interface DashboardStats {
@@ -57,6 +59,8 @@ export function useDashboardFilters({
tenantId,
globalAdminMode,
tenantIdFilter,
+ hasMore,
+ loadingMore,
}: UseDashboardFiltersParams): UseDashboardFiltersReturn {
const [searchQuery, setSearchQuery] = useState("");
const [statusFilter, setStatusFilter] = useState(null);
@@ -213,7 +217,24 @@ export function useDashboardFilters({
}, [sortedSessions, currentPage, sessionsPerPage]);
const handlePreviousPage = () => setCurrentPage((prev) => Math.max(1, prev - 1));
- const handleNextPage = () => setCurrentPage((prev) => Math.min(totalPages, prev + 1));
+ // Allow advancing past totalPages when the server has more pages; the auto-load
+ // effect in page.tsx will fetch the next batch and totalPages catches up. Without
+ // this overshoot the user could never trigger a load while staying inside a single
+ // Prev/Next control — they would have to click a separate "Load more" button.
+ const handleNextPage = () => setCurrentPage((prev) => {
+ if (prev < totalPages) return prev + 1;
+ if (hasMore && !loadingMore) return prev + 1;
+ return prev;
+ });
+
+ // Snap currentPage back to the last valid page once a load finishes that did NOT
+ // grow totalPages (e.g. an active filter narrowed the new batch to zero matches).
+ // Without this the user would be stuck on an empty paginated slice with no way
+ // to recover except clicking Prev.
+ useEffect(() => {
+ if (loadingMore) return;
+ if (totalPages > 0 && currentPage > totalPages) setCurrentPage(totalPages);
+ }, [currentPage, totalPages, loadingMore]);
return {
searchQuery, setSearchQuery,
diff --git a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx
index 3be9f249..5c3c04c7 100644
--- a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx
+++ b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx
@@ -66,6 +66,8 @@ export default function Home() {
tenantId,
globalAdminMode,
tenantIdFilter,
+ hasMore,
+ loadingMore,
});
// Redirect regular users (non-admin, non-operator) to progress portal – they must never see the session list
@@ -275,7 +277,6 @@ export default function Home() {
onSessionsPerPageChange={handleSessionsPerPageChange}
hasMore={hasMore}
loadingMore={loadingMore}
- onLoadMore={loadMore}
onLoadAll={loadAll}
adminMode={adminMode}
globalAdminMode={globalAdminMode}
diff --git a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx
index ce3be228..7e716bdd 100644
--- a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx
+++ b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx
@@ -14,7 +14,9 @@ import FleetStatCard from "./components/FleetStatCard";
import { Session } from "@/types";
import { useAdminMode } from "@/hooks/useAdminMode";
-const FLEET_PAGE_SIZE = 200;
+// Backend caps pageSize at 1000 — use the maximum so a 90-day window on a busy
+// install (10k+ sessions) drains in a handful of round-trips instead of 50+.
+const FLEET_PAGE_SIZE = 1000;
interface AppMetric {
appName: string;