feat(dashboard): tiles for HRV, blood oxygen, breathing rate, temperature, and body composition

Several readings were synced and charted but had no place on the dashboard
strip: heart-rate variability, blood oxygen, breathing rate, wrist temperature,
and — for body-composition scale users — muscle mass, body water, and bone mass.
Each now has a tile.

The tiles are pure client additions: the dashboard snapshot already ships a
summary for every measurement type, so no backend, query, or migration changed.
Each tile is data-availability gated (renders only when the account has that
reading) and is toggleable and reorderable under Settings like the rest.

hrv and respiratoryRate graduate from iOS-only to web-writable widget ids, and
muscleMass is a new writable id (catalogue 36 to 37, within the 40-id PUT cap);
wristTemperature moves from pin-only to a web-rendered tile. All additive — the
widget enum only widens, which the iOS contract treats as non-breaking.
This commit is contained in:
Marc-André Bombeck committed 2026-07-16 15:21:03 +02:00
1 parent e883b64b1f
commit 7c45c876a0
12 files changed
+389 -58

No files matched your search

@@ -55,6 +55,15 @@ const TILE_CAPABLE_WIDGET_IDS = new Set<string>([
"glucose",
"bpInTarget",
"vo2Max",
// v1.28.52 — vitals + body-composition strip tiles: each paints one
// strip card and self-gates on having a sample of its MeasurementType.
"hrv",
"oxygenSaturation",
"respiratoryRate",
"wristTemperature",
"muscleMass",
"totalBodyWater",
"boneMass",
]);
/**
@@ -383,7 +383,8 @@ describe("<DashboardLayoutSection> — iOS-pin-only ids hidden from web (v1.11.2
stairAscentSpeed: "Stair ascent speed",
stairDescentSpeed: "Stair descent speed",
breathingDisturbances: "Breathing disturbances",
wristTemperature: "Wrist temperature",
// v1.28.52 — `wristTemperature` is no longer pin-only; it now renders
// a web row, so it left both IOS_PIN_ONLY_WIDGET_IDS and this map.
falls: "Falls",
walkingSteadiness: "Walking steadiness",
};
@@ -138,8 +138,13 @@ const WIDGET_LABEL_KEYS: Record<DashboardWidgetId, string> = {
glucose: "measurements.typeBloodGlucose",
totalBodyWater: "measurements.typeTotalBodyWater",
boneMass: "measurements.typeBoneMass",
// v1.28.52 — muscle mass joins the body-composition strip tiles.
muscleMass: "measurements.typeMuscleMass",
bpInTarget: "dashboard.bpInTarget",
oxygenSaturation: "measurements.typeOxygenSaturation",
// v1.28.52 — HRV + respiratory rate graduate to web-writable widgets.
hrv: "measurements.typeHeartRateVariability",
respiratoryRate: "measurements.typeRespiratoryRate",
achievements: "achievements.title",
// v1.4.25 W8d — VO2 max secondary-metric tile (opt-in).
vo2Max: "dashboard.vo2Max",