Repository navigation
Tours: piste routing, Tours layers from TREK Places, tour times and fixes from testing - #2693
Merged
Merged
Conversation
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.
… 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.
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.
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.
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.
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.
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.
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.
A fresh install gets Tours enabled from the addon seeder. An install that already has the row is switched on by a migration that runs once, so an admin who turns Tours off afterwards keeps it off.
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.
…er 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.
…hout 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.
… was before The table holds the seeded addons too, so compare against a snapshot taken before the migration with only tours switched on.
The trail grades under a tour (BIK-05, MAP-03, MAP-04, RUN-02) and the horse routes around a map view (HOR-01) asked the public Overpass mirrors. The places host now serves both from its own planet build: GET /v1/ways for the tags of ways by id and GET /v1/routes for route relations per box, each in Overpass element form. trek-places.client gains trekPlacesWays (batches of 500, one after another) and trekPlacesRoutes, both through getJson with its off switch, breaker, timeout, size cap and instance header, each element validated on its own. TrekPlacesLayersService in the maps domain hands their answers to the tours services, or why there is none (switched off, layer not built, failed), and logs that once per layer until it answers again. Both tours services ask the layer first and fall back to the existing Overpass path; the responses TREK sends its clients are unchanged.
…rtial way answers The ways and routes layers now count failures on a breaker of their own, so busy or slow layer answers no longer send place search to the fallback for a minute, and a layer's 404 no longer clears the count of search failures. When a later batch of /v1/ways fails, the batches that answered are kept and only the ids still open go to the Overpass mirrors. The wiki, the compose file and the chart now say that the way ids of a planned tour and the horse routes box go to the TREK Places API.
…the paddle domain The binary heap and the flat-frame distance helpers are not about water; the piste router needs the same two. They move to src/lib/geo, where any domain may import them without reaching into paddle-routing. Nothing changes in what they do.
A new Nest domain plans the legs of a ski and winter tour on the runs, lifts, cross-country trails, ski touring and winter paths the Places host builds from OpenStreetMap, one SGR1 graph per ski area. TREK fetches the index once, downloads an area by its id when a planner first plans in it, checks it against the index's SHA-256 and keeps it in data/ski; no clicked point ever leaves the server. A leg whose area is slower than two seconds answers loading, and an older copy stands in while the host is down. The reader decodes the writer's golden file byte for byte, including the two edge flags it added (area_has_run, type_unknown). The search is A* in a worker thread over a profile per discipline (alpine, snowboard, cross-country by technique, touring, snowshoe, winter hike) with the times and penalties of the cost model, up to five snap candidates per point, lift stations as entry points, legs that go on from each other, pieces of a split network stitched by their boundary nodes, other ways by the penalty method, and a failed leg explained by relaxing one rule at a time (difficulty, lift class, technique, riding down, uphill) without ever handing out the relaxed line. POST /api/trips/:tripId/ski/route, GET .../ski/area-near and GET .../ski/network/:areaId sit behind Tours and the trip, with plan_ski_route as their MCP twin. A daily job looks for a new build and sweeps areas unused for 90 days. The admin switch ski_routing_enabled is on wherever TREK Places is.
A ski tour now saves the options its legs were planned with and the piste data build they ran on, as one JSON column (a new migration, since the ski migrations have shipped on this branch); the server keeps only the options its discipline reads. Both stay off every other type. The refusal of a ski time is lifted: the piste router works one out, and the planner sends it only when every leg followed the piste data. get_tour_plan names the legs of a tour the router planned as routed, and list_tours says what the new fields hold.
A ski tour with a discipline now sends its legs to the piste router and takes back runs, lifts and trails: each stretch is coloured by its grade in the area's scheme, links and lift rides down are dotted, and a leg the router cannot plan stays straight and unrouted with its reason and the one change that would plan it. Snowshoe and winter hike legs off the piste data follow summer paths instead, said so. The router's time and heights are used once every leg is planned, and the options, the build and the time are saved with the tour. - skiRouteRepo and api: one request per tour, batched, remembered unless the answer may change, offline legs failed as offline - planner: router options per discipline, leg steps and failure rows with fixes, a piste route summary, draft and reopen keep the options - admin: switch for the piste router under Tours - i18n: new ski keys in all 27 locales, ski info and time texts rewritten
… refresh The router thread now takes one job at a time from a queue kept on the main thread, so a job's clock starts when the thread takes it up. A job that times out ends only its own thread, and only while that thread is still the current one; the jobs in line go to a fresh thread instead of waiting out their own timers and killing the new thread in turn. A thread that dies fails the job it held, and a thread that cannot start fails each job on its own. - the daily refresh fetches changed areas two at a time and stops once the TREK Places breaker opens; the rest keep their older copies - the winter index cap is on the unpacked JSON fetch hands over, so it follows from the host's 8 MB gzip cap (64 MB) instead of matching it - a build name is read to the rule a ski tour stores it by, so a build TREK could not save is refused when the winter layer is read - an unused import in the piste router contract is gone
…lanned A saved ski tour now opens with the line, heights, time, build and planned legs it was saved with, read from the place this device keeps, and nothing is asked of the piste router until a point, an option or the discipline changes. Opened offline, while TREK Places is down or with piste routing switched off, it no longer turns every leg straight, and a rename saves the planned tour as it was. A kept line whose length is not the tour's is another save's, and the tour is planned afresh. - the save names the legs the router planned (ski_planned_legs, checked against the tour's own legs); get_tour_plan reports each leg routed or drawn from them instead of from the build alone, a tour that names none counting as planned only with the router's time - copies keep ski_options in every path: in the trip, taken over, kept in a collection and made from one (collection_tours gets the column in the same unshipped migration) - the route summary shows the data build, the km of runs, the height skied down on them and the lift rides, and the credit the server sends in place of a fixed one; a tour opened as saved says so - answers refused while piste routing is off, or planned on an older kept copy, are not remembered, so they are asked again later - terrain heights between known ones are filled in one walk along the line - i18n: five summary keys in all 27 locales
…es as generated A ski leg is routed where the piste router planned it and free elsewhere; the description said both. The collection tours entity takes its generated form again after the merge.
Contributor
❌ Lint & Prettier check failedPlease fix the issues locally by running the following commands inside the cd shared
npm run lint:fix
npx prettier --write <file> # each file lint:format names
npm run lint:format -- --update # when a listed file is formatted nowThen commit and push the changes. |
…lanner under the lint limits The saved ski route compared against an undefined skiKey, so opening a saved ski tour threw. The held seed now lives in useSavedSkiSeed and is matched by skiRouteKey(skiChoice). The ski route facts move to skiRouteFacts.ts so the summary and leg rows only export components, the rail renders SkiPlannerSummary, and openTour, useTourRoute and useAddonManager shed the branches and lines the new ski code had added.
…ki route type from its schema ski-areas.service checks the pending load and download against null and undefined, the area refresh lane recurses instead of awaiting in a loop, TourSkiRoute is inferred from its schema, the ways answer is read by complete === false, and /v1/routes no longer needs a truncated field.
…ice settle before asserting
…an, format three tests
…pped files The place form's time section moves into PlaceFormTimeSection, its tour test into PlaceFormModal.tour.test.tsx over a shared tests/helpers/placeForm setup, the page hook hands the place form its close, day plan and tour, and the day plan's surface classes and tones move into dayPlanSurfaces. The size baseline drops to the new counts.
…ow-up The unused day pills go, a client-only type stops being exported, the place form context moves out of the page hook so its view model stays the first object it returns, the place form test helpers split the stub component from the plain setup, and four router files are formatted.
…m it on Putting a multi-day tour on a day through any of the usual ways put the whole tour on that one day. Now the way it goes on is a choice: the whole tour on this day, or stage 1 on this day and each next stage on the next day of the trip. The day menu of the tour lists and the detail's "Add to day" ask in the same menu, as a second step after the day; a tour dragged onto a day, or added from a place where no menu asked, gets a small dialog on the desktop and a card on the phone. Only the trip's days are used: when fewer days are left than stages, the menu says up to which stage fits and the rest stay without a day. A stage already on a day moves to its new day, the whole tour comes off the days it was on, and a stage the route no longer has comes off too. The writes run in order through the store, the repo and the mutation queue, so they work offline, and one undo takes the spread back, the whole tour onto its day again. The plan lives in stageSpread.ts, the writes and the question in useTourDayChoice, which every way onto a day now passes through on both the desktop and the phone.
…d, and ask on the phone too Spreading a multi-day tour wrote through the store directly and skipped the via re-anchoring every other write on the plan does. A tour with a start counts as a road-trip stop, so taking the whole tour, a stale stage or a moved stage off the middle of a day shifted every later stop, and the vias anchored by position shaped the wrong leg. The undo had the same gap when it put the whole tour back mid-day. Each stop a spread or its undo takes off a day now carries the day's vias along (reanchorAfterRemove), and the whole tour put back carries them the other way (reanchorAfterInsert). The stops are read from the store as each write goes out and the vias are kept as the last correction left them, since one run can touch a day twice before the plan renders. The phone's place sheet greyed out a day that holds a multi-day tour, so its stages could not be spread from there. It now checks the day the way the desktop menus do and leaves the choice to the plan, which opens the card with only the stages offered. The second step of the day menu names the day picked, and a greyed-out "Whole tour on this day" says why right under it. The toast for a tour that sat whole on several days now says "days" instead of "day", in all 27 languages.
GHSA-22jm-h49p-29qw and GHSA-6prh-2h8m-c8cw (MCP SDK, high) and GHSA-5r4p-p66f-jhc7 (hono, moderate) are fixed in these versions. npm audit for what the server installs reports none left.
… and test against the reloaded vias The vias the spread keeps on their legs are taken over in a layout effect instead of during render, the route redraw takes the planner's async updateRouteForDay, and the menu items for whole or stages move out of the button component into their own module. Two leftovers of the old day pills in tourParts go. The hook test's reanchor reloads the vias like the real one does, and the detail test finds the button by its label, Add to Day.
…import The pair rule wants TourDayAddButton to import stageSpread; the items it builds belong there anyway. The addon manager test answers the Tours switches, so a failed list is the only thing that toasts.
… where the key scan sees them
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Follow-up to #2691: piste routing for ski and winter tours, the Tours layers read from TREK Places instead of the public Overpass mirrors, tour times in the day plan, Tours on by default, and a round of fixes from testing.
Piste routing for ski and winter tours (SKI-03)
plan_ski_route, andget_tour_plannames the options, build and routed legs.Tours layers from TREK Places instead of Overpass
/v1/ways). Horse routes read from/v1/routes.Tour times
Stages of a multi-day tour onto days
Tours on by default
Collections
Fixes from testing
Migrations
046140: Tours on for every install.046150: a ski tour keeps its router options, the piste data build and the legs the router planned.Related Issue or Discussion
Tours board SKI-03, follow-up to #2691.
Type of Change
Checklist
devdevbranch, notmain(wiki-only PRs are exempt)