Phase 2 slice of the universal-filter migration (Phase 1 was
t-paliad-163 → /inbox; remaining /agenda /events /deadlines
/appointments stay queued).
What ships:
- FilterBar gains two non-invasive options that future surfaces will
also need:
customRunner — bypass the substrate POST and hand the effective
spec to a surface-supplied runner. Required by
surfaces whose data path can't move to the substrate
yet (Verlauf still uses /api/projects/{id}/events for
subtree expansion + cursor pagination, both absent
from the substrate's project_event runner).
timePresets — per-surface override of the time chip cluster, so
backward-looking surfaces can show past_*+all without
forcing forward-looking next_* chips on every host.
systemViewSlug becomes optional; the bar enforces "exactly one of
customRunner | systemViewSlug" at construction.
- project_event_kind axis renderer (was a null stub) — chip cluster
over KnownProjectEventKinds, labels reuse the existing
event.title.<kind> i18n table so the chip text matches the Verlauf
row title for the same kind.
- HorizonPast7d added end-to-end (substrate validate +
computeViewSpecBounds; FilterBar TimeOverlay + parseHorizon; views
TimeHorizon mirror) so the chip value is valid in every layer when a
later SystemView reuses it.
- Verlauf tab on /projects/<id> mounts the bar with
axes=["time","project_event_kind"], timePresets=
["past_7d","past_30d","past_90d","any"], showSaveAsView=false. The
customRunner reads predicates.project_event.event_types + time.horizon
off the effective spec, sets a verlaufFilters global, and routes
through the legacy loadEvents/loadMoreEvents pipeline (which now
applies the filter set client-side and tracks raw cursor IDs so
"Mehr laden" still walks the underlying pagination boundary even when
most rows get filtered out of a page).
- Subtree toggle drives loadEvents through verlaufBar.refresh() so the
current filter state survives the toggle.
URL state reuses the bar's existing keys (?time=past_30d, ?pe_kind=…).
Empty filter → identity passthrough → current behaviour preserved.
Out of scope (deferred to t-paliad-169 SmartTimeline):
- Migrating Verlauf to the substrate (needs scope-with-descendants)
- Past/future split, dated/undated split, source-track facet
Refs m/paliad#23.