From 39e7ac467532be1d98dc2c15d114cc9c9c77b27e Mon Sep 17 00:00:00 2001 From: Suresh Chaudhary Date: Tue, 19 May 2026 20:06:53 +0530 Subject: [PATCH 1/4] Chore: Added a close button to the toast notification --- ui/app/clientLayout.tsx | 2 +- ui/app/globals.css | 14 ++++++++++++++ ui/app/pprof/layout.tsx | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/app/clientLayout.tsx b/ui/app/clientLayout.tsx index 85e501f2d0..49d095f501 100644 --- a/ui/app/clientLayout.tsx +++ b/ui/app/clientLayout.tsx @@ -73,7 +73,7 @@ export function ClientLayout({ children }: { children: React.ReactNode }) { return ( - + diff --git a/ui/app/globals.css b/ui/app/globals.css index a54de67f73..474730b3bf 100644 --- a/ui/app/globals.css +++ b/ui/app/globals.css @@ -388,4 +388,18 @@ div.content-container:has(.no-border-parent) #trial-notification-banner { [data-streamdown="code-block"], [data-streamdown="code-block-body"] { @apply rounded-sm!; +} + +/* Move Sonner toast close button to top-right */ +[data-sonner-toaster][dir="ltr"], +[data-sonner-toaster] { + --toast-close-button-start: unset !important; + --toast-close-button-end: 0 !important; + --toast-close-button-transform: translate(35%, -35%) !important; +} + +[data-sonner-toast][data-styled="true"] [data-close-button] { + left: auto !important; + right: 0 !important; + transform: translate(35%, -35%) !important; } \ No newline at end of file diff --git a/ui/app/pprof/layout.tsx b/ui/app/pprof/layout.tsx index 9a64e7319a..a866de5eed 100644 --- a/ui/app/pprof/layout.tsx +++ b/ui/app/pprof/layout.tsx @@ -13,7 +13,7 @@ function PprofLayout({ children }: { children: React.ReactNode }) { return ( - +
{children}
From 6ca2e787f3e6ff0d6e30f6900e987a104229648d Mon Sep 17 00:00:00 2001 From: Suresh Chaudhary Date: Tue, 19 May 2026 22:31:58 +0530 Subject: [PATCH 2/4] fix: dropdown open state in the vkey table --- .../overrides/scopedPricingOverridesView.tsx | 98 ++++++++------ .../governance/views/customerTable.tsx | 14 +- .../workspace/governance/views/teamsTable.tsx | 5 +- ui/app/workspace/logs/views/columns.tsx | 52 +++++--- .../mcp-logs/views/mcpLogDetailsSheet.tsx | 27 ++-- .../mcp-registry/views/mcpClientsTable.tsx | 120 +++++++++++------- .../model-limits/views/modelLimitsTable.tsx | 108 ++++++++++------ .../views/modelProviderKeysTableView.tsx | 86 +++++++++---- .../routing-rules/views/routingRulesTable.tsx | 108 ++++++++++------ .../virtual-keys/views/virtualKeysTable.tsx | 5 +- 10 files changed, 395 insertions(+), 228 deletions(-) diff --git a/ui/app/workspace/custom-pricing/overrides/scopedPricingOverridesView.tsx b/ui/app/workspace/custom-pricing/overrides/scopedPricingOverridesView.tsx index 92f0f64d93..1a6d419081 100644 --- a/ui/app/workspace/custom-pricing/overrides/scopedPricingOverridesView.tsx +++ b/ui/app/workspace/custom-pricing/overrides/scopedPricingOverridesView.tsx @@ -32,6 +32,61 @@ import { toast } from "sonner"; import PricingOverrideSheet from "./pricingOverrideSheet"; import { PricingOverridesEmptyState } from "./pricingOverridesEmptyState"; +function PricingOverrideActionsMenu({ + row, + onEdit, + onDelete, +}: { + row: PricingOverride; + onEdit: (row: PricingOverride) => void; + onDelete: (row: PricingOverride) => void; +}) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + event.stopPropagation()}> + + + + { + e.preventDefault(); + onEdit(row); + setIsOpen(false); + }} + > + + Edit + + { + e.preventDefault(); + onDelete(row); + setIsOpen(false); + }} + > + + Delete + + + + ); +} + type ScopeFilter = "all" | PricingOverrideScopeKind; function parseScopeKind(value: string | null): ScopeFilter { @@ -314,44 +369,11 @@ export default function ScopedPricingOverridesView() { {row.pattern} e.stopPropagation()}>
- - event.stopPropagation()}> - - - - { - event.stopPropagation(); - openEditDrawer(row); - }} - > - - Edit - - { - event.stopPropagation(); - setDeleteTarget(row); - }} - > - - Delete - - - +
diff --git a/ui/app/workspace/governance/views/customerTable.tsx b/ui/app/workspace/governance/views/customerTable.tsx index a51ab10784..a5415a5587 100644 --- a/ui/app/workspace/governance/views/customerTable.tsx +++ b/ui/app/workspace/governance/views/customerTable.tsx @@ -44,8 +44,10 @@ interface CustomerActionsMenuProps { } function CustomerActionsMenu({ customer, canUpdate, canDelete, onEdit, onDelete }: CustomerActionsMenuProps) { + const [isOpen, setIsOpen] = useState(false); + return ( - + + + + { + e.preventDefault(); + onDelete(log); + setIsOpen(false); + }} + > + + Delete + + + + ); +} function getAssistantToolCallSummary(log?: LogEntry): string { const toolCalls = log?.output_message?.tool_calls || []; @@ -357,27 +387,7 @@ export const createColumns = ( const log = row.original; return (
- - event.stopPropagation()}> - - - - { - event.stopPropagation(); - onDelete(log); - }} - > - - Delete - - - +
); }, diff --git a/ui/app/workspace/mcp-logs/views/mcpLogDetailsSheet.tsx b/ui/app/workspace/mcp-logs/views/mcpLogDetailsSheet.tsx index 878d5543fe..7bae311537 100644 --- a/ui/app/workspace/mcp-logs/views/mcpLogDetailsSheet.tsx +++ b/ui/app/workspace/mcp-logs/views/mcpLogDetailsSheet.tsx @@ -7,7 +7,6 @@ import { AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, - AlertDialogTrigger, } from "@/components/ui/alertDialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -77,6 +76,7 @@ export function MCPLogDetailSheet({ hasNext = false, }: MCPLogDetailSheetProps) { const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [dropdownOpen, setDropdownOpen] = useState(false); const { data: fullLog, isLoading, @@ -144,7 +144,7 @@ export function MCPLogDetailSheet({ - + + + + {hasUpdateAccess && ( + { + e.preventDefault(); + onReconnect(client); + setIsOpen(false); + }} + > + + Reconnect + + )} + {hasDeleteAccess && ( + { + e.preventDefault(); + onDelete(client); + setIsOpen(false); + }} + > + + Delete + + )} + + + ); +} + interface MCPClientsTableProps { mcpClients: MCPClient[]; totalCount: number; @@ -318,51 +384,15 @@ export default function MCPClientsTable({ className={`bg-card group-hover:bg-muted/50 sticky right-0 z-10 text-right ${PIN_SHADOW_RIGHT}`} onClick={(e) => e.stopPropagation()} > - - - - - - {hasUpdateMCPClientAccess && ( - { - e.preventDefault(); - void handleReconnect(c); - }} - > - - Reconnect - - )} - {hasDeleteMCPClientAccess && ( - { - e.preventDefault(); - setClientToDelete(c); - }} - > - - Delete - - )} - - + void handleReconnect(client)} + onDelete={setClientToDelete} + /> ); diff --git a/ui/app/workspace/model-limits/views/modelLimitsTable.tsx b/ui/app/workspace/model-limits/views/modelLimitsTable.tsx index f3e94c2f12..e8a1d0d5ef 100644 --- a/ui/app/workspace/model-limits/views/modelLimitsTable.tsx +++ b/ui/app/workspace/model-limits/views/modelLimitsTable.tsx @@ -40,6 +40,67 @@ const toTestIdPart = (value: string) => .replace(/[^a-z0-9]+/g, "-") .replace(/^-|-$/g, ""); +function ModelLimitActionsMenu({ + config, + hasUpdateAccess, + hasDeleteAccess, + onEdit, + onDelete, +}: { + config: ModelConfig; + hasUpdateAccess: boolean; + hasDeleteAccess: boolean; + onEdit: (config: ModelConfig) => void; + onDelete: (configId: string) => void; +}) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + e.stopPropagation()}> + + + + { + e.preventDefault(); + onEdit(config); + setIsOpen(false); + }} + > + + Edit + + { + e.preventDefault(); + onDelete(config.id); + setIsOpen(false); + }} + > + + Delete + + + + ); +} + interface ModelLimitsTableProps { modelConfigs: ModelConfig[]; totalCount: number; @@ -371,46 +432,13 @@ export default function ModelLimitsTable({ e.stopPropagation()}>
- - e.stopPropagation()}> - - - - { - e.stopPropagation(); - handleEditModelLimit(config); - }} - data-testid={`model-limit-button-edit-${toTestIdPart(config.model_name)}-${toTestIdPart(config.provider || "all")}`} - > - - Edit - - { - e.stopPropagation(); - setDeleteModelConfigId(config.id); - }} - data-testid={`model-limit-button-delete-${toTestIdPart(config.model_name)}-${toTestIdPart(config.provider || "all")}`} - > - - Delete - - - +
diff --git a/ui/app/workspace/providers/views/modelProviderKeysTableView.tsx b/ui/app/workspace/providers/views/modelProviderKeysTableView.tsx index e6f4e91868..a0f6c12d6d 100644 --- a/ui/app/workspace/providers/views/modelProviderKeysTableView.tsx +++ b/ui/app/workspace/providers/views/modelProviderKeysTableView.tsx @@ -31,6 +31,57 @@ interface Props { isKeyless?: boolean; } +function ProviderKeyActionsMenu({ + keyId, + hasUpdateAccess, + hasDeleteAccess, + onEdit, + onDelete, +}: { + keyId: string; + hasUpdateAccess: boolean; + hasDeleteAccess: boolean; + onEdit: (keyId: string) => void; + onDelete: (keyId: string) => void; +}) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + + + + + { + e.preventDefault(); + onEdit(keyId); + setIsOpen(false); + }} + disabled={!hasUpdateAccess} + > + + Edit + + { + e.preventDefault(); + onDelete(keyId); + setIsOpen(false); + }} + disabled={!hasDeleteAccess} + > + + Delete + + + + ); +} + export default function ModelProviderKeysTableView({ provider, className, headerActions, isKeyless }: Props) { const providerName = provider.name?.toLowerCase() ?? ""; const isVLLM = providerName === "vllm"; @@ -265,34 +316,13 @@ export default function ModelProviderKeysTableView({ provider, className, header
{hasUpdateProviderAccess || hasDeleteProviderAccess ? ( - - - - - - { - setShowAddNewKeyDialog({ show: true, keyId: key.id }); - }} - disabled={!hasUpdateProviderAccess} - > - - Edit - - { - setShowDeleteKeyDialog({ show: true, keyId: key.id }); - }} - disabled={!hasDeleteProviderAccess} - > - - Delete - - - + setShowAddNewKeyDialog({ show: true, keyId })} + onDelete={(keyId) => setShowDeleteKeyDialog({ show: true, keyId })} + /> ) : null}
diff --git a/ui/app/workspace/routing-rules/views/routingRulesTable.tsx b/ui/app/workspace/routing-rules/views/routingRulesTable.tsx index 728d6fc30b..051ed548ce 100644 --- a/ui/app/workspace/routing-rules/views/routingRulesTable.tsx +++ b/ui/app/workspace/routing-rules/views/routingRulesTable.tsx @@ -29,6 +29,67 @@ import { ChevronLeft, ChevronRight, Edit, MoreHorizontal, Search, Trash2 } from import { useState } from "react"; import { toast } from "sonner"; +function RoutingRuleActionsMenu({ + rule, + canUpdate, + canDelete, + onEdit, + onDelete, +}: { + rule: RoutingRule; + canUpdate: boolean; + canDelete: boolean; + onEdit: (rule: RoutingRule) => void; + onDelete: (ruleId: string) => void; +}) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + e.stopPropagation()}> + + + + { + e.preventDefault(); + onEdit(rule); + setIsOpen(false); + }} + > + + Edit + + { + e.preventDefault(); + onDelete(rule.id); + setIsOpen(false); + }} + > + + Delete + + + + ); +} + interface RoutingRulesTableProps { rules: RoutingRule[] | undefined; totalCount: number; @@ -192,46 +253,13 @@ export function RoutingRulesTable({ e.stopPropagation()}>
- - e.stopPropagation()}> - - - - { - e.stopPropagation(); - onEdit(rule); - }} - data-testid={`routing-rule-edit-${rule.id}-btn`} - > - - Edit - - { - e.stopPropagation(); - setDeleteRuleId(rule.id); - }} - data-testid={`routing-rule-delete-${rule.id}-btn`} - > - - Delete - - - +
diff --git a/ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx b/ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx index 9d6397f1b2..7de9e77a4a 100644 --- a/ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx +++ b/ui/app/workspace/virtual-keys/views/virtualKeysTable.tsx @@ -168,12 +168,13 @@ function VKActionsMenu({ onEdit: (vk: VirtualKey) => void; onDelete: (vkId: string) => void; }) { + const [isOpen, setIsOpen] = useState(false); const { isManagedByProfile } = useVirtualKeyUsage(vk); const [deleteOpen, setDeleteOpen] = useState(false); return ( <> - +