diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetAllSessionsFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetAllSessionsFunction.cs index 74009e42..3db7d3fa 100644 --- a/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetAllSessionsFunction.cs +++ b/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetAllSessionsFunction.cs @@ -39,6 +39,11 @@ namespace AutopilotMonitor.Functions.Functions.Sessions if (!string.IsNullOrEmpty(daysParam) && int.TryParse(daysParam, out var parsedDays) && parsedDays > 0) days = parsedDays; + var limitParam = query["limit"]; + int limit = 100; + if (!string.IsNullOrEmpty(limitParam) && int.TryParse(limitParam, out var parsedLimit)) + limit = Math.Clamp(parsedLimit, 1, 100); + SessionPage page; if (!string.IsNullOrEmpty(tenantIdFilter)) @@ -50,13 +55,13 @@ namespace AutopilotMonitor.Functions.Functions.Sessions return badRequest; } - _logger.LogInformation("Fetching sessions for tenant {TenantId} (User: {UserEmail}, cursor: {Cursor}, days: {Days})", tenantIdFilter, userEmail, cursor ?? "none", days?.ToString() ?? "all"); - page = await _sessionRepo.GetSessionsAsync(tenantIdFilter, maxResults: 100, cursor: cursor, days: days); + _logger.LogInformation("Fetching sessions for tenant {TenantId} (User: {UserEmail}, cursor: {Cursor}, days: {Days}, limit: {Limit})", tenantIdFilter, userEmail, cursor ?? "none", days?.ToString() ?? "all", limit); + page = await _sessionRepo.GetSessionsAsync(tenantIdFilter, maxResults: limit, cursor: cursor, days: days); } else { - _logger.LogInformation("Fetching all sessions across all tenants (User: {UserEmail}, cursor: {Cursor}, days: {Days})", userEmail, cursor ?? "none", days?.ToString() ?? "all"); - page = await _sessionRepo.GetAllSessionsAsync(maxResults: 100, cursor: cursor, days: days); + _logger.LogInformation("Fetching all sessions across all tenants (User: {UserEmail}, cursor: {Cursor}, days: {Days}, limit: {Limit})", userEmail, cursor ?? "none", days?.ToString() ?? "all", limit); + page = await _sessionRepo.GetAllSessionsAsync(maxResults: limit, cursor: cursor, days: days); } return await req.OkAsync(new diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetSessionsFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetSessionsFunction.cs index 1a08ed4a..37d4977c 100644 --- a/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetSessionsFunction.cs +++ b/src/Backend/AutopilotMonitor.Functions/Functions/Sessions/GetSessionsFunction.cs @@ -35,9 +35,14 @@ namespace AutopilotMonitor.Functions.Functions.Sessions if (!string.IsNullOrEmpty(daysParam) && int.TryParse(daysParam, out var parsedDays) && parsedDays > 0) days = parsedDays; - _logger.LogInformation("Fetching sessions for tenant {TenantId} (cursor: {Cursor}, days: {Days})", tenantId, cursor ?? "none", days?.ToString() ?? "all"); + var limitParam = query["limit"]; + int limit = 100; + if (!string.IsNullOrEmpty(limitParam) && int.TryParse(limitParam, out var parsedLimit)) + limit = Math.Clamp(parsedLimit, 1, 100); - var page = await _sessionRepo.GetSessionsAsync(tenantId, maxResults: 100, cursor: cursor, days: days); + _logger.LogInformation("Fetching sessions for tenant {TenantId} (cursor: {Cursor}, days: {Days}, limit: {Limit})", tenantId, cursor ?? "none", days?.ToString() ?? "all", limit); + + var page = await _sessionRepo.GetSessionsAsync(tenantId, maxResults: limit, cursor: cursor, days: days); return await req.OkAsync(new { diff --git a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardSessions.ts b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardSessions.ts index 607775f4..4a842fc0 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardSessions.ts +++ b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardSessions.ts @@ -146,13 +146,22 @@ export function useDashboardSessions({ } }, [getAccessToken, addNotification, setBlockedDevicesSet]); + const getInitialLimit = (): number | undefined => { + if (typeof window === "undefined") return undefined; + const stored = window.localStorage.getItem("sessionsPerPage"); + const parsed = stored ? parseInt(stored, 10) : NaN; + const value = Number.isFinite(parsed) && parsed > 0 ? parsed : 10; + return Math.min(value, 100); + }; + const fetchSessions = useCallback(async (loadMoreCursor?: string, globalTenantIdOverride?: string) => { try { const rawFilter = globalTenantIdOverride !== undefined ? globalTenantIdOverride : tenantIdFilterRef.current.trim(); const effectiveTenantFilter = asGuidOrUndefined(rawFilter); + const initialLimit = loadMoreCursor ? undefined : getInitialLimit(); let endpoint = globalAdminModeRef.current - ? api.globalSessions.list(effectiveTenantFilter) - : api.sessions.list(tenantIdRef.current ?? undefined); + ? api.globalSessions.list(effectiveTenantFilter, undefined, initialLimit) + : api.sessions.list(tenantIdRef.current ?? undefined, undefined, initialLimit); if (loadMoreCursor) { endpoint += endpoint.includes("?") ? "&" : "?"; diff --git a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx index 69e98cf6..ff623d5b 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx +++ b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx @@ -91,6 +91,17 @@ export default function Home() { if (!globalAdminMode) setTenantIdFilter(""); }, [globalAdminMode]); + // Auto-load more when the user needs more sessions than currently loaded + // (e.g. increased sessionsPerPage, paginated forward, or applied a sort/column filter + // that would benefit from the full dataset). Cheap server roundtrip, paid only on demand. + useEffect(() => { + if (loading || loadingMore || !hasMore) return; + const needed = currentPage * sessionsPerPage; + if (sessions.length < needed) { + loadMore(); + } + }, [sessions.length, currentPage, sessionsPerPage, hasMore, loading, loadingMore, loadMore]); + const applyTenantIdFilter = (value: string) => { setTenantIdFilter(value); }; diff --git a/src/Web/autopilot-monitor-web/lib/api.ts b/src/Web/autopilot-monitor-web/lib/api.ts index 12f0cd2c..145a55f8 100644 --- a/src/Web/autopilot-monitor-web/lib/api.ts +++ b/src/Web/autopilot-monitor-web/lib/api.ts @@ -21,8 +21,8 @@ export const api = { // ── Sessions ────────────────────────────────────────────────────────────── sessions: { - list: (tenantId?: string, days?: number) => - `${API_BASE_URL}/api/sessions${qs({ tenantId, days: days?.toString() })}`, + list: (tenantId?: string, days?: number, limit?: number) => + `${API_BASE_URL}/api/sessions${qs({ tenantId, days: days?.toString(), limit: limit?.toString() })}`, get: (sessionId: string, tenantId?: string) => `${API_BASE_URL}/api/sessions/${sessionId}${qs({ tenantId })}`, events: (sessionId: string, tenantId?: string) => @@ -45,8 +45,8 @@ export const api = { // ── Global Sessions (global admin) ──────────────────────────────────────── globalSessions: { - list: (tenantId?: string, days?: number) => - `${API_BASE_URL}/api/global/sessions${qs({ tenantId, days: days?.toString() })}`, + list: (tenantId?: string, days?: number, limit?: number) => + `${API_BASE_URL}/api/global/sessions${qs({ tenantId, days: days?.toString(), limit: limit?.toString() })}`, }, // ── Config ────────────────────────────────────────────────────────────────