mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-15 05:29:28 +00:00
fix(webui): shared SearchInput/useSearchQuery, correct expand rationale
Address review of the user/group search filter (feat/user-search):
- Correct the "group name match does not auto-expand" rationale in
UsageView.vue and lib/search-expand.ts. The prior comment claimed
Overview has no provider-name search — false: OverviewView's
providerMatches checks each model's full ROUTABLE id
(`${provider}/${model}`, lib/format.ts's routableModelId), so a
provider-name query does match and auto-expand there. The actual
reason Usage withholds auto-expand from a name-only match: a group's
name is already legible on its collapsed trigger row, so expanding
every name match too would dump full member rosters for no reason;
a member-only match has no such shortcut and still needs the reveal.
Behavior is unchanged — only the (now accurate) justification.
- Extract components/SearchInput.vue and composables/useSearchQuery.ts.
OverviewView's model search, UsageView's user/group search, and
ChartsView's scope-picker search were three ~22-line copies of the
same icon+Input+clear-button markup, plus three copies of the
query/normalized/hasQuery/clear quartet. All three views now consume
the shared component/composable. SearchInput's clear button is a real
shadcn Button (variant="ghost", size="icon-xs" — 24x24px) instead of a
hand-rolled <button>, fixing a WCAG 2.2 SC 2.5.8 hit-target/
focus-visible gap once instead of three times.
- ChartsView's search input: w-48 (clipped the 22-char placeholder) to
w-56, matching the sibling SelectTrigger's width.
- UsageView.vue's visibleMembers now calls the exported, tested
matchingMembersOfGroup helper instead of re-implementing the same
filter inline with userMatches.
- Reworded the "shared with ChartsView.vue" claims on membersOfGroup
(usage-search.ts) and in UsageView.vue's visibleMembers doc comment:
ChartsView never calls membersOfGroup directly, only indirectly via
groupMatches -> matchingMembersOfGroup.
- UsageView's groups/users empty-state messages now follow Overview's
aliasEmptyMessage three-way pattern ("none configured" vs "no
groups/users match ..." vs "none"), distinguishing nothing-configured
from nothing-matches instead of collapsing both to the same text.
Gate unchanged: npm run build + npm test + vue-tsc, make admin-ui
(separate regen commit), go test ./... -count=1, gofmt/vet, make
yaegi-check.
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
/**
|
||||
* useSearchQuery is the one raw-query → {normalized, hasQuery, clear}
|
||||
* adapter every search filter in this panel uses — OverviewView's model
|
||||
* search, UsageView's user/group search, ChartsView's scope-picker search
|
||||
* all had their own copy of this identical query/normalizedQuery/hasQuery/
|
||||
* clearQuery quartet; extracted so it exists once (vue.md: "if you've
|
||||
* written it twice, you owe an abstraction"). Callers still own their own
|
||||
* matching logic entirely (OverviewView's modelMatches/providerMatches,
|
||||
* lib/usage-search.ts's helpers) — this only normalizes the raw input the
|
||||
* same way every call site already agreed on: trimmed, lowercased.
|
||||
*/
|
||||
export function useSearchQuery() {
|
||||
const query = ref('')
|
||||
const normalized = computed(() => query.value.trim().toLowerCase())
|
||||
const hasQuery = computed(() => normalized.value.length > 0)
|
||||
|
||||
function clear(): void {
|
||||
query.value = ''
|
||||
}
|
||||
|
||||
return { query, normalized, hasQuery, clear }
|
||||
}
|
||||
Reference in New Issue
Block a user