From 001542a3ce4af4069d78e0e03450f1448d51cce0 Mon Sep 17 00:00:00 2001 From: mAi Date: Mon, 25 May 2026 16:52:07 +0200 Subject: [PATCH] mAi: #113 - fix admin rules list 'undefined' proceeding name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProceedingType TS interface in admin-rules-list.ts and admin-rules-edit.ts declared `name_de` but the Go ProceedingType model serialises `db:"name"` as JSON key `name` (DE is the primary on the wire). Result: `pt.name_de` was undefined for every row, so `${pt.code} · ${pt.name_de}` produced the literal "upc.apl.cost · undefined" in the list (and the same in proceeding selects of the edit page). Frontend-only fix: - Rename the field to `name` to match the API contract. - Guard the label builder: if the active-language name is missing, fall back to just the proceeding code rather than rendering "code · " (or worse, the original "code · undefined" string). Other admin pages that fetch /api/proceeding-types-db (deadlines-new, deadlines-detail, project-form, fristenrechner) already read `pt.name` correctly, so the bug was scoped to these two files. TriggerEvent's `name_de` field is real and stays untouched. --- frontend/src/client/admin-rules-edit.ts | 8 ++++++-- frontend/src/client/admin-rules-list.ts | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/src/client/admin-rules-edit.ts b/frontend/src/client/admin-rules-edit.ts index 694a0b5..f91d60a 100644 --- a/frontend/src/client/admin-rules-edit.ts +++ b/frontend/src/client/admin-rules-edit.ts @@ -51,7 +51,10 @@ interface Rule { interface ProceedingType { id: number; code: string; - name_de: string; + // `name` is the German display name on the wire; the Go `ProceedingType` + // model serialises `db:"name"` as JSON key `name`. Don't reach for + // `name_de` — that field does not exist in this payload (m/paliad#113). + name: string; name_en: string; } @@ -169,7 +172,8 @@ function fillProceedingSelect(selectId: string, list: ProceedingType[]) { for (const pt of list) { const opt = document.createElement("option"); opt.value = String(pt.id); - opt.textContent = `${pt.code} · ${getLang() === "en" ? pt.name_en : pt.name_de}`; + const name = getLang() === "en" ? pt.name_en : pt.name; + opt.textContent = name ? `${pt.code} · ${name}` : pt.code; sel.appendChild(opt); } } diff --git a/frontend/src/client/admin-rules-list.ts b/frontend/src/client/admin-rules-list.ts index b360f46..be6f736 100644 --- a/frontend/src/client/admin-rules-list.ts +++ b/frontend/src/client/admin-rules-list.ts @@ -29,7 +29,11 @@ interface Rule { interface ProceedingType { id: number; code: string; - name_de: string; + // `name` is the German display name on the wire; the Go `ProceedingType` + // model serialises `db:"name"` as JSON key `name` (the schema treats DE + // as primary). EN lives in `name_en`. Don't reach for `name_de` — that + // field does not exist in this payload (cf. m/paliad#113). + name: string; name_en: string; category: string; } @@ -125,7 +129,12 @@ function proceedingLabel(id: number | null | undefined): string { if (id == null) return "—"; const pt = proceedings.find((p) => p.id === id); if (!pt) return `#${id}`; - const name = getLang() === "en" ? pt.name_en : pt.name_de; + const name = getLang() === "en" ? pt.name_en : pt.name; + // Guard against a proceeding row that's missing the active-language + // name (or against a stale field-name mismatch slipping back in). + // Show the code on its own rather than "code · undefined" — that + // literal string is the smell that surfaced this bug (m/paliad#113). + if (!name) return pt.code; return `${pt.code} · ${name}`; } @@ -153,7 +162,8 @@ async function loadProceedings(): Promise { for (const pt of proceedings) { const opt = document.createElement("option"); opt.value = String(pt.id); - opt.textContent = `${pt.code} · ${getLang() === "en" ? pt.name_en : pt.name_de}`; + const name = getLang() === "en" ? pt.name_en : pt.name; + opt.textContent = name ? `${pt.code} · ${name}` : pt.code; sel.appendChild(opt); } }