From 92dc32bf124ed7378c91e88ef96f3927b64650ba Mon Sep 17 00:00:00 2001 From: seb Date: Sun, 19 Jul 2026 19:43:23 +0200 Subject: [PATCH] cat --- docs/api/routes/article/search.md | 7 +++--- src/services/article/searchArticles.js | 30 +++++++++++++++++--------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/api/routes/article/search.md b/docs/api/routes/article/search.md index 5441f5c..6cc1b79 100644 --- a/docs/api/routes/article/search.md +++ b/docs/api/routes/article/search.md @@ -32,7 +32,7 @@ Fuzzy article search. Use this to build a search box / result list with category Pass category IDs as a comma-separated list: `filter=16,39`. -Whenever `filter` is present, **`categories` always includes every id from `filter`**, even when `length` is `0` or a filtered id has no hits. Those entries use master-data `name` / `parent` and may have `count: 0`. Other facet categories with hits are still returned as usual. +Whenever `filter` is present, **`categories` always includes every id from `filter` and its full ancestor chain** (parent → … → root), even when `length` is `0` or a filtered id has no hits. Those entries use master-data `name` / `parent` and may have `count: 0`. Other facet categories with hits are still returned as usual. ## Response `200` @@ -58,14 +58,15 @@ Whenever `filter` is present, **`categories` always includes every id from `filt } ``` -Empty result with an active filter still returns the applied category: +Empty result with a nested filter still returns the leaf and its ancestors: ```json { "length": 0, "recordset": [], "categories": { - "16": { "name": "Dünger", "count": 0, "parent": 0 } + "16": { "name": "Dünger", "count": 0, "parent": 0 }, + "39": { "name": "Erde", "count": 0, "parent": 16 } } } ``` diff --git a/src/services/article/searchArticles.js b/src/services/article/searchArticles.js index 71352e8..7085371 100644 --- a/src/services/article/searchArticles.js +++ b/src/services/article/searchArticles.js @@ -77,18 +77,27 @@ function shapeCategories(counts, byId) { return categories; } -/** Ensure every applied filter id appears in categories (count 0 if no hits). */ -function ensureFilterCategories(categories, filter, byId) { +/** + * Ensure every applied filter id and its ancestors appear in categories + * (count 0 if no hits), so the frontend can render hierarchy via parent links. + */ +function ensureFilterCategories(categories, filter, byId, parentMap) { for (const id of filter) { - if (id === '' || id === null || categories[id]) { + if (id === '' || id === null) { continue; } - const meta = byId[id] ?? {}; - categories[id] = { - count: 0, - name: meta.name ?? null, - parent: meta.parent ?? null, - }; + for (const ancestorId of getUpPath(id, parentMap)) { + const key = String(ancestorId); + if (categories[key]) { + continue; + } + const meta = byId[ancestorId] ?? byId[key] ?? {}; + categories[key] = { + count: 0, + name: meta.name ?? null, + parent: meta.parent ?? null, + }; + } } return categories; } @@ -206,7 +215,8 @@ export async function searchArticles(target, filter = [''], offset = 0, maxCount categoryData.byId ), filter, - categoryData.byId + categoryData.byId, + categoryData.parentMap ); const length = result.recordset.length; const recordset = result.recordset