From d6b987981339959eff8e083251f95fc5163524f5 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 21 Aug 2026 11:48:49 +0100 Subject: [PATCH] feat(webui): user and group search filter on usage and charts views Add a "Filter users or groups" search input to UsageView, mirroring OverviewView's model search (same Input component, icon, and clear-button styling). Case-insensitive, trimmed substring match: - A user matches when its own name contains the query. - A group matches when its own name contains the query OR it has at least one matching member. Groups accordion shows only matching groups, sorted through the existing Groups toolbar unchanged. A group that matches only via a member auto-expands (using the same tested override semantics as Overview's provider search); a group matched by its own name is not force-expanded, since the match is already visible on its collapsed trigger row. The nested members table inside an expanded group shows every member when the group matched by name, and only the matching members when it matched via a member. The flat Users table filters to matching users, plus every member of a name-matched group. The Total card and ChartsView's chart rendering are untouched by the filter. ChartsView's scope picker (Select) gets the identical search input, filtering the user/group option list it offers. "Total" always stays in the list, and the currently selected scope is always kept in the list even if a new query would otherwise hide it, so an active chart is never torn down or re-labeled by narrowing the picker. Generalize lib/provider-expand.ts into lib/search-expand.ts: the same two-set (manuallyExpanded/manuallyCollapsed) auto-expand/override state machine now drives both Overview's providers and Usage's groups, keyed on generic string ids instead of provider names specifically. OverviewView.vue is updated to the renamed computeExpandedItems/toggleItemExpand exports; its own behavior is unchanged. The moved spec (search-expand.spec.ts) keeps all 9 original cases plus 2 new ones pinning the same semantics against non-provider (group-shaped) ids. Add lib/usage-search.ts with the shared user/group matching helpers (userMatches, groupNameMatches, membersOfGroup, matchingMembersOfGroup, groupMatches) so UsageView and ChartsView share one matching implementation, with its own vitest spec. UsageTable.vue gains an optional emptyMessage prop (threaded to DataTable) so UsageView can show a "no users match ..."/"no groups match ..." message under an active filter, matching Overview's own alias-search empty-state pattern. No backend/Go logic changes; filtering is client-side over the already-polled GET /admin/api/usage response. --- webui/README.md | 9 +- webui/src/components/ChartsView.vue | 59 +++++- webui/src/components/OverviewView.vue | 27 +-- webui/src/components/UsageTable.vue | 3 + webui/src/components/UsageView.vue | 178 ++++++++++++++++-- webui/src/lib/provider-expand.ts | 83 -------- ...r-expand.spec.ts => search-expand.spec.ts} | 77 +++++--- webui/src/lib/search-expand.ts | 93 +++++++++ webui/src/lib/usage-search.spec.ts | 85 +++++++++ webui/src/lib/usage-search.ts | 58 ++++++ webui/vite.config.ts | 11 +- 11 files changed, 534 insertions(+), 149 deletions(-) delete mode 100644 webui/src/lib/provider-expand.ts rename webui/src/lib/{provider-expand.spec.ts => search-expand.spec.ts} (55%) create mode 100644 webui/src/lib/search-expand.ts create mode 100644 webui/src/lib/usage-search.spec.ts create mode 100644 webui/src/lib/usage-search.ts diff --git a/webui/README.md b/webui/README.md index 20b8fe7..6f234ae 100644 --- a/webui/README.md +++ b/webui/README.md @@ -80,9 +80,12 @@ npm run build # what `make admin-ui` runs, plus webui/generate.mjs expanding a group shows its member users' own usage rows, a client-side join on `AdminUsageEntryView.groupName`. - `src/lib/` — `api.ts` (the `/admin/api/*` fetch wrapper), `format.ts`, - `key-storage.ts`, `chart-setup.ts`, `provider-expand.ts` (search-aware - expand state, adapted to drive Accordion's v-model), `usage-columns.ts` - (shared `ColumnDef`s for every usage table). + `key-storage.ts`, `chart-setup.ts`, `search-expand.ts` (search-aware + expand state, adapted to drive Accordion's v-model — shared by + OverviewView's providers and UsageView's groups), `usage-search.ts` + (shared user/group query-matching helpers, used by UsageView and + ChartsView), `usage-columns.ts` (shared `ColumnDef`s for every usage + table). - `src/types/api.ts` — TypeScript mirrors of admin.go's JSON response shapes (`adminOverviewResponse`, `adminUsageResponse`, `usageHistoryResponse`). diff --git a/webui/src/components/ChartsView.vue b/webui/src/components/ChartsView.vue index 6f1f345..6a2253b 100644 --- a/webui/src/components/ChartsView.vue +++ b/webui/src/components/ChartsView.vue @@ -1,7 +1,9 @@