diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx index b25b556b..62162b80 100644 --- a/frontend/src/components/ui/dialog.tsx +++ b/frontend/src/components/ui/dialog.tsx @@ -53,7 +53,9 @@ function DialogContent({ ControlledResizeObserver.instances.at(-1)?.trigger()); + // AppShell registers more than one observer (activity split + app-area CSS vars): + // trigger them all so the layout sync isn't skipped. + act(() => ControlledResizeObserver.instances.forEach((o) => o.trigger())); } function deferred() { diff --git a/frontend/src/shell/AppShell.tsx b/frontend/src/shell/AppShell.tsx index 4921ba57..68a83a9e 100644 --- a/frontend/src/shell/AppShell.tsx +++ b/frontend/src/shell/AppShell.tsx @@ -34,6 +34,29 @@ import type { CSSProperties } from "react"; */ export function AppShell() { const { containerRef, panelWidth, desktopSplit, resizing, separatorProps } = useActivityPanelResize(); + // Publish the app area's horizontal geometry as CSS vars on : when the app + // is embedded beside the portal's left sidebar, viewport-fixed dialogs (dialog.tsx) + // must center on the ThothII area, not on the whole browser window. + useEffect(() => { + const el = containerRef.current; + if (!el) return; + const doc = document.documentElement; + const publish = () => { + const r = el.getBoundingClientRect(); + doc.style.setProperty("--app-area-left", `${r.left}px`); + doc.style.setProperty("--app-area-width", `${r.width}px`); + }; + publish(); + const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(publish); + observer?.observe(el); + window.addEventListener("resize", publish); + return () => { + observer?.disconnect(); + window.removeEventListener("resize", publish); + doc.style.removeProperty("--app-area-left"); + doc.style.removeProperty("--app-area-width"); + }; + }, [containerRef]); const activityWidthStyle = { "--activity-panel-width": `${panelWidth}px`, } as CSSProperties; diff --git a/frontend/src/widgets/ArtifactGateWidget.tsx b/frontend/src/widgets/ArtifactGateWidget.tsx index cdc78fd7..110bccf1 100644 --- a/frontend/src/widgets/ArtifactGateWidget.tsx +++ b/frontend/src/widgets/ArtifactGateWidget.tsx @@ -30,7 +30,7 @@ export function ArtifactGateWidget({ descriptor, onRespond, sessionId }: WidgetP {descriptor.title ?? "Artifact review"} diff --git a/tools/replay/server.mjs b/tools/replay/server.mjs index 2a68fb12..b7d44c56 100644 --- a/tools/replay/server.mjs +++ b/tools/replay/server.mjs @@ -397,7 +397,9 @@ const server = createServer(async (req, res) => { } else { console.error("[resume] reset cursore a 0 (nessun client SSE attivo)"); } - return sendNoContent(res); + // The frontend's runResume reads result.alreadyActive (post-f979ada contract): + // a bare 204 makes it throw and toast "Failed to resume session". + return sendJson(res, 200, { id: REPLAY_SESSION_ID, alreadyActive: Boolean(sseClient) }); } if (method === "POST" && /^\/sessions\/[^/]+\/(close|steer|rename|group|archive|unarchive)$/.test(path)) { return sendNoContent(res);