Web: Kategorie-Filter - Oberkategorie subtil + als eigener Eintrag waehlbar

Die DataTable kann jetzt je Spalte mehrere Filter-Werte pro Zeile (filterValues/Tokens) und eine eigene Option-Darstellung (filterOptionLabel). Die Kategorie-Spalte liefert als Tokens jede Ebene kumuliert (Klamotten, Klamotten -> kurze Hosen); so erscheint die Oberkategorie als eigener, anklickbarer Eintrag und selektiert alle Unterkategorien. Ober-Ebenen werden in Zelle und Dropdown kleiner/gedaempft dargestellt (CategoryPathLabel), das Blatt normal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-27 17:44:38 +02:00
parent 487c5f5f38
commit 08ee1f20f5
6 changed files with 91 additions and 35 deletions

View File

@@ -1,23 +1,33 @@
// Kategorien sind verschachtelbar (Klamotten → kurze Hosen). Produkte hängen an
// der Blatt-Kategorie; um „alle Klamotten" filtern zu können, arbeiten die
// Listen mit dem vollen Pfad statt nur dem Blattnamen.
// der Blatt-Kategorie; um „alle Klamotten" filtern zu können, arbeiten die Listen
// mit dem Pfad. `tokens` enthält jede Ebene als eigenen Wert (Ober- und eigene
// Kategorie), damit im Filter-Dropdown auch die Oberkategorie wählbar ist.
/** Map Kategorie-ID → voller Pfad "Klamotten → kurze Hosen". */
export function categoryPathMap(categories) {
/**
* Map Kategorie-ID → { path, parts, tokens }.
* path = "Klamotten → kurze Hosen"
* parts = ["Klamotten", "kurze Hosen"]
* tokens = ["Klamotten", "Klamotten → kurze Hosen"] (jede Ebene kumuliert)
*/
export function categoryInfoMap(categories) {
const byId = new Map((categories || []).map((c) => [c.id, c]));
const cache = new Map();
const pfad = (id, seen) => {
if (cache.has(id)) return cache.get(id);
const partsCache = new Map();
const parts = (id, seen) => {
if (partsCache.has(id)) return partsCache.get(id);
const c = byId.get(id);
if (!c) return "";
if (seen.has(id)) return c.name; // Ringschutz
if (!c) return [];
if (seen.has(id)) return [c.name]; // Ringschutz
seen.add(id);
const oben = c.parent_id != null ? pfad(c.parent_id, seen) : "";
const p = oben ? `${oben}${c.name}` : c.name;
cache.set(id, p);
return p;
const oben = c.parent_id != null ? parts(c.parent_id, seen) : [];
const arr = [...oben, c.name];
partsCache.set(id, arr);
return arr;
};
const out = new Map();
for (const c of categories || []) out.set(c.id, pfad(c.id, new Set()));
for (const c of categories || []) {
const arr = parts(c.id, new Set());
const tokens = arr.map((_, i) => arr.slice(0, i + 1).join(" → "));
out.set(c.id, { path: arr.join(" → "), parts: arr, tokens });
}
return out;
}