Commit Graph
3744 Commits
Author SHA1 Message Date
Sameh Khamis 2d5db9f63d Never let a share rewrite the Data Library entries remembered as on
Every restore wrote the selection it applied to browser storage, so
opening a link that switched no library entry on stored every saved
entry as off, and the next bare visit restored them off. Core layer
state never writes a recipient's preferences from a share. The library
now keeps what is remembered as on apart from what a share switches on
for the session: a share's entries still join the library, but only a
local restore and the viewer's own choices change what is remembered.
2026-11-12 15:58:22 -08:00
Sameh Khamis 53f0a32a1b Keep a Data Library entry whose layer fails to tear down
Remove dropped an entry from the selection and reported success even
when the manager could not disable or destroy its layer, leaving a
registered, possibly visible layer that Browse, share links and saved
state no longer knew. Remove now keeps the entry and reports failure,
so its row and Remove all still reach it and a later Remove can retry.
2026-11-12 15:57:02 -08:00
Sameh Khamis f33a6ada52 Refuse a Data Library entry past the 64-entry cap before it registers
Add registered and switched on an entry before the selection was cut to
its first 64, so a 65th was dropped from the selection but stayed on:
Browse showed it as not added, share links left it out and Remove all
missed it. Start-up registered a share's entries the same way past the
cap. Add now refuses an entry a full library cannot keep, and start-up
registers only what the selection keeps.
2026-11-12 15:53:29 -08:00
Sameh Khamis e25cce874d Read an ArcGIS load stopped at maxFeatures as truncated
Paging stopped once maxFeatures were read before it noted that the
upstream had more, so a page holding exactly the cap with
exceededTransferLimit set read as the whole dataset. FEMA USA
Structures (2,000 features, one page) never showed PARTIAL in a dense
view. Stopping at the cap or the last page with more upstream now marks
the load truncated.
2026-11-12 15:52:31 -08:00
Sameh Khamis 134239fa5a Read a view over an incomplete GeoParquet index as PARTIAL
The browser's partition index kept whether it was complete only to
schedule a rebuild and handed the partitions on without it, so a view
counted unread partitions from an index that might be missing some and
could read as complete, even empty, over an area it had never indexed.
A view over an incomplete index now reads PARTIAL until a rebuild
completes.
2026-11-12 15:51:52 -08:00
Sameh Khamis e05a9566e4 Retry a GeoParquet footer whose body fails mid-stream
Only a failed fetch() marked a footer read as worth retrying. A body cut
off after its headers arrived (a reset, the proxy's 20-second timeout)
was taken for an unparseable file: the partition was left out and the
index still read as complete, so the server cached it without that
partition for the entry's cacheSeconds (24 hours for EPC). Such a read
is now retried like any fetch failure; an oversized body is still final.
2026-11-12 15:50:46 -08:00
Sameh Khamis 7d91a1875b Cancel a view-bounded load when the camera returns to the drawn view
Moving from view A to B started B's request; moving back to A before it
finished returned early because A was already drawn, so B's request ran
on and its features replaced A's while the camera was at A. Returning to
the drawn view now cancels the request in between.
2026-11-12 15:49:56 -08:00
Sameh Khamis 0f13c0a1c2 Let a newer share switch off a library layer still switching on
A share restore skipped every entry whose settled state already matched
the share, but a layer still switching on for an earlier share reads as
off until it settles. Opening a second share in that window left the
first share's layer to come on anyway. The restore now compares with the
manager's effective visibility (the newest request), so the newer share
supersedes the earlier one.
2026-11-12 15:49:11 -08:00
Sameh Khamis d58ba23fba Refresh live Data Library datasets once older than cacheSeconds
A dataset layer loaded its features once and kept them until it was
removed: the parsed set survives disable/enable, so NWS alerts, GDACS and
EONET showed what they held when first switched on for the whole session.

A library dataset now asks the manager for a refresh every cacheSeconds.
Once its data is that old it loads again, and swaps the new set in only
when it is ready, so the old features stay drawn while the request runs
and stay if it fails. An enable after cacheSeconds also loads afresh.
Disable and destroy cancel a refresh in flight.
2026-11-12 15:48:14 -08:00
Said Turksever 1a2589d4ef Port the Data Library Browse dialog to Vue and Pinia
The dialog is now DataLibraryDialog.vue (with DataLibraryCard.vue for each
entry), placed with the Browse button by DataLibraryBrowse.vue in
LayerPanelsView and teleported to the body. It renders what the
gev-data-library store holds and sends clicks and typing to the owner.

src/ui/libraryBrowser.js is now the framework-free owner: it presents the
open state, filters, the rows they show, the stat summary and Remove all
through `publish`, and its controls answer the view. Its text helpers are
what the view renders with t(), so every label follows the locale without
rebuilding anything. Only showModal/close and focus moves stay imperative;
focus returns to Browse also when the browser closes the dialog on Escape
itself.

Component tests mount the view over the real owner (open, filters, Add to
Remove keeping focus, Zoom, Remove all, a language switch, clean view).
2026-11-12 23:01:00 +00:00
Said Turksever 24ccdd4dc3 Fix Data Library share restore, dense tile layers and EPC partition reads
- Share links: the compact /share/<code> format carries the switched-on
  library entries (field 29), so Copy Link keeps them; a share opened in the
  same tab restores them; any share decides what is on, so one with every
  library entry off no longer switches on the recipient's stored entries.
- A tile entry too dense at its minimum zoom (Norway cadastre z14, depth z11)
  is hidden below that scale via minimumTerrainLevel instead of allocating
  millions of tiles when zoomed out.
- EPC partitions keep the full extent for exclusion and the 98 % extent for
  ranking only; the old trimmed-only extents are retired.
- Partition index footers that fail transiently are retried; an incomplete
  index is never cached as complete, a complete prior index is kept, and it
  is rebuilt after five minutes.
- Views that leave touching partitions unread are partial; listing and
  footer bodies are capped and ranges validated.
- The Browse dialog relabels after a language switch.
2026-11-12 22:37:34 +00:00
Said Turksever 871b7f0fcc Remove Data Library entries whose licence or provider links are broken
A link check of every manifest found 404 licence or provider pages for
OpenSeaMap seamarks, EMODnet bathymetry and the PDOK, basemap.at, Geneva
SITG, ICGC Catalunya, Luxembourg and Vlaanderen aerial photos, and no
answer from the SEDAC GPW, Minnesota and Bangor hosts. Drop those 11
entries, renumber the unpublished share-token ledger, point the tests at
remaining entries and regenerate DATA_SOURCES.md.
2026-11-12 17:05:21 +00:00
Said TurkseverandMaher Kurdi 11706a68cb Add Amsterdam traffic and ANPR camera positions to the Data Library
The City of Amsterdam's verkeersinformatiesystemen register lists where
its ~500 traffic and ANPR cameras stand, with type and asset number, but
publishes no pictures. That fits a Data Library dataset better than a
CCTV pack: the register answers GeoJSON in WGS84 with CORS headers, so
the entry fetches it browser-direct with no proxy code.

The register names no licence ("public unless stated otherwise"), so the
entry stays operator opt-in, as #251 had it. The dataset and the
position-only camera idea come from @Maher-Reven's #251, which this
replaces; the entry lists them as maintainer and in its attribution.

Co-authored-by: Maher Kurdi <[email protected]>
2026-11-12 12:26:45 +00:00
Said Turksever db80d82b8d Add the Data Library: live regional datasets, tiles and packs
DATA LAYERS keeps its curated core layers; regional and niche sources
live in the Data Library, opened from Browse data library at the foot
of the panel. Each entry is a JSON manifest in src/library/entries/
pointing at a live upstream (query API, provider-hosted file or tile
endpoint), so nothing is bundled and a self-hosted instance hosts no
data. Sources without CORS go through one allowlisted /api/library
route. Kinds: dataset (GeoJSON, CSV, JSON records, ArcGIS, partitioned
GeoParquet), tiles (XYZ, WMS/ArcGIS bbox export, terrarium relief) and
pack. Selections persist and travel in share links as lib=, separate
from the core layer tokens. Library rows get Zoom and Remove icon
chips that work while the layer is off, rendered through RailChips.
Strings are translated in every locale.
2026-11-12 12:26:45 +00:00
Sameh Khamis 10a788db78 Merge pull request #1683 from bilawalsidhu/sameh/news-cards-every-height
fix(news): an application's picture cards stay at every height
2026-11-11 19:52:44 -08:00
Sameh Khamis a105e819e0 fix(news): an application's picture cards stay at every height
Zoomed out, a hotspot's reports give way to its beacon, and the cards an application draws through pictureCards went with them; they came back only once the camera had stopped after zooming in. The cards now come from every report the close-up view would mark, at any height; the layer's own markers and beacons are unchanged.
2026-11-11 19:43:06 -08:00
Sameh Khamis 202cb8c3dc Merge pull request #1677 from ZloyS/denis/news-world-clock
feat(news): the News layer reads its time from the world clock
2026-11-11 15:28:35 -08:00
Sameh Khamis 2b1784d7ed Merge remote-tracking branch 'upstream/main' into denis/news-world-clock 2026-11-11 15:17:44 -08:00
Sameh Khamis beeb29f0fa Merge pull request #1675 from ZloyS/denis/rail-layer
feat(rail): add a Rail layer with keyless live trains
2026-11-11 15:07:54 -08:00
Sameh Khamis b7015f8819 Merge remote-tracking branch 'upstream/main' into denis/news-world-clock
# Conflicts:
#	docs/CURRENT-STATE.md
#	src/app/constructCatalog.js
2026-11-11 15:03:45 -08:00
Sameh Khamis 283890cee0 fix(rail): trip-update delays are as old as the server's read
The browser stamped every trip-updates answer as just read. While an
operator's feed fails, the rail proxy replays its last good copy for up to
ten minutes, and a cached copy can be a TTL old, so those delays never
reached RAIL_UPDATES_MAX_AGE_MS and a selected train's card showed them as
current. Delays now take their age from the snapshot's fetchedAt (capped
at now), as positions do in ingestion.js, so they stop applying 75 s after
the server last read the operator.
2026-11-11 14:57:02 -08:00
Sameh Khamis ace2160002 fix(rail): Montpellier tram speeds are converted from km/h
TaM publishes km/h where GTFS-Realtime asks m/s, and the Transit layer's
entry for the same feed already sets speedUnit: 'km/h'. The Rail entry did
not, so the proxy passed the readings through and the card multiplied them
by 3.6 again: a tram at 30 km/h read about 108 km/h. A registry test now
requires a Rail feed that Transit also reads to declare the same unit.
2026-11-11 14:54:01 -08:00
Sameh Khamis 0f18c03041 chore(news): credit the #1677 changelog fragment 2026-11-11 14:48:05 -08:00
Denis Groshev 9b3ca481ce Merge upstream main into denis/rail-layer 2026-11-11 23:23:58 +01:00
Sameh Khamis 632da1cebd Merge pull request #1680 from bilawalsidhu/sameh/news-host-cards
feat(news): an application may draw the News picture cards itself
2026-11-11 14:01:22 -08:00
Sameh Khamis 99a1e06b61 feat(news): an application may draw the News picture cards itself
createNewsLayer takes a pictureCards(cards, { selectedId }) function; createApplicationCatalog passes it through newsOptions. With it, the layer paints no picture cards of its own and hands the function one card per pictured event on the map, most severe then newest first, with the selected report's id; it hands no cards when the layer turns off.
2026-11-11 13:53:10 -08:00
German Khokhlov c19495644d Merge pull request #1509 from quanticsoul4772/upstream/route-outage-unavailable
fix(routes): report an upstream routing outage as unavailable
2026-11-11 23:14:47 +04:00
Kevin Rajan ca58e113c0 test(routes): cover HTML 502 outage in MCP plan_route (#1509)
Preserve quanticsoul4772's routing-outage fix and add a focused voice-facing regression for a non-JSON gateway response.
2026-11-11 09:44:24 -08:00
German Khokhlov 94ff78be3b refactor(routes): inline the single-use 502 responder
The outage branch is the only caller, so it writes its 502 directly.
Same status, headers and body.
2026-11-11 21:23:35 +04:00
German Khokhlov 82e2b716bc docs(routes): tighten the outage comments and notes
Shorter comments, changelog and CURRENT-STATE text for the 502 outage
path; the CURRENT-STATE paragraph now also names the 429 exception and
which budget expiry answers busy and which answers 502. Text only.
2026-11-11 21:21:07 +04:00
German Khokhlov a29611ca17 Merge branch 'main' into upstream/route-outage-unavailable 2026-11-11 21:16:50 +04:00
Denis Groshev 72c24a86d1 chore(news): name the changelog fragment for #1677 2026-11-11 18:06:15 +01:00
Denis Groshev 13818d0b9f Merge upstream main into denis/rail-layer 2026-11-11 18:02:52 +01:00
Denis Groshev 44d2c0695c feat(news): the News layer reads its time from the world clock
Core's catalog passes worldClock.timeFor('news') as the layer's now, so a host that follows the clock for News can show a past time's reports with their ages, window and counts as they were then. Core does not follow the clock for the layer, so it keeps reading the wall clock.
2026-11-11 18:00:24 +01:00
German Khokhlov aa95c2c25f Merge pull request #1531 from quanticsoul4772/upstream/firms-age-rounding
fix(fires): show a 47.6-hour-old detection as 2d, not 48h
2026-11-11 20:24:53 +04:00
German Khokhlov 1c08482fa8 Merge branch 'main' into upstream/firms-age-rounding 2026-11-11 20:14:57 +04:00
German Khokhlov 98b642869e Merge pull request #1113 from asturksever/pr/street-level-show-action
feat(street-level): "show me X on Street View" — assistant action, view field and share link
2026-11-11 19:13:30 +04:00
Denis Groshev d793406aef docs(changelog): add the #1675 fragment 2026-11-11 16:08:24 +01:00
Denis Groshev 830c080803 feat(rail): add a Rail layer with keyless live trains
Live trains from 30 keyless operator feeds: GPS positions from 29 and
Irish Rail's station reports, shown as the operators publish them. 28
work out of the box; Renfe long and medium distance and KTMB appear once
their pack is built, because their vehicles name no route.

Packs are opt-in (scripts/build-rail-paths.mjs): the operator's own
route lines, stop names, next stops and trip-update delays for live
trains. Nothing downloads when the app starts, no train is placed from a
timetable, and no request carries a deployer's key.
2026-11-11 16:06:22 +01:00
German Khokhlov 71797427d6 Street Level: a posted view whose camera was taken stands down whole again
Applying the rest of a posted view after the camera was taken during its
terrain wait still let it change the camera: stop_tracking dropped a follow
the user had just started, and annotate_map framed the view's marks. A
camera taken during the wait now ends the view again, as before. The 2 s
terrain timeout and the per-view catch on the queue stay.
2026-11-11 19:01:58 +04:00
German Khokhlov 0ebc09079d Street Level: polar look-at, a bounded terrain wait, takeovers during the flight
- The look-at longitude wraps fully, so a tilted camera at a pole gives a
  point on the globe. The strict off-globe check on street_level is undone:
  points are clamped again, as before.
- A posted view that fails is answered, and the views behind it still apply.
- A posted view waits at most 2 s for the terrain under its camera, then
  keeps its own estimate.
- A camera taken during that wait stays where it is: the rest of the view
  applies, and only its photos stand down.
- show_street_level keeps a search or a press on the globe made during its
  own flight: it adopts only its own navigation stamps on landing, and a
  gesture is never forgiven.
2026-11-11 18:02:15 +04:00
Said Turksever ae66d07575 i18n(sv): the PR's 27 Street Level strings
Main added a Swedish catalog in #1630, so the catalog test failed on the
strings this PR adds. They use the catalog's terms (Gatunivå, nyckel,
bilder på gatunivå, vyns mitt).
2026-11-11 12:16:58 +00:00
Said Turksever 43893697aa Merge upstream main into pr/street-level-show-action 2026-11-11 12:15:18 +00:00
German Khokhlov 4fd36c44e0 Street Level: a replacement keeps its own state, and a posted view stands down
- Releasing a held viewer frees the old source's adapter without resetting
  the panel, so a replacement's error, outcome and armed OPEN survive; a
  cross-source replacement drops the old photo's details and marker.
- The action holds the open photo only for its own switch-off: a source
  switched by hand during the load stops it and reports cancelled.
- A posted view waiting on terrain watches the camera and stands down after a
  navigation or a globe press; a flat or straight-down camera asks no terrain.
- An arming link opens the panel without persisting the layout, and a posted
  view's street-level step runs as programmatic.
- An off-globe street_level point throws TypeError.
- zh-Hant uses the file's wording for the new strings; README and
  CURRENT-STATE count 35 tools.
2026-11-11 16:05:26 +04:00
German Khokhlov 14db73f201 Merge pull request #1630 from Kajjan7610/sv-locale
i18n: add Swedish (sv)
2026-11-11 14:37:04 +04:00
German Khokhlov 45d9ff1d86 Merge branch 'main' into sv-locale
Translate the 148 strings main added since (mostly the News layer) and
prune the 5 it no longer uses; keep both Hebrew and Swedish in the
language lists.
2026-11-11 13:59:40 +04:00
German Khokhlov 45a33b54df Street Level: docs for the OPEN exception, panel freshness and what stops a request
- SECURITY.md: OPEN also takes the link's point when the screen centre
  cannot be picked at all.
- TOOLS.md: the panel's own link opens Street View only for a result issued
  in the last five minutes; an older one only arms.
- Changelog: the hiding modes stop a request, collapsing the panel does not;
  failure cards are in the interface language.
- CURRENT-STATE: a posted view without a point grounds its look-at too.
2026-11-11 13:46:35 +04:00
German Khokhlov f612fc2180 Street Level: a posted view without a photo point grounds its look-at too
show_in_gods_eye_view measured a view's altitude from the terrain before
taking the point the camera looks at; a view posted straight into the
embedded app used the ellipsoid altitude, so a camera over high ground
opened photos kilometres ahead. groundedLookAt moves to the view module,
and the embedded app uses it with the app's terrain heights for a posted
street_level that names no point.
2026-11-11 13:46:10 +04:00
German Khokhlov a8970c1f18 Street Level: a geocoder that throws fails show_street_level at its location stage
A provider that threw while geocoding (offline, an upstream down) escaped
the action as a bare error. show_street_level now reports it as its
location stage ("Could not arrive at …", the cause in detail), and nothing
is switched or looked up; fly_to_location itself is unchanged.
2026-11-11 13:46:10 +04:00
German Khokhlov 8334262109 Street Level: the action's failure cards in the interface language
The voice card showed English for show_street_level failures the catalog
did not know: a missing key, a map or source that could not be switched on,
the layer, invalid coordinates, an imagery fallback and the filter clause.
They now translate like the other action errors (exact messages and
patterns in speech.js), in all twelve languages; the spoken line stays
English, and the filter clause names the filters as their chips do.
2026-11-11 13:46:10 +04:00