Compare commits

..

27 Commits

Author SHA1 Message Date
jubnl 62723b37e8 fix(tests): memory leak 2026-06-23 18:02:35 +02:00
Maurice dbfceddb1a ci: give client test workers 8 GB heap (no coverage) to fix worker OOM (#1258) 2026-06-22 23:26:37 +02:00
Maurice 697f9d723d ci: run client tests without coverage to avoid the v8 report OOM (#1258) 2026-06-22 23:13:53 +02:00
Maurice fe1ae5c4bf ci: raise client coverage heap to 12 GB for the v8 report phase (#1258) 2026-06-22 22:49:18 +02:00
Maurice 72d9f62f39 ci: raise Node heap for the client coverage run to fix OOM (#1258) 2026-06-22 22:22:41 +02:00
Maurice 7cfff1f6a3 fix(map): draw the route line to and from the day's accommodation (#1275)
The map route ran first-activity to last-activity only, while the sidebar
already showed the hotel-to-first-stop and last-stop-to-hotel legs with
their drive times. Feed the day's accommodation bookends into the map
route too, reusing the same getDayBookendHotels lookup and the
"optimize from accommodation" gate, so the drawn line starts and ends at
the hotel, including single-activity and transfer days.
2026-06-22 22:08:30 +02:00
Maurice 7a8a3ee4f2 fix(costs): allow recording an expense with no split or payer (#1286)
Adding an expense required at least one participant, so a cost you only
want to record — e.g. a booking paid on-site later — could not be saved
without splitting it. Drop the participant requirement: with nobody
selected the expense saves as a recorded total, counted in the trip
total and shown as Unfinished, and kept out of settlements until
who-paid is filled in. The shared schema and server already supported
this case.
2026-06-22 21:50:23 +02:00
Maurice 927ddd6421 fix(packing): keep a custom category when its last item is removed (#1289)
Removing the only item of a user-created category deleted the whole
category. Turn that row back into the existing ... placeholder in
place instead, so the category keeps its position and colour; adding an
item reuses the placeholder slot. Deleting the placeholder (or the
category menu) still removes an empty category.
2026-06-22 21:27:28 +02:00
Maurice c0b5d941dd fix(dashboard): show an error instead of a blank trip list when the server is unreachable (#1283)
When the backend or identity provider was unreachable, a returning user with a
persisted session landed on the dashboard with an empty trip grid and no error.
That looks identical to a logged-in user who simply has no trips, so people
assumed their data had been lost.

Three client-side layers were quietly swallowing the failure: the auth check
only cleared state on a 401, so a 5xx or a network error left the stale session
in place and kept rendering the protected route; the offline-first trip repo
turned a failed fetch into the empty cache without throwing; and the dashboard
had neither an error nor an empty state, so a blank grid meant both "outage" and
"no trips".

The auth check now tells genuine offline (keep serving the cache silently, the
PWA happy path) apart from a server outage while online (keep the session but
flag it). The dashboard shows a reassuring "couldn't reach the server, your
trips are safe" banner with a retry, and a real zero-trip account finally gets a
proper empty state so the two cases never look alike. New strings added across
all locales.
2026-06-21 23:08:25 +02:00
Maurice a074debd61 fix(auth): keep the last admin when OIDC claims would demote it (#1274)
On OIDC-only instances the bootstrap admin (first SSO user) rarely carries the configured admin claim, so a forced re-login — e.g. after a JWT-secret rotation — re-derived its role purely from claims and demoted it to user, locking the instance out with no recovery. The OIDC login role sync now skips a downgrade that would strip the last remaining admin, and the admin user-update endpoint guards the same case.
2026-06-21 00:28:39 +02:00
Maurice 5f44cd1403 feat(planner): bring back the Google Maps route export button (#1255)
The day-plan route bar lost its Open in Google Maps action in the 3.1.0 redesign. A small button with the Google logo (monochrome, theme-aware) now sits next to the Route toggle and opens the day stops, in planned order, as a Google Maps directions link in a new tab.
2026-06-21 00:00:35 +02:00
Maurice 459b092e28 fix(admin): show non-Docker update steps when not running in Docker (#1269)
The "How to Update" modal always rendered Docker commands and claimed the instance runs in Docker, even on bare-metal / LXC installs like Proxmox Community Scripts. It now branches on the is_docker flag the backend already returns: non-Docker installs get a generic "re-run your install method" note plus a link to the update guide. Docker stays the default when the flag is absent, so existing installs are unaffected.
2026-06-20 23:41:04 +02:00
Alejandro Pinar Ruiz 4a5cf3d83d feat(helm): add annotations support for PVCs (#1270)
Co-authored-by: Maurice <mauriceboe@icloud.com>
2026-06-20 23:23:08 +02:00
Maurice a8cb2e672a fix(atlas): give the country-GeoJSON fetch a longer timeout (#1254)
The gzipped admin0 GeoJSON is still a few MB, so behind a slow reverse proxy or Cloudflare Tunnel it could exceed the global 8s axios timeout and abort, leaving the map with no countries. It now gets a 30s per-request timeout, matching the existing /maps/pois exception.
2026-06-20 22:58:23 +02:00
Maurice ef7a3d32d8 fix(dashboard): add a text-shadow so spotlight and card titles stay legible (#1267)
When no trip is ongoing the spotlight falls back to a trip gradient, and several of those are light enough that the white title vanished in light mode. A subtle text-shadow on the hero title and trip-card names keeps them readable without affecting dark covers or dark mode.
2026-06-20 22:48:02 +02:00
Maurice e05e16de3f fix(costs): move the unfinished marker to the category icon on mobile (#1266)
A long expense title pushed the "Unfinished" pill into the price on narrow screens. On mobile the status now shows as a small marker on the category icon, freeing the title and price row; desktop keeps the labelled pill.
2026-06-20 22:32:06 +02:00
Maurice 1656ddcae2 test(days): bump over-long-time assertion to the new 250 limit (#1252)
Follow-up to raising the day-note time cap to 250: the unit test still sent 151 chars expecting a 400, which now passes validation and fell through to an unmocked service call.
2026-06-19 18:09:04 +02:00
Maurice 22ad5d73f2 fix(chart): allow setting storageClassName on PVCs (#1261)
The PVC templates rendered no storageClassName and values exposed no key, so clusters without a default StorageClass (or needing a specific class) couldn't install. Add persistence.{data,uploads}.storageClassName, omitted when empty so the default class is still used.
2026-06-19 17:56:42 +02:00
Maurice 5367d24f9f fix(pdf): show photos for OSM places in the trip PDF (#1130)
The PDF photo pre-fetch only fired for places with a google_place_id, so OSM/Nominatim places (osm_id only) fell back to category icons even though they show photos in-app. Recover osm_id from the full places pool (the assignment projection drops it) and key the photo off google_place_id || osm_id || coords, matching the UI.
2026-06-19 17:56:41 +02:00
Maurice 17822aa9eb fix(days): align note time limit to 250 and keep toasts above modal blur (#1252)
The day-note 'time' field capped at 150 server-side while the dialog and shared schema allow 250, so 151-250 char notes 400'd with a confusing 'time must be 150...' message. Raise the controller and MCP limits to 250. Also lift the toast container above modal overlays so the error toast isn't rendered behind the modal's backdrop blur.
2026-06-19 17:56:41 +02:00
Maurice 87e8a44764 fix(dashboard): count archived trips in travel stats (#1264)
The trips/days widgets filtered out archived trips while places, countries and flight distance did not, so archiving a trip zeroed only those two. Drop the is_archived filter so all stats stay consistent.
2026-06-19 17:56:26 +02:00
Maurice f8c77bff8e fix(security): allow same-origin PDF previews under CSP (#1253)
Firefox/Chrome enforce object-src, so object-src 'none' blocked the inline <object> PDF preview (worked only in Safari). Relax to 'self' for same-origin file previews.
2026-06-19 17:56:26 +02:00
Maurice 0b995cfd55 chore: add ca_profile.xml for Unraid Community Apps submission 2026-06-19 17:22:40 +02:00
Neil Soult 7a4c9998af fix(atlas): gzip-compress responses so large country GeoJSON loads behind reverse proxies (#1262)
The admin-0 country GeoJSON served at /api/addons/atlas/countries/geo is
~30 MB uncompressed. With no compression in the request pipeline the
transfer aborts (~8s, net::ERR_FAILED despite a 200) behind reverse
proxies / Cloudflare Tunnel, so the Atlas map never colours visited
countries. LAN is unaffected.

Add the `compression` middleware to the shared applyGlobalMiddleware
pipeline (gzip brings ~30 MB down to ~4 MB). text/event-stream is
excluded so the /mcp StreamableHTTP (SSE) transport is not buffered.

Adds BOOT-008 asserting content-encoding: gzip on the geo endpoint.

Fixes #1254

Co-authored-by: pai <pai@stabpablo.eu>
2026-06-19 16:19:12 +02:00
jubnl 26ade89bc8 chore: dockerignore spec.ts files 2026-06-19 13:59:16 +02:00
jubnl b150b576aa fix(budget): scale category bars relative to top category 2026-06-19 13:52:15 +02:00
jubnl a162289829 fix(budget): accept comma decimal separator in expense amounts
The expense Total Amount, per-person "Who paid", and settlement amount
inputs used type="number" with a bare parseFloat. On desktop the number
input normalized comma→dot for free, but mobile keyboards drop the comma
before onChange fires, so parseFloat("39,99") silently became 39.

Switch the three inputs to type="text" inputMode="decimal" and normalize
comma→dot in their onChange handlers, matching the pattern already used
by the other budget inputs (BudgetPanelInlineEditCell, BudgetPanelAddItemRow,
DashboardPage). Both comma and dot now work on every device.

Closes #1256
2026-06-19 13:16:29 +02:00
5 changed files with 9 additions and 9 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trek/client",
"version": "3.1.2",
"version": "3.1.1",
"private": true,
"type": "module",
"scripts": {
+5 -5
View File
@@ -1,12 +1,12 @@
{
"name": "@trek/root",
"version": "3.1.2",
"version": "3.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@trek/root",
"version": "3.1.2",
"version": "3.1.1",
"workspaces": [
"client",
"server",
@@ -24,7 +24,7 @@
},
"client": {
"name": "@trek/client",
"version": "3.1.2",
"version": "3.1.1",
"dependencies": {
"@fontsource/geist-sans": "^5.2.5",
"@fontsource/poppins": "^5.2.7",
@@ -20543,7 +20543,7 @@
},
"server": {
"name": "@trek/server",
"version": "3.1.2",
"version": "3.1.1",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.28.0",
"@nestjs/common": "^11.1.24",
@@ -20900,7 +20900,7 @@
},
"shared": {
"name": "@trek/shared",
"version": "3.1.2",
"version": "3.1.1",
"dependencies": {
"isomorphic-dompurify": "^3.15.0",
"zod": "^4.3.6"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@trek/root",
"private": true,
"version": "3.1.2",
"version": "3.1.1",
"workspaces": [
"client",
"server",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trek/server",
"version": "3.1.2",
"version": "3.1.1",
"main": "src/index.ts",
"scripts": {
"start": "node --require tsconfig-paths/register dist/index.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trek/shared",
"version": "3.1.2",
"version": "3.1.1",
"private": true,
"description": "Shared API contracts (Zod schemas) — single source of truth for TREK server and client.",
"type": "module",