feat(search): recherche intelligente — parsing backend + pg_trgm fuzzy
- parseSearchTokens() côté backend : extrait type (async/openapi), version (v1, 1.2.3) et latestOnly depuis la chaîne brute - Recherche fuzzy via word_similarity (pg_trgm, seuil 0.5) + ILIKE - latestOnly automatique quand champ non vide sans version explicite - Suppression de parseSearch() dans BrowseComponent et CatalogComponent - Suppression de version/latestOnly de ApiListQuery (géré par le backend) - Activation de pg_trgm via CREATE EXTENSION dans SeederService - Tests unitaires Vitest pour parseSearchTokens (24 cas) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -74,7 +74,7 @@ import { CategoryDeleteModalComponent } from '../../shared/category-delete-modal
|
||||
<!-- Barre de recherche -->
|
||||
<div class="fr-search-bar fr-mb-3w">
|
||||
<label class="fr-label" for="search-api">Rechercher</label>
|
||||
<input id="search-api" class="fr-input" type="search" placeholder="Titre, description..."
|
||||
<input id="search-api" class="fr-input" type="search" placeholder="Ex : auth async v1.0, openapi latest..."
|
||||
[value]="searchQuery()"
|
||||
(input)="onSearchChange($any($event.target).value)" />
|
||||
</div>
|
||||
@@ -365,10 +365,11 @@ export class BrowseComponent implements OnInit {
|
||||
|
||||
loadSearch() {
|
||||
this.searchLoading.set(true);
|
||||
const q = this.searchQuery().trim().toLowerCase();
|
||||
const raw = this.searchQuery();
|
||||
const q = raw.trim().toLowerCase();
|
||||
|
||||
forkJoin({
|
||||
apis: this.apiService.list({ search: this.searchQuery(), page: this.searchPage(), limit: this.searchLimit }),
|
||||
apis: this.apiService.list({ search: raw || undefined, page: this.searchPage(), limit: this.searchLimit }),
|
||||
categories: this.categoryService.list(),
|
||||
}).subscribe({
|
||||
next: ({ apis, categories }) => {
|
||||
@@ -376,9 +377,7 @@ export class BrowseComponent implements OnInit {
|
||||
this.searchTotal.set(apis.total);
|
||||
this.searchCategoryResults.set(
|
||||
categories.items.filter(
|
||||
(c) =>
|
||||
c.name.toLowerCase().includes(q) ||
|
||||
(c.description ?? '').toLowerCase().includes(q),
|
||||
(c) => c.name.toLowerCase().includes(q) || (c.description ?? '').toLowerCase().includes(q),
|
||||
),
|
||||
);
|
||||
this.searchLoading.set(false);
|
||||
|
||||
@@ -41,7 +41,7 @@ import { ApiEntryListItem, ApiType } from '@datacat/shared';
|
||||
id="search-input"
|
||||
class="fr-input"
|
||||
type="search"
|
||||
placeholder="Rechercher par titre ou description..."
|
||||
placeholder="Ex : auth async v1.0, openapi latest..."
|
||||
[ngModel]="search()"
|
||||
(ngModelChange)="onSearchChange($event)"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user