From 3f6b1b7cfb96b9d52609ef4ea219fb61142b37a9 Mon Sep 17 00:00:00 2001 From: Suresh Chaudhary Date: Mon, 17 Aug 2026 16:50:06 +0530 Subject: [PATCH] fix: responsive view fixes post notification center addition --- .../library/views/mcpLibraryFilterSidebar.tsx | 23 +------ .../views/mcpClientsFilterSidebar.tsx | 23 +------ .../views/mcpSessionsFilterSidebar.tsx | 36 ++-------- .../views/oauthGrantsFilterSidebar.tsx | 34 +--------- .../filters/filterSidebarTrigger.tsx | 65 +++++++++++++++++++ ui/components/filters/logsFilterSidebar.tsx | 24 +------ ui/components/filters/mcpFilterSidebar.tsx | 24 +------ ui/components/notificationCenter.tsx | 2 +- ui/components/topbar.tsx | 22 +++++-- ui/lib/contexts/topbarContext.tsx | 18 ++++- 10 files changed, 118 insertions(+), 153 deletions(-) create mode 100644 ui/components/filters/filterSidebarTrigger.tsx diff --git a/ui/app/workspace/mcp-registry/library/views/mcpLibraryFilterSidebar.tsx b/ui/app/workspace/mcp-registry/library/views/mcpLibraryFilterSidebar.tsx index 2e3fff66abd..c6101587b9f 100644 --- a/ui/app/workspace/mcp-registry/library/views/mcpLibraryFilterSidebar.tsx +++ b/ui/app/workspace/mcp-registry/library/views/mcpLibraryFilterSidebar.tsx @@ -1,3 +1,4 @@ +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -7,7 +8,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { useIsMobile } from "@/hooks/use-mobile"; import { useGetMCPLibraryFilterDataQuery } from "@/lib/store"; import { cn } from "@/lib/utils"; -import { ChevronDown, Filter, PanelLeftClose, PanelLeftOpen, RotateCcw, Search } from "lucide-react"; +import { ChevronDown, PanelLeftClose, RotateCcw, Search } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; const COLLAPSE_STORAGE_KEY = "mcp-library-filter-sidebar-collapsed"; @@ -75,25 +76,7 @@ export function MCPLibraryFilterSidebar({ filters, onFiltersChange }: SidebarPro if (collapsed) { return ( - + ); } diff --git a/ui/app/workspace/mcp-registry/views/mcpClientsFilterSidebar.tsx b/ui/app/workspace/mcp-registry/views/mcpClientsFilterSidebar.tsx index 0bfb7ab3515..d2452737c8b 100644 --- a/ui/app/workspace/mcp-registry/views/mcpClientsFilterSidebar.tsx +++ b/ui/app/workspace/mcp-registry/views/mcpClientsFilterSidebar.tsx @@ -1,3 +1,4 @@ +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -6,7 +7,7 @@ import { ScrollArea } from "@/components/ui/scrollArea"; import { useIsMobile } from "@/hooks/use-mobile"; import { useGetVirtualKeysQuery } from "@/lib/store"; import { cn } from "@/lib/utils"; -import { ChevronDown, Filter, LoaderCircle, PanelLeftClose, PanelLeftOpen, RotateCcw, Search } from "lucide-react"; +import { ChevronDown, LoaderCircle, PanelLeftClose, RotateCcw, Search } from "lucide-react"; import { type Ref, useCallback, useEffect, useMemo, useRef, useState } from "react"; const COLLAPSE_STORAGE_KEY = "mcp-clients-filter-sidebar-collapsed"; @@ -131,25 +132,7 @@ export function MCPClientsFilterSidebar({ filters, onFiltersChange }: SidebarPro if (collapsed) { return ( - + ); } diff --git a/ui/app/workspace/mcp-sessions/views/mcpSessionsFilterSidebar.tsx b/ui/app/workspace/mcp-sessions/views/mcpSessionsFilterSidebar.tsx index 06b664ccef7..ab0d273a688 100644 --- a/ui/app/workspace/mcp-sessions/views/mcpSessionsFilterSidebar.tsx +++ b/ui/app/workspace/mcp-sessions/views/mcpSessionsFilterSidebar.tsx @@ -4,6 +4,7 @@ // State/behavior mirrors mcpClientsFilterSidebar.tsx; kept as its own copy // since the two pages filter on unrelated fields. +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -13,18 +14,7 @@ import { useIsMobile } from "@/hooks/use-mobile"; import { getUserSearchQuery } from "@/lib/registries/userPicker"; import { useGetMCPClientsQuery, useGetVirtualKeysQuery } from "@/lib/store"; import { cn } from "@/lib/utils"; -import { - ChevronDown, - Filter, - Fingerprint, - KeyRound, - LoaderCircle, - PanelLeftClose, - PanelLeftOpen, - RotateCcw, - Search, - UserRound, -} from "lucide-react"; +import { ChevronDown, Fingerprint, KeyRound, LoaderCircle, PanelLeftClose, RotateCcw, Search, UserRound } from "lucide-react"; import { type Ref, useCallback, useEffect, useMemo, useRef, useState } from "react"; // Side-effect import: registers the enterprise user search hook (if this is // an enterprise build) before this module's first render. OSS has no user @@ -165,25 +155,11 @@ export function MCPSessionsFilterSidebar({ filters, onFiltersChange }: SidebarPr if (collapsed) { return ( - + testId="mcp-sessions-filter-sidebar-toggle-show" + /> ); } diff --git a/ui/app/workspace/oauth-grants/views/oauthGrantsFilterSidebar.tsx b/ui/app/workspace/oauth-grants/views/oauthGrantsFilterSidebar.tsx index 11c1ab924c6..83c1b334c76 100644 --- a/ui/app/workspace/oauth-grants/views/oauthGrantsFilterSidebar.tsx +++ b/ui/app/workspace/oauth-grants/views/oauthGrantsFilterSidebar.tsx @@ -4,6 +4,7 @@ // State/behavior mirrors mcpSessionsFilterSidebar.tsx; kept as its own copy // since this page filters on unrelated fields. +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -13,18 +14,7 @@ import { useIsMobile } from "@/hooks/use-mobile"; import { getUserSearchQuery } from "@/lib/registries/userPicker"; import { useGetVirtualKeysQuery } from "@/lib/store"; import { cn } from "@/lib/utils"; -import { - ChevronDown, - Filter, - Fingerprint, - KeyRound, - LoaderCircle, - PanelLeftClose, - PanelLeftOpen, - RotateCcw, - Search, - UserRound, -} from "lucide-react"; +import { ChevronDown, Fingerprint, KeyRound, LoaderCircle, PanelLeftClose, RotateCcw, Search, UserRound } from "lucide-react"; import { type Ref, useCallback, useEffect, useMemo, useRef, useState } from "react"; // Side-effect import: registers the enterprise user search hook (if this is // an enterprise build) before this module's first render. OSS has no user @@ -133,25 +123,7 @@ export function OAuthGrantsFilterSidebar({ filters, onFiltersChange }: SidebarPr if (collapsed) { return ( - + ); } diff --git a/ui/components/filters/filterSidebarTrigger.tsx b/ui/components/filters/filterSidebarTrigger.tsx new file mode 100644 index 00000000000..d39eab286cb --- /dev/null +++ b/ui/components/filters/filterSidebarTrigger.tsx @@ -0,0 +1,65 @@ +import { Button } from "@/components/ui/button"; +import { useMobileFilterSlot } from "@/lib/contexts/topbarContext"; +import { Filter, PanelLeftOpen } from "lucide-react"; +import { createPortal } from "react-dom"; + +interface FilterSidebarTriggerProps { + activeFilterCount: number; + onClick: () => void; + testId?: string; +} + +/** + * Shared collapsed-state trigger for filter sidebars. + * + * On mobile the compact trigger is portalled into the topbar, immediately + * before notifications. Desktop keeps the existing full-height sidebar rail. + */ +export function FilterSidebarTrigger({ activeFilterCount, onClick, testId }: FilterSidebarTriggerProps) { + const mobileFilterSlot = useMobileFilterSlot(); + + return ( + <> + {mobileFilterSlot && + createPortal( + , + mobileFilterSlot, + )} + + + + ); +} \ No newline at end of file diff --git a/ui/components/filters/logsFilterSidebar.tsx b/ui/components/filters/logsFilterSidebar.tsx index 22115246a93..aeebfde2d63 100644 --- a/ui/components/filters/logsFilterSidebar.tsx +++ b/ui/components/filters/logsFilterSidebar.tsx @@ -1,3 +1,4 @@ +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -10,7 +11,7 @@ import { RequestTypeLabels, RequestTypes, RoutingEngineUsedLabels, Statuses } fr import { useGetAvailableFilterDataQuery, useGetProvidersQuery } from "@/lib/store"; import type { LogFilters } from "@/lib/types/logs"; import { cn } from "@/lib/utils"; -import { ChevronDown, Filter, LoaderCircle, PanelLeftClose, PanelLeftOpen, Plus, RotateCcw, Search } from "lucide-react"; +import { ChevronDown, LoaderCircle, PanelLeftClose, Plus, RotateCcw, Search } from "lucide-react"; import { Ref, useCallback, useEffect, useMemo, useRef, useState } from "react"; const COLLAPSE_STORAGE_KEY = "logs-filter-sidebar-collapsed"; @@ -71,26 +72,7 @@ export function LogsFilterSidebar({ filters, onFiltersChange }: LogsSidebarProps // Collapsed: thin rail with vertical "Filters" label — whole rail is clickable to expand if (collapsed) { - return ( - - ); + return ; } return ( diff --git a/ui/components/filters/mcpFilterSidebar.tsx b/ui/components/filters/mcpFilterSidebar.tsx index 18d20066472..74bed9842ac 100644 --- a/ui/components/filters/mcpFilterSidebar.tsx +++ b/ui/components/filters/mcpFilterSidebar.tsx @@ -1,3 +1,4 @@ +import { FilterSidebarTrigger } from "@/components/filters/filterSidebarTrigger"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; @@ -10,7 +11,7 @@ import { Statuses } from "@/lib/constants/logs"; import { useGetMCPLogsFilterDataQuery } from "@/lib/store"; import type { MCPToolLogFilters } from "@/lib/types/logs"; import { cn } from "@/lib/utils"; -import { ChevronDown, Filter, LoaderCircle, PanelLeftClose, PanelLeftOpen, Plus, RotateCcw, Search } from "lucide-react"; +import { ChevronDown, LoaderCircle, PanelLeftClose, Plus, RotateCcw, Search } from "lucide-react"; import { Ref, useCallback, useEffect, useMemo, useRef, useState } from "react"; const COLLAPSE_STORAGE_KEY = "mcp-filter-sidebar-collapsed"; @@ -68,26 +69,7 @@ export function MCPFilterSidebar({ filters, onFiltersChange }: MCPFilterSidebarP // Collapsed: thin rail with vertical "Filters" label — whole rail is clickable to expand if (collapsed) { - return ( - - ); + return ; } return ( diff --git a/ui/components/notificationCenter.tsx b/ui/components/notificationCenter.tsx index 36e78ae48a4..35621b5f9bc 100644 --- a/ui/components/notificationCenter.tsx +++ b/ui/components/notificationCenter.tsx @@ -78,7 +78,7 @@ export default function NotificationCenter() { {unreadCount > 0 && ( {unreadCount > 99 ? "99+" : unreadCount} diff --git a/ui/components/topbar.tsx b/ui/components/topbar.tsx index a69bebc9e55..5424820b330 100644 --- a/ui/components/topbar.tsx +++ b/ui/components/topbar.tsx @@ -12,13 +12,15 @@ import { } from "@/components/ui/dropdownMenu"; import { SidebarTrigger } from "@/components/ui/sidebar"; import { IS_ENTERPRISE } from "@/lib/constants/config"; -import { useDescriptionSlotRef, useTopbarTitle } from "@/lib/contexts/topbarContext"; +import { useDescriptionSlotRef, useMobileFilterSlotRef, useTopbarTitle } from "@/lib/contexts/topbarContext"; +import { useBranding } from "@/lib/hooks/useBranding"; import { useGetCoreConfigQuery, useLogoutMutation } from "@/lib/store"; import type { UserInfo } from "@enterprise/lib/store/utils/tokenManager"; import { getUserInfo } from "@enterprise/lib/store/utils/tokenManager"; import { BooksIcon, DiscordLogoIcon, GithubLogoIcon } from "@phosphor-icons/react"; import { useLocation, useNavigate } from "@tanstack/react-router"; import { BugIcon, ChevronDown, LogOut, Menu, User } from "lucide-react"; +import { useTheme } from "next-themes"; import { useEffect, useMemo, useState } from "react"; // External links that used to live in the sidebar footer icon row. They now @@ -84,9 +86,12 @@ function usePageTitle() { export default function Topbar() { const title = usePageTitle(); const setDescriptionSlot = useDescriptionSlotRef(); + const setMobileFilterSlot = useMobileFilterSlotRef(); const navigate = useNavigate(); const [logout] = useLogoutMutation(); const { data: coreConfig } = useGetCoreConfigQuery({}); + const { resolvedTheme } = useTheme(); + const { logoSrc, logoAlt } = useBranding(resolvedTheme === "dark"); // Enterprise SCIM/OAuth stashes the profile in localStorage. Read it after // mount so SSR/first paint doesn't diverge from the hydrated tree. @@ -119,16 +124,18 @@ export default function Topbar() {
+ {logoAlt} {/* text-lg font-semibold is the existing in-page

scale, so hoisting the title here doesn't visually demote it. */} -

{title}

+

{title}

{/* Anchor for 's description popover. Pages portal into this node, so the topbar never has to know their content. */} - +
{/* Theme stays a first-class topbar control rather than a menu entry — it's a display preference, not an account action. */} + @@ -139,16 +146,17 @@ export default function Topbar() { type="button" data-testid="topbar-user-pill" aria-label="Account menu" - className="border-border bg-card/60 text-foreground hover:bg-accent hover:text-accent-foreground flex h-8 max-w-[140px] min-w-0 cursor-pointer items-center gap-1.5 rounded-full border py-0 pr-2 pl-1 transition-colors sm:max-w-[220px]" + className="text-muted-foreground hover:bg-accent hover:text-accent-foreground md:border-border md:bg-card/60 md:text-foreground flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors md:h-8 md:w-auto md:max-w-[220px] md:min-w-0 md:gap-1.5 md:rounded-full md:border md:py-0 md:pr-2 md:pl-1" > - + + {/* min-w-0 + truncate is what keeps a 200-character display name from stretching the pill and pushing the page title out of the topbar. */} - {displayName} - + {displayName} + ) : (