From aa3cee641051220c5a05055bdc8fedc41206c28c Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Wed, 18 Mar 2026 11:46:56 +0000 Subject: [PATCH] fix: polish agents UI (sidebar width, combobox, limits padding, back button) (#23204) --- site/src/pages/AgentsPage/AgentCreateForm.tsx | 106 ++++++++++-------- site/src/pages/AgentsPage/AgentsSidebar.tsx | 2 +- .../LimitsTab/DefaultLimitSection.tsx | 8 +- .../LimitsTab/GroupLimitsSection.tsx | 4 +- .../pages/AgentsPage/LimitsTab/LimitsTab.tsx | 13 +-- .../LimitsTab/UserOverridesSection.tsx | 4 +- .../pages/AgentsPage/SettingsPageContent.tsx | 31 +++-- 7 files changed, 86 insertions(+), 82 deletions(-) diff --git a/site/src/pages/AgentsPage/AgentCreateForm.tsx b/site/src/pages/AgentsPage/AgentCreateForm.tsx index ed97a73099..aa11d7d773 100644 --- a/site/src/pages/AgentsPage/AgentCreateForm.tsx +++ b/site/src/pages/AgentsPage/AgentCreateForm.tsx @@ -7,15 +7,19 @@ import { ChevronDownIcon } from "components/AnimatedIcons/ChevronDown"; import type { ModelSelectorOption } from "components/ai-elements"; import { Button } from "components/Button/Button"; import { - Combobox, - ComboboxContent, - ComboboxEmpty, - ComboboxInput, - ComboboxItem, - ComboboxList, - ComboboxTrigger, -} from "components/Combobox/Combobox"; -import { MonitorIcon } from "lucide-react"; + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "components/Command/Command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "components/Popover/Popover"; +import { Check, MonitorIcon } from "lucide-react"; import { useDashboard } from "modules/dashboard/useDashboard"; import { type FC, @@ -191,6 +195,7 @@ export const AgentCreateForm: FC = ({ modelOptions.some((modelOption) => modelOption.id === userSelectedModel) ? userSelectedModel : preferredModelID; + const [workspacePopoverOpen, setWorkspacePopoverOpen] = useState(false); const workspacesQuery = useQuery(workspaces({ q: "owner:me", limit: 0 })); const [selectedWorkspaceId, setSelectedWorkspaceId] = useState( () => { @@ -377,19 +382,17 @@ export const AgentCreateForm: FC = ({ uploadStates={uploadStates} previewUrls={previewUrls} leftActions={ - - handleWorkspaceChange(value ?? autoCreateWorkspaceValue) - } + {/* pointer-events-auto overrides the pointer-events:none - that Radix Select's DismissableLayer sets on - document.body when the Model Selector is open. - Without it the first click only dismisses the - Select and a second click is needed to open - the Combobox. */} - + that Radix Select's DismissableLayer sets on + document.body when the Model Selector is open. + Without it the first click only dismisses the + Select and a second click is needed to open + the popover. */} + - - - - - - Auto-create Workspace - - {workspaceOptions.map((workspace) => ( - - {workspace.owner_name}/{workspace.name} - - ))} - - No workspaces found - - + + + + + + No workspaces found + + { + handleWorkspaceChange(autoCreateWorkspaceValue); + setWorkspacePopoverOpen(false); + }} + > + Auto-create Workspace + {selectedWorkspaceId == null && ( + + )} + + {workspaceOptions.map((workspace) => ( + { + handleWorkspaceChange(workspace.id); + setWorkspacePopoverOpen(false); + }} + > + {workspace.owner_name}/{workspace.name} + {selectedWorkspaceId === workspace.id && ( + + )} + + ))} + + + + + } />

diff --git a/site/src/pages/AgentsPage/AgentsSidebar.tsx b/site/src/pages/AgentsPage/AgentsSidebar.tsx index 8eec996306..daa5b8d8aa 100644 --- a/site/src/pages/AgentsPage/AgentsSidebar.tsx +++ b/site/src/pages/AgentsPage/AgentsSidebar.tsx @@ -709,7 +709,7 @@ export const AgentsSidebar: FC = (props) => { aria-hidden={sidebarView.panel === "settings"} inert={sidebarView.panel === "settings" ? true : undefined} > -

+
{logoUrl ? ( diff --git a/site/src/pages/AgentsPage/LimitsTab/DefaultLimitSection.tsx b/site/src/pages/AgentsPage/LimitsTab/DefaultLimitSection.tsx index e2fd4a5396..ec62f7028f 100644 --- a/site/src/pages/AgentsPage/LimitsTab/DefaultLimitSection.tsx +++ b/site/src/pages/AgentsPage/LimitsTab/DefaultLimitSection.tsx @@ -28,7 +28,6 @@ interface DefaultLimitSectionProps { onAmountDollarsChange: (amount: string) => void; unpricedModelCount: number; adminBadge: ReactNode; - panelClassName: string; } export const DefaultLimitSection: FC = ({ @@ -40,20 +39,19 @@ export const DefaultLimitSection: FC = ({ onAmountDollarsChange, unpricedModelCount, adminBadge, - panelClassName, }) => { const periodId = useId(); const amountId = useId(); return ( - <> +
-
+

@@ -134,6 +132,6 @@ export const DefaultLimitSection: FC = ({

)} - +
); }; diff --git a/site/src/pages/AgentsPage/LimitsTab/GroupLimitsSection.tsx b/site/src/pages/AgentsPage/LimitsTab/GroupLimitsSection.tsx index 619c37543f..a314560bbc 100644 --- a/site/src/pages/AgentsPage/LimitsTab/GroupLimitsSection.tsx +++ b/site/src/pages/AgentsPage/LimitsTab/GroupLimitsSection.tsx @@ -29,7 +29,6 @@ interface GroupLimitsSectionProps { member_count: number; spend_limit_micros: number | null; }>; - panelClassName: string; showGroupForm: boolean; onShowGroupFormChange: (show: boolean) => void; selectedGroup: Group | null; @@ -50,7 +49,6 @@ interface GroupLimitsSectionProps { export const GroupLimitsSection: FC = ({ groupOverrides, - panelClassName, showGroupForm, onShowGroupFormChange, selectedGroup, @@ -78,7 +76,7 @@ export const GroupLimitsSection: FC = ({ description="Override the default limit for specific groups. When a user belongs to multiple groups, the lowest group limit applies." /> -
+
{groupOverrides.length > 0 ? ( diff --git a/site/src/pages/AgentsPage/LimitsTab/LimitsTab.tsx b/site/src/pages/AgentsPage/LimitsTab/LimitsTab.tsx index d1c3022124..5f20025b86 100644 --- a/site/src/pages/AgentsPage/LimitsTab/LimitsTab.tsx +++ b/site/src/pages/AgentsPage/LimitsTab/LimitsTab.tsx @@ -30,8 +30,6 @@ import { GroupLimitsSection } from "./GroupLimitsSection"; import { normalizeChatUsageLimitPeriod } from "./limitsFormLogic"; import { UserOverridesSection } from "./UserOverridesSection"; -const sectionPanelClassName = "space-y-4 rounded-lg border border-border p-4"; - interface DefaultLimitFormValues { enabled: boolean; period: ChatUsageLimitPeriod; @@ -305,8 +303,8 @@ export const LimitsTab: FC = () => { saveDefault, }) => ( <> -
-
+
+
} enabled={enabled} @@ -325,12 +323,9 @@ export const LimitsTab: FC = () => { onAmountDollarsChange(nextAmountDollars); }} unpricedModelCount={unpricedModelCount} - panelClassName={sectionPanelClassName} /> - { } groupsError={groupsQuery.isError ? groupsQuery.error : null} /> - {
-
+
{updateConfigMutation.isError && (

diff --git a/site/src/pages/AgentsPage/LimitsTab/UserOverridesSection.tsx b/site/src/pages/AgentsPage/LimitsTab/UserOverridesSection.tsx index b833348a9f..939384a885 100644 --- a/site/src/pages/AgentsPage/LimitsTab/UserOverridesSection.tsx +++ b/site/src/pages/AgentsPage/LimitsTab/UserOverridesSection.tsx @@ -26,7 +26,6 @@ interface UserOverridesSectionProps { avatar_url: string; spend_limit_micros: number | null; }>; - panelClassName: string; showUserForm: boolean; onShowUserFormChange: (show: boolean) => void; selectedUser: User | null; @@ -44,7 +43,6 @@ interface UserOverridesSectionProps { export const UserOverridesSection: FC = ({ overrides, - panelClassName, showUserForm, onShowUserFormChange, selectedUser, @@ -68,7 +66,7 @@ export const UserOverridesSection: FC = ({ description="Override the deployment default spend limit for specific users. User overrides take highest priority, followed by group limits, then the deployment default." /> -

+
{overrides.length > 0 ? (
diff --git a/site/src/pages/AgentsPage/SettingsPageContent.tsx b/site/src/pages/AgentsPage/SettingsPageContent.tsx index 8cc82ad465..5a15cae9cf 100644 --- a/site/src/pages/AgentsPage/SettingsPageContent.tsx +++ b/site/src/pages/AgentsPage/SettingsPageContent.tsx @@ -35,7 +35,7 @@ import { import dayjs from "dayjs"; import { useDebouncedValue } from "hooks/debounce"; import { useClickableTableRow } from "hooks/useClickableTableRow"; -import { FlaskConicalIcon, ShieldIcon } from "lucide-react"; +import { ChevronLeftIcon, FlaskConicalIcon, ShieldIcon } from "lucide-react"; import { type FC, type FormEvent, useCallback, useMemo, useState } from "react"; import { keepPreviousData, @@ -182,20 +182,9 @@ const UsageContent: FC = ({ now }) => { } badge={} action={ - selectedUser ? ( - - ) : ( - - {dateRange.rangeLabel} - - ) + + {dateRange.rangeLabel} + } /> ); @@ -203,7 +192,17 @@ const UsageContent: FC = ({ now }) => { if (selectedUser) { return (
- {header} +
+ + {header} +