From 7742113b293f32046158bdaa436b86681f4b3aef Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Mon, 29 Jun 2026 10:43:09 +0200 Subject: [PATCH] fix(delegated): pass ?tenantId= on dashboard session links so delegated detail drill-in resolves Phase 7 deleted the /fleet/[tenantId] session browser (which appended ?tenantId= via sessionLinkTarget) and re-routed delegated viewing through the dashboard SessionTable, but the dashboard never passed sessionLinkTarget. Row-click/search-nav went to a bare /sessions/{id}; the detail page resolves the target tenant for a delegated admin SOLELY from ?tenantId= (no global scope -> bare id falls back to the JWT home tenant -> wrong partition -> empty events + "No issues detected"). - SessionTable.sessionLinkTarget signature (sessionId) -> (session): the target tenant is per-row (session.tenantId), not derivable from the id. - dashboard passes sessionLinkTarget when crossTenant -> /sessions/{id}?tenantId=. Harmless for real GA. tsc clean; web 485 tests green. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../app/dashboard/components/SessionTable.tsx | 17 +++++++++-------- .../app/dashboard/page.tsx | 8 ++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/dashboard/components/SessionTable.tsx b/src/Web/autopilot-monitor-web/app/dashboard/components/SessionTable.tsx index e33e3c49..27422e9c 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/components/SessionTable.tsx +++ b/src/Web/autopilot-monitor-web/app/dashboard/components/SessionTable.tsx @@ -96,9 +96,10 @@ interface SessionTableProps { onBlockDevice: (serialNumber: string, tenantId: string, deviceName?: string) => void; fullWidth: boolean; onToggleFullWidth: () => void; - /** Builds the row's navigation target. Defaults to `/sessions/{id}`; the Fleet drill-in overrides it to - * append `?tenantId=` so a delegated viewer opens the session in the managed tenant's (read-only) context. */ - sessionLinkTarget?: (sessionId: string) => string; + /** Builds the row's navigation target. Defaults to `/sessions/{id}`; a cross-tenant viewer overrides it to + * append `?tenantId=` so a delegated viewer opens the session in the managed tenant's (read-only) context. + * Receives the whole session because the target tenant is per-row (session.tenantId), not derivable from id. */ + sessionLinkTarget?: (session: Session) => string; } export function SessionTable({ @@ -142,8 +143,8 @@ export function SessionTable({ sessionLinkTarget, }: SessionTableProps) { const router = useRouter(); - const linkFor = (sessionId: string) => - sessionLinkTarget ? sessionLinkTarget(sessionId) : `/sessions/${sessionId}`; + const linkFor = (session: Session) => + sessionLinkTarget ? sessionLinkTarget(session) : `/sessions/${session.sessionId}`; const [visibleColumns, setVisibleColumns] = useState>(getInitialVisibleColumns); const [showColumnSelector, setShowColumnSelector] = useState(false); const [openFilterColumn, setOpenFilterColumn] = useState(null); @@ -551,7 +552,7 @@ export function SessionTable({ const selected = searchSuggestions[searchSelectedIndex]; setShowSearchSuggestions(false); setSearchSelectedIndex(-1); - router.push(linkFor(selected.session.sessionId)); + router.push(linkFor(selected.session)); return; } if (e.key === "Escape") { @@ -593,7 +594,7 @@ export function SessionTable({ onClick={() => { setShowSearchSuggestions(false); setSearchSelectedIndex(-1); - router.push(linkFor(s.session.sessionId)); + router.push(linkFor(s.session)); }} className={`w-full text-left px-4 py-2.5 flex items-center gap-3 transition-colors ${ idx === searchSelectedIndex ? "bg-blue-50" : "hover:bg-gray-50" @@ -786,7 +787,7 @@ export function SessionTable({ paginatedSessions.map((session) => ( { trackEvent("session_opened", { sessionId: session.sessionId, status: session.status ?? "" }); router.push(linkFor(session.sessionId)); }} + onClick={() => { trackEvent("session_opened", { sessionId: session.sessionId, status: session.status ?? "" }); router.push(linkFor(session)); }} className="hover:bg-gray-50 cursor-pointer transition-colors" > {activeColumns.map((col) => ( diff --git a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx index 94a313e4..ad101df2 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/page.tsx +++ b/src/Web/autopilot-monitor-web/app/dashboard/page.tsx @@ -465,6 +465,14 @@ function HomeContent() { onBlockDevice={blockDevice} fullWidth={fullWidth} onToggleFullWidth={toggleFullWidth} + sessionLinkTarget={ + crossTenant + ? (s) => + s.tenantId + ? `/sessions/${s.sessionId}?tenantId=${encodeURIComponent(s.tenantId)}` + : `/sessions/${s.sessionId}` + : undefined + } /> )}