Commit Graph

2015 Commits

Author SHA1 Message Date
Maurice 6c6e285c3d test(tours): expect the time estimate on imported tours and hikes without a time
Since the estimate rule, an import without its own time shows the worked-out estimate on the day plan tile, and the sidebar metrics lead with it. Add the estimate field to the RS-01 fixture.
2026-10-20 21:11:43 +02:00
Maurice 93e1156aa4 refactor(tours): bring the tour time parts, collection rows and flyover back under the lint baseline
Move workedOutEndHint and totalText into tourDayTimeHint.ts so TourDayTimeParts only exports components, render the collection row's type icon without a component made during render, and pass the chase camera's lens and scene as one view object.
2026-10-20 21:11:43 +02:00
Maurice dc19807126 fix(tours): zoom the flyover around the rider and keep no stale GPX file
The flyover asked wheel and pinch to zoom around the centre with enable()
on handlers that were already on. MapLibre returns from enable() at once
in that case, so the option never took and a wheel zoom still went to the
cursor before the camera pulled back to the line. Each handler is now
switched off and on again with the centre anchor, and the same way back to
the cursor on pause, stop and unmount. The map stub refuses an enable() on
a handler that is on, like MapLibre does, so the tests see the real anchor.

The GPX file kept for the share sheet was only dropped when the tour's id
or name changed. A route saved elsewhere arrives live with a new revision
and the dialog kept handing out the old file. The kept file now carries the
revision it was read at; a new revision drops it and fetches again, and a
file a tap kept is not shared for another revision.
2026-10-20 20:56:19 +02:00
Maurice e42622d71d feat(tours): let the user zoom during the 3D flyover
The chase camera set a fixed zoom and pitch on every frame, so wheel,
pinch and the +/- keys were undone at once. It now keeps the zoom and
tilt of the user's latest gesture and only follows position and
bearing. While a zoom is still easing the flyover holds for those
frames, since any camera move would cancel the gesture. Wheel and pinch
zoom around the rider while flying, and drag panning is off until the
flyover stops. Starting over returns to the flyover's own zoom.
2026-10-20 20:56:19 +02:00
Maurice 94674e7572 fix(tours): open the GPX share sheet inside the tap
Sharing a tour fetched the GPX file first and only then called
navigator.share, so the tap that asked had often run out by then. The
retry path kept that file for one more tap only, and a tap while a sheet
was still open made the browser throw InvalidStateError, which read as a
failed share.

The share button now fetches the file ahead where sharing is offered
(not while the planner has unsaved changes), and every tap hands a fresh
File built from the kept bytes to the sheet before anything is awaited.
A file a tap had to fetch is kept for the next tap. A tap while a sheet
is open is let be, and InvalidStateError and a closed sheet stay quiet;
only a real failure still says the download is left.
2026-10-20 20:56:19 +02:00
Maurice 7f14dde362 fix(tours): tidy the day times of a tour after review
The get_tour_plan description named the estimate of a tour "such a field"
right after the values of a recording, so it could be read as one of them.
It now follows the sentence on derived fields and says outright that it is
one of them, worked out from distance and heights or the pace of a run.

The arrow between a tour's start and end points from the start to the end
in a right-to-left language as well. A tour just added to a day, which
carries no tour_place_id until the next refresh, now says its overrun like
the row above it. A phone row of an import with a total the travellers
entered shows that one time, the estimate joining its words as on the
desktop. The German overrun line reads naturally without an item name.
2026-10-20 20:52:31 +02:00
Maurice 9765cf3fee feat(tours): give a tour its start and end in the day plan
A tour on a day had no place in the day's timeline: its time was not tied
to the slot it was planned in, so several hikes on one day could not be
lined up. A tour now sits there the way a place does, on the times of its
day entry, one model for every tour type. With a start and a known time
(the planned total, else the estimate of an import) its end follows as the
start plus that time; it is shown fainter, marked with an approximate sign
where it comes from an estimate, and says in its tooltip how it was worked
out. An end typed by hand wins. A day that holds one stage of a multi-day
tour gets no end from the whole route.

When the end runs past the start of the day's next timed item, the row
says so in one quiet line, as a late connection between two city walks
does; nothing is moved. The existing time fields of the day entry, on the
desktop form and the phone sheet, say what the end works out to while none
is typed. City walks keep their arrivals per station. The logic lives in
one module both day plans run on.
2026-10-20 20:52:30 +02:00
Maurice c38eb7ebf0 feat(tours): estimate the walking time of imported tours
A hike imported from GPX, KML/KMZ or wanderer had no time at all, so
several hikes on one day could not be planned against each other. It now
gets the walking time the planner times a hike by (DIN 33466), worked out
from its own distance, ascent and descent; a run gets its distance at the
pace entered. Without heights in the track the time is unknown rather
than the time on the flat, and types timed by a router, by a speed of
their own or by nothing get no estimate.

The estimate is derived on every read and never stored, so tours imported
before get it too and no stored or entered time is touched. The rule moved
to @trek/shared, where the planner, the client and the server read it.
The tour list, the day rows on desktop and phone and the tour detail say
it as an estimate, apart from a planned total; list_tours and
get_tour_plan carry it as time_estimate and name it as derived.
2026-10-20 20:52:30 +02:00
Maurice e653733390 fix(notifications): a little more room for the unread count, with a test 2026-10-20 20:52:23 +02:00
Maurice 2655e510fc fix(notifications): give the unread count room in its badge 2026-10-20 20:48:33 +02:00
Maurice 904eb31e62 fix(tours): even the tour detail's rows and footer
The times fill their row when there are two, the trip days are boxes in
the look of the measures with the date under the day, the footer's
collection button carries its label like the others and the copy button
says Copy, and the name field keeps its distance to a save button as large
as the close button.
2026-10-20 20:48:33 +02:00
Maurice 76ec302526 feat(tours): kept tours are rows of a collection's list, on the phone too
A tour kept in a collection was a card in a box of its own above the list,
and its button lost its look to the collections page's button reset. It is
now a row of the list like a saved place: its grade or type tile, its name,
type and the trip it came from, its measures, and Add to a trip, with
removing dimmed beside it. The list's search narrows the tours too. The
phone shows the same rows and takes a tour into a trip from a sheet, on the
same hooks as the desktop.
2026-10-20 20:48:33 +02:00
Maurice 810feba413 fix(tours): open the tour dialogs in the middle of the screen
The walk from a Google Maps link, the take-over from another trip and the
other new tour dialogs sat at the top of the screen; they now open centred
like the planner's own dialogs.
2026-10-20 20:15:05 +02:00
Maurice 9bc543a387 chore(tours): keep the client ratchets where they were
Snowshoe is no longer exported, useRouteCalculation takes the stage stops
type through dayRoutePlan, and tourPlannerFacts and useTourRoute hand the
saved duration, the ski check and the planned key to small helpers.
2026-10-20 19:07:13 +02:00
Maurice 7291555e95 test(tours): follow the ski tour changes in the tests
The collection tour fixture no longer writes the dropped winter_activity
column, the drafts are saved as version 11, and a hike no longer offers
the pistes layer, which belongs to a ski track only.
2026-10-20 19:07:12 +02:00
Maurice 69df85bfa2 chore(tours): format the ski and winter files 2026-10-20 18:41:55 +02:00
Maurice be6702f3ab fix(tours): keep the shipped ski migrations and follow the ski tour through
The winter label and four-discipline migrations are already on
feat/tours-board-rest, so a database that ran them would refuse to boot
or fail the old CHECK. 045500, 045520 and 046100 are back as they
shipped, and a new migration drops both winter_activity columns and
adds ski_discipline again with the six disciplines. The entity and
table types follow the column to its new place.

German, Hungarian, Indonesian and English no longer name the whole type
with the ski touring word, and the info dot speaks of ski tours and
tracks. search_tour_pois and its wiki row list rides and ski and winter
tours. Snowshoeing gets a snowshoe glyph instead of the walk's
footprints, a ski import without a discipline can be planned over (the
planner asks for it), and an overlay shown by default tries its tiles
afresh each time it comes on.
2026-10-20 18:40:48 +02:00
Maurice 164a3633ac feat(tours): plan ski and winter tours, snowshoeing and winter hiking among them
Ski becomes "Ski & winter", a type the planner plans with six disciplines
(alpine, snowboard, cross-country, ski touring, snowshoeing, winter hiking),
nothing preselected; saving needs a discipline, and a technique for
cross-country. Every leg is drawn straight between the points through
planner/skiRouting.ts, the one place the piste router will plug in, with its
heights from the elevation source and no ski time worked out.

The hike's winter label goes entirely: its migration, column, field, marks,
GPX rule, MCP field and strings. A hike is summer only; a ski tour with the
snowshoe discipline exports as snowshoeing. The unreleased ski migration takes
the six disciplines and the collection migration loses the winter column.

The pistes are offered for a ski tour, shown until switched off, and with no
tour open, never for a hike. Export, copy, collections, stages (untimed),
actual tracks, the atlas, list and day marks (one glyph per discipline), 3D,
planning over a ski import and list_tours/get_tour_plan know the planned ski
tour.
2026-10-20 18:40:48 +02:00
Maurice 204ee2ef86 chore(ci): give the server test typecheck room, format new client files
The server's src and tests together are past 570,000 lines and the test
typecheck needs about 4.3 GB, over Node's default heap; it now gets 8 GB like
the test jobs. Forty new client files are formatted, and the react-hooks/refs
baseline drops by the one warning a split hook removed.
2026-10-20 18:39:58 +02:00
Maurice baba2de344 refactor(planner): hand the day plan its tours as one bundle from the page hook
Which places are tours, their planned times and where their stages run
travel together to the desktop and the phone day plan. useTripPlannerPage
now puts them together as dayPlanTours, and the page passes that bundle
instead of naming the three props at both places.
2026-10-20 18:26:56 +02:00
Maurice 49dd2db040 refactor(planner): project a day's tours by assignment in one place
The day route plan and the day plan sidebar both built the map of a day's
stops projected onto their tours, each stage on its own stretch, by hand.
projectedById in dayTourProjection builds it for both, and the sidebar's
drive runs reuse the route plan's point type instead of spelling it out
twice.
2026-10-20 18:26:00 +02:00
Maurice 49e306ea48 refactor(map): report the GL viewport from a module of its own
reportGlViewport says what a GL map shows, its bounds and its zoom on the
raster tile scale, and has its own test for that scale. MapViewGL only
wires it to moveend and idle, and its test checks that wiring. The GL map
tests put the zoom back to its default before each test, as they do for
every other value a test overrides, instead of each test restoring it.
2026-10-20 18:23:50 +02:00
Maurice 1d7c8a63e2 refactor(tours): hold the planner's routing choices in a hook of their own
The hike's limit and preferences, the bike profile and the run profile were
four states with four refs kept in step by hand in every handler that set
them. useRoutingChoices holds them as one value with one ref, so a history
step, an undo, a new draft and an opened tour each lay them in with one
call, and useTourPlanner is back under the size limit.
2026-10-20 18:21:46 +02:00
Maurice 20bd384feb fix(tours): send a ski import's technique only when one is chosen
The classification request may clear the technique with null; the GPX
import fields take it or leave it out, so the null never reaches them.
2026-10-20 18:05:40 +02:00
Maurice 58302dc9e4 fix(tours): keep the planner page hook's view model its only object return
The map focus helpers split out of useTripPlannerPage returned object
literals ahead of the hook's own return, which the B4A wiring test reads as
the view model. They move to tourMapFocus.ts beside the hook.
2026-10-20 18:05:40 +02:00
Maurice b460cfd9a7 refactor(tours): move non-component exports out of component files and split long hooks
Clears the client lint ratchet: helpers move to sibling .ts files for react-refresh, complex render paths get small helpers, floating promises are voided, the stage rail lets a stale request go during render, and the collections page reads the active list's tours and rights in ActiveCollectionTours. StageNumber is no longer exported.
2026-10-20 17:51:28 +02:00
Maurice 2fc9b1991a test(tours): fix client test expectations and mocks
The type order puts run before kayak, the import button reads Import GPX or KML, and the mocks gain what the components now read: routeRun, packing items and links, the map's zoom, the translation provider and the compare store's map flag.
2026-10-20 17:51:27 +02:00
Maurice 0f600d04f5 fix(tours): import the walk icon, keep one stop menu open and count only stage ends a change lost
The activity section used Footprints without importing it. Opening one stop's menu now closes any other. lostStageEnds no longer counts a stop the change kept without its mark as lost twice over. The wanderer watch switch keeps the same tree once the connection is known, so it is not remounted and keeps its focus.
2026-10-20 17:51:26 +02:00
Maurice e40e576e39 fix(tours): preset a ski tour's actual track as ski, and cover the run and ride presets
Ski has been an importable type since SKI-02, yet a ski tour's recording
still opened in the GPX preview as a hike. It now opens as ski with the
tour's discipline, and its technique for cross-country. The run profile
fallback and the ride preset get their tests.
2026-10-20 16:57:27 +02:00
Maurice 223b056de2 fix(tours): name a round hike's distance bounds {from} and {to}
The three round hike strings passed formatted distances as {min} and
{max}, and {max} is a quantity param, so i18n parity read them as count
strings outside a plural group and failed. The bounds are now {from} and
{to} in every locale and in the card.
2026-10-20 16:56:45 +02:00
Maurice 981c372640 fix(tours): let only the latest read set a collection's kept tours
Two reads of the same collection, after two changes by other members or
the first read overlapping one, could answer in either order and an older
list replace a newer one. A refused removal also restored the list from
before it, dropping changes read meanwhile; it now only puts its own tour
back.
2026-10-20 16:56:15 +02:00
Maurice 839d736905 fix(atlas): keep tour exclusions right when their answers come back out of order
Each exclusion replaced the whole list with its answer, so two quick
exclusions answered in the other order, or a read answered after an
exclusion landed, put back a tour as counted although the server held it
excluded. Only the answer to the latest request is now taken whole, with
the exclusions still on their way laid over it; an older answer only
confirms its own tour.
2026-10-20 16:55:34 +02:00
Maurice b9391a9921 fix(tours): hold an actual track change back while the tour is offline or queued
Linking or unlinking a recorded track went out even in offline mode and
behind a queued write of the same tour, and its answer replaced the whole
cached tour with the server's older state, losing the local change. Both
now refuse as online only in those cases and for a tour the server has
not got, the view says so, and the answer only updates the cached
tour's recordings.
2026-10-20 16:54:35 +02:00
Maurice a249c861e6 fix(tours): read and write a run's pace in the user's distance unit
The pace was always min/km and the run's time sum forced kilometres, so
with distances in miles the run card disagreed with every other figure in
the planner. The pace is still kept per km, but is typed, shown and
checked per mile when distances are in miles, and the time sum reads in
that unit too.
2026-10-20 16:51:34 +02:00
Maurice 2a40b884a1 fix(tours): keep a kept tour's remove button in sight, dimmed
It was invisible until hover or focus, so a phone or tablet had no way to
find it. It now shows dimmed and comes up fully on hover or focus.
2026-10-20 16:48:09 +02:00
Maurice f5be556c27 fix(tours): list a kept tour with its type's marks, pace and stages
The collection copy keeps the winter, run, ski, bike and stage columns,
but its list item only carried the older fields, so a kept ski track lost
its discipline mark, a snowshoe hike its winter mark, a run its pace and
a multi-day tour its stage count. The item now carries them, and a kept
tour's card shows the pace and the stages beside its measures.
2026-10-20 16:48:00 +02:00
Maurice 6b1488994f fix(tours): give an actual track its own mark and a winter tile its label's icon
Footprints stood for a snowshoe hike, an actual track and a walk's moving
time at once, with the snowshoe pill and the track pill side by side in a
tour's head. An actual track now goes by the done mark on the list row,
in the head and on a recording's tile, and a winter tile's corner takes
the icon its head pill shows.
2026-10-20 16:46:08 +02:00
Maurice 2ee4ea1e65 fix(tours): keep a multi-day tour's days in sight in the list row
The stage count sat in the row's fixed-height line of badges, so a tour
with stages and a recorded track wrapped and lost its days badge. The
count now sits on the fold button, a moon with the number at its corner,
or beside the row where it does not unfold, and the days come before the
measures so the ascent is what gets cut.
2026-10-20 16:44:55 +02:00
Maurice a1d683d7bc fix(tours): show a run's ways in the hike's trail details card
A run described its ways in a card of its own, with the bike's sections,
the bike's paint for the SAC grades (T5 and T6 merged) and its own words,
so the same path read differently on a hike and on a run. The run now
uses the hike's card, matched as a run, and keeps only the unpaved share
and the hardest grade in its head. The run's grade labels and the now
unused SAC paint go.
2026-10-20 16:42:47 +02:00
Maurice ae726ed370 fix(tours): time a run's stages at its pace and leave a ride's stages untimed
A multi-day run's stages took a share of the foot router's time while the
run itself is timed at the runner's pace, so the stages did not add up to
the run. A ride has no time at all, so its stages have none either.
2026-10-20 16:38:42 +02:00
Maurice f4750352e6 fix(tours): fit the merged tracks together after integration
Types, test expectations and helpers the seven tracks each changed on their
own, brought in line with the integrated code. tours.service.ts and the tours
repository grew past the size limit with every track and hand their row and
write helpers to modules of their own.
2026-10-20 16:30:55 +02:00
Maurice fbba4fd73b fix(tours): refresh the wanderer watch after a fixed token and truly disable its switch offline
The watch row only re-read its state when the connection came or went, so after
a passing connection test or a newly saved token it kept saying "Token refused"
until a reload. The connection card now hands it a key built from the saved
connection and its last check, and the row re-reads the watch whenever that
changes.

Without a connection the switch was only dimmed: the button stayed in the tab
order and was announced as active. ToggleSwitch gains a disabled prop that
disables the button and marks it aria-disabled, and the reason stays reachable
through a focusable wrapper carrying the tooltip.
2026-10-20 15:35:32 +02:00
Maurice 2e1dca9fe9 feat(tours): let a background check hint at changes of your own wanderer trails
Settings, Integrations, wanderer gains an optional background check of the
trails you imported, off until you switch it on. While on, TREK reads the
short record of each such trail at most once a day (never its GPX file) and
leaves a hint when the trail may have moved on: "may have changed" when only
wanderer's change time moved, "changed" when its name or description proves
it, and "not checkable" when the trail is gone, no longer yours or carries no
change time. Nothing is ever said to be unchanged. A new hint arrives as a
notification that opens the tour (a new ?place= link in the planner); the
tour's provenance shows it with the source check right beside it, and the
card lists all open hints in a dialog, each leading to its tour. The check
reads the source in full as before and spends the hint; taking a change in
stays the confirmed reimport. No tour is ever changed or deleted.

The check only asks through your own connection, only about trails your
account imported into trips you can still open, and stops when you switch it
off, remove the connection, wanderer refuses the token (until a test passes
or a new token is saved) or the admin switches wanderer off; hints and
snapshots stay. A run asks at most 25 connections for at most 10 records
each, one after another, and an instance that fails (an outage, a rate
limit) is left alone for an hour, doubling up to two days.

Server: migration 046120 adds the switch and the run bookkeeping to
wanderer_connections and the tour_source_hints table (one row per snapshot,
for its importer, gone with it). WandererWatchService and an hourly
wanderer-watch job on the CronRegistrar live in the tours domain and read
through WandererService; GET and PUT /api/integrations/wanderer/watch and GET
/api/trips/:tripId/tours/wanderer/sources/:placeId/hint (place_edit, like the
check) answer with @trek/shared contracts. A new user notification event,
wanderer_source_hint, can be muted per channel. Saving a new token now clears
what the last check said about the old one. There is no MCP tool, as for the
rest of the personal wanderer connection. All 27 locales carry the strings,
and the admin wiki page says what the check does.
2026-10-20 15:35:32 +02:00
Maurice aacc7f2c8d fix(tours): open a tour's packing list on Packing, and ask before letting go of it while Packing is off
"Open packing list" switched to the Lists tab but left it on whichever
sub-tab was open last, so someone who had been in the to-dos landed there.
It now picks the packing side first, and a Lists tab already on screen
follows the choice; storage that is blocked no longer throws either.

With the Packing addon off, "Remove link" let go of the link on one click,
and the link cannot be made again until Packing is back on. It now opens
the tour's packing dialog with only the dimmed link and the Remove link and
Cancel buttons, so nothing changes without a second, deliberate click.
2026-10-20 15:35:09 +02:00
Maurice f833a05461 feat(tours): point a tour at its trip's packing list
A tour can now point at the packing list of its trip, as a whole or at one
of its categories (say "Hiking gear" for a hike), and shows it in its detail.
The new Packing list section reads the list live as the user may see it: the
backpack tile with the item count on its corner and the category's own
colour, how many are packed with a thin progress bar, the first items ticked
off or not with their quantity, how many more there are, and a button that
opens the trip's Lists tab. Who may change the tour links one, changes it or
lets go through a dialog that lists the whole list and every category with
its colour and item count, and writes only on its confirm.

It is a reference, never a copy: the items stay in Packing, are ticked off
and edited there, and each traveller sees in the tour only the items Packing
shows them, so an item kept to oneself never shows through a tour. A
category that is renamed, cleared or only holds items of others reads as
missing, an empty one as empty, a link that could not be read says so with a
retry, and while Lists are switched off the link stays, dimmed, and can
still be let go. Removing the link, or the tour, leaves the list and every
item as they are. Nothing suggests or changes an item by itself.

On the server the link is a row of its own in the tours domain
(tour_packing_links, migration 046110), one per tour and gone with it.
GET, PUT and DELETE /api/trips/:tripId/tours/:placeId/packing-link read it
with the trip and change it with place_edit; linking needs the Lists addon
and, for a category, an item of it the user can see. The writes answer the
tour with its link and tell the trip through tours:changed, so the offline
client queues them as writes of the tour and replays them like one. A copied
trip keeps its tours' links, a tour saved as new or taken over does not.
The MCP tools get_tour_packing, link_tour_packing and unlink_tour_packing run
over the same service and checks; the read also hands the tour's facts as
context for suggesting what to pack, which only becomes an item through the
packing tools. The empty category placeholder now lives in @trek/shared so
both sides leave it out alike. All 27 locales carry the new strings, and
the wiki describes the link and the tools.
2026-10-20 15:35:08 +02:00
Maurice 65fe8cd6e5 fix(tours): explain a kept tour without a line, and say the take-over once
Taking a tour kept in a collection into a trip left the user guessing in
two places when the tour had no line. The map box stayed an empty grey
square that read as a broken map; it now says that there is no line yet,
only the waypoints. Why "Line only" is dimmed was only in the tooltip of a
disabled button, which never shows on hover, focus or touch; the reason now
stands under the two choices, and a disabled tile sits in a span so its
tooltip can show as well.

A successful take-over said the same sentence twice, as a toast and as the
dialog's last word with "Open trip". The toast is gone.

The collection strings move out of tours.ts into a tourCollection.ts per
locale, keeping their keys, so no locale's tours file grows past the
1000-line limit. The tours locale spec now holds both files to their own
counts.
2026-10-20 15:34:09 +02:00
Maurice 3fe34061fd feat(tours): keep whole tours in collections and take them into trips
A saved tour can now be kept in a collection, apart from any trip, and
later made into a tour of another trip. The bookmark button in a tour's
footer and in the planner's head (waiting for the save while there are
unsaved changes) opens a dialog with every list of the user; a list they
may only read stays in it, dimmed with a lock and a tooltip. The list
keeps an independent copy: the line, the type, every measure and setting,
the waypoints in order with their roles, the origin, and the trip and tour
it was saved from as they were called then. Its days, its links to places
of the trip and its obstacle decisions stay in the trip, and later changes
to the tour do not reach the copy.

A collection shows its kept tours as cards above its places: the grade
tile with the source badge, measures and the waypoint count as badges,
the trip it came from, and who kept it. The owner or an admin of the list
can remove one after a question; tours made from it stay. "Add to a trip"
shows the kept tour on a map with its facts and numbered waypoints, lists
the user's trips (the ones they may not add tours to dimmed), and asks
outright whether the waypoints come along. "Line only" keeps the line as
saved and adds no waypoints; a tour kept without a line can only bring
them. The new tour has an id of its own, no days and no new places, and
names the trip and tour it was saved from; the dialog then offers to open
that trip. Neither the collection nor the original tour changes.

On the server the kept tours are a table of their own in the tours domain
(collection_tours, migration 046100), each row written whole once. Every
copy, the in-trip "save as new tour", the take-over from another trip and
both directions here, now goes through one copy model (tour-copy.helpers)
instead of a second one. Reading and removing follow the collection's
roles, keeping one also needs access to the source trip, and taking one
over needs place_edit on the target trip; the kept tour is read again
inside the write, so one removed meanwhile leaves no half-made tour. The
MCP tools list_collection_tours, get_collection_tour,
save_tour_to_collection, take_over_collection_tour and
delete_collection_tour run over the same service and checks. All 27
locales carry the new strings, and the wiki describes the flow.
2026-10-20 15:32:47 +02:00
Maurice 3659297af1 feat(tours): import KML and KMZ routes as tours, with a preview first
A route planned in Google My Maps or Google Earth can now become a tour
without converting it to GPX first. The import button and a file dropped on
the tours workspace take .kml and .kmz files beside .gpx, through the same
preview, the same import routes and the same transaction as a GPX file.

The preview shows every line of the file on its own, numbered, with its
distance and heights; two lines of one placemark are numbered after its name
and never joined. Heights count only where they are heights: kept for an
absolute line, dropped for any other altitude mode and for the all-zero
placeholder My Maps writes, so a missing height stays unknown. What the file
holds besides its lines (pins, areas, overlays, links to other files) is
counted in a dashed card, and nothing is fetched from elsewhere.

The KML reading reuses the place import's codec. A KMZ only ever has its KML
entry unpacked, counted byte by byte against the decompressed cap whatever
its header claims. A file that cannot be read is refused with its reason
(damaged, an archive without KML, too large unpacked), and the toast names
the file and the reason. A KML or KMZ import keeps the gpx origin of a file
import; its provenance names the real format from the stored file name.
2026-10-20 15:30:18 +02:00
Maurice f57a0dbd31 fix(tours): let an unwanted stage go and read a tour's stages once
Two review findings of MDT-02 in the planner's list and the day plan:

- A stage asked for while the draft has unsaved changes stayed pending when
  the changes were kept or the tour failed to open, so opening that tour
  later from its row jumped to a stage nobody asked for then. The rail now
  has cancel(), which the discard question calls when it is dismissed and
  the open calls when it fails, and it lets a stage go once the opened
  tour's points are in and none of its stages starts at that stop.
- Every day holding a stage of a tour read the whole tour on its own, so a
  five stage tour sent five identical requests on top of the list's own.
  tourPointsRepo shares one read per trip, tour and revision among the
  views showing it at the same time, through the tour repo as before, and
  drops it once the last view lets go or the read fails.
2026-10-20 15:28:23 +02:00
Maurice 8fa75b3c4e feat(tours): show a multi-day tour's stages in the list and put each on a day
A multi-day tour in the planner's list of the trip's tours now unfolds into
its stages (MDT-02), so the stages can be seen together and fitted into the
trip without leaving the one route they are cut from.

- The fold beside a multi-day tour lists its stages in route order, each
  from stop to stop with its distance, climb, descent and moving time, read
  off the saved tour the way the planner reads them, and below them what the
  whole tour adds up to. A value no stage tells is left out, a total some
  stages do not tell is marked as at least that much and says for how many,
  and a stage whose route is not planned yet says so.
- Each stage has its own day: a pill opens the trip's days, moves the stage
  to another one or takes it off again. A stage without a day shows a dashed
  "No day" pill. A day holds a tour, or one of its stages, once, and a stage
  is on one day at most; the plan's own offline path writes it.
- A stage opens in the planner: the tour opens as any tour does and the
  stage is shown once its points are in.
- The day plan names the stage a day holds with its own figures, and the
  day's route runs to that stage's start and on from its end; the trip map
  draws that stretch only. The tour list still counts a tour once, however
  many days hold it or its stages.
- A saved change that takes a stage away (its stage end gone, the tour a day
  tour again, back to the recorded track) takes it off its day in the same
  write and tells every client; the planner says so before the save.
- REST and the assign_place_to_day tool take the stage by the key of the
  stop it starts at, with the same checks; list_tours names the stops
  between the stages and the stage each day holds.

A day assignment remembers its stage by that key (migration 046010); every
assignment made before holds the whole tour, as it did.
2026-10-20 15:28:22 +02:00