75 lines
3.1 KiB
Markdown
75 lines
3.1 KiB
Markdown
# Phase 4: Heatmap Interaction - Context
|
|
|
|
**Gathered:** 2026-04-08
|
|
**Status:** Ready for planning
|
|
|
|
<domain>
|
|
## Phase Boundary
|
|
|
|
Add 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.
|
|
|
|
</domain>
|
|
|
|
<decisions>
|
|
## Implementation Decisions
|
|
|
|
### Click 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.href` to 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)
|
|
|
|
</decisions>
|
|
|
|
<code_context>
|
|
## Existing Code Insights
|
|
|
|
### Reusable Assets
|
|
- `renderHeatmap(container, data, config)` in `assets/src/heatmap.ts` — main rendering function, can be called again with new data for filter updates
|
|
- `HeatmapData` / `DayEntry` types in `assets/src/types.ts` — shared data shape
|
|
- `HeatmapController::data()` already accepts `?project` query parameter
|
|
- `HeatmapService::getDailyAggregation()` already supports `?int $projectId` parameter
|
|
|
|
### Established Patterns
|
|
- d3 selections for SVG rendering with data binding
|
|
- Tooltip positioning via fixed-position div (mouseenter/mouseleave)
|
|
- IIFE format with `KimaiHeatmap` global, `kimai.initialized` event for deferred init
|
|
- Tabler CSS variables for theming (`--tblr-bg-surface`, `--tblr-body-color`, etc.)
|
|
|
|
### Integration Points
|
|
- `data-url` attribute on container div passes API endpoint to JS
|
|
- Widget template at `Resources/views/widget/heatmap.html.twig` with Tabler card embed
|
|
- CSS at `Resources/public/heatmap.css`
|
|
- Route `heatmap_data` resolves to `/heatmap/data`
|
|
|
|
</code_context>
|
|
|
|
<specifics>
|
|
## 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
|
|
|
|
</specifics>
|
|
|
|
<deferred>
|
|
## Deferred Ideas
|
|
|
|
None — discussion stayed within phase scope.
|
|
|
|
</deferred>
|