diff --git a/apps/web/src/components/settings/ProviderInstanceCard.tsx b/apps/web/src/components/settings/ProviderInstanceCard.tsx index 9a00ccb75ae..430ec3637e0 100644 --- a/apps/web/src/components/settings/ProviderInstanceCard.tsx +++ b/apps/web/src/components/settings/ProviderInstanceCard.tsx @@ -29,6 +29,7 @@ import { Button } from "../ui/button"; import { Collapsible, CollapsibleContent } from "../ui/collapsible"; import { DraftInput } from "../ui/draft-input"; import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover"; +import { ScrollArea } from "../ui/scroll-area"; import { Switch } from "../ui/switch"; import { stackedThreadToast, toastManager } from "../ui/toast"; import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; @@ -697,8 +698,12 @@ export function ProviderInstanceCard({ } /> - -
+ +

Update available @@ -735,10 +740,12 @@ export function ProviderInstanceCard({

) : null} {updateCommand ? ( -
- - {updateCommand} - +
+ + + {updateCommand} + + { instanceId: ProviderInstanceId.make("codex"), }); }); + + it("keeps long provider update commands inside the fixed-width popover", async () => { + const longUpdateCommand = + "npm install -g @anthropic-ai/claude-code@latest --registry=https://registry.npmjs.org --cache=/tmp/t3code-provider-update-cache"; + + setServerConfigSnapshot({ + ...createBaseServerConfig(), + providers: [createOutdatedProvider("codex", longUpdateCommand)], + }); + + mounted = await render( + + + , + ); + + await page.getByRole("button", { name: "Update available — view details" }).click(); + await expect.element(page.getByText(longUpdateCommand)).toBeInTheDocument(); + + await vi.waitFor(() => { + const popup = document.querySelector('[data-slot="popover-popup"]'); + const commandCode = Array.from(document.querySelectorAll("code")).find( + (element) => element.textContent === longUpdateCommand, + ); + const scrollViewport = commandCode?.closest( + '[data-slot="scroll-area-viewport"]', + ); + + expect(popup).toBeTruthy(); + expect(commandCode).toBeTruthy(); + expect(scrollViewport).toBeTruthy(); + + const popupRect = popup!.getBoundingClientRect(); + const viewportRect = scrollViewport!.getBoundingClientRect(); + + expect(popupRect.width).toBeGreaterThan(300); + expect(popupRect.width).toBeLessThanOrEqual(337); + expect(viewportRect.right).toBeLessThanOrEqual(popupRect.right + 0.5); + expect(scrollViewport!.scrollWidth).toBeGreaterThan(scrollViewport!.clientWidth); + }); + }); }); describe("SourceControlSettingsPanel discovery states", () => {