Bucket B of the v1.4.3 polish pass.
Three issues, one commit because they're the same surface:
1. **API & Tokens tables overflowed the settings content column.**
Each table set `min-w-[760px]` (or 860px) so the table never
compressed below that width. On mobile this is intentional (it
gives the inner cells breathing room while the outer wrapper
horizontally scrolls). On md+ the parent column is smaller than
the min-width on common laptop sizings (~800px content area when
the browser isn't full-width), which forced an inline scrollbar
for no benefit. Switched to `min-w-[760px] md:min-w-0` per table
so the constraint releases at the breakpoint where the layout
stops scrolling.
2. **"Auf Updates prüfen" button silently did nothing.** The
client-side handler called `https://api.github.com/.../releases/
latest` directly. Production CSP locks `connect-src` down to
`'self'` + `https://wbsapi.withings.net`, so the fetch was
blocked at the browser before it left the tab. Replaced with a
server-side proxy at `/api/version/check-updates` that fetches
GitHub for the user, compares the running `package.json` version
against `tag_name`, and returns one of `up_to_date | newer_
available | unknown`. The route is auth-gated (cookie OR bearer)
so anonymous traffic can't burn through GitHub's 60-req/hr anon
rate limit on the deployment's IP. The route also annotates the
external call into the Wide Event so a future spike is visible
in the logs.
3. **The About surface had no headings and a stray Badge box.** The
v1.4.2 version put the License inside a `<Badge variant=
"outline">`, which created a small framed pill that read as a
separate widget rather than a peer of the version number. Below
that, the Sources/Changelog/Docs and the update-check button
each lived in their own card with no h2 — three nameless cards
stacked on the page. Restructured into three titled cards:
- **HealthLog** — identity, with version + license rendered
inline as plain monospace pairs (no Badge, no nested grid).
Build SHA + build timestamp ride along on the same row when
set.
- **Quellen & Dokumentation / Sources & docs** — links unchanged
but now under their own h2.
- **Updates** — manual `Check now` button + a passive "Last
checked: …" line that pulls from localStorage so the user
can see when the previous check ran. On mount, if the last
successful check is >24h ago (or has never run), the page
auto-checks once. The 24h window is a deliberate compromise
between "always fresh" and "GitHub anon rate limit". The
error path renders a non-blocking "Couldn't reach GitHub"
message with the alert role so screen readers announce it.
i18n keys touched in both `de.json` + `en.json`:
- `settings.about.linksHeading` (new)
- `settings.about.updatesHeading` (new)
- `settings.about.checkUpdates` (label shortened)
- `settings.about.checking` (button busy state — new)
- `settings.about.lastChecked` / `lastCheckedNever` (new)
- `settings.about.checkFailed` (new — replaces the misleading
`testConnection.errors.connection_failed` reuse)
Tests updated for the new heading + button strings; 669/669 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the SectionPlaceholder fallbacks for Account, AI, Integrations,
Notifications, Dashboard, API, Advanced, and About with real per-section
components. Every /settings/<slug> URL now renders working content; the
placeholder only fires for unknown slugs.
A2-content extraction
- Account: profile + passkeys + password change (account-section.tsx)
- AI: insights + per-user provider override (ai-section.tsx)
- Integrations: Withings + moodLog (integrations-section.tsx)
- Notifications: Telegram + ntfy + Web Push (split into telegram-card,
ntfy-card, web-push-card to keep each file under ~600 LOC)
- Dashboard: layout + thresholds wrappers (dashboard-section.tsx)
- API: endpoints + tokens (api-section.tsx)
- Advanced: export + danger zone (advanced-section.tsx)
- About (greenfield): version, license, build SHA, repo/changelog/docs
links + "Check for updates" against GitHub releases
A2-about
- Reads /api/version via TanStack Query, surfaces app version, AGPL-3.0
badge, short build SHA, build timestamp, repo/changelog/docs links.
- "Check for updates" button compares against api.github.com latest
release tag with up-to-date / newer-available / failure feedback.
A8-UI test buttons
- Shared TestConnectionButton primitive that POSTs to a test endpoint,
surfaces ok-with-latency or translated meta.errorCode failures.
- Wired into Withings + moodLog (Integrations) and Web Push
(Notifications). Glitchtip + Umami remain admin-only.
i18n
- New settings.about.* and settings.testConnection.* key groups in en.json
and de.json.
Cleanup
- Delete src/app/settings/page.legacy.tsx (3230 LOC monolith).
- Convert sync-from-server patterns to the React-recommended
prev-payload-id render-time pattern so the strict
react-hooks/set-state-in-effect rule passes without a file-level disable.
Tests
- New src/components/settings/__tests__/sections.test.tsx with 9 SSR smoke
tests (one per section) — total suite 514 (was 505).