Web: eigene Felder nachträglich bearbeiten
Backend und API-Client konnten Felddefinitionen laengst aendern (PATCH), nur die Oberflaeche bot bisher nur Anlegen und Loeschen. In der Felder-Verwaltung einer Kategorie gibt es jetzt je Feld einen Bearbeiten-Knopf: er laedt Name, Typ, Einheit, Auswahlmoeglichkeiten und Pflicht ins Formular; Speichern aktualisiert das Feld (oder Abbrechen). Geerbte und eingebaute Felder bleiben unveraendert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -287,6 +287,7 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const [fields, setFields] = useState([]);
|
const [fields, setFields] = useState([]);
|
||||||
const [form, setForm] = useState(EMPTY_FIELD);
|
const [form, setForm] = useState(EMPTY_FIELD);
|
||||||
|
const [editId, setEditId] = useState(null); // null = neues Feld, sonst bearbeiten
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
@@ -298,21 +299,45 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
}
|
}
|
||||||
useEffect(() => { load(); }, [category.id]);
|
useEffect(() => { load(); }, [category.id]);
|
||||||
|
|
||||||
async function add(e) {
|
// Ein bestehendes Feld in das Formular laden (mehrfach getrennte Optionen
|
||||||
|
// wieder als Komma-Liste).
|
||||||
|
function startEdit(f) {
|
||||||
|
setEditId(f.id);
|
||||||
|
setForm({
|
||||||
|
label: f.label,
|
||||||
|
field_type: f.field_type,
|
||||||
|
unit: f.unit || "",
|
||||||
|
options: (f.options || []).join(", "),
|
||||||
|
required: f.required,
|
||||||
|
});
|
||||||
|
setError(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelEdit() {
|
||||||
|
setEditId(null);
|
||||||
|
setForm(EMPTY_FIELD);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setError(null);
|
setError(null);
|
||||||
|
const body = {
|
||||||
|
label: form.label,
|
||||||
|
field_type: form.field_type,
|
||||||
|
unit: form.field_type === "number" ? (form.unit || null) : null,
|
||||||
|
options: form.field_type === "select"
|
||||||
|
? form.options.split(",").map((o) => o.trim()).filter(Boolean)
|
||||||
|
: null,
|
||||||
|
required: form.required,
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
await api.createFieldDefinition({
|
if (editId) {
|
||||||
category_id: category.id,
|
await api.updateFieldDefinition(editId, body);
|
||||||
label: form.label,
|
} else {
|
||||||
field_type: form.field_type,
|
await api.createFieldDefinition({ category_id: category.id, ...body });
|
||||||
unit: form.field_type === "number" ? (form.unit || null) : null,
|
}
|
||||||
options: form.field_type === "select"
|
|
||||||
? form.options.split(",").map((o) => o.trim()).filter(Boolean)
|
|
||||||
: null,
|
|
||||||
required: form.required,
|
|
||||||
});
|
|
||||||
setForm(EMPTY_FIELD);
|
setForm(EMPTY_FIELD);
|
||||||
|
setEditId(null);
|
||||||
load();
|
load();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.message);
|
setError(err.message);
|
||||||
@@ -351,7 +376,7 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
) : (
|
) : (
|
||||||
<ul className="clean-list">
|
<ul className="clean-list">
|
||||||
{fields.map((f) => (
|
{fields.map((f) => (
|
||||||
<li key={f.id} className="cell-row">
|
<li key={f.id} className={`cell-row ${editId === f.id ? "row-active" : ""}`}>
|
||||||
<span className="strong">{f.label}</span>
|
<span className="strong">{f.label}</span>
|
||||||
<span className="badge nowrap">{fieldTypeLabel(f.field_type)}</span>
|
<span className="badge nowrap">{fieldTypeLabel(f.field_type)}</span>
|
||||||
{f.field_type === "number" && f.unit && <span className="muted small">{f.unit}</span>}
|
{f.field_type === "number" && f.unit && <span className="muted small">{f.unit}</span>}
|
||||||
@@ -360,10 +385,16 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
<span className="badge nowrap" title="stammt aus einer Oberkategorie">geerbt</span>
|
<span className="badge nowrap" title="stammt aus einer Oberkategorie">geerbt</span>
|
||||||
) : (
|
) : (
|
||||||
isAdmin && (
|
isAdmin && (
|
||||||
<button className="btn-icon danger" style={{ marginLeft: "auto" }}
|
<span style={{ marginLeft: "auto", display: "flex", gap: 4 }}>
|
||||||
title="Feld löschen" onClick={() => remove(f)}>
|
{!f.is_builtin && (
|
||||||
<Icon name="trash" size={15} />
|
<button className="btn-icon" title="Feld bearbeiten" onClick={() => startEdit(f)}>
|
||||||
</button>
|
<Icon name="edit" size={15} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button className="btn-icon danger" title="Feld löschen" onClick={() => remove(f)}>
|
||||||
|
<Icon name="trash" size={15} />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
@@ -372,7 +403,12 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<form onSubmit={add} className="stack" style={{ marginTop: "var(--sp-3)" }}>
|
<form onSubmit={submit} className="stack" style={{ marginTop: "var(--sp-3)" }}>
|
||||||
|
{editId && (
|
||||||
|
<div className="muted small" style={{ display: "flex", alignItems: "center", gap: 6 }}>
|
||||||
|
<Icon name="edit" size={14} />Feld bearbeiten
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<label>
|
<label>
|
||||||
Feldname
|
Feldname
|
||||||
<input value={form.label} placeholder="z.B. Kapazität"
|
<input value={form.label} placeholder="z.B. Kapazität"
|
||||||
@@ -406,7 +442,15 @@ function CategoryFields({ category, isAdmin, onClose }) {
|
|||||||
onChange={(e) => setForm({ ...form, required: e.target.checked })} />
|
onChange={(e) => setForm({ ...form, required: e.target.checked })} />
|
||||||
<span>Pflichtfeld</span>
|
<span>Pflichtfeld</span>
|
||||||
</label>
|
</label>
|
||||||
<button className="btn primary"><Icon name="plus" size={16} />Feld hinzufügen</button>
|
<div className="field-inline">
|
||||||
|
<button className="btn primary">
|
||||||
|
<Icon name={editId ? "check" : "plus"} size={16} />
|
||||||
|
{editId ? "Änderungen speichern" : "Feld hinzufügen"}
|
||||||
|
</button>
|
||||||
|
{editId && (
|
||||||
|
<button type="button" className="btn ghost" onClick={cancelEdit}>Abbrechen</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user