mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 12:12:47 +00:00
fix(app): keep agents running when image viewer closes (#4161)
The shared image lightbox handled Escape after the global shortcut dispatcher had already routed the same key to agent interruption. Register the viewer with the established web overlay owner so dismissal takes first refusal while ordinary Escape interruption remains intact.
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
switchAwayAndBackWithoutImageInstability,
|
||||
userPagesUntilAssistantImageRenders,
|
||||
} from "../support/helpers/assistant-images";
|
||||
import { expectAgentReadyToInterrupt } from "../support/helpers/agent-stream";
|
||||
import { seedWorkspace, type SeededWorkspace } from "../support/helpers/seed-client";
|
||||
|
||||
const test = base.extend<{ imageWorkspace: SeededWorkspace }>({
|
||||
@@ -84,8 +85,15 @@ test("opens a timeline image in a zoomable lightbox", async ({
|
||||
.poll(async () => Math.round((await transformedContent.boundingBox())?.width ?? 0))
|
||||
.toBe(Math.round(initialBox!.width));
|
||||
|
||||
await canvas.click({ position: { x: 4, y: 4 } });
|
||||
await workspace.client.sendAgentMessage(
|
||||
imageAgent.id,
|
||||
"Stay running while the assistant image lightbox is closed.",
|
||||
);
|
||||
await expectAgentReadyToInterrupt(page);
|
||||
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(lightboxImage).toHaveCount(0);
|
||||
await expectAgentReadyToInterrupt(page);
|
||||
});
|
||||
|
||||
test("reloading a timeline anchors near-tail assistant image growth", async ({
|
||||
|
||||
@@ -136,6 +136,8 @@ let container: HTMLElement | null = null;
|
||||
|
||||
beforeEach(() => {
|
||||
const dom = new JSDOM("<!doctype html><html><body></body></html>");
|
||||
dom.window.requestAnimationFrame = vi.fn(() => 1);
|
||||
dom.window.cancelAnimationFrame = vi.fn();
|
||||
vi.stubGlobal("React", React);
|
||||
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
||||
vi.stubGlobal("window", dom.window);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { SPACING } from "@/styles/theme";
|
||||
import { WindowChromeRootRegion } from "@/utils/desktop-window";
|
||||
import { ZoomableImage } from "@/components/zoomable-viewport/image";
|
||||
import type { ViewportSize } from "@/components/zoomable-viewport/geometry";
|
||||
import { useGlobalWebOverlayLayer, useWebOverlayRegistration } from "@/lib/overlay-root";
|
||||
|
||||
export type ImageLightboxSource =
|
||||
| { type: "attachment"; metadata: AttachmentMetadata }
|
||||
@@ -33,23 +34,27 @@ export function AttachmentLightbox({ source, onClose }: AttachmentLightboxProps)
|
||||
const url = source?.type === "uri" ? source.uri : attachmentUrl;
|
||||
const contentSize = source?.type === "uri" ? source.contentSize : undefined;
|
||||
const [errored, setErrored] = useState(false);
|
||||
const modalLayer = useGlobalWebOverlayLayer("modal", isWeb && source !== null);
|
||||
|
||||
useEffect(() => {
|
||||
setErrored(false);
|
||||
}, [metadata?.id, url]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isWeb || !source) return;
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Escape") {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
window.addEventListener("keydown", handleKeydown);
|
||||
return () => {
|
||||
window.removeEventListener("keydown", handleKeydown);
|
||||
};
|
||||
}, [onClose, source]);
|
||||
const handleWebOverlayKeyDown = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.key !== "Escape") return false;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onClose();
|
||||
return true;
|
||||
},
|
||||
[onClose],
|
||||
);
|
||||
const setWebOverlayScope = useWebOverlayRegistration({
|
||||
active: isWeb && source !== null,
|
||||
layer: modalLayer,
|
||||
onKeyDown: handleWebOverlayKeyDown,
|
||||
});
|
||||
|
||||
const contentLayerStyle = useMemo(
|
||||
() => [
|
||||
@@ -87,7 +92,7 @@ export function AttachmentLightbox({ source, onClose }: AttachmentLightboxProps)
|
||||
<Modal transparent animationType="fade" statusBarTranslucent visible onRequestClose={onClose}>
|
||||
<ModalRoot style={styles.root}>
|
||||
<WindowChromeRootRegion corners="both">
|
||||
<View style={styles.root}>
|
||||
<View ref={setWebOverlayScope} style={styles.root}>
|
||||
<Pressable
|
||||
testID="attachment-lightbox-backdrop"
|
||||
accessibilityRole="button"
|
||||
|
||||
Reference in New Issue
Block a user