3.1 KiB
3.1 KiB
Phase 4: Heatmap Interaction - Context
Gathered: 2026-04-08 Status: Ready for planning
## Phase BoundaryAdd click-through navigation from heatmap day cells to Kimai's timesheet view, and a project filter dropdown that re-fetches and re-renders the heatmap without page reload.
## Implementation DecisionsClick Navigation
- Clicking any day cell navigates to Kimai's timesheet list filtered by that date (
/en/timesheet/?daterange=YYYY-MM-DD) - Empty cells (no data) are clickable too — user may want to add time for that day
- Pointer cursor + subtle hover highlight (opacity change) on all cells as click affordance
- If a project filter is active, preserve it in the timesheet URL (
&projects[]=N)
Project Filter
- Filter dropdown positioned next to the heatmap SVG (right side), using the spare horizontal space since the heatmap isn't full card width
- Projects only — no activity filter (API already supports
?project=N) - Default state: "All Projects" selected, no filter applied
- Selecting a project fetches from API with
?project=N, re-renders heatmap in place; color scale recalculates for filtered data
Testing Strategy
- Vitest tests for click navigation: verify click handler sets
window.location.hrefto correct Kimai URL pattern - Vitest tests for filter dropdown: verify dropdown renders, selecting fires fetch with correct query param, heatmap re-renders with new data
- Fixture data matching existing HeatmapData shape from prior tests
Claude's Discretion
- Exact Kimai timesheet URL format (verify against Kimai source)
- Filter dropdown styling details (should use Tabler/Kimai form classes)
- How to populate the project list (new API endpoint or extend existing one)
<code_context>
Existing Code Insights
Reusable Assets
renderHeatmap(container, data, config)inassets/src/heatmap.ts— main rendering function, can be called again with new data for filter updatesHeatmapData/DayEntrytypes inassets/src/types.ts— shared data shapeHeatmapController::data()already accepts?projectquery parameterHeatmapService::getDailyAggregation()already supports?int $projectIdparameter
Established Patterns
- d3 selections for SVG rendering with data binding
- Tooltip positioning via fixed-position div (mouseenter/mouseleave)
- IIFE format with
KimaiHeatmapglobal,kimai.initializedevent for deferred init - Tabler CSS variables for theming (
--tblr-bg-surface,--tblr-body-color, etc.)
Integration Points
data-urlattribute on container div passes API endpoint to JS- Widget template at
Resources/views/widget/heatmap.html.twigwith Tabler card embed - CSS at
Resources/public/heatmap.css - Route
heatmap_dataresolves to/heatmap/data
</code_context>
## Specific Ideas- User wants filter next to the heatmap (not in header or below) since the SVG doesn't fill the full card width — use the horizontal space to the right
None — discussion stayed within phase scope.