diff --git a/packages/web/src/app/sessions/[id]/page.tsx b/packages/web/src/app/sessions/[id]/page.tsx index fb32d5a67..cbd7efb63 100644 --- a/packages/web/src/app/sessions/[id]/page.tsx +++ b/packages/web/src/app/sessions/[id]/page.tsx @@ -5,9 +5,17 @@ import { useParams, usePathname, useRouter } from "next/navigation"; import { ACTIVITY_STATE, SESSION_STATUS, isOrchestratorSession } from "@aoagents/ao-core/types"; import { SessionDetail } from "@/components/SessionDetail"; import { ErrorDisplay } from "@/components/ErrorDisplay"; -import { ProjectSidebar } from "@/components/ProjectSidebar"; +import { + ProjectSidebar, + type ProjectSidebarOrchestrator, +} from "@/components/ProjectSidebar"; import { useMediaQuery, MOBILE_BREAKPOINT } from "@/hooks/useMediaQuery"; -import { type DashboardSession, type ActivityState, getAttentionLevel } from "@/lib/types"; +import { + type DashboardSession, + type DashboardOrchestratorLink, + type ActivityState, + getAttentionLevel, +} from "@/lib/types"; import { activityIcon } from "@/lib/activity-icons"; import type { ProjectInfo } from "@/lib/project-name"; import { getSessionTitle } from "@/lib/format"; @@ -170,6 +178,7 @@ function SessionPageShell({ projects, projectsLoading, sidebarSessions, + sidebarOrchestrators, sidebarLoading, sidebarError, onRetrySidebar, @@ -180,6 +189,7 @@ function SessionPageShell({ projects: ProjectInfo[]; projectsLoading: boolean; sidebarSessions: DashboardSession[] | null; + sidebarOrchestrators?: ProjectSidebarOrchestrator[]; sidebarLoading: boolean; sidebarError: boolean; onRetrySidebar: () => void; @@ -251,6 +261,7 @@ function SessionPageShell({ ( () => cachedSidebarSessions, ); + const [sidebarOrchestrators, setSidebarOrchestrators] = useState< + ProjectSidebarOrchestrator[] | undefined + >(undefined); const [loading, setLoading] = useState(cachedSession === null); const [routeError, setRouteError] = useState(null); const [sessionMissing, setSessionMissing] = useState(false); @@ -596,18 +610,19 @@ export default function SessionPage() { const controller = new AbortController(); sidebarFetchControllerRef.current = controller; try { - const body = await fetchJsonWithTimeout<{ sessions?: DashboardSession[] } | null>( - "/api/sessions?fresh=true", - { - signal: controller.signal, - timeoutMs: PROJECT_SIDEBAR_FETCH_TIMEOUT_MS, - timeoutMessage: `Sidebar sessions request timed out after ${PROJECT_SIDEBAR_FETCH_TIMEOUT_MS}ms`, - }, - ); + const body = await fetchJsonWithTimeout<{ + sessions?: DashboardSession[]; + orchestrators?: DashboardOrchestratorLink[]; + } | null>("/api/sessions?fresh=true", { + signal: controller.signal, + timeoutMs: PROJECT_SIDEBAR_FETCH_TIMEOUT_MS, + timeoutMessage: `Sidebar sessions request timed out after ${PROJECT_SIDEBAR_FETCH_TIMEOUT_MS}ms`, + }); const restSessions = body?.sessions ?? []; const nextSessions = applyMuxSessionPatches(restSessions, pendingMuxSessionsRef.current ?? []) ?? restSessions; cachedSidebarSessions = nextSessions; + setSidebarOrchestrators(body?.orchestrators); setSidebarError(false); setSidebarSessions((current) => areSidebarSessionsEqual(current, nextSessions) ? current : nextSessions, @@ -724,6 +739,7 @@ export default function SessionPage() { projects={projects} projectsLoading={projectsLoading} sidebarSessions={sidebarSessions} + sidebarOrchestrators={sidebarOrchestrators} sidebarLoading={sidebarSessions === null} sidebarError={sidebarError} onRetrySidebar={fetchSidebarSessions} @@ -754,6 +770,7 @@ export default function SessionPage() { projects={projects} projectsLoading={projectsLoading} sidebarSessions={sidebarSessions} + sidebarOrchestrators={sidebarOrchestrators} sidebarLoading={sidebarSessions === null} sidebarError={sidebarError} onRetrySidebar={fetchSidebarSessions} @@ -782,6 +799,7 @@ export default function SessionPage() { projects={projects} projectsLoading={projectsLoading} sidebarSessions={sidebarSessions} + sidebarOrchestrators={sidebarOrchestrators} sidebarLoading={sidebarSessions === null} sidebarError={sidebarError} onRetrySidebar={fetchSidebarSessions} @@ -819,6 +837,7 @@ export default function SessionPage() { projects={projects} projectsLoading={projectsLoading} sidebarSessions={sidebarSessions} + sidebarOrchestrators={sidebarOrchestrators} sidebarLoading={sidebarSessions === null} sidebarError={sidebarError} onRetrySidebar={fetchSidebarSessions} @@ -849,6 +868,7 @@ export default function SessionPage() { projectOrchestratorId={projectOrchestratorId} projects={projects} sidebarSessions={sidebarSessions} + sidebarOrchestrators={sidebarOrchestrators} sidebarLoading={sidebarSessions === null} sidebarError={sidebarError} onRetrySidebar={fetchSidebarSessions} diff --git a/packages/web/src/components/Dashboard.tsx b/packages/web/src/components/Dashboard.tsx index a98c75b31..b66f7dc00 100644 --- a/packages/web/src/components/Dashboard.tsx +++ b/packages/web/src/components/Dashboard.tsx @@ -605,6 +605,7 @@ function DashboardInner({ new Map((orchestrators ?? []).map((o) => [o.projectId, o])), + [orchestrators], + ); + const sessionsByProject = useMemo(() => { const map = new Map(); // Build a set of valid project IDs to filter sessions strictly @@ -390,21 +411,7 @@ function ProjectSidebarInner({ const visibleSessions = workerSessions; const hasActiveSessions = visibleSessions.length > 0; - const projectPrefix = prefixByProject.get(project.id); - const canonicalOrchestratorId = projectPrefix - ? getOrchestratorSessionId({ sessionPrefix: projectPrefix }) - : null; - const orchestratorSession = sessions?.find( - (s) => s.projectId === project.id && s.id === canonicalOrchestratorId, - ); - const liveOrchestrator = - orchestratorSession && - !isTerminalSession({ - status: orchestratorSession.status, - activity: orchestratorSession.activity, - }) - ? orchestratorSession - : null; + const orchestratorLink = orchestratorByProject.get(project.id) ?? null; return (
@@ -506,9 +513,9 @@ function ProjectSidebarInner({ ) : null} {/* Orchestrator button */} - {!isDegraded && orchestratorSession && ( + {!isDegraded && orchestratorLink && ( { e.stopPropagation(); onMobileClose?.(); @@ -571,17 +578,14 @@ function ProjectSidebarInner({ role="menu" aria-label={`${project.name} actions`} > - {liveOrchestrator ? ( + {orchestratorLink ? (