Gruppen hierarchisch: in allen Auswahlfeldern und in der Artikelliste
Die Gruppen-Dropdowns waren flache, alphabetische Listen - man sah nicht, dass "Grillwurst" unter "Wurst" haengt. Ein gemeinsamer Helfer (gruppenOptionen) rollt den Graphen zum Baum aus und rueckt ein; eine Gruppe mit mehreren Obergruppen erscheint unter jeder, denn genau das ist ihr Sinn, und ausgewaehlt wird ohnehin dieselbe ID. Eingerueckt wird mit GESCHUETZTEN Leerzeichen - normale fasst der Browser in einem <option> zusammen, die Einrueckung waere sonst wirkungslos. Betroffen: Gruppen-Auswahl im Artikelformular (beide Zweige), beim Einlagern, die Ziel-Auswahl der Mindestbestaende und die Obergruppen-Mehrfachauswahl (die beim Suchen bewusst abflacht, weil eine Einrueckung ohne die Eltern in die Irre fuehrt). In der App dasselbe in beiden Gruppen-Pickern. Die Gruppen-Spalte der Artikelliste zeigt jetzt den Weg von oben statt eines Etiketts - "Wurst → Grillwurst", mit gedaempften Vorfahren wie bei der Kategorie. Gefiltert wird ueber ALLE Wege: wer auf "Wurst" filtert, sieht auch die Artikel aus den Untergruppen. Dafuer gibt es gruppenInfoMap als Gegenstueck zu categoryInfoMap, das mit mehreren Wegen je Gruppe umgehen kann. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,3 +75,74 @@ export function elternNamen(groups, group) {
|
||||
const map = byId(groups);
|
||||
return (group?.parent_ids || []).map((id) => map.get(id)?.name).filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gruppen für ein Auswahlfeld: als Baum ausgerollt und eingerückt.
|
||||
*
|
||||
* Eine Gruppe mit mehreren Obergruppen erscheint unter JEDER – genau das ist
|
||||
* der Sinn mehrerer Obergruppen. Der Wert ist ohnehin dieselbe ID, egal welche
|
||||
* Zeile man trifft.
|
||||
*
|
||||
* Eingerückt wird mit GESCHÜTZTEN Leerzeichen: normale fasst der Browser in
|
||||
* einem <option> zusammen, die Einrückung wäre dann wirkungslos.
|
||||
*/
|
||||
export function gruppenOptionen(groups) {
|
||||
const liste = groups || [];
|
||||
const vorhanden = new Set(liste.map((g) => g.id));
|
||||
const nachName = (a, b) => a.name.localeCompare(b.name, "de");
|
||||
const kinderVon = new Map();
|
||||
const wurzeln = [];
|
||||
for (const g of liste) {
|
||||
const eltern = (g.parent_ids || []).filter((id) => vorhanden.has(id));
|
||||
if (eltern.length === 0) wurzeln.push(g);
|
||||
for (const e of eltern) {
|
||||
if (!kinderVon.has(e)) kinderVon.set(e, []);
|
||||
kinderVon.get(e).push(g);
|
||||
}
|
||||
}
|
||||
|
||||
const out = [];
|
||||
const walk = (g, tiefe, pfad, gesehen) => {
|
||||
const eigen = `${pfad}/${g.id}`;
|
||||
out.push({
|
||||
id: g.id,
|
||||
key: eigen,
|
||||
gruppe: g,
|
||||
tiefe,
|
||||
label: `${"\u00A0\u00A0\u00A0".repeat(tiefe)}${tiefe > 0 ? "\u21B3 " : ""}${g.name}`,
|
||||
});
|
||||
if (gesehen.has(g.id)) return; // Ringschutz
|
||||
const weiter = new Set(gesehen).add(g.id);
|
||||
for (const k of (kinderVon.get(g.id) || []).slice().sort(nachName)) {
|
||||
walk(k, tiefe + 1, eigen, weiter);
|
||||
}
|
||||
};
|
||||
for (const w of wurzeln.slice().sort(nachName)) walk(w, 0, "", new Set());
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gegenstück zu categoryInfoMap für Gruppen: je Gruppe der Weg von oben.
|
||||
*
|
||||
* Anders als bei Kategorien kann es MEHRERE Wege geben („Grillwurst" unter
|
||||
* „Wurst" und unter „Grillgut"). Angezeigt wird der erste, gefiltert wird über
|
||||
* alle – wer auf „Wurst" filtert, will „Grillwurst" mitsehen.
|
||||
*/
|
||||
export function gruppenInfoMap(groups) {
|
||||
const out = new Map();
|
||||
for (const g of groups || []) {
|
||||
const wege = pfade(groups, g.id);
|
||||
const erster = wege[0]?.length ? wege[0] : [g.name];
|
||||
const tokens = new Set();
|
||||
for (const weg of wege) {
|
||||
weg.forEach((_, i) => tokens.add(weg.slice(0, i + 1).join(" → ")));
|
||||
}
|
||||
out.set(g.id, {
|
||||
parts: erster,
|
||||
path: erster.join(" → "),
|
||||
alle: wege.map((w) => w.join(" → ")),
|
||||
tokens: [...tokens],
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user