fix(t-paliad-172): null-guard renderEvents to unblock tab clicks

Slice 1 of SmartTimeline (t-paliad-171, commit 7057fe5) removed the
legacy <ul#project-events-list> + <p#project-events-empty> markup from
projects-detail.tsx but didn't prune the renderEvents() call sites. The
function still runs from main() and several other paths; with non-null
assertions on getElementById, the null deref threw a TypeError mid-init.

The throw aborted main() between body.style.display = "" and initTabs(),
so the .entity-tab click handlers were never attached. Default-action
clicks on <a href="#"> just appended "#" to the URL while the user was
already viewing whatever panel happened to be the default-display
section (tab-history) — making the Verlauf tab feel "stuck" because the
visible panel never changed.

Fix: drop the non-null assertions, null-guard the legacy DOM lookups,
and return early when the targets are gone. renderEvents() becomes a
silent no-op in the SmartTimeline layout, which matches euler's intent
documented in 7057fe5: "The legacy renderEvents() rendering path stays
as-is (dead, but the function is still called in places). It will be
removed once /timeline?include=audit_full has had a deploy of soak time
… Slice 2 revisits."

Verified locally with the projects-detail.js bundle + a fetch mock:
clicks on Team / Projektbaum / Parteien / etc. now switch the active
tab and panel display, the URL updates via replaceState, the
SmartTimeline still renders its empty state, and the "+ Eintrag" modal
still opens and closes correctly.
This commit is contained in:
m
2026-05-09 12:38:24 +02:00
parent 3e1bbd3c77
commit 0835be4a7f

View File

@@ -867,9 +867,17 @@ function renderHeader() {
}
function renderEvents() {
const list = document.getElementById("project-events-list")!;
const empty = document.getElementById("project-events-empty")!;
// Slice 1 of t-paliad-171 replaced the legacy <ul#project-events-list>
// markup with <div#project-smart-timeline>. The renderEvents() call sites
// weren't pruned in the same commit, so this function is still invoked
// but its DOM targets no longer exist. Return early instead of crashing —
// a null deref here halts main() before initTabs() runs, which is what
// made the Verlauf tab feel "stuck" (t-paliad-172). Slice 2 will remove
// the orphan call sites entirely.
const list = document.getElementById("project-events-list");
const empty = document.getElementById("project-events-empty");
const moreWrap = document.getElementById("project-events-loadmore-wrap");
if (!list || !empty) return;
if (events.length === 0) {
list.innerHTML = "";
empty.style.display = "block";