Add disasters mission profile : Disasters light demo - #347
Open
kyle-lesinger wants to merge 12 commits into
Open
Add disasters mission profile : Disasters light demo#347kyle-lesinger wants to merge 12 commits into
kyle-lesinger wants to merge 12 commits into
Conversation
Adds a `disasters` profile and its generated config for the NASA Disasters learning portal, carrying the two GAIA gridded building- exposure collections from the VEDA disasters STAC as titiler-pgstac tile layers. - Layers reuse each collection's STAC `renders` colormap, nodata, bidx and resampling, and set tileformat=wmts: titiler-pgstac serves xyz, and the MMGIS default of tms would flip the Y axis. - GAIA is hazard-agnostic exposure data, so both layers carry all five hazard tags and the Public Safety sector. - The Event theme and its activation catalog are overridden away in LayerFilterThemes and LayerFilter, since GAIA carries no activation. - The bottom Timeline panel is dropped: Timeline declares no `defaults` block so the generator cannot emit it, and neither layer is time-enabled. Also syncs configure/package-lock.json's version field, which had drifted from configure/package.json.
8 tasks
8 tasks
The demo browses by hazard and by activation, not by sector, so the Need theme is dropped and Event restored alongside Hazard, which becomes the default theme. Seeds three activations from the team's tracking sheet, keyed by their STAC metadata event names: - 202501_Fire_CA — California Wildfires January 2025 - 202606_Earthquake_Venezuela — Venezuela Earthquake June 2026 - 202604_Typhoon_Sinlaku — Typhoon Sinlaku April 2026 Each carries a polygon covering its named locations: the Location filter is a geocode intersection against activation geometry, so a search for "Los Angeles" only matches when the geometry actually covers it. Layer associations are empty for now. None of these activations involve GAIA, and the products they do list are not yet in the mission; the pairings land with those layers.
Adds the two layers from the California sequence in disasters-tracking#61 that are currently ingested, and pairs them to 202501_Fire_CA in the curated order: - OPERA Surface Disturbance (DIST-S1), default on - Sentinel-2 SWIR Each layer's time window is pinned to a range that actually returns imagery. DIST-S1's collection holds a single 2025-01-09 acquisition and returns 204 for the activation's own 01-10 to 01-31 window, so the layer is pinned to the data that exists rather than to the event dates; widen it once the fire-period product lands. Selecting an activation does not currently drive the time window — LayerFilter only emits plugin:layerfilter:changed and calls layers:setListed — so the layer config is the only thing steering the datetime parameter. The remaining curated layers are not in the STAC yet: FIRMS, FEDS and Sentinel-1 damaged structures for California; all five for Venezuela; and four of five for Sinlaku. Sentinel-2 mNDWI is present but holds only a 2019-03-16 scene over Nebraska and Iowa, so it is not wired to the Sinlaku activation. Venezuela and Sinlaku keep empty layer lists.
nisar-gunw-composite is now ingested, so the first layer of the Venezuela sequence in disasters-tracking#61 can be wired up. It is paired to 202606_Earthquake_Venezuela and defaults on. Render parameters are taken from the collection's own STAC renders block rather than chosen here: rdylbu_r rescaled -40 to 40 cm with nodata -9999 and bilinear resampling. That answers the open question in disasters-portal#395, which asked for a diverging colormap centred on zero because line-of-sight displacement is signed. The collection landed with three interferometric pairs rather than the single scene NASA-AMMOS#395 anticipated, spanning 2026-06-13 to 2026-06-30. The layer's time window covers that whole extent so all three mosaic; narrowing it to the activation's own 06-26 to 07-14 window drops the earliest pair and roughly halves the returned coverage.
Every time-enabled layer here is time.type "global", which means TimeControl.updateLayersTime is what fills its time.start and time.end from the global window. The top-level time block had been disabled back when GAIA — which carries no time — was the only layer, so nothing ever filled them. The failure was silent and misattributed. With start and end left null the time formatter yields empty strings, the tile URL degrades to "datetime=/", and titiler answers HTTP 500. That error response carries no CORS headers, so the browser reports it as a CORS policy failure against dev.disasters.openveda.cloud and the real 500 never surfaces. Verified directly: the same request without the empty datetime returns 200 with access-control-allow-origin set. Restores the global time block from the reference 42-layer config, with visible false: Timeline declares no defaults block, so the generator cannot emit the tool and there is no panel for a timeline UI to render into. The machinery still runs and still fills the placeholders. Also builds the themes, which had never been compiled in this checkout — dist/ was absent, so the disasters theme and the default fallback both failed to load and the modern layout rendered without its panels.
Two gaps surfaced while standing up the disasters portal. Filtering narrowed the layers list but never moved the map, so selecting an activation on the other side of the world left the user on the default view with its layers loading off-screen — indistinguishable from a layer that failed to load. LayerFilter now resolves a destination for the current match, most specific first: an authored `view` on the selected entry's layer pairing (documented in SCHEMA.md but never read by anything), else the union of the matched layers' extents, else the selected entry's geometry. It fails soft at every step, and is gated on real user interaction for the same reason the listed-updates are — on boot the default theme is auto-selected, and flying the map then would override the mission's configured starting view. Timeline declared no `defaults` block, so generate-mission-config could not emit it and a profile listing it threw. Any panel naming it was therefore dead config, which is why the reference layout's bottom panel rendered nothing. Adding the block lets a profile opt in; full-demo excludes it explicitly to stay byte-identical, since that profile has no bottom panel for it to occupy. The disasters profile takes the timeline back: the reference config's bottom panel, time.visible restored, and Timeline switched on.
Toggling a layer whose data sits outside the viewport drew it correctly and looked broken: the tiles loaded, the checkbox ticked, and the screen did not change. LayerManager now moves the map to a layer it has just switched on. Only when the layer's extent lies entirely outside the viewport. A layer that already overlaps what the user is looking at is left alone, so stacking layers over one area never yanks the camera, and switching a layer off never moves anything. Reading the viewport needs both adapter shapes: Leaflet returns plain southWest/northEast corners while deck.gl returns Leaflet-style getSouthWest()/getNorthEast() accessors. A corner tuple is accepted too. An unreadable viewport, or a layer with no extent, leaves the map where it is rather than guessing. This is the layer-level counterpart to the filter-level move added for activation selection; between them, both gestures that reveal data now take the user to it.
Adds sentinel1-dmgassessment-daily as a sixth layer, bound to the California Wildfires January 2025 activation alongside OPERA DIST-S1. Tiles are rendered from the collection's own `damage` render definition so the colours match what the data producer intended. opera-distalert-s1-daily was already configured and is unchanged.
A deck.gl TileLayer was built without an extent, so a layer scoped to one footprint still requested the full tile pyramid. Those tiles come back empty at best, and from a single-item raster endpoint as an error, so a scoped layer generated failed requests on every pan and zoom. The tile path already builds bounds for Leaflet; it now passes the same bounds to the deck.gl path, where resolveExtent converts them to deck.gl's [minX, minY, maxX, maxY]. Leaflet's LatLngBounds reaches corners through getSouthWest()/getNorthEast() rather than plain properties, so that shape is unwrapped before conversion — reading it as a plain object yields undefined and silently drops the extent.
A float zone had no height bound, so a panel holding tall content stretched it past the viewport. Every descendant then resolved its height against an unbounded parent, so a panel body set to scroll grew instead and its overflow ran off the bottom of the screen with no way to reach it. Clamps the zone to its parent and lets panels shrink to fit, which is what lets the existing overflow-y on the panel body take effect.
The NISAR layer drew from a collection mosaic of three granules on different tracks. titiler-pgstac picks contributing granules per tile, so a tile at one zoom intersected three footprints and at the next only one: coverage vanished as you zoomed in, and the discontinuities landed on tile boundaries as straight seams no swath edge would produce. Each track is now its own layer reading its own STAC item, so what draws no longer depends on the tile grid. The three granules also span different date pairs, which a single merged layer left indistinguishable; separate layers make that legible. Rescale moves from +/-40 to +/-25 cm. The wider range was not clipping anything worth keeping — under 1% of pixels exceeded it — while compressing the bulk of the field, which sits within a few cm, into the middle of the ramp. Measured over an area of interest, the 2nd to 98th percentile spans -20 to +5. Also enables area analysis on every layer, each pointing at a concrete item with the assets, bidx and nodata read back off its own tile URL so statistics match what is drawn. The Chart tool moves to its own opaque floating panel: a transparent panel turns off the panel body's overflow so tool dropdowns can escape, which left a long results list unscrollable.
A float zone accepts exactly one panel, so moving the Chart tool into its own panel alongside the existing one at float-top-right made the config invalid and the modern interface refused to initialize. The tool goes back where it was. Scrolling is instead handled where the conflict actually is. A transparent panel's body keeps visible overflow so tool dropdowns can escape, which means it can never be the scroll container; a tool with more content than the zone can show has to bound and scroll itself, and that requires its card to give up height. Which cards give way falls out of flex's automatic minimum rather than any name in the stylesheet: a card keeps min-height auto, so it cannot shrink past its content's intrinsic minimum. A tool that scrolls internally reports almost none and yields; map controls report their full height and stay rigid.
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.
Purpose
disastersmission profile so MMGIS can be stood up as the NASA Disasters Learning Portal's mapping interface, carrying the two GAIA gridded building-exposure collections from the VEDA disasters STAC as its initial layers.Proposed Changes
mission-profiles/disasters.json— the hand-maintained profile (tools, overrides, scaffold, layers).mission-profiles/generated/disasters-mission.json— the generated, uploadable mission config (9 tools, 2 layers).configure/package-lock.json— version field synced toconfigure/package.json, which it had drifted from.Layer details:
nodata,bidxandresamplingdeclared in each collection's STACrendersblock, so they render the way VEDA intends.tileformat: "wmts". titiler-pgstac reports"scheme":"xyz"in its tilejson; MMGIS'stileformatdefault istms, which would flip the Y axis.Public Safetysector.Eventtheme and its activation catalog are overridden away inLayerFilterThemesandLayerFilter— GAIA carries no activation.Timelinedeclares nodefaultsblock so the generator cannot emit it, and neither layer is time-enabled (both are single January-2025 composites).Issues
Testing
Verified locally against a fresh deployment (Postgres 16 + PostGIS,
npm run start:no-docker):node scripts/generate-mission-config.js disasters --check→OK: mission-profiles/generated/disasters-mission.json is up to date.(artifact reproduces deterministically from the profile)validate()the server runs on upsert — returns{"valid": true}for the generated config.GAIA Building Exposure (Total)→200 image/png 14774bat z5/5/12GAIA Building Exposure (Wood)→200 image/png 10529bat z5/5/12full-demo --checkandminimal --checkboth report up to date, so the CI drift check stays green.