Commit Graph
7789 Commits
Author SHA1 Message Date
Marc-André Bombeck c816946140 Tidy the token, connector and share-link settings cards
The API tokens card names every kind of token it lists and reads in
sentence case. Each ingest card and the connector card fold the
shown-once note into the paragraph about what the token can do, and
their name fields suggest a fitting example instead of one phone
shortcut everywhere, short enough to stay whole on a phone. The
connector card drops the status badge that repeated its switch. Share
links get their own card next to the one that creates them.
2026-10-08 20:35:56 +02:00
Marc-André Bombeck c90d28e597 Name the admin account and invite cards apart from their pages
The users page card is now "Accounts" and the invites card "Invite
links", so neither repeats the page title above it, and the token
overview reads "API tokens" in sentence case. The role filter pills
stay neutral when selected, and the three icon tools on a phone row
wrap as one group instead of leaving the sign-out icon on its own line.
2026-10-08 20:35:56 +02:00
Marc-André Bombeck 161963c82b Put the passkey and security-key add actions in the card's action row
Both cards now end in the one right-aligned action row with the add
action as the card's primary, like the authenticator card's set-up
button, and both show the same plain empty state. The error line moves
above the row so nothing follows it.
2026-10-08 20:35:55 +02:00
Marc-André Bombeck f363405df0 Merge the settings and admin UI round into release/v1.42.0 2026-10-08 20:21:39 +02:00
Marc-André Bombeck ee16d3ca72 Update settings and admin copy
New card titles and one-sentence descriptions, sentence case for admin
titles, a current anamnesis subtitle, and the keys the pass retired.
2026-10-08 20:20:04 +02:00
Marc-André Bombeck f4d2ec8988 Tidy admin settings cards
Offer every shipped locale as the server default language, move the app
log refresh out of the header status slot, let filter selects fill their
grid cells, name the coverage table as a focusable region, hide the
legacy-key badge when only one key exists, keep the encryption cards
still while they load, and stop repeating the page title in card titles.
2026-10-08 20:20:03 +02:00
Marc-André Bombeck 37f922af97 Fix settings field rows, defaults and narrow layouts
Module rows drop the field-label colon and inset, the reminder number
fields align, target defaults print at their own precision, the
appointment offer wraps instead of squeezing to one word per line, the
export format legend matches its neighbour label, and the profile-photo
explainer reads as body text.
2026-10-08 20:20:03 +02:00
Marc-André Bombeck 2dda933d77 Align layout settings cards and the insights arrange editor
The insights arrange list becomes a Settings card with its own header and
a Save that waits for a change; the self-link back to the page it sits on
and the focus grab on load are gone. The medications view card takes the
header shape the labs and documents cards use, the order card shares
their title and loads with row placeholders, and the documents view card
uses their icon.
2026-10-08 20:20:03 +02:00
Marc-André Bombeck 991764b0c8 Give settings cards one action row at the foot
The TOTP enable, the source-priority reset, the biomarker and record add
actions, and the about-me, profile-facts, emergency and condition saves
move into SettingsCardActions, right-aligned and last in the card. The
emergency Save waits for a change like its neighbours, an empty list
leaves its add action to the empty state, and the source ladder keeps
its up/down buttons side by side on a phone.
2026-10-08 20:20:03 +02:00
Marc-André Bombeck 97e4dd4c05 Split the AI provider settings into one card per concern
The page was one card titled like the page, holding seven grey panels
with three primary Saves, each left-aligned mid-card. Provider, fallback
chain, response timeout, document reading, consents and the check row
are separate Settings cards now, each with one action row at its foot.
The chain rows keep the name on its own line on a phone, and the cards
below the provider card wait for its reads so they do not jump.
2026-10-08 20:20:02 +02:00
Marc-André Bombeck 8fc467f8c5 Merge the second UI round into release/v1.42.0 2026-10-08 20:05:44 +02:00
Marc-André Bombeck a1a0afe675 Let the vaccination journey wait for its list before adding
The header add disappears once an empty Impfpass has loaded; the
journey now waits for a record or the empty state and clicks whichever
add control is on screen.
2026-10-08 20:03:47 +02:00
Marc-André Bombeck 276cac1d5b Point the e2e add flows at whichever add control a surface shows
A list that is empty now carries its add action in the empty state
instead of the header, and on the phone shell the dashboard's add opens
the capture sheet. The overflow, mood timestamp, measurement flow,
onboarding tour and delegated-write journeys accept either control; the
measurement list's empty-state add gets a stable data-slot for that.
2026-10-08 19:51:16 +02:00
Marc-André Bombeck 5be7a9c242 Label the privacy page's sign-in link in German like its headings 2026-10-08 19:37:31 +02:00
Marc-André Bombeck a5e947ce97 Keep the unit and the time whole when the phone meta line wraps
'vor 10 Stunden' broke across two lines; the unit and the time now
wrap as units, the source badge after them.
2026-10-08 19:37:02 +02:00
Marc-André Bombeck 0bcf465e38 Close the off-switch token comment
A broken comment terminator swallowed the light theme's off-track
value, leaving the track unset.
2026-10-08 19:36:02 +02:00
Marc-André Bombeck 3b4d031e1e Lay the medication tabs out three-up on a phone
Wrapped, the last two tabs stretched across the second row.
2026-10-08 19:34:16 +02:00
Marc-André Bombeck 7d3ee68bf1 Describe a device-served strain score by the device line alone
The proxy's TRIMP method sat above the device note and described a
number the card was not showing.
2026-10-08 19:33:51 +02:00
Marc-André Bombeck dd49ec63a6 Sort the shell-variant classes the way the formatter orders them 2026-10-08 19:20:49 +02:00
Marc-André Bombeck e227f8e4f3 Give off switches and disabled primary buttons light-mode contrast
In the light theme an off switch's track was the input grey at ~1.4:1
on the card, and a disabled primary button was white on a half-opacity
violet at ~2:1. An off track now has its own token at ~3.5:1, and a
disabled primary button a pale violet fill with a dark violet label at
~5.5:1. The dark theme keeps its look through the same tokens.
2026-10-08 19:17:50 +02:00
Marc-André Bombeck 28458448c2 Bring the day surfaces into one language
The cycle and travel rows of a day read their server sentinels
('cycle', 'travel', a raw flow level) instead of words, so a day said
'cycle · Tag 8'. They are worded in the reader's language now. The
date in the phone measurement row and the workout row wrapped to
'vor 9 Stunden…' because the text column shrank to its value; it takes
the row's width and wraps instead of truncating. The intraday pulse
card drops its coloured identity edge, takes a title that says what it
shows, and says there is not enough for a course instead of drawing one
dot across 24 hours. The day body's top inset moves from the banned
pt-5 to pt-4.
2026-10-08 19:14:22 +02:00
Marc-André Bombeck e9a5614733 Colour insight series from the chart palette, not the status tokens
Metric pages coloured their series with success, info, warning,
destructive or a raw palette yellow, picked per page, so a steps line
read as 'good' and a resting-pulse line as an alarm. Series now take
the chart tokens by hue family (chart-2 green, chart-3 pink, chart-4
cyan, chart-5 orange), and the systolic/diastolic pair and the pulse
pair stay paired. Status colours remain where they carry meaning:
target bands, time in range, mood score scales. The mood tag scale
drops its raw palette reds and greens for the status tokens, which are
tuned for the light theme.
2026-10-08 19:08:51 +02:00
Marc-André Bombeck a1b46eb2f4 Write workout durations and pace the reader's way
Workout durations read '38m 00s' and '1h 02m' in every locale, the pace
'5:51 /km', and the detail header printed its raw source key. The
detail now shows a clock reading with the locale's unit ('38:00 Min.',
'1:02:05 Std.'), the list and the dashboard tile the shared localised
minutes label, the pace 'min/km', and the header the source's name.
2026-10-08 19:07:37 +02:00
Marc-André Bombeck 8302f5f62a Write mood insight figures with the reader's decimal separator
Averages, deltas and correlation figures on the mood insights went
through toFixed and read '3.4' in German. They use the locale formatter
now, and the whole-number crosstab cells pick up thousands grouping.
2026-10-08 19:04:30 +02:00
Marc-André Bombeck 7d738c0e49 Lead the meta line with the unit in the phone measurement list
On a phone a long unit beside the value ('12,5 Atemzüge/min') pushed
the row's controls. The value stands alone and the unit opens the muted
meta line beside the time and source, where meta belongs.
2026-10-08 19:03:32 +02:00
Marc-André Bombeck 5850036527 Number the Telegram steps once and spell Client-ID one way
The setup steps carried '1.' in their copy inside a numbered list, so
the card read '1. 1.'. The list numbers them now. Three integration
cards spelled 'Client ID' and 'Client Secret' where the others write
'Client-ID' and 'Client-Secret'.
2026-10-08 19:02:32 +02:00
Marc-André Bombeck b3fb9afa2c Lead the privacy and about pages with the reader's language
The privacy policy is German first in every body, but its section
headings, title and table of contents led in English and its date read
2026-08-11 on both lines. Headings now lead in German with the English
title beside them, the contents list follows, and each date line writes
the date as its language does. The about page's headings, date and
sign-in link follow the reader's locale. No legal wording changed.
2026-10-08 19:02:00 +02:00
Marc-André Bombeck 5bb6b6ad21 Name the share segment's not-found page in the URL-credential guard
It sits under the [token] segment, so the route-shape leg finds it; it
reads no token and resolves nothing.
2026-10-08 18:56:02 +02:00
Marc-André Bombeck f944c07cdf Explain a dead share link and a broken invite in the reader's terms
A practice opening an expired or revoked share link met the app's own
404, 'this page does not exist', with a button to a dashboard it has no
account for. The share segment now has its own not-found page: link
expired or invalid, ask the person who shared it for a new one, and no
link anywhere. It still answers 404 for every failure class alike.

A malformed invite link fell through to the plain registration form.
It now says the invitation is invalid and offers sign-in; the shape
check is public, so this reveals nothing about which tokens exist, and
a well-formed token still goes on to registration.
2026-10-08 18:55:45 +02:00
Marc-André Bombeck 005cb32ea8 Give every empty list one empty state and one add action
EmptyState now has a single action shape: centred at its own width on
the 44 px tap floor, never stretched edge to edge on some pages and
compact on others; the per-call-site size switch is gone, and the
dashed card takes the card radius. While a list is empty its empty
state carries the add action, so the header drops its own add button
there (measurements, mood, medications, labs, vaccinations, documents,
illness, check-ups, visits, procedures). The dashboard medication tile
of an account without medications offers 'Add a medication' instead of
'no data in the chosen range'.
2026-10-08 18:53:24 +02:00
Marc-André Bombeck 793c19e179 Keep delete affordances neutral until the confirmation
Row delete buttons, overflow-menu delete items and per-row revoke
buttons painted red in lists, so a list of tokens or shares read as a
wall of alarms. They now sit in the muted tone (foreground on hover)
or as an outline button; the red is kept for the confirmation dialog
that every one of them opens, and for the danger zones, which are a
destructive card-wide action by design.
2026-10-08 18:45:02 +02:00
Marc-André Bombeck 142dfa9360 Let the score section test settle its reveal
The section now waits for its reads before it shows; the mocked query
client reports nothing in flight.
2026-10-08 18:45:02 +02:00
Marc-André Bombeck aa3049a14c Emit the strain device block on every wellness read
The published WellnessScoreValue lists every field the engine sends, and
the contract test holds the two sets equal. The computed path now sends
device: null like anchor and components, and the device path has its
own contract case.
2026-10-08 18:45:01 +02:00
Marc-André Bombeck 651ec3aea8 Merge complete-window folding and the fold repair into release/v1.42.0 2026-10-08 18:42:46 +02:00
Marc-André Bombeck adc7baca14 Fold only complete local days and repair means folded from part of one
The daily-mean consolidation and the dense hourly fold cut at
`now - threshold` instead of a local day boundary. A day was folded in two
runs and the second run overwrote the stored mean with the mean of the
later part alone: every mean-type day, and the boundary hour of every
heart-rate, HRV and SpO2 day, plus the derived resting figure and the DAY
rollup of such a day. The Health Connect importer split its raw window at
the same unaligned instant.

- Fold up to the start of the account's local day the threshold ends in
  (`foldBoundary`), for every consolidation pass and the Health Connect
  importer's raw/hourly split.
- A window that already has a live `stats:` row is refolded from every
  sample of it, live rows plus the fold's own tombstones; with none left
  the stored mean stays.
- `folded_window` refuses a raw sample only when its local day lies before
  the aligned boundary and a live `stats:` row of its source covers it,
  also within reach of the sample after a timezone change.
- A deletion inside a day the fold had not finished is class B.
- Add a one-time, resumable fold repair per account that recomputes each
  hourly and daily mean from its remaining samples and writes only values
  that differ, recorded in `measurement_fold_repairs` (migration 0389).
- The compaction-tombstone purge waits for the repair per account, and the
  boot sends no purge run before one account is repaired.
- The restore keys live `stats:` ids by source, and writes compaction
  tombstones back from a file older than the account's repair, resetting
  the repair.
2026-10-08 18:42:01 +02:00
Marc-André Bombeck 2b91953cc9 Title the illness page as the navigation names it
The page called itself 'Krankheitstagebuch' while the navigation says
'Krankheit', and at 390 px the long word broke with a hyphen beside the
header actions. The title now reads the navigation label in every
locale.
2026-10-08 18:39:30 +02:00
Marc-André Bombeck d867c4bf83 Fold the medication API tab back into Erweitert
Seven tabs on a medication cut the strip off mid-label at 390 px. The
API tab's one group (per-medication tokens and drug coding) now sits in
Erweitert as a collapsed group before the danger zone, an old ?tab=api
link lands there, and on a phone the six remaining tabs wrap into two
rows instead of scrolling a label off the edge.
2026-10-08 18:39:12 +02:00
Marc-André Bombeck 6ca33882f1 Open the capture sheet from the dashboard's add button on phones
On the phone shell the header's 'Add' opened a dropdown while the plus
in the bottom nav, one thumb below, opened the capture sheet. The header
button now opens the same sheet there; the desktop rail keeps the
dropdown. The onboarding tour anchors on whichever of the two is laid
out.
2026-10-08 18:36:46 +02:00
Marc-André Bombeck b53782810f Keep the phone shell on a phone held sideways
A phone in landscape is 844 to 932 px wide, past md, so it got the
desktop rail and top bar: a sliver of content and no thumb-reachable
navigation. Two variants now decide the shell: shell-desktop from md up
except on a touch screen at most 520 px tall, shell-mobile otherwise.
The sidebar, top bar, bottom nav, the main column's bottom clearance,
the Coach button, the selection bar and the two full-height Coach pages
all key on them instead of a bare md.
2026-10-08 18:36:45 +02:00
Marc-André Bombeck a0c5ab6591 Hold data-shaped page bodies until their reads settle
Several pages stacked cards whose final height is the data's: the
illness day timeline, the measurement list, the insights arrange list,
the system status cards, the score notices that land with the slower
report. Each resolving on its own pushed the rest down the page, for a
CLS of 0.11 to 0.18 at desktop width. RevealWhenSettled mounts the body
at once but keeps it out of layout until no query is in flight (two
frames running, two seconds at most), with a placeholder in its place.

The chart loading shells were also ~100 px shorter than the card they
became: they now reserve the day-dot row, its caption and the collapsed
data-table disclosure, and the range-tab row at its 44 px height.
2026-10-08 18:34:11 +02:00
Marc-André Bombeck 1a52384a1d Open stat strips on the chart's window instead of all time
The strip painted the all-time summary until the chart reported its
visible window, then swapped to it, so every number jumped a beat after
load. The chart now reports only once its read has settled (a failed
read settles too), and until then the strip holds its cells at their
final height.
2026-10-08 18:20:57 +02:00
Marc-André Bombeck f7b6ea5dad Read Apple Health liveness off the data, not only the batch stamp
The status verdict looked only at the user's last-batch column, which
moves on a live batch alone. Rows that reached the account another way,
such as the export.zip import, left it null, and the card said 'waiting
for first data' beside a four-digit record count. The verdict now takes
the newest of that stamp, the per-type arrival ledger and the newest
stored sample.
2026-10-08 18:18:46 +02:00
Marc-André Bombeck ac482c508d Serve the device's day strain on the strain page when no proxy exists
The recovery page charts the band's own DAY_STRAIN while the strain
score page read only the computed proxy, so one account showed weeks of
strain on one page and 'not enough data' on the other. Without a proxy
row in the window the derived strain read now falls back to DAY_STRAIN:
the score is the reading as a share of the device scale, an additive
'device' block carries the native value, and the course below the card
charts that same series.
2026-10-08 18:17:20 +02:00
Marc-André Bombeck 605d9b1fb4 Stop rewarding a doubled or a skipped dose
The 'took it twice' and 'skipped a dose' badges rewarded over- and
under-dosing. Both definitions, their metrics and their copy in every
locale are gone. An unlock row already persisted for either id stays in
the database and in backups, but no longer renders: the evaluator only
walks the shipped catalogue.
2026-10-08 18:12:13 +02:00
Marc-André Bombeck d0e2238b65 Merge the app-wide UI audit into release/v1.42.0 2026-10-08 18:03:26 +02:00
Marc-André Bombeck 3a20f23f0f Give touch screens 44 px targets through the primitives
A pointer-coarse variant sits beside the pointer-fine one. Under it the
default, small and icon buttons, tab triggers, the sidebar rail rows and
the phone logo link reach the 44 px touch floor; a mouse keeps the
compact desktop density. The rail's height steps now apply to a mouse
only. A phone held sideways crosses the md breakpoint at about 390 px of
height, where the fixed footer left the list three rows: there the whole
rail scrolls as one column, without a native scrollbar.
2026-10-08 17:52:44 +02:00
Marc-André Bombeck 492c2a4131 Merge remote-tracking branch 'origin/release/v1.42.0' into v142/ui-audit 2026-10-08 17:44:00 +02:00
Marc-André Bombeck d286cf5bcd Merge PWA and mobile fixes into release/v1.42.0 2026-10-08 17:40:46 +02:00
Marc-André Bombeck 4673973a79 Title the mood sheet like the other capture sheets; fit the documents search hint
The mood page's sheet now reads 'Stimmung erfassen' like the same sheet
everywhere else, and the documents search placeholder is short enough to
show whole on a phone.
2026-10-08 17:34:21 +02:00
Marc-André Bombeck 105c293544 Size the catalog row skeleton to the row, drop the sparkline focus stop
The catalog's loading rows were 6 px shorter than the loaded ones, so the
groups below moved when a probe landed. The decorative score sparklines
sit in an aria-hidden wrapper, and Recharts' accessibility layer put a
focusable surface inside it.
2026-10-08 17:34:20 +02:00