inventorySearch.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import type { InventorySpool } from '../api/client';
  2. import { resolveSpoolColorName } from './colors';
  3. /**
  4. * Return true when spool matches the search query across all searchable text fields.
  5. * Case-insensitive. Empty query always returns true.
  6. */
  7. export function spoolMatchesQuery(spool: InventorySpool, query: string): boolean {
  8. const q = query.trim().toLowerCase();
  9. if (!q) return true;
  10. // A hash-prefixed number is an explicit spool ID lookup. Keep plain numeric
  11. // searches backwards-compatible ("3" can still match #3, #13, #30, ...),
  12. // while "#3" selects only the physical spool whose label says #3.
  13. const exactIdQuery = q.match(/^#(\d+)$/);
  14. if (exactIdQuery) {
  15. return spool.id === Number(exactIdQuery[1]);
  16. }
  17. return (
  18. String(spool.id).includes(q) ||
  19. spool.material.toLowerCase().includes(q) ||
  20. (spool.brand?.toLowerCase().includes(q) ?? false) ||
  21. // Both the stored name and the displayed one. They differ often: a Bambu
  22. // tag may carry no colour name or an internal code, and Spoolman has no
  23. // such field, so what the list shows is usually resolved from the swatch's
  24. // hex. Searching only the stored value means typing what you can plainly
  25. // read finds nothing (#3090).
  26. (spool.color_name?.toLowerCase().includes(q) ?? false) ||
  27. (resolveSpoolColorName(spool.color_name, spool.rgba, spool.color_name_is_synthesized)
  28. ?.toLowerCase()
  29. .includes(q) ??
  30. false) ||
  31. (spool.subtype?.toLowerCase().includes(q) ?? false) ||
  32. (spool.note?.toLowerCase().includes(q) ?? false) ||
  33. (spool.slicer_filament_name?.toLowerCase().includes(q) ?? false) ||
  34. (spool.storage_location?.toLowerCase().includes(q) ?? false) ||
  35. (spool.material_number?.toLowerCase().includes(q) ?? false) ||
  36. (spool.suppliers?.some(
  37. (link) =>
  38. link.supplier_name.toLowerCase().includes(q) ||
  39. (link.supplier_article_number?.toLowerCase().includes(q) ?? false)
  40. ) ?? false)
  41. );
  42. }
  43. /** Filter a spool list by a free-text search query. */
  44. export function filterSpoolsByQuery(spools: InventorySpool[], query: string): InventorySpool[] {
  45. if (!query) return spools;
  46. return spools.filter((spool) => spoolMatchesQuery(spool, query));
  47. }