feat(dashboard): show the VO2max tile by default when data exists

The VO2max strip tile was opt-in, so accounts that already sync a
cardio-fitness sample from Withings, Apple Health, Fitbit, or Oura saw
nothing on the dashboard. Default the strip tile on; it still self-gates
on having a VO2_MAX sample, so empty accounts keep a clean tile strip.
The chart row stays off — VO2max charts live on /insights/cardio-fitness.
This commit is contained in:
Marc-André Bombeck committed 2026-06-20 12:09:51 +02:00
1 parent b0e6079858
commit d9ed7961bb
2 files changed
+29 -10

No files matched your search

@@ -154,6 +154,21 @@ describe("DEFAULT_DASHBOARD_LAYOUT contract", () => {
expect(widget?.tileVisible).toBe(true);
});
it("ships the vo2Max strip tile default-on, chart row default-off (v1.18.9)", () => {
// VO2max is ingested from Withings / Apple Health / Fitbit / Oura but
// the tile used to be opt-in, so accounts that already synced a sample
// saw nothing on the dashboard. The strip tile is now on by default
// (it still self-gates on having a VO2_MAX sample in page.tsx), while
// the chart row stays off because VO2max charts live on the
// /insights/cardio-fitness sub-page.
const widget = DEFAULT_DASHBOARD_LAYOUT.widgets.find(
(w) => w.id === "vo2Max",
);
expect(widget).toBeDefined();
expect(widget?.tileVisible).toBe(true);
expect(widget?.visible).toBe(false);
});
it("does NOT advertise a retired insightsPreview widget (v1.4.27 B1)", () => {
// v1.4.27 B1 retired the standalone dashboard preview because it
// duplicated the much-richer `/insights` advisor surface. The
+14 -10
View File
@@ -29,11 +29,12 @@ export const DASHBOARD_WIDGET_IDS = [
"bpInTarget",
"oxygenSaturation",
"achievements",
// v1.4.25 W8d — VO2 max trend tile (opt-in, secondary-metric pattern).
// Self-gates on having any VO2_MAX sample; default-invisible so
// existing dashboards stay unchanged until the user enables it in
// Settings → Dashboard. Only the tile-strip surface; chart row
// lands alongside the iOS-app body-composition sub-page in v1.5.
// v1.4.25 W8d — VO2 max trend tile (secondary-metric pattern). The
// strip tile is on by default and self-gates on having any VO2_MAX
// sample, so accounts that sync cardio fitness see it without enabling
// it in Settings → Dashboard, while empty accounts get a clean tile
// strip. Only the tile-strip surface; the chart row lives on the
// /insights/cardio-fitness sub-page.
"vo2Max",
// v1.4.32 — "Recent workouts" tile. Surfaces the three most-recent
// canonical workouts; self-gates on at least one row. Default-on
@@ -379,11 +380,14 @@ export const DEFAULT_DASHBOARD_LAYOUT: DashboardLayout = {
// `tileVisible` is forced false because there is no tile surface
// for this widget; only the chart-row card.
{ id: "achievements", visible: true, tileVisible: false, order: 13 },
// v1.4.25 W8d — VO2 max trend tile. Default-invisible on both
// surfaces; opt-in via Settings → Dashboard. Only the tile-strip
// representation today (`visible` stays false so the chart-row
// gate never fires; the chart card lands in v1.5).
{ id: "vo2Max", visible: false, tileVisible: false, order: 14 },
// v1.4.25 W8d — VO2 max trend tile. The strip tile is on by default
// (`tileVisible: true`) so accounts that already sync a VO2max sample
// see cardio fitness without hunting through Settings → Dashboard; the
// tile self-gates on having any VO2_MAX sample (see `showVo2Tile` in
// page.tsx), so accounts with no sample still get a clean dashboard.
// The chart row stays off (`visible: false`) — VO2max charts live on
// the /insights/cardio-fitness and /insights/pulse sub-pages.
{ id: "vo2Max", visible: false, tileVisible: true, order: 14 },
// v1.4.32 — Recent workouts dashboard tile. Default-visible so
// brand-new accounts discover the workout surface without
// hunting through Settings; the tile self-gates on a non-empty