From 0c9771a38bbaa8f90d4a7c92446a680c5909f71c Mon Sep 17 00:00:00 2001 From: Matt Vollmer Date: Thu, 19 Mar 2026 19:14:10 -0400 Subject: [PATCH] fix: search usage by name or username (#23317) ## Summary The search field on `/agents/settings/usage` previously only matched against usernames. This updates the SQL query to also match against the user's display name via `ILIKE`, and updates the frontend placeholder and variable names to reflect the broader search scope. ## Changes - **SQL** (`coderd/database/queries/chats.sql`, `coderd/database/queries.sql.go`): Added `OR u.name ILIKE '%' || @username::text || '%'` to the `GetChatCostPerUser` query's WHERE clause. - **Frontend** (`site/src/pages/AgentsPage/SettingsPageContent.tsx`): Renamed `usernameFilter`/`debouncedUsername` to `searchFilter`/`debouncedSearch`, updated placeholder to "Search by name or username". --- PR generated with Coder Agents --- coderd/database/queries.sql.go | 1 + coderd/database/queries/chats.sql | 1 + .../AgentsPage/SettingsPageContent.stories.tsx | 4 ++-- site/src/pages/AgentsPage/SettingsPageContent.tsx | 14 +++++++------- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 9421b60260..41fc0175b9 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -4062,6 +4062,7 @@ WITH chat_cost_users AS ( AND ( $5::text = '' OR u.username ILIKE '%' || $5::text || '%' + OR u.name ILIKE '%' || $5::text || '%' ) GROUP BY c.owner_id, diff --git a/coderd/database/queries/chats.sql b/coderd/database/queries/chats.sql index a6b405a576..4a8af3921f 100644 --- a/coderd/database/queries/chats.sql +++ b/coderd/database/queries/chats.sql @@ -725,6 +725,7 @@ WITH chat_cost_users AS ( AND ( @username::text = '' OR u.username ILIKE '%' || @username::text || '%' + OR u.name ILIKE '%' || @username::text || '%' ) GROUP BY c.owner_id, diff --git a/site/src/pages/AgentsPage/SettingsPageContent.stories.tsx b/site/src/pages/AgentsPage/SettingsPageContent.stories.tsx index 87097cd85e..9b6891c110 100644 --- a/site/src/pages/AgentsPage/SettingsPageContent.stories.tsx +++ b/site/src/pages/AgentsPage/SettingsPageContent.stories.tsx @@ -203,7 +203,7 @@ export const UsageUserList: Story = { // Verify the search field is present. await expect( - canvas.getByPlaceholderText("Filter by username"), + canvas.getByPlaceholderText("Search by name or username"), ).toBeInTheDocument(); }, }; @@ -302,7 +302,7 @@ export const UsageUserDrillInAndBack: Story = { // The search field should be present, confirming we're // back on the list view. await expect( - body.getByPlaceholderText("Filter by username"), + body.getByPlaceholderText("Search by name or username"), ).toBeInTheDocument(); }, }; diff --git a/site/src/pages/AgentsPage/SettingsPageContent.tsx b/site/src/pages/AgentsPage/SettingsPageContent.tsx index afbc45dcdb..3ff9377b70 100644 --- a/site/src/pages/AgentsPage/SettingsPageContent.tsx +++ b/site/src/pages/AgentsPage/SettingsPageContent.tsx @@ -125,8 +125,8 @@ interface UsageContentProps { const UsageContent: FC = ({ now }) => { const [searchParams, setSearchParams] = useSearchParams(); - const [usernameFilter, setUsernameFilter] = useState(""); - const debouncedUsername = useDebouncedValue(usernameFilter, 300); + const [searchFilter, setSearchFilter] = useState(""); + const debouncedSearch = useDebouncedValue(searchFilter, 300); const [page, setPage] = useState(1); const dateRange = useMemo(() => { const end = now ?? dayjs(); @@ -143,7 +143,7 @@ const UsageContent: FC = ({ now }) => { ...chatCostUsers({ start_date: dateRange.startDate, end_date: dateRange.endDate, - username: debouncedUsername || undefined, + username: debouncedSearch || undefined, limit: pageSize, offset, }), @@ -283,13 +283,13 @@ const UsageContent: FC = ({ now }) => {
{ - setUsernameFilter(value); + setSearchFilter(value); setPage(1); }} - placeholder="Filter by username" - aria-label="Filter usage by username" + placeholder="Search by name or username" + aria-label="Search usage by name or username" />
{usersQuery.data && (