diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-09-08 13:44:59 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-09-08 13:44:59 +0200 |
| commit | 212c3adc8a584e6517a2816fc6683688d5ac5d7a (patch) | |
| tree | 59cccb6155a739376fce05faa833076ac4b52ad4 /src/lib/server/services | |
| parent | e1d80af9899e078f53d2232d2d7ef4680a14bf1c (diff) | |
Project health chart on LayerChart
Project page gets a Sante chart: daily mean of per-routine health
via computeProjectHealthSeries, ending at the current health score.
Both charts share a HealthChart component built on LayerChart's
AreaChart (time x-axis, fixed 0-100 y-axis, completion dots).
Diffstat (limited to 'src/lib/server/services')
| -rw-r--r-- | src/lib/server/services/routines.test.ts | 3 | ||||
| -rw-r--r-- | src/lib/server/services/routines.ts | 12 |
2 files changed, 13 insertions, 2 deletions
diff --git a/src/lib/server/services/routines.test.ts b/src/lib/server/services/routines.test.ts index e8c4f35..04151c2 100644 --- a/src/lib/server/services/routines.test.ts +++ b/src/lib/server/services/routines.test.ts @@ -141,6 +141,9 @@ describe('routines service', () => { expect(dashboard.routines).toHaveLength(1); expect(dashboard.routines[0].status).toBe('veryLate'); expect(dashboard.healthScore).toBe(0); + const last = dashboard.healthSeries[dashboard.healthSeries.length - 1]; + expect(last.at).toBe(now); + expect(last.health).toBe(dashboard.healthScore); }); it('overview aggregates per-project health and a global score', async () => { diff --git a/src/lib/server/services/routines.ts b/src/lib/server/services/routines.ts index b314d50..ec03c50 100644 --- a/src/lib/server/services/routines.ts +++ b/src/lib/server/services/routines.ts @@ -6,7 +6,9 @@ import type { Routine, RoutineCompletion } from './types'; import { computeRoutineState, computeHealthScore, + computeProjectHealthSeries, type RoutineState, + type HealthPoint, } from '$lib/shared/routine-metrics'; // ponytail: next routine id via MAX(id)+1, safe enough for a single-user app; @@ -199,6 +201,7 @@ export async function complete( export interface ProjectDashboard { routines: RoutineState[]; healthScore: number; + healthSeries: HealthPoint[]; } export async function loadProjectDashboard( @@ -219,7 +222,8 @@ export async function loadProjectDashboard( if (!existing || r.version > existing.version) current.set(r.id, r); } const routines_ = [...current.values()].filter((r) => !r.archived); - if (routines_.length === 0) return { routines: [], healthScore: 100 }; + if (routines_.length === 0) + return { routines: [], healthScore: 100, healthSeries: [] }; const completions = await db .select() @@ -232,7 +236,11 @@ export async function loadProjectDashboard( ); const states = routines_.map((r) => computeRoutineState(r, completions, now)); - return { routines: states, healthScore: computeHealthScore(states) }; + return { + routines: states, + healthScore: computeHealthScore(states), + healthSeries: computeProjectHealthSeries(routines_, completions, now), + }; } export interface ProjectsOverview { |
