Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -75,25 +76,7 @@ export function MCPLibraryFilterSidebar({ filters, onFiltersChange }: SidebarPro

if (collapsed) {
return (
<Button
type="button"
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
data-testid="mcpLibraryFilterSidebar-toggle-show"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
<FilterSidebarTrigger activeFilterCount={activeFilterCount} onClick={toggleCollapsed} testId="mcpLibraryFilterSidebar-toggle-show" />
);
}

Expand Down
23 changes: 3 additions & 20 deletions ui/app/workspace/mcp-registry/views/mcpClientsFilterSidebar.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -131,25 +132,7 @@ export function MCPClientsFilterSidebar({ filters, onFiltersChange }: SidebarPro

if (collapsed) {
return (
<Button
type="button"
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group md:bg-card md:hover:bg-card md:dark:bg-card md:dark:hover:bg-card fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
data-testid="mcpClientsFilterSidebar-toggle-show"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
<FilterSidebarTrigger activeFilterCount={activeFilterCount} onClick={toggleCollapsed} testId="mcpClientsFilterSidebar-toggle-show" />
);
}

Expand Down
36 changes: 6 additions & 30 deletions ui/app/workspace/mcp-sessions/views/mcpSessionsFilterSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
Expand Down Expand Up @@ -165,25 +155,11 @@ export function MCPSessionsFilterSidebar({ filters, onFiltersChange }: SidebarPr

if (collapsed) {
return (
<Button
type="button"
<FilterSidebarTrigger
activeFilterCount={activeFilterCount}
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group md:bg-card md:hover:bg-card md:dark:bg-card md:dark:hover:bg-card fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
data-testid="mcp-sessions-filter-sidebar-toggle-show"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
testId="mcp-sessions-filter-sidebar-toggle-show"
/>
);
}

Expand Down
34 changes: 3 additions & 31 deletions ui/app/workspace/oauth-grants/views/oauthGrantsFilterSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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
Expand Down Expand Up @@ -133,25 +123,7 @@ export function OAuthGrantsFilterSidebar({ filters, onFiltersChange }: SidebarPr

if (collapsed) {
return (
<Button
type="button"
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group md:bg-card md:hover:bg-card md:dark:bg-card md:dark:hover:bg-card fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
data-testid="oauthGrantsFilterSidebar-toggle-show"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
<FilterSidebarTrigger activeFilterCount={activeFilterCount} onClick={toggleCollapsed} testId="oauthGrantsFilterSidebar-toggle-show" />
);
}

Expand Down
65 changes: 65 additions & 0 deletions ui/components/filters/filterSidebarTrigger.tsx
Original file line number Diff line number Diff line change
@@ -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(
<Button
type="button"
onClick={onClick}
variant="ghost"
size="sm"
className="group relative flex size-8 shrink-0 items-center justify-center rounded-sm border-0 p-0 shadow-none md:hidden"
title="Show filters"
aria-label="Show filters"
data-testid={testId ? `${testId}-mobile` : undefined}
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors" />
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium">
{activeFilterCount}
</span>
)}
</Button>,
mobileFilterSlot,
)}

<Button
type="button"
onClick={onClick}
variant="outline"
size="sm"
className="group bg-card hover:bg-card dark:bg-card dark:hover:bg-card hidden h-full w-10 shrink-0 flex-col items-center justify-start gap-3 rounded-l-none rounded-r-md border-0 py-4 shadow-none hover:text-current active:scale-100 md:flex"
title="Show filters"
aria-label="Show filters"
data-testid={testId}
>
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground size-4 transition-colors" />
<span className="rotate-180 select-none [writing-mode:vertical-rl]">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary/10 text-primary flex size-6 items-center justify-center rounded-full text-xs font-medium">
{activeFilterCount}
</span>
)}
</Button>
</>
);
}
24 changes: 3 additions & 21 deletions ui/components/filters/logsFilterSidebar.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -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 (
<Button
type="button"
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group md:bg-card md:hover:bg-card md:dark:bg-card md:dark:hover:bg-card fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
);
return <FilterSidebarTrigger activeFilterCount={activeFilterCount} onClick={toggleCollapsed} />;
}

return (
Expand Down
24 changes: 3 additions & 21 deletions ui/components/filters/mcpFilterSidebar.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";
Expand Down Expand Up @@ -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 (
<Button
type="button"
onClick={toggleCollapsed}
variant="outline"
size="sm"
className="group md:bg-card md:hover:bg-card md:dark:bg-card md:dark:hover:bg-card fixed top-2 right-4 z-30 flex h-8 w-8 shrink-0 flex-row items-center justify-center gap-0 rounded-md p-0 shadow-lg md:static md:h-full md:w-10 md:flex-col md:justify-start md:gap-3 md:rounded-l-none md:rounded-r-md md:border-0 md:py-4 md:shadow-none md:hover:text-current md:active:scale-100"
title="Show filters"
aria-label="Show filters"
>
<Filter className="text-muted-foreground group-hover:text-foreground size-4 transition-colors md:hidden" />
<PanelLeftOpen className="text-muted-foreground group-hover:text-foreground hidden size-4 transition-colors md:block" />
<span className="hidden rotate-180 select-none [writing-mode:vertical-rl] md:block">Filters</span>
{activeFilterCount > 0 && (
<span className="bg-primary text-primary-foreground md:bg-primary/10 md:text-primary absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full text-[10px] font-medium md:static md:size-6 md:text-xs">
{activeFilterCount}
</span>
)}
</Button>
);
return <FilterSidebarTrigger activeFilterCount={activeFilterCount} onClick={toggleCollapsed} />;
}

return (
Expand Down
2 changes: 1 addition & 1 deletion ui/components/notificationCenter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export default function NotificationCenter() {
{unreadCount > 0 && (
<span
data-testid="topbar-notifications-badge"
className="bg-destructive text-destructive-foreground absolute -top-1.5 -right-2 flex min-w-4 items-center justify-center rounded-full px-1 text-[9px] leading-4 font-semibold"
className="absolute -top-1.5 -right-2 flex min-w-4 items-center justify-center rounded-full bg-red-600 px-1 text-[9px] leading-4 font-semibold text-white dark:bg-red-700"
>
{unreadCount > 99 ? "99+" : unreadCount}
</span>
Expand Down
Loading
Loading