Web: alle Kategorie-Auswahlen als aufklappbarer Baum

Statt der nativen "— —"-Dropdowns nutzen jetzt auch Produktformular
(Kategorie + Inline-"Neue Kategorie"-Elternwahl), Einlagern-Maske und
Produkte-Filter den CategorySelect-Baum. CategorySelect um optionale
Zusatz-Eintraege (extraOptions) erweitert, damit der Produkte-Filter
"Alle Kategorien"/"Ohne Kategorie" weiter anbietet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-26 13:07:36 +02:00
parent 956a472c04
commit dc66a6d7ff
4 changed files with 51 additions and 35 deletions

View File

@@ -10,6 +10,7 @@ import ProduktBild from "../components/ProduktBild";
import { useToast } from "../toast";
import { useSettings } from "../settings";
import { asTree } from "../categoryTree";
import CategorySelect from "../components/CategorySelect";
import { DynamicFields, FIELD_TYPES } from "../fields";
import ObjektBestand from "../components/ObjektBestand";
import Einzelstuecke from "../components/Einzelstuecke";
@@ -696,15 +697,13 @@ export default function ProductForm() {
<span className="tip" title="Nur Kategorien des gewählten Typs. Gegenstands-Kategorien zeigen Menge je Lagerort, Lebensmittel MHD/Chargen.">
Kategorie
</span>
<select value={form.category_id} onChange={(e) => set("category_id", e.target.value)}
disabled={readOnly}>
<option value=""> keine </option>
{asTree(categories).filter((c) => c.tracking === modus).map((c) => (
<option key={c.id} value={c.id}>
{"— ".repeat(c.depth)}{c.name}
</option>
))}
</select>
<CategorySelect
value={form.category_id === "" ? null : Number(form.category_id)}
nodes={asTree(categories).filter((c) => c.tracking === modus)}
rootLabel=" keine "
disabled={readOnly}
onChange={(id) => set("category_id", id == null ? "" : String(id))}
/>
</label>
{isAdmin && (
<div className="grow" style={{ display: "flex", alignItems: "flex-end" }}>
@@ -729,13 +728,12 @@ export default function ProductForm() {
onChange={(e) => setNewCat({ ...newCat, name: e.target.value })} />
</label>
<label className="grow">Untergeordnet (optional)
<select value={newCat.parent_id}
onChange={(e) => setNewCat({ ...newCat, parent_id: e.target.value })}>
<option value=""> oberste Ebene </option>
{asTree(categories).filter((c) => c.tracking === modus).map((c) => (
<option key={c.id} value={c.id}>{"— ".repeat(c.depth)}{c.name}</option>
))}
</select>
<CategorySelect
value={newCat.parent_id === "" ? null : Number(newCat.parent_id)}
nodes={asTree(categories).filter((c) => c.tracking === modus)}
rootLabel=" oberste Ebene "
onChange={(id) => setNewCat({ ...newCat, parent_id: id == null ? "" : String(id) })}
/>
</label>
</div>
<button type="button" className="btn primary" onClick={createCategoryInline}>