mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-20 14:12:59 +03:00
This commit is contained in:
committed by
GitHub
parent
cc5f596b5f
commit
6d649d3d3f
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Button, Badge, Input, Modal, Toggle } from "@/shared/components";
|
||||
import { Button, Badge, Input, Modal, Toggle, TALL_MODAL_PROPS } from "@/shared/components";
|
||||
import {
|
||||
providerAllowsOptionalApiKey,
|
||||
supportsBulkApiKey,
|
||||
@@ -445,7 +445,7 @@ export default function AddApiKeyModal({
|
||||
title={getAddCredentialModalTitle(t, providerDisplayName, webSessionCredential)}
|
||||
onClose={onClose}
|
||||
size="lg"
|
||||
bodyClassName="p-6 max-h-[85vh] overflow-y-auto"
|
||||
{...TALL_MODAL_PROPS}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
{webProviderHostLink && (
|
||||
|
||||
@@ -4,6 +4,14 @@ import { useEffect, useRef, useId } from "react";
|
||||
import { cn } from "@/shared/utils/cn";
|
||||
import Button from "./Button";
|
||||
|
||||
// #6265 — preset for content-heavy modals: caps height on the OUTERMOST dialog
|
||||
// wrapper only (single scroll owner) and keeps the inner body plain (no
|
||||
// independent max-h/overflow), avoiding a double height cap that clips content.
|
||||
export const TALL_MODAL_PROPS = {
|
||||
className: "max-h-[90vh] overflow-y-auto",
|
||||
bodyClassName: "p-6",
|
||||
};
|
||||
|
||||
interface ModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
|
||||
@@ -6,7 +6,7 @@ export { default as Checkbox } from "./Checkbox";
|
||||
export { default as Textarea } from "./Textarea";
|
||||
export { default as Card } from "./Card";
|
||||
export { default as Collapsible } from "./Collapsible";
|
||||
export { default as Modal, ConfirmModal } from "./Modal";
|
||||
export { default as Modal, ConfirmModal, TALL_MODAL_PROPS } from "./Modal";
|
||||
export { default as Loading, Spinner, PageLoading, Skeleton, CardSkeleton } from "./Loading";
|
||||
export { default as Avatar } from "./Avatar";
|
||||
export { default as Badge } from "./Badge";
|
||||
|
||||
81
tests/unit/ui/web-session-cookie-modal-size-6265.test.tsx
Normal file
81
tests/unit/ui/web-session-cookie-modal-size-6265.test.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
// @vitest-environment jsdom
|
||||
// Issue #6265 — the "Add session cookie" modal (AddApiKeyModal, shared by every
|
||||
// `-web` cookie provider) was undersized on a 1920x1080 viewport: users had to
|
||||
// scroll *inside* the modal to reach Save, and the top of the cookie helper text
|
||||
// was clipped. Root cause: the height cap (`max-h-*` + `overflow-y-auto`) lived on
|
||||
// the INNER body div only, while the OUTERMOST dialog wrapper had no height bound
|
||||
// at all — so the whole box (header + body) could grow taller than the viewport
|
||||
// and get clipped by the centering flexbox, independent of the inner scrollbar.
|
||||
//
|
||||
// Fix: move the single height cap to the outermost dialog wrapper (`role="dialog"`)
|
||||
// and stop giving the inner body container its own independent `max-h-`/`overflow`
|
||||
// cap, so there is exactly one scroll owner for the whole modal.
|
||||
import React, { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { describe, it, expect, vi, afterEach } from "vitest";
|
||||
|
||||
vi.mock("next-intl", () => ({
|
||||
useTranslations: () => (key: string) => key,
|
||||
}));
|
||||
|
||||
const { default: AddApiKeyModal } =
|
||||
await import("../../../src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal");
|
||||
|
||||
const containers: Array<{ root: ReturnType<typeof createRoot>; el: HTMLDivElement }> = [];
|
||||
|
||||
function render(props: Record<string, unknown>) {
|
||||
const el = document.createElement("div");
|
||||
document.body.appendChild(el);
|
||||
const root = createRoot(el);
|
||||
act(() => {
|
||||
root.render(
|
||||
<AddApiKeyModal
|
||||
isOpen
|
||||
onSave={async () => undefined}
|
||||
onClose={() => {}}
|
||||
{...(props as any)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
containers.push({ root, el });
|
||||
return el;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const { root, el } of containers.splice(0)) {
|
||||
act(() => root.unmount());
|
||||
el.remove();
|
||||
}
|
||||
});
|
||||
|
||||
describe("AddApiKeyModal — cookie modal sizing (#6265)", () => {
|
||||
it("caps height on the OUTERMOST dialog wrapper, not on an inner body div", () => {
|
||||
// chatgpt-web is a `kind: "cookie"` web-session provider — same shared modal
|
||||
// path lmarena/claude-web/gemini-web/kimi-web/z-ai all go through.
|
||||
const el = render({ provider: "chatgpt-web", providerName: "ChatGPT (Web)" });
|
||||
|
||||
const dialog = el.querySelector<HTMLElement>('[role="dialog"]');
|
||||
expect(dialog).toBeTruthy();
|
||||
|
||||
// The outermost wrapper must be the single owner of the height cap + scroll.
|
||||
expect(dialog!.className).toMatch(/max-h-\[90vh\]/);
|
||||
expect(dialog!.className).toMatch(/overflow-y-auto/);
|
||||
|
||||
// The body container (last child of the dialog — header is first, no footer
|
||||
// prop is used by AddApiKeyModal) must NOT carry its own independent max-h/
|
||||
// overflow cap — otherwise the outer cap and the inner cap fight (double cap),
|
||||
// clipping content before the outer 90vh bound ever kicks in.
|
||||
const bodyDiv = dialog!.children[dialog!.children.length - 1] as HTMLElement;
|
||||
expect(bodyDiv).toBeTruthy();
|
||||
expect(bodyDiv.className).not.toMatch(/max-h-/);
|
||||
expect(bodyDiv.className).not.toMatch(/overflow-y-auto/);
|
||||
|
||||
// Sanity: the cookie helper text and Save button are both present in the DOM
|
||||
// (this modal renders the full guide + form Save/Cancel inline in the body).
|
||||
expect(el.textContent).toContain("How to get the session credential");
|
||||
const saveBtn = Array.from(el.querySelectorAll("button")).find(
|
||||
(b) => b.textContent?.trim() === "save"
|
||||
);
|
||||
expect(saveBtn).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user