mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 00:53:38 +02:00
Keep an explicit link to prepared Boat previews
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
1f358b7079
commit
76a499cc54
2 files changed
+39
-5
No files matched your search
@@ -41,6 +41,35 @@ beforeEach(() => {
|
||||
afterEach(async () => { if (!unmounted) await unmount(); host.remove(); delete (Element.prototype as { checkVisibility?: unknown }).checkVisibility; vi.restoreAllMocks(); vi.useRealTimers(); });
|
||||
|
||||
describe("Computer connection lifetime", () => {
|
||||
it("offers an explicit preview link when the browser blocks the new window", async () => {
|
||||
vi.spyOn(window, "open").mockReturnValue(null);
|
||||
vi.mocked(computersApi.preview).mockResolvedValue({ url: "https://preview.example/app" });
|
||||
await render();
|
||||
await act(async () => host.querySelector("form")!.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true })));
|
||||
expect(computersApi.preview).toHaveBeenCalledWith("task-a", "environment-a", 5173);
|
||||
const link = host.querySelector("a")!;
|
||||
expect(link.href).toBe("https://preview.example/app");
|
||||
expect(link.textContent).toBe("Open port 5173 in a new tab");
|
||||
expect(link.rel).toBe("noopener noreferrer");
|
||||
await render({ environmentId: "environment-b" });
|
||||
expect(host.querySelector("a")).toBeNull();
|
||||
});
|
||||
|
||||
it("discards a preview response after the task changes", async () => {
|
||||
const close = vi.fn();
|
||||
const replace = vi.fn();
|
||||
vi.spyOn(window, "open").mockReturnValue({ close, location: { replace } } as unknown as Window);
|
||||
const pending = deferred<{ url: string }>();
|
||||
vi.mocked(computersApi.preview).mockReturnValue(pending.promise);
|
||||
await render();
|
||||
await act(async () => host.querySelector("form")!.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true })));
|
||||
await render({ issueId: "task-b" });
|
||||
await act(async () => pending.resolve({ url: "https://preview.example/app" }));
|
||||
expect(close).toHaveBeenCalledOnce();
|
||||
expect(replace).not.toHaveBeenCalled();
|
||||
expect(host.querySelector("a")).toBeNull();
|
||||
});
|
||||
|
||||
it("connects only after the explicit action and keeps credentials in the iframe with no referrer", async () => {
|
||||
await render(); await tick(60_000);
|
||||
expect(computersApi.connect).not.toHaveBeenCalled();
|
||||
|
||||
@@ -23,19 +23,22 @@ function ComputerConnection({ issueId, environmentId, active = true }: ComputerP
|
||||
const connectPending = useRef(false);
|
||||
const [port, setPort] = useState("5173");
|
||||
const [previewPending, setPreviewPending] = useState(false);
|
||||
const [preview, setPreview] = useState<{ url: string; port: string } | null>(null);
|
||||
|
||||
async function openPreview() {
|
||||
const previewWindow = window.open("about:blank", "_blank");
|
||||
if (!previewWindow) { setError("Allow a new tab to open the preview."); return; }
|
||||
previewWindow.opener = null;
|
||||
if (previewWindow) previewWindow.opener = null;
|
||||
setPreviewPending(true);
|
||||
setPreview(null);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await computersApi.preview(issueId, environmentId, Number(port));
|
||||
if (mounted.current) previewWindow.location.replace(result.url);
|
||||
else previewWindow.close();
|
||||
if (mounted.current) {
|
||||
setPreview({ url: result.url, port });
|
||||
previewWindow?.location.replace(result.url);
|
||||
} else previewWindow?.close();
|
||||
} catch (cause) {
|
||||
previewWindow.close();
|
||||
previewWindow?.close();
|
||||
if (mounted.current) setError(cause instanceof Error ? cause.message : "Could not open the preview.");
|
||||
} finally { if (mounted.current) setPreviewPending(false); }
|
||||
}
|
||||
@@ -155,6 +158,8 @@ function ComputerConnection({ issueId, environmentId, active = true }: ComputerP
|
||||
className="min-w-0 flex-1" onChange={event => setPort(event.target.value)} />
|
||||
<Button type="submit" variant="outline" disabled={previewPending || !port}>Open preview</Button>
|
||||
</form>
|
||||
{preview && preview.port === port && <a href={preview.url} target="_blank" rel="noopener noreferrer"
|
||||
className="text-sm text-primary underline">Open port {preview.port} in a new tab</a>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
Reference in new issue
Block a user