fix(settings): open the docs pages themselves, not their old addresses

The integration runbooks, the Garmin note, the guardian note on a managed
record's connections, the backups admin link and the README's self-hosting
link all pointed at retired docs paths that only resolve through redirects
(or not at all, on a host without them). They now go to the final guide
pages, and the settings tests assert the new addresses.
This commit is contained in:
Marc-André Bombeck committed 2026-10-25 12:12:15 +01:00
1 parent a57d2ffe83
commit 72d90282d5
10 files changed
+29 -22

No files matched your search

+1 -1
View File
@@ -85,7 +85,7 @@ Verify the running version:
curl -s http://localhost:3000/api/version # returns version + buildSha + builtAt
```
`SESSION_COOKIE_SECURE=false` is the one setting plain-HTTP self-hosts must set: without it the session cookie carries the `Secure` flag, the browser drops it over HTTP, and login silently fails. Leave it unset (or `true`) only when a TLS reverse proxy serves HTTPS — and then set `NEXT_PUBLIC_APP_URL` and `APP_URL` to the public URL first (see the [self-hosting guide](https://docs.healthlog.dev/self-hosting/)).
`SESSION_COOKIE_SECURE=false` is the one setting plain-HTTP self-hosts must set: without it the session cookie carries the `Secure` flag, the browser drops it over HTTP, and login silently fails. Leave it unset (or `true`) only when a TLS reverse proxy serves HTTPS — and then set `NEXT_PUBLIC_APP_URL` and `APP_URL` to the public URL first (see the [self-hosting guide](https://docs.healthlog.dev/getting-started/self-host-in-10-minutes/)).
Persistent state lives in exactly one named volume (`postgres-data`, the Postgres data); the app container is stateless, so backing up the database backs up everything. An install from v1.45 or earlier moves its Postgres 16 database into it on the first start ([details](docs/ops/postgres-major-upgrade.md)).
@@ -1,7 +1,7 @@
{
"$comment": "Comment lines that open with a release version, per file under src/. Maintained by src/__tests__/version-stamp-ratchet.test.ts.",
"count": 2897,
"total": 9246,
"total": 9243,
"entries": {
"__tests__/account-payload-consumer-guard.test.ts": 2,
"__tests__/acting-account-boundary-guard.test.ts": 7,
@@ -1381,7 +1381,7 @@
"components/settings/integrations/connections-panel.tsx": 5,
"components/settings/integrations/garmin-info-note.tsx": 1,
"components/settings/integrations/notification-channels-panel.tsx": 1,
"components/settings/integrations/setup-guide-link.tsx": 5,
"components/settings/integrations/setup-guide-link.tsx": 2,
"components/settings/integrations/shared.tsx": 3,
"components/settings/labs-section.tsx": 1,
"components/settings/layout-groups.ts": 2,
+1 -1
View File
@@ -98,7 +98,7 @@ export function BackupsSection() {
{/* External docs link — `noopener noreferrer` because this
leaves the admin shell. */}
<a
href="https://docs.healthlog.dev/admin/backups"
href="https://docs.healthlog.dev/guides/backups/"
target="_blank"
rel="noopener noreferrer"
className="text-primary inline-flex items-center gap-1 underline-offset-2 hover:underline"
@@ -251,8 +251,13 @@ describe("IntegrationsSection — one status display per card", () => {
for (const provider of PROVIDERS) {
expect(html).toContain(`data-testid="${provider}-setup-guide"`);
expect(html).toContain(
`href="https://docs.healthlog.dev/integrations/${provider}"`,
`href="https://docs.healthlog.dev/guides/connect-${provider}/"`,
);
}
// Garmin has no connector; its note goes straight to the section of the
// Google Health guide that explains the route, not through a redirect.
expect(html).toContain(
'href="https://docs.healthlog.dev/guides/connect-google-health/#garmin-owners"',
);
});
});
@@ -139,7 +139,7 @@ describe("<ManagedIntegrationStatus>", () => {
"Services you connect here send their data to Managed record&#x27;s record, not to yours.",
);
expect(html).toContain(
'href="https://docs.healthlog.dev/self-hosting/account-sharing#records-with-no-login"',
'href="https://docs.healthlog.dev/guides/managed-profiles/#connected-services"',
);
});
@@ -31,7 +31,7 @@ describe("<FitbitRetirementNotice>", () => {
expect(html).toContain("Google Health reads the same Fitbit and Pixel");
expect(html).toContain("Everything already imported stays.");
expect(html).toContain('href="#google-health"');
expect(html).toContain("/google-health");
expect(html).toContain("/guides/connect-google-health/");
});
it("says the connection has stopped once the day has come", () => {
@@ -11,7 +11,7 @@ import { ExternalLink, Watch } from "lucide-react";
import { SettingsCard } from "@/components/settings/settings-card";
import { SettingsCardHeader } from "@/components/settings/_card-header";
import { INTEGRATION_DOCS_BASE } from "@/components/settings/integrations/setup-guide-link";
import { GARMIN_DOCS_HREF } from "@/components/settings/integrations/setup-guide-link";
import { useTranslations } from "@/lib/i18n/context";
export function GarminInfoNote() {
@@ -25,7 +25,7 @@ export function GarminInfoNote() {
<p className="text-muted-foreground">
{t("settings.garminInfo.body")}{" "}
<a
href={`${INTEGRATION_DOCS_BASE}/garmin`}
href={GARMIN_DOCS_HREF}
target="_blank"
rel="noopener noreferrer"
data-testid="garmin-docs-link"
@@ -17,11 +17,16 @@ import { ExternalLink } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
/**
* Base for every provider setup runbook. The provider key is appended as a
* path segment, e.g. `https://docs.healthlog.dev/integrations/whoop`. Kept as
* a single constant so the host never drifts across cards.
* The docs site's guides, where every provider runbook lives at
* `connect-<provider>/`, e.g. `https://docs.healthlog.dev/guides/connect-whoop/`.
* These are the pages themselves: the older `/integrations/<provider>` paths
* only resolve through redirects. Kept as a single constant so the host never
* drifts across cards.
*/
export const INTEGRATION_DOCS_BASE = "https://docs.healthlog.dev/integrations";
export const DOCS_GUIDES_BASE = "https://docs.healthlog.dev/guides";
/** Garmin has no connector; the Google Health guide explains the route. */
export const GARMIN_DOCS_HREF = `${DOCS_GUIDES_BASE}/connect-google-health/#garmin-owners`;
export type IntegrationDocsProvider =
| "whoop"
@@ -30,15 +35,12 @@ export type IntegrationDocsProvider =
| "polar"
| "oura"
| "nightscout"
// v1.27.0 — Google Health runbook (docs.healthlog.dev/integrations/google-health).
| "google-health"
// v1.28.x — Strava runbook (docs.healthlog.dev/integrations/strava).
| "strava"
// v1.43 — Dawarich runbook (docs.healthlog.dev/integrations/dawarich).
| "dawarich";
export function integrationDocsHref(provider: IntegrationDocsProvider): string {
return `${INTEGRATION_DOCS_BASE}/${provider}`;
return `${DOCS_GUIDES_BASE}/connect-${provider}/`;
}
/**
@@ -54,7 +54,7 @@ const INTEGRATION_DISPLAY_NAMES = {
/** Where the guardian boundary is explained, connected services included. */
const SHARING_DOCS_HREF =
"https://docs.healthlog.dev/self-hosting/account-sharing#records-with-no-login";
"https://docs.healthlog.dev/guides/managed-profiles/#connected-services";
function iconFor(key: ManagedIntegrationKey) {
if (key === "nightscout") return Droplet;
@@ -2,8 +2,8 @@
* Doc ↔ code parity guard for the Google Health operator runbook.
*
* The setup-guide link on the Settings card sends a mid-setup user to
* `docs.healthlog.dev/integrations/google-health`, rendered from
* `docs/integrations/google-health.md`. If the client ever requests a scope the
* `docs.healthlog.dev/guides/connect-google-health/`; the operator runbook in
* this repository is `docs/integrations/google-health.md`. If the client ever requests a scope the
* runbook doesn't list, or the walkthrough regresses back to a wrong provider
* (the file was once a Fitbit-Web-API walkthrough), a self-hoster follows a
* broken recipe and the OAuth consent screen rejects the connection.
@@ -20,7 +20,7 @@ import { describe, expect, it } from "vitest";
import { GOOGLE_HEALTH_CORE_SCOPES } from "@/lib/google-health/oauth";
import {
INTEGRATION_DOCS_BASE,
DOCS_GUIDES_BASE,
integrationDocsHref,
} from "@/components/settings/integrations/setup-guide-link";
@@ -70,7 +70,7 @@ describe("google-health setup runbook parity", () => {
// The literal argument also compile-checks that "google-health" is a member
// of the IntegrationDocsProvider union.
expect(integrationDocsHref("google-health")).toBe(
`${INTEGRATION_DOCS_BASE}/google-health`,
`${DOCS_GUIDES_BASE}/connect-google-health/`,
);
});
});