# Feature Landscape **Domain:** Time-tracking heatmap dashboard widget (v1.1 milestone -- modes, filtering, toggles) **Researched:** 2026-04-08 ## Table Stakes Features that users of a multi-mode heatmap widget would expect once modes are advertised. Missing any of these makes the feature set feel unfinished. | Feature | Why Expected | Complexity | Notes | |---------|--------------|------------|-------| | Mode switcher UI | Users need a way to switch views. Without it, modes are invisible. | Low | Use Tabler's `nav-segmented` component -- it exists specifically for toggling views within the same context. Maps to `data-bs-toggle="tab"`. Max 4-5 segments. | | Year-view heatmap (existing) | Already shipped in v1.0. Must remain default mode. | Done | Existing `renderHeatmap()` in `heatmap.ts` | | Day-of-week aggregation (week mode) | Standard "punchcard" analysis -- which weekdays are busiest. Every time-tracking analytics tool offers this. | Medium | Aggregate existing `DayEntry[]` client-side by `Date.getDay()`. No new backend query needed -- sum/average existing daily data by weekday. 7-row or 7-column chart with color intensity. | | Hours vs entry-count toggle | The data already has both `hours` and `count` fields. Users expect to choose which metric colors the heatmap. | Low | Toggle the `colorScale` domain between `hours` and `count`. A small segmented control or pair of radio buttons. Applies to all modes. | | Cascading entity pickers (customer -> project -> activity) | Kimai users see TomSelect pickers everywhere else in the app. A plain `` with TomSelect instances, wire cascading via Kimai's API routes (`get_projects?customer=N`, `get_activities?project=N`) 6. **Activity filtering** -- Backend `?activity=N` param + frontend wiring 7. **Customer filtering** -- Backend `?customer=N` param (join through project.customer) Phase 3 -- Advanced Modes (defer or stretch): 8. **Day mode (time-of-day)** -- Needs new backend query + new data shape 9. **Combined day/hour matrix** -- Most complex layout, depends on hour-level backend data 10. **Color scale legend** -- Nice polish, do alongside advanced modes **Rationale:** Phase 1 proves the multi-mode rendering architecture with zero backend changes. Phase 2 improves filtering UX with Kimai-native patterns and enables activity filtering. Phase 3 adds the data-intensive visualizations requiring new queries. Each phase delivers user-visible value independently. ## Complexity Notes ### TomSelect Integration (the hardest part that looks easy) Kimai's TomSelect integration runs through a plugin lifecycle: `KimaiFormPlugin` -> `KimaiFormTomselectPlugin` -> `KimaiFormSelect`. The cascading logic in `_activateApiSelects()` (line 386-447 of `KimaiFormSelect.js`) listens for `change` events on selects with `data-related-select` attributes, fetches from `data-api-url` with form field interpolation (`%fieldname%` patterns), and updates the target select via `_updateOptions()` which dispatches `data-reloaded` events. **Why the plugin cannot use Kimai's system directly:** - Requires Kimai's `KimaiContainer` DI (for `getPlugin('api')`) - Requires `KimaiFormPlugin` base class registration - URL interpolation (`%fieldname%`) assumes Symfony form field naming conventions - Lifecycle hooks (`activateForm`/`destroyForm`) expect to be called by Kimai's page init **Two integration approaches:** **(a) Direct TomSelect instantiation (recommended):** - Import TomSelect standalone (already loaded in Kimai's global JS) - Create `