fix(ui): drop deprecation banners from kept features and make the rest permanent (#46314)

* fix(ui): drop deprecation banners from kept features and make the rest permanent

* test(ui): pin deprecation banner copy, dismissal and kept-feature absence

* fix(ui): point deprecation banner at the discussion instead of asking for feedback

* test(ui): drop copy-pinning and removed-banner absence tests

* refactor(ui): build the deprecation banner on the shadcn Alert primitive
This commit is contained in:
yuneng-jiang 2026-10-13 16:48:32 -07:00 • committed by GitHub
parent 29202d2b50
commit bdc0893c28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 25 additions and 97 deletions

View file

@ -14,7 +14,6 @@ import {
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { UiLoadingSpinner } from "@/components/ui/ui-loading-spinner";
import { DeprecationBanner } from "@/components/DeprecationBanner";
import { toast } from "@/lib/toast";
import {
getGeneralSettingsCall,
@ -317,7 +316,6 @@ const MCPNetworkSettings: React.FC<MCPNetworkSettingsProps> = ({ accessToken })
return (
<div className="space-y-6 p-4">
<DeprecationBanner featureName="MCP Network Settings and the internal-network-only flag" />
<div>
<p className="text-lg font-semibold">Private IP Ranges</p>
<p className="mt-1 text-sm text-muted-foreground">

View file

@ -49,10 +49,4 @@ describe("Memory page access by role", () => {
await waitFor(() => expect(requestedUrls().filter((url) => url.includes("/v1/memory"))).toEqual([]));
},
);
it("hides the deprecation banner along with the page body for a denied role", () => {
renderAs("Internal User");
expect(screen.queryByText(/draft deprecation list/i)).not.toBeInTheDocument();
});
});

View file

@ -1,7 +1,6 @@
"use client";
import { MemoryView } from "./_components/MemoryView";
import { DeprecationBanner } from "@/components/DeprecationBanner";
import { AdminOnlyNotice } from "@/components/shared/AdminOnlyNotice";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import useCan from "@/app/(dashboard)/hooks/useCan";
@ -14,10 +13,5 @@ export default function Memory() {
return <AdminOnlyNotice pageTitle="Memory" />;
}
return (
<>
<DeprecationBanner featureName="Memory" />
<MemoryView accessToken={accessToken} userID={userId} userRole={userRole} />
</>
);
return <MemoryView accessToken={accessToken} userID={userId} userRole={userRole} />;
}

View file

@ -7,7 +7,6 @@ import CompareUI from "@/app/(dashboard)/playground/components/compareUI/Compare
import ComplianceUI from "@/app/(dashboard)/playground/components/complianceUI/ComplianceUI";
import SystemOneUI from "@/app/(dashboard)/playground/components/systemOneUI/SystemOneUI";
import BetaBadge from "@/components/BetaBadge";
import { DeprecationBanner } from "@/components/DeprecationBanner";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import { fetchProxySettings } from "@/utils/proxyUtils";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
@ -100,7 +99,6 @@ export default function PlaygroundPage() {
<SystemOneUI accessToken={accessToken} disabledPersonalKeyCreation={disabledPersonalKeyCreation} />
</TabsContent>
<TabsContent value="agent-builder" className="mt-0 h-full data-hidden:hidden" keepMounted>
<DeprecationBanner featureName="The Playground's Agent Builder" />
<AgentBuilderView
accessToken={accessToken}
token={token}

View file

@ -1,15 +1,9 @@
"use client";
import PromptsPanel from "./_components";
import { DeprecationBanner } from "@/components/DeprecationBanner";
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
export default function Prompts() {
const { accessToken, userRole } = useAuthorized();
return (
<>
<DeprecationBanner featureName="Prompt Management" />
<PromptsPanel accessToken={accessToken} userRole={userRole} />
</>
);
return <PromptsPanel accessToken={accessToken} userRole={userRole} />;
}

View file

@ -50,9 +50,9 @@ describe("Workflows page access by role", () => {
},
);
it("hides the deprecation banner along with the page body for a denied role", () => {
renderAs("Internal User");
it("shows an admin the deprecation notice", () => {
renderAs("Admin");
expect(screen.queryByText(/draft deprecation list/i)).not.toBeInTheDocument();
expect(screen.getByRole("alert")).toHaveTextContent("Workflows");
});
});

View file

@ -1,44 +1,20 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it } from "vitest";
import { DeprecationBanner } from "./DeprecationBanner";
describe("DeprecationBanner", () => {
it("names the deprecated feature in the heading and the body", () => {
render(<DeprecationBanner featureName="Memory" />);
it("names the deprecated feature", () => {
render(<DeprecationBanner featureName="Workflows" />);
expect(screen.getByText("Memory is on a draft deprecation list")).toBeInTheDocument();
expect(screen.getByText(/Memory is one of several experimental features/)).toBeInTheDocument();
});
it("states the target removal date and that the list is not final", () => {
render(<DeprecationBanner featureName="Memory" />);
expect(screen.getByText(/as early as September 1, 2026/)).toBeInTheDocument();
expect(screen.getByText(/This list is a draft and is not final/)).toBeInTheDocument();
expect(screen.getByRole("alert")).toHaveTextContent("Workflows");
});
it("links to the deprecation discussion in a new tab without leaking the opener", () => {
render(<DeprecationBanner featureName="Memory" />);
render(<DeprecationBanner featureName="Workflows" />);
const link = screen.getByRole("link", { name: "deprecation discussion" });
expect(link).toHaveAttribute("href", "https://github.com/BerriAI/litellm/discussions/32090");
expect(link).toHaveAttribute("target", "_blank");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
});
it("exposes a named close control", () => {
render(<DeprecationBanner featureName="Memory" />);
expect(screen.getByRole("button", { name: /close/i })).toBeInTheDocument();
});
it("hides the banner once the close control is used", async () => {
const user = userEvent.setup();
render(<DeprecationBanner featureName="Memory" />);
await user.click(screen.getByRole("button", { name: /close/i }));
expect(screen.queryByText("Memory is on a draft deprecation list")).not.toBeInTheDocument();
});
});

View file

@ -1,52 +1,26 @@
"use client";
import React, { useState } from "react";
import React from "react";
import Link from "next/link";
import { Info, X } from "lucide-react";
import { Info } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
const DEPRECATION_DISCUSSION_URL = "https://github.com/BerriAI/litellm/discussions/32090";
const DEPRECATION_TARGET_DATE = "September 1, 2026";
interface DeprecationBannerProps {
featureName: string;
}
export const DeprecationBanner: React.FC<DeprecationBannerProps> = ({ featureName }) => {
const [isClosed, setIsClosed] = useState(false);
if (isClosed) {
return null;
}
return (
<div
role="alert"
className="mb-4 flex items-start gap-3 rounded-lg border border-border bg-muted/50 px-4 py-3 text-sm"
>
<Info className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<div className="min-w-0 flex-1">
<p className="font-medium">{`${featureName} is on a draft deprecation list`}</p>
<p className="mt-1 break-words text-muted-foreground">
{`${featureName} is one of several experimental features we're considering removing, potentially as early as ${DEPRECATION_TARGET_DATE}. This list is a draft and is not final. If you rely on this feature, please share feedback on the `}
<Link
href={DEPRECATION_DISCUSSION_URL}
target="_blank"
rel="noopener noreferrer"
className="underline underline-offset-4"
>
deprecation discussion
</Link>
.
</p>
</div>
<button
type="button"
aria-label="Close"
onClick={() => setIsClosed(true)}
className="shrink-0 rounded-md p-0.5 text-muted-foreground transition-colors hover:text-foreground"
>
<X className="size-4" />
</button>
</div>
);
};
export const DeprecationBanner: React.FC<DeprecationBannerProps> = ({ featureName }) => (
<Alert className="mb-4">
<Info />
<AlertTitle>{`${featureName} is deprecated`}</AlertTitle>
<AlertDescription>
{`${featureName} will be removed in the near future. See the `}
<Link href={DEPRECATION_DISCUSSION_URL} target="_blank" rel="noopener noreferrer">
deprecation discussion
</Link>
{" for details."}
</AlertDescription>
</Alert>
);