Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
f3116e6
Allow setting the meal when editing logs from the overview
rolandgeider Jul 30, 2026
0d7eb3a
Save and use unit data from the measurement extra_data field
rolandgeider Jul 30, 2026
c3afd3e
Validate the weight form limits in the selected unit
rolandgeider Jul 30, 2026
8a4f021
Keep the stored unit when inline edits do not touch the weight
rolandgeider Jul 30, 2026
3069d54
Raise a clear error when the body weight category is missing
rolandgeider Jul 30, 2026
8feb645
Wait for the profile before rendering the weight form
rolandgeider Jul 30, 2026
a5e6a4c
Preserve unknown extra_data keys on the edit round trip
rolandgeider Jul 30, 2026
9cab379
Other cleanups
rolandgeider Jul 30, 2026
4319473
Validate inline weight edits against the plausibility bounds
rolandgeider Jul 30, 2026
256bc0e
Add health-sync related fields to categories and their entries
rolandgeider Jul 30, 2026
0897c70
Route measurement charts by metric type
rolandgeider Jul 30, 2026
dacd419
Add metric type and group selection to the category form
rolandgeider Jul 31, 2026
7a6cec6
Render multi-value groups with a combined chart and group entry form
rolandgeider Jul 31, 2026
f290735
olish the group display on the dashboard and delete dialog
rolandgeider Jul 31, 2026
d6f9f1c
Add drag-and-drop reordering for measurement categories
rolandgeider Jul 31, 2026
8e48810
Read measurement values through a unit-aware helper
rolandgeider Jul 31, 2026
b4e8952
Add the chart series model and its data functions
rolandgeider Jul 31, 2026
8c3dd64
Draw measurement charts from a list of typed series
rolandgeider Jul 31, 2026
d09ecfc
Size chart marks by how many share the width
rolandgeider Jul 31, 2026
8b12692
Chart a two-component group as one bar per reading
rolandgeider Jul 31, 2026
aa09c9d
Format chart axes, tooltips and legends
rolandgeider Jul 31, 2026
f00d8bb
Show the overall change and tie group rows to their lines
rolandgeider Jul 31, 2026
614e22c
Fold a band's bounds into the row of its own line
rolandgeider Jul 31, 2026
04073b4
Drop the WeightEntry model in favour of MeasurementEntry
rolandgeider Jul 31, 2026
6e3a489
Chart body weight with the shared measurement chart
rolandgeider Jul 31, 2026
2fb3134
Let the charts show a range and the nutrition plans behind it
rolandgeider Jul 31, 2026
99d4de7
Drop the unused weight FilterButtons widget
rolandgeider Jul 31, 2026
dbb0039
Mirror the typed measurement category rules
rolandgeider Aug 1, 2026
a9ffacf
Mirror the sleep stage metric types
rolandgeider Aug 2, 2026
682a345
Stack the sleep stages in the group chart
rolandgeider Aug 2, 2026
ec874bc
Fetch only the range the charts show
rolandgeider Aug 2, 2026
a11efb0
Mirror the per-metric value limits from the server
rolandgeider Aug 2, 2026
34178db
Fetch body weight through the measurement loader
rolandgeider Aug 2, 2026
e99c2e4
Put body weight on the measurement API and cache layer
rolandgeider Aug 2, 2026
ca5d80c
Show body weight in the measurement data grid
rolandgeider Aug 2, 2026
7c12e2a
Fold the weight domain into the measurements one
rolandgeider Aug 2, 2026
d2d3f6b
Show typed categories under their translated name
rolandgeider Aug 2, 2026
1198a6b
Let the user pick the chart of a measurement category
rolandgeider Aug 2, 2026
8789a8e
Do not offer a chart type where it has no effect
rolandgeider Aug 2, 2026
e55ee4c
Do not offer a chart type where it has no effect
rolandgeider Aug 3, 2026
5309aa1
Show the user when a measurement write is refused
rolandgeider Aug 3, 2026
9007633
Show the user when a write is refused, everywhere
rolandgeider Aug 3, 2026
1b94a45
Stop measurement views from fetching whole histories
rolandgeider Aug 3, 2026
14a8f44
Ask a category itself whether it has components
rolandgeider Aug 3, 2026
4ef4c8a
Pick the metric instead of typing it into a form
rolandgeider Aug 3, 2026
8a9e1fa
Merge branch 'master' into feature/health-sync
rolandgeider Aug 4, 2026
0991511
Read durations in hours and minutes
rolandgeider Aug 4, 2026
44a61a6
Add a weekly change (delta) chart type
rolandgeider Aug 5, 2026
2297f8a
Read duration deltas in hours and minutes
rolandgeider Aug 5, 2026
4958cd5
Add distribution histogram chart type
rolandgeider Aug 5, 2026
a0a9d5b
Add per-category chart settings (trend, average window)
rolandgeider Aug 5, 2026
80b1df5
Add a one-month chart range
rolandgeider Aug 5, 2026
143189c
Read the measurement charts from the aggregate endpoints
rolandgeider Aug 6, 2026
120a062
Read the histogram over the range it is labelled with
rolandgeider Aug 6, 2026
c2166cb
Draw the bar charts in one shared frame
rolandgeider Aug 6, 2026
55e6815
Read only what the measurement screens show
rolandgeider Aug 6, 2026
5754e38
Read the measurement entries where they are shown
rolandgeider Aug 6, 2026
ab4e04d
Read the measurement table one page at a time
rolandgeider Aug 7, 2026
986a53d
Let the pages hand the plan periods to the measurement screens
rolandgeider Aug 7, 2026
533a688
Untangle the last import cycles
rolandgeider Aug 7, 2026
f28af6e
Put the filter objects into the query keys
rolandgeider Aug 7, 2026
e87a942
Give each measurement chart its own file
rolandgeider Aug 7, 2026
b5d2c94
Add blood oxygen as a metric type
rolandgeider Aug 7, 2026
6253aa1
Add lean body mass as a metric type
rolandgeider Aug 7, 2026
61c519d
Drop the "count" unit from step categories
rolandgeider Aug 7, 2026
c7c4f47
Lay the measurement overview out as a grid of linked cards
rolandgeider Aug 7, 2026
3bd41dd
Lay the measurement overview out as a grid of linked cards
rolandgeider Aug 8, 2026
43d8e99
Show the card headlines at the metric's own resolution
rolandgeider Aug 8, 2026
c4c906c
Share and persist the chart range across the measurement screens
rolandgeider Aug 9, 2026
b36418a
Default the measurement charts to one month
rolandgeider Aug 9, 2026
a242fc2
Draw the measurement charts in the theme's own colours
rolandgeider Aug 9, 2026
2ab35b5
Show a group's readings as one row per measurement
rolandgeider Aug 9, 2026
0a787d8
Merge branch 'master' into feature/health-sync
rolandgeider Aug 10, 2026
ca7fe14
Use the new datetime fields for workout sessions
rolandgeider Aug 10, 2026
ba00d1a
Show session API errors in the form
rolandgeider Aug 10, 2026
896258f
Merge branch 'feature/health-sync' into feature/release-2.7
rolandgeider Aug 13, 2026
eb9b155
Merge branch 'feature/refactor-workout-session' into feature/release-2.7
rolandgeider Aug 13, 2026
80cc862
Refresh the body weight views after an entry is written
rolandgeider Aug 13, 2026
b840cdf
Read the calendar month as instants instead of dates
rolandgeider Aug 13, 2026
6da5885
List only the selected range in the body weight table
rolandgeider Aug 13, 2026
59215d6
Cut every view of a range at the same day
rolandgeider Aug 13, 2026
ce8494c
Read the theme from context in the chart widgets
rolandgeider Aug 13, 2026
744563e
Show measurement categories under their metric type on the dashboard
rolandgeider Aug 13, 2026
a708964
Deduplicate the measurement widgets and forms
rolandgeider Aug 13, 2026
9d632dd
Search the session of a day as a local time window
rolandgeider Aug 13, 2026
31fe52b
Extract the overview floating action button
rolandgeider Aug 13, 2026
dc264f2
Translate the empty chart placeholder
rolandgeider Aug 13, 2026
5968040
Build the reference time of the relative-date tests inside the test
rolandgeider Aug 13, 2026
976b6b8
Give the observer test mocks the constructor of the real API
rolandgeider Aug 13, 2026
1d47f66
Read the calculated categories
rolandgeider Aug 15, 2026
1fa1283
Replace the slick carousel with CSS scroll snapping
rolandgeider Aug 15, 2026
101ebce
Merge branch 'master' into feature/release-2.7
rolandgeider Aug 18, 2026
0fb4bff
Filter the workout sessions by day
rolandgeider Aug 18, 2026
2c2f6c7
Allow users setting up calculated categories
rolandgeider Aug 20, 2026
03c5496
Allow disabling the average and the trend lines
rolandgeider Aug 20, 2026
77c0885
Report the browser timezone to the profile
rolandgeider Aug 23, 2026
4249c4d
Build a real Profile in the timezone test fixture
rolandgeider Aug 23, 2026
affa389
Ask for the session day as a date filter
rolandgeider Aug 24, 2026
623535b
Stop echoing the metric type on category updates
rolandgeider Aug 24, 2026
bc388b8
Refuse dates the picker cannot vouch for
rolandgeider Aug 24, 2026
eba89de
Refresh the entry reads when a category changes
rolandgeider Aug 24, 2026
a05cca3
Serve the category entry flags from cache
rolandgeider Aug 25, 2026
80453f1
Refresh the calendar's session list on session writes
rolandgeider Aug 25, 2026
ddf91cc
Check the value limits in one place
rolandgeider Aug 25, 2026
132f9a6
Route the exercise reads of the category form through query hooks
rolandgeider Aug 25, 2026
6562cff
Split the measurement chart module
rolandgeider Aug 25, 2026
067934a
Lift the calculation prefill and the chart settings out of CategoryForm
rolandgeider Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ const DOMAINS = [
'User',
];

// The key must not import the values: nutrition reads measurements, not the
// other way round, or the two form a module initialisation cycle.
const FORBIDDEN_DEPENDENCIES = {
Measurements: ['Nutrition'],
};

const restrictAllDomains = {
"patterns": [{
"group": DOMAINS.map(d => `@/components/${d}/*`),
Expand All @@ -32,12 +38,18 @@ const domainOverrides = DOMAINS.map(domain => ({
files: [`src/components/${domain}/**/*.{ts,tsx}`],
rules: {
"no-restricted-imports": ["error", {
"patterns": [{
"group": DOMAINS
.filter(d => d !== domain)
.map(d => `@/components/${d}/*`),
"message": `Import other domains via their public surface (e.g. '@/components/${DOMAINS[0]}'), not internal sub-paths.`,
}]
"patterns": [
{
"group": DOMAINS
.filter(d => d !== domain)
.map(d => `@/components/${d}/*`),
"message": `Import other domains via their public surface (e.g. '@/components/${DOMAINS[0]}'), not internal sub-paths.`,
},
...(FORBIDDEN_DEPENDENCIES[domain] ?? []).map(target => ({
"group": [`@/components/${target}`, `@/components/${target}/*`],
"message": `${domain} must not import ${target}: the dependency runs the other way. Take what you need as a prop, from the page that composes both.`,
})),
]
}],
}
}));
Expand Down
74 changes: 6 additions & 68 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@
"react-i18next": "^17.0.8",
"react-is": "^19.2.7",
"react-router-dom": "^7.17.0",
"react-slick": "^0.31.0",
"react-simple-wysiwyg": "^3.4.1",
"recharts": "^3.8.1",
"slick-carousel": "^1.8.1",
"slug": "^12.0.1",
"typescript": "^6.0.3",
"yup": "^1.7.1"
Expand All @@ -80,7 +79,6 @@
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/react-is": "^19.2.0",
"@types/react-slick": "^0.23.13",
"@types/slug": "^5.0.9",
"@vitest/coverage-v8": "^4.1.9",
"eslint": "^10.7.0",
Expand Down
2 changes: 1 addition & 1 deletion public/locales/cs/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
"filterVegan": "Vegan",
"filterVegetarian": "Vegetarián",
"filterNutriscore": "Nutri-Score filter",
"filterNutriscoreOff": "Vypnout",
"filterNutriscoreNoFilter": "Žádný filtr",
"filterNutriscoreOrBetter": "{{grade}} nebo lepší"
},
Expand All @@ -129,6 +128,7 @@
"weight": "Váha",
"date": "Datum",
"timeOfDay": "Čas",
"off": "Vypnout",
"submit": "Potvrdit",
"edit": "Upravit",
"delete": "Odstranit",
Expand Down
105 changes: 103 additions & 2 deletions public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,10 @@
"max_reps": "Max. Wdh.",
"plates": "Gewichtsscheiben"
},
"off": "Aus",
"submit": "Abschicken",
"weight": "Gewicht",
"syncedEntryInfo": "Dieser Eintrag wurde aus einer Health-App synchronisiert und kann nur dort geändert werden",
"workout": "Training",
"images": "Bilder",
"description": "Beschreibung",
Expand Down Expand Up @@ -175,6 +177,9 @@
"logsHeader": "Trainingsprotokoll für das Workout",
"addLogToDay": "Protokoll zu diesem Tag hinzufügen",
"otherLoggedExercises": "Weitere protokollierte Übungen",
"multipleSessions": "An diesem Tag wurde mehr als eine Trainingseinheit protokolliert, wähle die aus, die du bearbeiten willst",
"newSession": "Neue Trainingseinheit",
"changeSession": "Andere Trainingseinheit auswählen",
"backToRoutine": "Zurück zur Routine",
"maxLengthRoutine": "Die Routine darf maximal {{number}} Wochen lang sein",
"resultingRoutine": "Resultierende Routine",
Expand Down Expand Up @@ -250,9 +255,106 @@
"preferences": "Voreinstellungen",
"success": "Geschafft!",
"measurements": {
"calculations": {
"sourceManual": "Von Hand eingetragen",
"sourceCalculated": "Von wger berechnet",
"type": "Berechnung",
"locked": "Die Berechnung kann nicht geändert werden. Lösche die Kategorie, um sie zu beenden.",
"paramsIncomplete": "Die Berechnung ist noch nicht vollständig eingerichtet",
"missingHeight": "In deinem Profil fehlt die Körpergröße, daher können noch keine Werte berechnet werden.",
"noSourceCategory": "Du hast noch keine andere Kategorie, aus der gelesen werden kann.",
"badge": "Berechnet",
"entryInfo": "Dieser Wert wird von wger berechnet und kann nicht geändert werden",
"names": {
"BMI": "BMI",
"WHTR": "Taille-Größe-Verhältnis",
"ONE_REP_MAX": "1RM",
"ONE_RM_TOTAL": "1RM-Summe"
},
"descriptions": {
"BMI": "Aus deinem Körpergewicht und der Körpergröße in deinem Profil",
"WHTR": "Aus {{category}} und der Körpergröße in deinem Profil"
},
"params": {
"category_id": "Quellkategorie",
"max_reps": "Maximale Wiederholungen",
"window_days": "Zeitfenster in Tagen"
},
"paramsHelp": {
"exercise_ids": "Zwischen {{min}} und {{max}} Übungen, {{count}} ausgewählt.",
"max_reps": "{{min}} bis {{max}}. Sätze darüber werden ignoriert.",
"window_days": "{{min}} bis {{max}}. Wie weit zurück ein bester Satz zählt."
}
},
"reorderCategories": "Kategorien neu anordnen",
"deleteInfo": "Dies wird die Kategorie sowie alle seine Einträge löschen",
"deleteInfoGroup": "Dies wird die Gruppe sowie alle ihre Komponenten und deren Einträge löschen",
"unitFormHelpText": "Die Einheit, in der die Kategorie gemessen wird, wie cm oder %",
"measurements": "Messungen"
"measurements": "Messungen",
"metricType": "Metrik-Typ",
"chartType": "Diagrammtyp",
"chartTypes": {
"auto": "Automatisch",
"line": "Linie",
"bar": "Balken",
"heatmap": "Heatmap",
"delta": "Veränderung",
"distribution": "Verteilung"
},
"chartTrend": "Trendlinie",
"trends": {
"reactive": "Reaktiv",
"balanced": "Ausgewogen",
"sluggish": "Geglättet"
},
"chartAverageWindow": "Durchschnitt über",
"chartAverageWindowDays_one": "1 Tag",
"chartAverageWindowDays_other": "{{count}} Tage",
"distributionMedian": "Median",
"distributionLatest": "Aktuell",
"distributionEntryCount_one": "1 Eintrag",
"distributionEntryCount_other": "{{count}} Einträge",
"distributionDayCount_one": "1 Tag",
"distributionDayCount_other": "{{count}} Tage",
"partOfGroup": "Teil der Gruppe",
"noGroup": "Keine Gruppe",
"metricTypes": {
"custom": "Benutzerdefiniert",
"body_weight": "Körpergewicht",
"body_fat": "Körperfett",
"lean_body_mass": "Magermasse",
"height": "Körpergröße",
"blood_pressure": "Blutdruck",
"blood_pressure_systolic": "Systolisch",
"blood_pressure_diastolic": "Diastolisch",
"heart_rate": "Herzfrequenz",
"resting_heart_rate": "Ruhepuls",
"blood_oxygen": "Sauerstoffsättigung",
"steps": "Schritte",
"distance": "Distanz",
"energy": "Energie",
"sleep": "Schlaf",
"sleep_total": "Gesamtschlaf",
"sleep_light": "Leichtschlaf",
"sleep_deep": "Tiefschlaf",
"sleep_rem": "REM-Schlaf",
"sleep_awake": "Wach"
},
"indicatorRaw": "raw",
"indicatorAvg": "Durchschn.",
"indicatorTrend": "Trend",
"noDataAvailable": "Keine Daten vorhanden",
"overallChangeWeight": "Allgemeine Veränderung",
"chartRangeAll": "Gesamt",
"chartRangeMonths_one": "1 Monat",
"chartRangeMonths_other": "{{count}} Monate",
"chartRangeWeeks_one": "1 Woche",
"chartRangeWeeks_other": "{{count}} Wochen",
"chartRangeYears_one": "1 Jahr",
"chartRangeYears_other": "{{count}} Jahre",
"customMeasurement": "Eigene Messung",
"metricAlreadyTracked": "Wird bereits aufgezeichnet",
"categoryFormHelpText": "Messkategorie, z. B. „Bizeps“ oder „Körperfett“"
},
"timeOfDay": "Uhrzeit",
"notes": "Notizen",
Expand Down Expand Up @@ -322,7 +424,6 @@
"filterVegan": "Vegan",
"filterVegetarian": "Vegetarisch",
"filterNutriscore": "Nährwertfilter",
"filterNutriscoreOff": "Aus",
"filterNutriscoreNoFilter": "Kein Filter",
"filterNutriscoreOrBetter": "{{grade}} oder besser"
},
Expand Down
Loading
Loading