mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-25 02:32:47 +00:00
fix(app): dismiss file link tooltips when leaving their panel
Retained chats suspend while their tooltip portals remain mounted. Remove the surface before suspension and clear open state and pending hover timers so returning to the chat does not revive it.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { test, expect, type Page } from "../support/fixtures";
|
||||
import { openAgentRoute, seedMockAgentWorkspace } from "../support/helpers/mock-agent";
|
||||
|
||||
async function readFileLinkTooltip(page: Page): Promise<void> {
|
||||
const link = page.getByRole("link", { name: "the guide", exact: true });
|
||||
await link.hover();
|
||||
await expect(page.getByRole("tooltip")).toContainText("guide.md");
|
||||
}
|
||||
|
||||
async function leaveFileLink(page: Page): Promise<void> {
|
||||
await page.mouse.move(5, 5);
|
||||
await expect(page.getByRole("tooltip")).toHaveCount(0);
|
||||
}
|
||||
|
||||
async function openLinkedFile(page: Page): Promise<void> {
|
||||
await page.getByRole("link", { name: "the guide", exact: true }).click();
|
||||
await expect(page.getByTestId("markdown-preview-frame")).toContainText("Example guide");
|
||||
await leaveFileLink(page);
|
||||
}
|
||||
|
||||
async function returnToAgent(page: Page): Promise<void> {
|
||||
await page.getByRole("button", { name: "Tooltip regression", exact: true }).click();
|
||||
await expect(page.getByRole("link", { name: "the guide", exact: true })).toBeVisible();
|
||||
await leaveFileLink(page);
|
||||
}
|
||||
|
||||
async function switchToFileTab(page: Page): Promise<void> {
|
||||
await page.getByRole("button", { name: "guide.md", exact: true }).click();
|
||||
await expect(page.getByTestId("markdown-preview-frame")).toContainText("Example guide");
|
||||
await leaveFileLink(page);
|
||||
}
|
||||
|
||||
test("opening an assistant file link dismisses its tooltip over the file tab", async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
testInfo.setTimeout(120_000);
|
||||
const agent = await seedMockAgentWorkspace({
|
||||
repoPrefix: "tooltip-5811-",
|
||||
title: "Tooltip regression",
|
||||
featureValues: {
|
||||
mockStreamingAssistantResponse: "Read [the guide](./guide.md).",
|
||||
mockStreamingAssistantIntervalMs: 5,
|
||||
},
|
||||
});
|
||||
try {
|
||||
await writeFile(
|
||||
path.join(agent.cwd, "guide.md"),
|
||||
"# Example guide\n\n" + "Plain paragraph.\n\n".repeat(150),
|
||||
);
|
||||
await openAgentRoute(page, agent);
|
||||
await agent.client.sendAgentMessage(agent.agentId, "Show the file link.");
|
||||
await agent.client.waitForFinish(agent.agentId, 30_000);
|
||||
|
||||
await readFileLinkTooltip(page);
|
||||
await leaveFileLink(page);
|
||||
await readFileLinkTooltip(page);
|
||||
await openLinkedFile(page);
|
||||
await returnToAgent(page);
|
||||
await readFileLinkTooltip(page);
|
||||
await switchToFileTab(page);
|
||||
await returnToAgent(page);
|
||||
await readFileLinkTooltip(page);
|
||||
await leaveFileLink(page);
|
||||
} finally {
|
||||
await agent.cleanup();
|
||||
}
|
||||
});
|
||||
@@ -27,6 +27,7 @@ import { FadeIn, FadeOut } from "react-native-reanimated";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { useIsCompactFormFactor } from "@/constants/layout";
|
||||
import { FloatingSurface } from "@/components/ui/floating";
|
||||
import { useRetainedPanelActive } from "@/components/retained-panel";
|
||||
import { isNative, isWeb } from "@/constants/platform";
|
||||
import { getOverlayRoot, OVERLAY_Z } from "@/lib/overlay-root";
|
||||
|
||||
@@ -256,8 +257,15 @@ export function Tooltip({
|
||||
});
|
||||
|
||||
const isCompact = useIsCompactFormFactor();
|
||||
const active = useRetainedPanelActive();
|
||||
const opensOnPress = isNative || isCompact;
|
||||
const enabled = opensOnPress ? enabledOnMobile : enabledOnDesktop;
|
||||
const enabled = active && (opensOnPress ? enabledOnMobile : enabledOnDesktop);
|
||||
|
||||
// Remove the portal in the inactive commit, before the retained chat freezes.
|
||||
// Closing also prevents the tooltip from returning when its panel is shown again.
|
||||
useEffect(() => {
|
||||
if (!active && isOpen) setIsOpen(false);
|
||||
}, [active, isOpen, setIsOpen]);
|
||||
|
||||
const value = useMemo<TooltipContextValue>(
|
||||
() => ({
|
||||
@@ -329,6 +337,10 @@ export function TooltipTrigger({
|
||||
};
|
||||
}, [clearOpenTimer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ctx.enabled) clearOpenTimer();
|
||||
}, [ctx.enabled, clearOpenTimer]);
|
||||
|
||||
const handleHoverIn = useCallback(
|
||||
(e?: unknown) => {
|
||||
if (isCallable(onHoverIn)) onHoverIn(e);
|
||||
|
||||
Reference in New Issue
Block a user