diff --git a/ui/litellm-dashboard/src/app/globals.css b/ui/litellm-dashboard/src/app/globals.css index 4589d0f528a..97f61a610d9 100644 --- a/ui/litellm-dashboard/src/app/globals.css +++ b/ui/litellm-dashboard/src/app/globals.css @@ -235,3 +235,10 @@ .custom-border { border: 1px solid var(--neutral-border); } + +/* A dialog opened from inside another dialog reads as a drill-down, not a stack: base-ui stamps + this attribute on the parent while a child is open, so the parent steps aside instead of + showing its own edges around a differently sized child. */ +[data-slot="dialog-content"][data-nested-dialog-open] { + visibility: hidden; +} diff --git a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx index 9b36218e17a..29101b38e24 100644 --- a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx +++ b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx @@ -6,12 +6,19 @@ import { fireEvent, renderWithProviders, screen, waitFor, within } from "@/../te import NotificationsManager from "@/components/molecules/notifications_manager"; import EditAutoRouterModal from "./edit_auto_router_modal"; -const { modelPatchUpdateCall, modelAvailableCall } = vi.hoisted(() => ({ +const { modelPatchUpdateCall, modelAvailableCall, getAutoRouterClassifierDefaultPromptCall } = vi.hoisted(() => ({ modelPatchUpdateCall: vi.fn().mockResolvedValue({}), modelAvailableCall: vi.fn().mockResolvedValue({ data: [] }), + getAutoRouterClassifierDefaultPromptCall: vi.fn().mockResolvedValue("Classify the request into exactly one tier."), })); -vi.mock("../networking", () => ({ modelPatchUpdateCall, modelAvailableCall })); +vi.mock("../networking", () => ({ + modelPatchUpdateCall, + modelAvailableCall, + getAutoRouterClassifierDefaultPromptCall, +})); + +vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({ default: () => ({ accessToken: "sk-test" }) })); vi.mock("@/components/llm_calls/fetch_models", () => ({ fetchAvailableModels: vi.fn().mockResolvedValue([{ model_group: "gpt-4o-mini" }]), @@ -243,6 +250,22 @@ describe("EditAutoRouterModal classifier context window", () => { expect(config.classifier_context_per_turn_chars).toBe(300); }); + // The prompt editor is a base-ui Dialog at z-index 50. Housing this form in an antd Modal put a + // z-index 1000 overlay between the operator and it, so the editor opened underneath and could + // not be read or typed into. jsdom does not paint, so the assertion is the invariant behind the + // stacking: both overlays come from the one Dialog primitive the create form already uses. + it("opens the classifier prompt editor in the same overlay layer as the form", async () => { + const user = userEvent.setup(); + const { baseElement } = renderLlmModal(); + + await user.click(await screen.findByText("Advanced: Classification Method")); + await user.click(await screen.findByRole("button", { name: /prompt/i })); + + expect(await screen.findByLabelText("Classifier system prompt")).toBeInTheDocument(); + expect(baseElement.querySelectorAll('[data-slot="dialog-content"]')).toHaveLength(2); + expect(baseElement.querySelector(".ant-modal")).toBeNull(); + }); + it("persists an edited classifier context window size", async () => { const user = userEvent.setup(); renderLlmModal(); diff --git a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx index cf1a5727948..aba0ee9f58a 100644 --- a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx +++ b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; -import { Modal, Form, Button, Select as AntdSelect, Tooltip } from "antd"; -import { Text, TextInput } from "@tremor/react"; +import { Form, Button, Select as AntdSelect, Tooltip } from "antd"; +import { TextInput } from "@tremor/react"; import { modelAvailableCall, modelPatchUpdateCall } from "../networking"; import { fetchAvailableModels, ModelGroup } from "@/components/llm_calls/fetch_models"; import RouterConfigBuilder from "../add_model/RouterConfigBuilder"; @@ -24,6 +24,14 @@ import ComplexityRouterConfig, { DEFAULT_TIER_DISTANCE_PENALTY, } from "../add_model/ComplexityRouterConfig"; import NotificationsManager from "../molecules/notifications_manager"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; interface EditAutoRouterModalProps { isVisible: boolean; @@ -432,27 +440,14 @@ const EditAutoRouterModal: React.FC = ({ })); return ( - - Cancel - , - - - , - ]} - width={1000} - destroyOnHidden - > -
- - Edit the auto router configuration including routing logic, default models, and access settings. - + !open && onCancel()}> + + + Edit Auto Router Configuration + + Edit the auto router configuration including routing logic, default models, and access settings. + +
{/* Auto Router Name */} @@ -552,8 +547,17 @@ const EditAutoRouterModal: React.FC = ({ )} -
-
+ + + + + + + + + ); };