mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(onboarding): offer Garmin as a source
The setup question about where readings come from listed every other connection on Settings and not Garmin, so the flow could neither record it nor end on connecting it. Garmin is now a Q4 source and a browser connectable one: the key is pasted on its card, so nothing can be missing up front. A guard now pins that every connection the health read covers is either an onboarding source or named with the reason it is not. Refs #1333
This commit is contained in:
1 parent
148af765c9
commit
afdb8163ce
16 files changed
+68
-2
No files matched your search
@@ -24,6 +24,9 @@
|
||||
cycles like a period logged by hand, a finished Garmin period also marks
|
||||
its last day, and periods imported earlier are repaired once on the next
|
||||
start. A day you logged yourself is never changed. (#1333)
|
||||
- **Garmin in the setup questions.** The onboarding question about where
|
||||
your readings come from now offers Garmin, and can end on connecting it.
|
||||
(#1333)
|
||||
- **Typing into the smoking history.** "When you stopped" only took text
|
||||
that was already a whole YYYY-MM month, so every keystroke was dropped
|
||||
and only a paste got in. The start year clamped each keystroke into its
|
||||
|
||||
@@ -36694,7 +36694,7 @@ components:
|
||||
type: string
|
||||
const: done
|
||||
sources:
|
||||
maxItems: 10
|
||||
maxItems: 11
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
@@ -36705,6 +36705,7 @@ components:
|
||||
- oura
|
||||
- whoop
|
||||
- polar
|
||||
- garmin
|
||||
- fitbit
|
||||
- strava
|
||||
- nightscout
|
||||
@@ -83103,6 +83104,7 @@ components:
|
||||
- oura
|
||||
- whoop
|
||||
- polar
|
||||
- garmin
|
||||
- fitbit
|
||||
- strava
|
||||
- nightscout
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -5277,6 +5277,7 @@
|
||||
"oura": "Oura",
|
||||
"whoop": "WHOOP",
|
||||
"polar": "Polar",
|
||||
"garmin": "Garmin",
|
||||
"fitbit": "Fitbit",
|
||||
"strava": "Strava",
|
||||
"nightscout": "Nightscout",
|
||||
|
||||
@@ -8,6 +8,7 @@ import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { CONNECTION_KEYS } from "@/lib/integrations/connection-health";
|
||||
import { ONBOARDING_AREA_KEYS } from "@/lib/modules/registry";
|
||||
import { NAV_DESTINATIONS } from "@/components/layout/nav-model";
|
||||
|
||||
@@ -18,8 +19,22 @@ import {
|
||||
deliveringSources,
|
||||
SOURCE_INTEGRATION,
|
||||
} from "../first-result-config";
|
||||
import { ONBOARDING_SOURCE_KEYS } from "../needs";
|
||||
import { BROWSER_CONNECTABLE_SOURCES } from "../wizard-steps";
|
||||
|
||||
/**
|
||||
* Connections the setup flow deliberately does not ask about, each with its
|
||||
* reason. Every other connection must be a Q4 source; a provider shipped on
|
||||
* Settings and missing here was absent from the flow without anybody deciding
|
||||
* it.
|
||||
*/
|
||||
const NOT_AN_ONBOARDING_SOURCE: Record<string, string> = {
|
||||
"google-health":
|
||||
"the successor transport behind the Fitbit answer, which still links the classic Fitbit card",
|
||||
dawarich:
|
||||
"movement context for the environment module, not a source of readings",
|
||||
};
|
||||
|
||||
describe("first-result targets", () => {
|
||||
it("covers every area with exactly one of a form or a page", () => {
|
||||
for (const area of ONBOARDING_AREA_KEYS) {
|
||||
@@ -36,6 +51,33 @@ describe("first-result targets", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("asks about every connection Settings offers, or says why not", () => {
|
||||
const sources = new Set<string>(ONBOARDING_SOURCE_KEYS);
|
||||
const missing = CONNECTION_KEYS.filter(
|
||||
(key) => !sources.has(key) && !(key in NOT_AN_ONBOARDING_SOURCE),
|
||||
);
|
||||
expect(missing).toEqual([]);
|
||||
for (const key of Object.keys(NOT_AN_ONBOARDING_SOURCE)) {
|
||||
expect(CONNECTION_KEYS as readonly string[]).toContain(key);
|
||||
}
|
||||
});
|
||||
|
||||
it("offers Garmin as a source the browser connects with a pasted key", () => {
|
||||
expect(BROWSER_CONNECTABLE_SOURCES).toContain("garmin");
|
||||
expect(SOURCE_INTEGRATION.garmin).toEqual({
|
||||
anchor: "garmin",
|
||||
statusKey: "garmin",
|
||||
credentials: "self-hosted",
|
||||
});
|
||||
const view = connectSourceView("garmin", {
|
||||
connected: false,
|
||||
configured: false,
|
||||
syncHealth: { verdict: "disconnected", since: null },
|
||||
lastSuccessAt: null,
|
||||
});
|
||||
expect(view?.slot).toBe("connect");
|
||||
});
|
||||
|
||||
it("names an integration for every source the browser can connect", () => {
|
||||
for (const source of BROWSER_CONNECTABLE_SOURCES) {
|
||||
expect(SOURCE_INTEGRATION[source].anchor).toBeTruthy();
|
||||
|
||||
@@ -61,7 +61,8 @@ export const AREA_PAGE_HREF: Readonly<
|
||||
* a dead end.
|
||||
* - `shared` — an operator env app is the fallback (`available` says whether
|
||||
* any usable credentials resolve, own or shared).
|
||||
* - `self-hosted` — a URL the person pastes; nothing can be missing up front.
|
||||
* - `self-hosted` — a URL or a key the person pastes; nothing can be missing
|
||||
* up front.
|
||||
*/
|
||||
export type SourceCredentialModel = "byo" | "shared" | "self-hosted";
|
||||
|
||||
@@ -80,6 +81,12 @@ export const SOURCE_INTEGRATION: Readonly<
|
||||
oura: { anchor: "oura", statusKey: "oura", credentials: "shared" },
|
||||
whoop: { anchor: "whoop", statusKey: "whoop", credentials: "byo" },
|
||||
polar: { anchor: "polar", statusKey: "polar", credentials: "shared" },
|
||||
// The person's own Personal API key, pasted on the card.
|
||||
garmin: {
|
||||
anchor: "garmin",
|
||||
statusKey: "garmin",
|
||||
credentials: "self-hosted",
|
||||
},
|
||||
fitbit: { anchor: "fitbit", statusKey: "fitbit", credentials: "byo" },
|
||||
strava: { anchor: "strava", statusKey: "strava", credentials: "shared" },
|
||||
nightscout: {
|
||||
|
||||
@@ -99,6 +99,7 @@ export const ONBOARDING_SOURCE_KEYS = [
|
||||
"oura",
|
||||
"whoop",
|
||||
"polar",
|
||||
"garmin",
|
||||
"fitbit",
|
||||
"strava",
|
||||
"nightscout",
|
||||
|
||||
@@ -34,6 +34,7 @@ export const BROWSER_CONNECTABLE_SOURCES = [
|
||||
"oura",
|
||||
"whoop",
|
||||
"polar",
|
||||
"garmin",
|
||||
"fitbit",
|
||||
"strava",
|
||||
"nightscout",
|
||||
|
||||
Reference in new issue
Block a user