From 4377d35fefc12b24d0dcdbd507ed321016d58891 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Thu, 11 Jun 2026 13:17:22 +0200 Subject: [PATCH] feat(web): show RealmJoin packages in Install Progress with RJ: prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit realmjoin_package_started/completed events now render as first-class install rows in the session-detail Install Progress, alongside Intune (app_install_*) and Office (office_install_*) entries. The "RJ: " name prefix keeps mixed Intune/RealmJoin installs distinguishable and doubles as the map key, avoiding collisions with IME app names. RealmJoin has no separate failed event — completed with success="false" routes to the Failed branch, and lastExitCode maps onto the existing exit-code badge (error-code catalog lookup included). Co-Authored-By: Claude Fable 5 --- .../app/sessions/[sessionId]/page.tsx | 4 ++- .../components/InstallProgress.tsx | 29 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/sessions/[sessionId]/page.tsx b/src/Web/autopilot-monitor-web/app/sessions/[sessionId]/page.tsx index 134aed6f..b806e90a 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/[sessionId]/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sessions/[sessionId]/page.tsx @@ -593,13 +593,15 @@ export default function SessionDetailPage() { {/* Install Progress (from app_install_* events, plus the office_install_* lifecycle — Office C2R is not an IME app but is rendered here as a first-class install with a live timer + - duration via its started/completed/failed events). */} + duration via its started/completed/failed events — and the realmjoin_package_* lifecycle, + rendered with an "RJ: " name prefix to keep mixed Intune/RealmJoin installs apart). */} {!isGatherRulesSession && (
e.eventType === "app_install_started" || e.eventType === "app_install_completed" || e.eventType === "app_install_failed" || e.eventType === "app_install_postponed" || e.eventType === "app_install_skipped" || e.eventType === "office_install_started" || e.eventType === "office_install_completed" || e.eventType === "office_install_failed" + || e.eventType === "realmjoin_package_started" || e.eventType === "realmjoin_package_completed" )} summaryStats={appSummaryStats} /> diff --git a/src/Web/autopilot-monitor-web/components/InstallProgress.tsx b/src/Web/autopilot-monitor-web/components/InstallProgress.tsx index 6ee7fc66..5dcb7c4f 100644 --- a/src/Web/autopilot-monitor-web/components/InstallProgress.tsx +++ b/src/Web/autopilot-monitor-web/components/InstallProgress.tsx @@ -90,20 +90,31 @@ export default function InstallProgress({ events, summaryStats }: InstallProgres const d = evt.data; if (!d) continue; - const appName = d.appName ?? d.app_name ?? d.appId ?? d.app_id ?? "Unknown App"; - if (appName === "Unknown App") continue; + const type = evt.eventType; + + // RealmJoin packages (realmjoin_package_*) carry packageId/displayName instead of + // appId/appName. The "RJ: " prefix keeps them distinguishable from Intune apps in + // mixed-install sessions and doubles as the map key (no collision with IME app names). + const isRealmJoin = type === "realmjoin_package_started" || type === "realmjoin_package_completed"; + const rawName = isRealmJoin + ? (d.displayName ?? d.display_name ?? d.packageId ?? d.package_id) + : (d.appName ?? d.app_name ?? d.appId ?? d.app_id); + if (!rawName) continue; + const appName = isRealmJoin ? `RJ: ${rawName}` : rawName; + const appId = (isRealmJoin ? (d.packageId ?? d.package_id) : (d.appId ?? d.app_id)) ?? appName; - const appId = d.appId ?? d.app_id ?? appName; const existing = installMap.get(appName); const eventTs = evt.timestamp; // The Office C2R lifecycle (office_install_*) is not an IME app but maps onto the same // started → completed/failed install flow, so it renders here as a first-class install row // with the live timer + duration. Office has no postponed/skipped variants. - const type = evt.eventType; - const isStarted = type === "app_install_started" || type === "office_install_started"; - const isCompleted = type === "app_install_completed" || type === "office_install_completed"; - const isFailed = type === "app_install_failed" || type === "office_install_failed"; + // RealmJoin has no separate failed event — realmjoin_package_completed carries + // success ("true"/"false") + lastExitCode, so success=false routes to the failed branch. + const rjFailed = type === "realmjoin_package_completed" && String(d.success).toLowerCase() === "false"; + const isStarted = type === "app_install_started" || type === "office_install_started" || type === "realmjoin_package_started"; + const isCompleted = type === "app_install_completed" || type === "office_install_completed" || (type === "realmjoin_package_completed" && !rjFailed); + const isFailed = type === "app_install_failed" || type === "office_install_failed" || rjFailed; if (isStarted) { // Don't reset an app that already completed — later batch re-scans @@ -153,7 +164,7 @@ export default function InstallProgress({ events, summaryStats }: InstallProgres isLikelyStuck: false, isDetectionFailure: false, isInstallFailure: false, - exitCode: d.exitCode ?? d.exit_code, + exitCode: d.exitCode ?? d.exit_code ?? d.lastExitCode ?? d.last_exit_code, hresultFromWin32: d.hresultFromWin32 ?? d.hresult_from_win32, firstSeenIndex: existing?.firstSeenIndex ?? insertionIndex++, eventData: d, @@ -187,7 +198,7 @@ export default function InstallProgress({ events, summaryStats }: InstallProgres confidence, errorDetail: d.errorDetail ?? d.error_detail, errorPatternId: d.errorPatternId ?? d.error_pattern_id, - exitCode: d.exitCode ?? d.exit_code, + exitCode: d.exitCode ?? d.exit_code ?? d.lastExitCode ?? d.last_exit_code, hresultFromWin32: d.hresultFromWin32 ?? d.hresult_from_win32, // Session 080edee9 follow-up — ESP-level HRESULT carried on promoted // app_install_failed events from the V2 termination handler.