From 9ff0daa24defccc9a6aa049e8a4c6f4a98b0f846 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 26 Jan 2026 16:58:38 -0800 Subject: [PATCH] Add dont ask me again option in nudges --- .../hooks/useDisableShowPrompts.ts | 35 +++++++++ .../src/components/navbar.tsx | 24 +++++- .../src/components/survey/NudgePrompt.tsx | 73 +++++++++++++++++-- 3 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/hooks/useDisableShowPrompts.ts diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/useDisableShowPrompts.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/useDisableShowPrompts.ts new file mode 100644 index 00000000000..801fbdbb99d --- /dev/null +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/useDisableShowPrompts.ts @@ -0,0 +1,35 @@ +// hooks/useDisableShowPrompts.ts +import { useSyncExternalStore } from "react"; +import { getLocalStorageItem } from "@/utils/localStorageUtils"; +import { LOCAL_STORAGE_EVENT } from "@/utils/localStorageUtils"; + +function subscribe(callback: () => void) { + const onStorage = (e: StorageEvent) => { + if (e.key === "disableShowPrompts") { + callback(); + } + }; + + const onCustom = (e: Event) => { + const { key } = (e as CustomEvent).detail; + if (key === "disableShowPrompts") { + callback(); + } + }; + + window.addEventListener("storage", onStorage); + window.addEventListener(LOCAL_STORAGE_EVENT, onCustom); + + return () => { + window.removeEventListener("storage", onStorage); + window.removeEventListener(LOCAL_STORAGE_EVENT, onCustom); + }; +} + +function getSnapshot() { + return getLocalStorageItem("disableShowPrompts") === "true"; +} + +export function useDisableShowPrompts() { + return useSyncExternalStore(subscribe, getSnapshot); +} diff --git a/ui/litellm-dashboard/src/components/navbar.tsx b/ui/litellm-dashboard/src/components/navbar.tsx index 6dac073b3a6..8179bb8a533 100644 --- a/ui/litellm-dashboard/src/components/navbar.tsx +++ b/ui/litellm-dashboard/src/components/navbar.tsx @@ -1,4 +1,5 @@ import { useHealthReadiness } from "@/app/(dashboard)/hooks/healthReadiness/useHealthReadiness"; +import { useDisableShowPrompts } from "@/app/(dashboard)/hooks/useDisableShowPrompts"; import { getProxyBaseUrl } from "@/components/networking"; import { useTheme } from "@/contexts/ThemeContext"; import { clearTokenCookies } from "@/utils/cookieUtils"; @@ -51,9 +52,9 @@ const Navbar: React.FC = ({ onToggleSidebar, }) => { const baseUrl = getProxyBaseUrl(); - console.log("baseUrl", baseUrl); const [logoutUrl, setLogoutUrl] = useState(""); const [disableShowNewBadge, setDisableShowNewBadge] = useState(false); + const disableShowPrompts = useDisableShowPrompts(); const { logoUrl } = useTheme(); const { data: healthData } = useHealthReadiness(); const version = healthData?.litellm_version; @@ -152,6 +153,27 @@ const Navbar: React.FC = ({ aria-label="Toggle hide new feature indicators" /> +
e.stopPropagation()} + > + Hide All Prompts + { + if (checked) { + setLocalStorageItem("disableShowPrompts", "true"); + emitLocalStorageChange("disableShowPrompts"); + } else { + removeLocalStorageItem("disableShowPrompts"); + emitLocalStorageChange("disableShowPrompts"); + } + }} + aria-label="Toggle hide all prompts" + /> +
), diff --git a/ui/litellm-dashboard/src/components/survey/NudgePrompt.tsx b/ui/litellm-dashboard/src/components/survey/NudgePrompt.tsx index 9095c6c21c5..ef72144b89f 100644 --- a/ui/litellm-dashboard/src/components/survey/NudgePrompt.tsx +++ b/ui/litellm-dashboard/src/components/survey/NudgePrompt.tsx @@ -1,6 +1,8 @@ import React, { useEffect, useState } from "react"; -import { X, LucideIcon } from "lucide-react"; +import { X, LucideIcon, Check } from "lucide-react"; import { Button } from "antd"; +import { useDisableShowPrompts } from "@/app/(dashboard)/hooks/useDisableShowPrompts"; +import { setLocalStorageItem, emitLocalStorageChange } from "@/utils/localStorageUtils"; interface NudgePromptProps { onOpen: () => void; @@ -15,6 +17,7 @@ interface NudgePromptProps { } const DISMISS_DURATION = 15000; // 15 seconds +const CONFIRMATION_DURATION = 5000; // 5 seconds export function NudgePrompt({ onOpen, @@ -27,11 +30,14 @@ export function NudgePrompt({ accentColor, buttonStyle, }: NudgePromptProps) { + const disableShowPrompts = useDisableShowPrompts(); const [progress, setProgress] = useState(100); + const [showConfirmation, setShowConfirmation] = useState(false); useEffect(() => { if (!isVisible) { setProgress(100); + setShowConfirmation(false); return; } @@ -49,13 +55,53 @@ export function NudgePrompt({ return () => clearInterval(interval); }, [isVisible]); - if (!isVisible) return null; + useEffect(() => { + if (showConfirmation) { + const timer = setTimeout(() => { + setShowConfirmation(false); + onDismiss(); + }, CONFIRMATION_DURATION); + + return () => clearTimeout(timer); + } + }, [showConfirmation, onDismiss]); + + const handleDontAskAgain = () => { + setLocalStorageItem("disableShowPrompts", "true"); + emitLocalStorageChange("disableShowPrompts"); + setShowConfirmation(true); + }; + + // Show confirmation even if disableShowPrompts is true (since we just set it) + if (showConfirmation) { + return ( +
+
+
+
+ +
+
+

+ Got it, we will not ask again. Reactivate this at any time in the User Menu. +

+
+
+
+
+ ); + } + + // Don't show the prompt if disabled (unless we're showing confirmation) + if (!isVisible || disableShowPrompts) return null; return (
{/* Progress bar at top showing time remaining */}
@@ -81,9 +127,20 @@ export function NudgePrompt({

{description}

- +
+ + +
);