From 185af655191ed04362b5ab4341da1e5a3a61f151 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Wed, 11 Feb 2026 15:32:54 +0100 Subject: [PATCH] fix(filters) : repair broken filters on catalog and document pages - modelTypes.ts: use API Platform OrderFilter format (order[field]=dir) and proper page param - product-catalog: load all products (itemsPerPage: 200) instead of default 30 - documents: load all documents (itemsPerPage: 200) instead of default 30 - useDocuments: support itemsPerPage option in loadDocuments/loadFromEndpoint - pieces-catalog + component-catalog: add force:true to bypass stale cache on sort/filter Co-Authored-By: Claude Opus 4.6 --- app/composables/useDocuments.ts | 9 +++--- app/pages/component-catalog.vue | 3 +- app/pages/documents.vue | 2 +- app/pages/pieces-catalog.vue | 3 +- app/pages/product-catalog.vue | 4 +-- app/services/modelTypes.ts | 56 +++++++++++++-------------------- 6 files changed, 33 insertions(+), 44 deletions(-) diff --git a/app/composables/useDocuments.ts b/app/composables/useDocuments.ts index b34e549..244dc6c 100644 --- a/app/composables/useDocuments.ts +++ b/app/composables/useDocuments.ts @@ -49,11 +49,12 @@ export function useDocuments() { const loadFromEndpoint = async ( endpoint: string, - { updateStore = false }: { updateStore?: boolean } = {}, + { updateStore = false, itemsPerPage }: { updateStore?: boolean; itemsPerPage?: number } = {}, ): Promise => { loading.value = true try { - const result = await get(endpoint) + const url = itemsPerPage ? `${endpoint}${endpoint.includes('?') ? '&' : '?'}itemsPerPage=${itemsPerPage}` : endpoint + const result = await get(url) if (result.success) { const data = extractCollection(result.data) if (updateStore) { @@ -76,9 +77,9 @@ export function useDocuments() { } const loadDocuments = async ( - options: { updateStore?: boolean } = {}, + options: { updateStore?: boolean; itemsPerPage?: number } = {}, ): Promise => { - return loadFromEndpoint('/documents', { updateStore: options.updateStore ?? true }) + return loadFromEndpoint('/documents', { updateStore: options.updateStore ?? true, itemsPerPage: options.itemsPerPage }) } const loadDocumentsBySite = async ( diff --git a/app/pages/component-catalog.vue b/app/pages/component-catalog.vue index 08caf40..93f4971 100644 --- a/app/pages/component-catalog.vue +++ b/app/pages/component-catalog.vue @@ -234,7 +234,8 @@ const fetchComposants = async () => { page: currentPage.value, itemsPerPage: itemsPerPage.value, orderBy: sortField.value, - orderDir: sortDirection.value + orderDir: sortDirection.value, + force: true }) } diff --git a/app/pages/documents.vue b/app/pages/documents.vue index 8280cb5..6603747 100644 --- a/app/pages/documents.vue +++ b/app/pages/documents.vue @@ -146,7 +146,7 @@ const previewDocument = ref(null) const previewVisible = ref(false) onMounted(() => { - loadDocuments() + loadDocuments({ itemsPerPage: 200 }) }) const filteredDocuments = computed(() => { diff --git a/app/pages/pieces-catalog.vue b/app/pages/pieces-catalog.vue index 0bcded7..b108e79 100644 --- a/app/pages/pieces-catalog.vue +++ b/app/pages/pieces-catalog.vue @@ -256,7 +256,8 @@ const fetchPieces = async () => { page: currentPage.value, itemsPerPage: itemsPerPage.value, orderBy: sortField.value, - orderDir: sortDirection.value + orderDir: sortDirection.value, + force: true }) } diff --git a/app/pages/product-catalog.vue b/app/pages/product-catalog.vue index 4d2a8ad..c139e2e 100644 --- a/app/pages/product-catalog.vue +++ b/app/pages/product-catalog.vue @@ -388,7 +388,7 @@ const resolvePreviewAlt = (product: Record) => { } const reload = async () => { - await loadProducts({ force: true }) + await loadProducts({ itemsPerPage: 200, force: true }) } const { confirm } = useConfirm() @@ -409,7 +409,7 @@ const confirmDelete = async (product: Record) => { onMounted(async () => { await Promise.all([ - loadProducts(), + loadProducts({ itemsPerPage: 200, force: true }), loadProductTypes() ]) }) diff --git a/app/services/modelTypes.ts b/app/services/modelTypes.ts index 7300467..2a34e7a 100644 --- a/app/services/modelTypes.ts +++ b/app/services/modelTypes.ts @@ -132,28 +132,19 @@ export async function listModelTypes(params: ModelTypeListParams = {}, opts: { s if (params.category) { query.category = params.category; } - if (params.sort) { - query.sort = params.sort; - } - if (params.dir) { - query.dir = params.dir; - } - const hasCategoryFilter = Boolean(params.category); - const effectiveLimit = typeof params.limit === 'number' ? params.limit : undefined; - const effectiveOffset = typeof params.offset === 'number' ? params.offset : 0; - if (hasCategoryFilter) { - // Fetch enough items to allow client-side category filtering + pagination. - query.itemsPerPage = Math.max(effectiveLimit ?? 200, 200); - query.offset = 0; - } else { - if (typeof params.limit === 'number') { - query.itemsPerPage = params.limit; - } - if (typeof params.offset === 'number') { - query.offset = params.offset; - } - } + // Sort: API Platform OrderFilter uses order[field]=direction + const sortField = params.sort || 'name'; + const sortDir = params.dir || 'asc'; + query[`order[${sortField}]`] = sortDir; + + // Pagination: API Platform uses page + itemsPerPage + const effectiveLimit = typeof params.limit === 'number' ? params.limit : 20; + const effectiveOffset = typeof params.offset === 'number' ? params.offset : 0; + const page = Math.floor(effectiveOffset / effectiveLimit) + 1; + + query.itemsPerPage = effectiveLimit; + query.page = page; const payload = await requestFetch>(ENDPOINT, createOptions({ method: 'GET', @@ -168,25 +159,20 @@ export async function listModelTypes(params: ModelTypeListParams = {}, opts: { s : Array.isArray(payload?.items) ? payload.items : []; - const filteredItems = params.category - ? rawItems.filter((item: any) => item?.category === params.category) - : rawItems; - const total = params.category - ? filteredItems.length - : typeof payload?.totalItems === 'number' - ? payload.totalItems - : Array.isArray(payload?.items) - ? payload.items.length - : rawItems.length; - const items = (params.category && typeof effectiveLimit === 'number' - ? filteredItems.slice(effectiveOffset, effectiveOffset + effectiveLimit) - : filteredItems).map(normalizeModelType); + + const total = typeof payload?.totalItems === 'number' + ? payload.totalItems + : typeof payload?.['hydra:totalItems'] === 'number' + ? payload['hydra:totalItems'] + : rawItems.length; + + const items = rawItems.map(normalizeModelType); return { items, total, offset: effectiveOffset, - limit: typeof effectiveLimit === 'number' ? effectiveLimit : items.length, + limit: effectiveLimit, } satisfies ModelTypeListResponse; }