diff --git a/internal b/internal index ee5b6604..66ebb051 160000 --- a/internal +++ b/internal @@ -1 +1 @@ -Subproject commit ee5b6604af686ef6cc1a18cbe591f9ff3a319a24 +Subproject commit 66ebb0511e50832fd7f0735fd60a3ab77061850b diff --git a/src/Web/autopilot-monitor-web/app/sessions/page.tsx b/src/Web/autopilot-monitor-web/app/sessions/page.tsx index 95f45938..6dbf500e 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sessions/page.tsx @@ -13,6 +13,7 @@ import PerformanceChart from '../../components/PerformanceChart'; import DownloadProgress from '../../components/DownloadProgress'; import InstallProgress from '../../components/InstallProgress'; import ScriptExecutions from '../../components/ScriptExecutions'; +import { findUserPhaseStartMs } from '@/lib/userPhaseBoundary'; import { useLatestVersions } from '@/lib/useLatestVersions'; import { useScriptDisplayNames } from '@/lib/scriptDisplayNames'; import { api } from "@/lib/api"; @@ -215,6 +216,8 @@ function SessionDetailContent() { // without a terminal event stop being "still running" — it becomes incomplete, its timer // bounded by the agent's last report. Live sessions pass null and keep ticking. const observedUntilMs = isTerminalStatus(displayStatus) ? lastObservedAtMs : null; + // One boundary for the Download / Install / Script panels, so all three split at the same moment. + const userPhaseStartMs = findUserPhaseStartMs(events); // All phase keys currently present. For WhiteGlove sessions we use prefixed keys // (pre-X, user-X) to avoid collisions. @@ -675,6 +678,7 @@ function SessionDetailContent() { latestBootstrapVersion={latestBootstrapVersion} displayNamesByRefKey={scriptDisplayNamesByRefKey} observedUntilMs={observedUntilMs} + userPhaseStartMs={userPhaseStartMs} /> )} @@ -688,6 +692,7 @@ function SessionDetailContent() { )} summaryStats={appSummaryStats} observedUntilMs={observedUntilMs} + userPhaseStartMs={userPhaseStartMs} /> )} @@ -707,6 +712,7 @@ function SessionDetailContent() { )} summaryStats={appSummaryStats} observedUntilMs={observedUntilMs} + userPhaseStartMs={userPhaseStartMs} /> )} diff --git a/src/Web/autopilot-monitor-web/components/DownloadProgress.tsx b/src/Web/autopilot-monitor-web/components/DownloadProgress.tsx index ba1c9678..c6ef73ed 100644 --- a/src/Web/autopilot-monitor-web/components/DownloadProgress.tsx +++ b/src/Web/autopilot-monitor-web/components/DownloadProgress.tsx @@ -1,9 +1,11 @@ "use client"; -import { useMemo, useState } from "react"; +import { Fragment, useMemo, useState } from "react"; import { partitionHistoricReplayEvents, type ReplayInputEvent } from "@/lib/historicReplay"; import TruncatedLabel from "@/components/TruncatedLabel"; import PendingAppRow from "@/components/PendingAppRow"; +import PhaseDivider from "@/components/PhaseDivider"; +import { userPhaseSplitIndex } from "@/lib/userPhaseBoundary"; import { shouldSkipLowBytesTotal, shouldSkipNoActivity, hasByteActivity } from "@/lib/downloadProgressFilters"; import { formatBytes, formatThroughput, formatDuration } from "@/lib/formatting"; import DoBreakdownBar from "./DoBreakdownBar"; @@ -64,6 +66,8 @@ interface DownloadProgressProps { // Epoch ms of the agent's last report, passed only once the session is terminal. A download // that never finished by then is incomplete, not active. observedUntilMs?: number | null; + // Epoch ms the device entered Account Setup; null when the session has no user phase. + userPhaseStartMs?: number | null; } interface DoStats { @@ -147,7 +151,7 @@ function effectiveDurationMs(dl: DownloadItem): number { return 0; } -export default function DownloadProgress({ events, summaryStats, observedUntilMs = null }: DownloadProgressProps) { +export default function DownloadProgress({ events, summaryStats, observedUntilMs = null, userPhaseStartMs = null }: DownloadProgressProps) { // Legacy-agent guard: drop download events replayed from a previous enrollment's IME log. // Silent (empty finals set) — the InstallProgress panel already reports the hidden count // for the same apps; a second note here would double-report them. @@ -352,6 +356,8 @@ export default function DownloadProgress({ events, summaryStats, observedUntilMs ? summaryStats.installed + summaryStats.installing + summaryStats.failed : null; + const userSplit = userPhaseSplitIndex(filteredDownloads, d => d.startedMs, userPhaseStartMs); + return (