chore(webui): drop dead clear() from useSearchQuery, add spec, doc composables

- useSearchQuery.ts: remove clear() — zero callers, since SearchInput's
  clear button already clears by emitting update:modelValue('') through
  v-model, no separate imperative clear needed.
- Add composables/useSearchQuery.spec.ts (3 cases: normalized trims,
  normalized lowercases, hasQuery false for whitespace-only query).
- README.md Structure section: document src/composables/ (useThemeColors,
  useSearchQuery) and mention the new shared SearchInput component
  alongside the existing components/lib entries.
This commit is contained in:
2026-08-21 12:17:10 +01:00
parent 3bce93971d
commit 9de2204752
3 changed files with 48 additions and 18 deletions
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest'
import { useSearchQuery } from './useSearchQuery'
describe('useSearchQuery', () => {
it('normalized trims leading/trailing whitespace', () => {
const { query, normalized } = useSearchQuery()
query.value = ' alice '
expect(normalized.value).toBe('alice')
})
it('normalized lowercases the query', () => {
const { query, normalized } = useSearchQuery()
query.value = 'AlIcE'
expect(normalized.value).toBe('alice')
})
it('hasQuery is false for a whitespace-only query', () => {
const { query, hasQuery } = useSearchQuery()
query.value = ' '
expect(hasQuery.value).toBe(false)
})
})
+14 -12
View File
@@ -1,24 +1,26 @@
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,
* useSearchQuery is the one raw-query → {normalized, hasQuery} 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
* pairing; 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.
*
* No `clear()` here — clearing is just setting `query.value = ''`, and
* every caller already gets that for free from SearchInput.vue's own
* clear button emitting `update:modelValue('')` through the `v-model`
* binding, so a separate clear function would be dead API surface no
* caller needs.
*/
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 }
return { query, normalized, hasQuery }
}