diff --git a/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx b/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx index 5a3a04da..2eb51e53 100644 --- a/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx +++ b/frontend/src/app/pages/Dashboard/canvas/DashboardCanvas.tsx @@ -373,7 +373,6 @@ const DashboardCanvas: React.FC = ({ {!anyFullscreen && ( ; cards: Record; viewCards: Record; browserCards: Record; @@ -39,7 +39,6 @@ const CARET_H = 13; /** Left-edge desktop dock: one tile per open card, hover previews, click focuses the window. */ function DesktopDock({ - sessions, cards, viewCards, browserCards, @@ -57,9 +56,14 @@ function DesktopDock({ const [edges, setEdges] = useState<{ top: boolean; bottom: boolean }>({ top: false, bottom: false }); const hoverTimer = useRef(null); + // The dock consumes only name + turn_label per session, but the whole-dict identity changes on + // every stream tick to ANY session; a primitive fingerprint keeps this from rebuilding per tick. + const sessionsKey = useAppSelector((s2) => + Object.values(s2.agents.sessions).map((x) => `${x.id}:${x.name ?? ''}:${x.turn_label?.label ?? ''}`).join('|')); const entries = useMemo( - () => buildDockEntries({ sessions, cards, viewCards, browserCards, workflowCards, outputs }), - [sessions, cards, viewCards, browserCards, workflowCards, outputs], + () => buildDockEntries({ sessions: store.getState().agents.sessions, cards, viewCards, browserCards, workflowCards, outputs }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [sessionsKey, cards, viewCards, browserCards, workflowCards, outputs], ); const { dockRef, scrollRef, tile, gap, iconSize, scrolls, scrollHeight, bleed, applyMagnify } = useDockLayout({ @@ -110,7 +114,7 @@ function DesktopDock({ ? `linear-gradient(to bottom, rgba(0,0,0,${edges.top ? 0 : 1}) 0px, #000 ${bleed}px, #000 calc(100% - ${bleed}px), rgba(0,0,0,${edges.bottom ? 0 : 1}) 100%)` : undefined; - const hoveredEntry = hovered ? entries.find((e) => e.id === hovered.id) : undefined; + const hoveredEntry = useMemo(() => (hovered ? entries.find((e) => e.id === hovered.id) : undefined), [entries, hovered]); const previewImage = hoveredEntry ? (liveShot?.id === hoveredEntry.id ? liveShot.dataUrl : hoveredEntry.thumbnail || undefined) : undefined;