From 7b3230d507c8fdbe4d16565b8ebed215b02682d7 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Sun, 23 Aug 2026 05:19:20 +0200 Subject: [PATCH] fix(web): mobile wrapping for App Details header, Software tables and SLA banner (#133) --- .../app/apps/components/InstallsTab.tsx | 98 ++-- .../app/apps/components/InventoryTab.tsx | 60 +-- .../app/apps/detail/page.tsx | 432 +++++++++--------- .../autopilot-monitor-web/app/sla/page.tsx | 18 +- 4 files changed, 309 insertions(+), 299 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/apps/components/InstallsTab.tsx b/src/Web/autopilot-monitor-web/app/apps/components/InstallsTab.tsx index 81492e94..741d79a2 100644 --- a/src/Web/autopilot-monitor-web/app/apps/components/InstallsTab.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/components/InstallsTab.tsx @@ -275,55 +275,57 @@ export default function InstallsTab({ scope, timeRange }: InstallsTabProps) { ) : ( <> - - - - - - - - - - - - - - {pageRows.map((row) => ( - openApp(row.appName)} className="hover:bg-gray-50 cursor-pointer text-sm"> - - - - - - - +
+
toggleSort("appName")}>App {sortIndicator("appName")} toggleSort("totalInstalls")}>Installs {sortIndicator("totalInstalls")} toggleSort("succeeded")}>Succeeded {sortIndicator("succeeded")} toggleSort("failed")}>Failed {sortIndicator("failed")} toggleSort("failureRate")}>Failure Rate {sortIndicator("failureRate")} toggleSort("avgDurationSeconds")} - title="Average duration of the final install attempt. IME evaluation passes and time queued behind other apps are not counted." - > - Avg Install Time {sortIndicator("avgDurationSeconds")} - toggleSort("trend")}>Trend {sortIndicator("trend")}
- {row.appName} - {appTypeBadge(row.appType)} - {row.totalInstalls} - {row.succeeded} - {row.skipped > 0 && ( - - +{row.skipped}s - - )} - {row.failed} - = 20 ? "text-red-700 font-semibold" : row.failureRate >= 5 ? "text-amber-700" : "text-gray-700"}> - {row.failureRate.toFixed(1)}% - - {formatDuration(row.avgDurationSeconds, "—")}{trendBadge(row)}
+ + + + + + + + + - ))} - -
toggleSort("appName")}>App {sortIndicator("appName")} toggleSort("totalInstalls")}>Installs {sortIndicator("totalInstalls")} toggleSort("succeeded")}>Succeeded {sortIndicator("succeeded")} toggleSort("failed")}>Failed {sortIndicator("failed")} toggleSort("failureRate")}>Failure Rate {sortIndicator("failureRate")} toggleSort("avgDurationSeconds")} + title="Average duration of the final install attempt. IME evaluation passes and time queued behind other apps are not counted." + > + Avg Install Time {sortIndicator("avgDurationSeconds")} + toggleSort("trend")}>Trend {sortIndicator("trend")}
+ + + {pageRows.map((row) => ( + openApp(row.appName)} className="hover:bg-gray-50 cursor-pointer text-sm"> + + {row.appName} + {appTypeBadge(row.appType)} + + {row.totalInstalls} + + {row.succeeded} + {row.skipped > 0 && ( + + +{row.skipped}s + + )} + + {row.failed} + + = 20 ? "text-red-700 font-semibold" : row.failureRate >= 5 ? "text-amber-700" : "text-gray-700"}> + {row.failureRate.toFixed(1)}% + + + {formatDuration(row.avgDurationSeconds, "—")} + {trendBadge(row)} + + ))} + + + {pageCount > 1 && (
{filteredAndSorted.length} apps · page {page + 1} of {pageCount} diff --git a/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx b/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx index 1ca9d538..8e50c6a6 100644 --- a/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx @@ -151,36 +151,38 @@ export default function InventoryTab({ scope }: { scope: SoftwareTabScope }) {
) : ( <> - - - - - - - - - - - - - {pageRows.map((row, idx) => ( - - - - - - - +
+
SoftwareVersionPublisherSessionsLast seenCPE
{row.displayName || row.normalizedName}{row.normalizedVersion || "—"}{row.publisher || "—"}{row.sessionCount}{formatDate(row.lastSeenAt)} - {row.cpeUri ? ( - mapped - ) : ( - unmatched - )} -
+ + + + + + + + - ))} - -
SoftwareVersionPublisherSessionsLast seenCPE
+ + + {pageRows.map((row, idx) => ( + + {row.displayName || row.normalizedName} + {row.normalizedVersion || "—"} + {row.publisher || "—"} + {row.sessionCount} + {formatDate(row.lastSeenAt)} + + {row.cpeUri ? ( + mapped + ) : ( + unmatched + )} + + + ))} + + + {pageCount > 1 && (
{filtered.length} titles · page {page + 1} of {pageCount} diff --git a/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx b/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx index 217973e2..245cfb3f 100644 --- a/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx @@ -459,12 +459,12 @@ function AppDetailContent() { > ← Back to all apps -
-
-

- {appName} +
+
+

+ {appName} {analytics?.appType && ( - + {analytics.appType} )} @@ -475,7 +475,7 @@ function AppDetailContent() { : ""}

-
+
{([7, 30, 90] as const).map((d) => (
) : ( )} @@ -750,44 +752,46 @@ function AppDetailContent() { {/* Device model breakdown */} {analytics.deviceModelBreakdown.length > 0 ? ( - - - - - - - - - - - - - {analytics.deviceModelBreakdown.map((row, i) => ( - - - - - - - +
+
ManufacturerModelInstallsFailedFailure RateLift vs baseline
{row.manufacturer}{row.model}{row.installs}{row.failed} - {row.failureRate.toFixed(1)}% - - = 2 - ? "bg-red-100 text-red-800" - : row.liftVsBaseline >= 1.2 - ? "bg-amber-100 text-amber-800" - : "bg-emerald-100 text-emerald-800" - }`} - > - {row.liftVsBaseline.toFixed(2)}× - -
+ + + + + + + + - ))} - -
ManufacturerModelInstallsFailedFailure RateLift vs baseline
+ + + {analytics.deviceModelBreakdown.map((row, i) => ( + + {row.manufacturer} + {row.model} + {row.installs} + {row.failed} + + {row.failureRate.toFixed(1)}% + + + = 2 + ? "bg-red-100 text-red-800" + : row.liftVsBaseline >= 1.2 + ? "bg-amber-100 text-amber-800" + : "bg-emerald-100 text-emerald-800" + }`} + > + {row.liftVsBaseline.toFixed(2)}× + + + + ))} + + +
) : ( )} @@ -795,7 +799,7 @@ function AppDetailContent() { {/* Affected sessions panel */} -
+
{(["failed", "all", "succeeded"] as const).map((s) => (
) : sessions && sessions.items.length > 0 ? ( <> - - - - {activeSessionColumns.map((col) => ( - - ))} - - - - {sessions.items.map((row) => { - const entry = row.failureCode ? getErrorCodeEntry(row.failureCode) : null; - return ( - router.push(sessionUrl(row.sessionId))} - className="hover:bg-gray-50 cursor-pointer" - > - {activeSessionColumns.map((col) => { - switch (col.key) { - case "device": - return ( - - ); - case "tenant": { - const friendly = tenantLookup.get(row.tenantId); - return ( - - ); - } - case "model": - return ( - - ); - case "version": - return ( - - ); - case "status": - return ( - + ); + case "attempts": + return ( + + ); + case "failureCode": + return ( + + ); + case "duration": + return ( + + ); + default: + return null; + } + })} + + ); + })} + +
- {col.label} -
- {row.deviceName || "—"} - - {friendly || `${row.tenantId.substring(0, 8)}…`} - - {row.manufacturer} {row.model} - - {row.appVersion || "—"} - - + + + + {activeSessionColumns.map((col) => ( + + ))} + + + + {sessions.items.map((row) => { + const entry = row.failureCode ? getErrorCodeEntry(row.failureCode) : null; + return ( + router.push(sessionUrl(row.sessionId))} + className="hover:bg-gray-50 cursor-pointer" + > + {activeSessionColumns.map((col) => { + switch (col.key) { + case "device": + return ( + + ); + case "tenant": { + const friendly = tenantLookup.get(row.tenantId); + return ( + - ); - case "attempts": - return ( - - ); - case "failureCode": - return ( - - ); - case "duration": - return ( - + ); + } + case "model": + return ( + + ); + case "version": + return ( + + ); + case "status": + return ( + - ); - default: - return null; - } - })} - - ); - })} - -
+ {col.label} +
+ {row.deviceName || "—"} + - {row.status} - - - {row.attemptNumber || "—"} - - {row.failureCode ? ( - - {formatErrorCode(row.failureCode)} - - ) : ( - — - )} - - {formatDuration(row.durationSeconds)} - {(row.installPassCount ?? 0) > 1 && ( + {friendly || `${row.tenantId.substring(0, 8)}…`} + + {row.manufacturer} {row.model} + + {row.appVersion || "—"} + - ×{row.installPassCount} + {row.status} - )} -
+
+ {row.attemptNumber || "—"} + + {row.failureCode ? ( + + {formatErrorCode(row.failureCode)} + + ) : ( + — + )} + + {formatDuration(row.durationSeconds)} + {(row.installPassCount ?? 0) > 1 && ( + + ×{row.installPassCount} + + )} +
+
{/* Pagination */} {sessions.total > SESSIONS_PAGE_SIZE && (
diff --git a/src/Web/autopilot-monitor-web/app/sla/page.tsx b/src/Web/autopilot-monitor-web/app/sla/page.tsx index 86651aa8..8708a003 100644 --- a/src/Web/autopilot-monitor-web/app/sla/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sla/page.tsx @@ -494,18 +494,18 @@ function OverallStatusBanner({ metrics }: { metrics: SlaMetricsResponse }) { const metCount = checks.filter(c => c.met).length; return ( -
-
+
{allMet ? ( - + ) : ( - + )} @@ -518,19 +518,19 @@ function OverallStatusBanner({ metrics }: { metrics: SlaMetricsResponse }) {
-
+
{checks.map((c) => ( -
+
{c.met ? ( - + ) : ( - + )} - + {c.label}