Skip to content

MMGIS 5.0.0 — React 18, Design System, Theming, UI Restructure#959

Open
tariqksoliman wants to merge 433 commits intoNASA-AMMOS:developmentfrom
JPL-Devin:development
Open

MMGIS 5.0.0 — React 18, Design System, Theming, UI Restructure#959
tariqksoliman wants to merge 433 commits intoNASA-AMMOS:developmentfrom
JPL-Devin:development

Conversation

@tariqksoliman
Copy link
Copy Markdown
Member

With Devin

MMGIS 5.0.0 — React 18, Design System, Theming, UI Restructure

Screenshot 2026-05-05 165916

Purpose

MMGIS 5.0.0 modernizes the frontend by upgrading from React 16 + jQuery/Materialize to React 18 + Base UI, introduces a configurable theme system with 18 built-in themes, rewrites the separated tools system as React components, restructures the UI layout (TopBar, BottomBar, globe controls), and adds a new design system with reusable components and CSS Modules. All changes are fully backward compatible with existing mission configurations.


Proposed Changes

React 18 + Base UI Migration

  • [ADD] Upgraded from React 16 to React 18 with Base UI replacing jQuery/Materialize for UI primitives
  • [ADD] New src/design-system/ directory with reusable React components: Button, Dropdown, IconButton, Modal, Toast, Toggle, Tooltip — all styled with CSS Modules
  • [ADD] dompurify dependency for safe HTML rendering in Help content
  • [CHANGE] Migrated Ancillary UI components (Modal, Tooltip, Toast, Help, ContextMenu, Coordinates) from jQuery/Materialize to React + Base UI
  • [CHANGE] Dissolved the src/essence/Ancillary/ directory — components reorganized into src/essence/Basics/UserInterface_/components/
  • [CHANGE] Service modules (DataShaders, LocalFilterer, QueryURL, Sprites) moved to src/essence/services/
  • [CHANGE] Upgraded react-chartjs-2 to ^4.3.1 and react-resize-detector to ^9.1.0 for React 18 compatibility

Configurable Theme System

  • [ADD] 18 built-in themes configurable from the Configure page UI tab:
    • Dark: Default, Blue, Warm, Mars, Midnight, Terra, Nebula, Lunar, Supernova, Heliosphere, Monokai
    • Light (experimental): Default, Cool, Slate, Warm, Botanical, Solarized
    • High Contrast: WCAG-oriented high-contrast theme
  • [ADD] --color-shadow CSS variable for theme-aware shadow styling
  • [ADD] Live ThemePreview component in the Configure page showing a miniature preview of each theme before selection
  • [ADD] New optional configuration fields: look.theme, look.primarycolor, look.secondarycolor, look.tertiarycolor, look.accentcolor, look.highlightcolor

Separated Tools System Rewrite

  • [CHANGE] Rewrote the entire separated/floating tools system from jQuery to React components
  • [CHANGE] Tool panel is now a floating panel with a close button and drag handle
  • [CHANGE] Removed separatedTool and justification configuration toggles (silently ignored if still present in existing configs)

Mobile UI

  • [ADD] Panel toggle, account button, and menu now accessible in the mobile top-right bar
  • [CHANGE] Exclusive panel toggling enforced on mobile — only one panel (Map/Globe/Viewer) open at a time

UI Restructure

  • [CHANGE] Moved Screenshot and Fullscreen buttons to the BottomBar; moved About to the TopBar kebab menu
  • [CHANGE] BottomBar buttons reordered (Copy Link, Screenshot, Fullscreen) with unified sizing
  • [CHANGE] TopBar hides Viewer/Globe toggles based on which panels are configured
  • [CHANGE] Repositioned Viewer and Globe panel buttons to top-right
  • [CHANGE] Cesium link button moved to top-right with Leaflet zoom button styling
  • [CHANGE] Globe controls rearranged: compass top-right circular, nav row vertical, panels open left
  • [CHANGE] Map logo anchored to document.body to avoid CSS filter containing-block issues; hidden on mobile
  • [CHANGE] Redesigned About modal
  • [CHANGE] Reverted tooltips to tippy.js for consistency

Tile Fade Behavior

  • [ADD] Per-layer fade control: time-enabled and shade/viewshed layers never fade during transitions
  • [ADD] Selective tile fade: tiles fade on pan/zoom but update instantly on refresh/reload

New Help Documentation

  • [ADD] In-app help content for 9 tools: Analysis, Animation, Chemistry, Curtain, Draw, Isochrone, Legend, Measure, Sites

Additional UI Polish

  • [ADD] Legend empty state message when no legend items are present
  • [ADD] Hover effect on MMGIS logo (subtle background highlight)
  • [CHANGE] Migrated ~69 ad-hoc CursorInfo toast calls to the proper Toast component
  • [CHANGE] Removed ~600 lines of dead CSS; deleted tools.css
  • [FIX] TimeUI dropdown z-index above tool panel; #toggleTimeUI click handler, tippy, and active class restored
  • [FIX] TimeControl .fina() assignment operator bug (used = instead of ===)
  • [FIX] TimeUI border radius and rounded corners on shell, action wrappers, mode dropdown
  • [FIX] time.initiallyOpen now respected when a live deep-link is set
  • [FIX] XSS prevention: HTML escaping in tooltip builders for GeoJSON values
  • [FIX] Help.jsx fetch error handling and HTML sanitization with DOMPurify
  • [FIX] Circular import in TimeUI.js

Internal

  • [CHANGE] Removed internal Test_ module, testModules, and DrawTool.test in favor of the Playwright-based E2E framework
  • [CHANGE] Updated CITATION.cff to version 5.0.0, dated 2026-05-01
  • [ADD] CHANGELOG.md entry for 5.0.0 release
  • [ADD] .knowledge/ directory with AI agent development context
  • [CHANGE] Updated AGENTS.md with current architecture documentation

Compatibility

  • Mission configurations: Fully backward compatible — no changes required to existing config JSON files. The removed justification field is silently ignored if still present.
  • JavaScript API (window.mmgisAPI): Fully backward compatible — all public API functions unchanged
  • End users: No breaking changes — UI is modernized but all functionality is preserved
  • Developers: Import paths changed for components previously under Ancillary/; jQuery UI component APIs replaced with React; Test_ module removed (use tests/e2e/ Playwright framework)

Issues

  • N/A — cumulative sync of the development fork

Testing

  • All changes individually tested and merged into JPL-Devin/MMGIS development
  • Existing Playwright E2E test suite passes
  • CI checks verified

devin-ai-integration Bot and others added 30 commits April 21, 2026 22:07
… null check

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- global-setup.js: prepare .env files from .env.example for enabled
  adjacent servers, rewriting relative TILEMATRIXSET_DIRECTORY to absolute
- global-setup.js: probe adjacent server ports after MMGIS server starts
  and log which ones came up
- playwright-tests.yml: add Python 3.11 + titiler/uvicorn/python-dotenv
  so TiTiler can run in CI
- titiler-planetcantile.spec.js: fix colorMaps endpoint (/colorMaps not
  /cog/colorMaps) and accept both colorMaps/colormaps response keys

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Spawn the MMGIS server with detached:true so it leads its own process
group. In killServer(), send SIGTERM/SIGKILL to -pid (the negative PID)
which kills the entire group — including adjacent server child processes
(Python uvicorn) that previously survived teardown and kept the test
runner alive.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…ebsockets in test env

- waitForMapReady: use 'load' instead of 'networkidle' to avoid
  indefinite hangs when WebSocket connections keep the network active
- global-setup: explicitly disable ENABLE_MMGIS_WEBSOCKETS and
  ENABLE_CONFIG_WEBSOCKETS in the test server env
- mmgis-api.spec.js: add build/index.pug existence check so tests
  skip gracefully in CI (where npm run build is not executed)

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- Add killProcessOnPort() that kills leftover processes from interrupted
  runs (cross-platform: lsof on Linux/macOS, netstat+taskkill on Windows)
- Call it before starting the test server
- Register SIGINT/SIGTERM/exit handlers so Ctrl+C during tests kills
  the detached process group instead of orphaning it

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…cantile-tests

Add TiTiler Planetcantile e2e tests and auto-start adjacent servers in test harness
…tion

feat: React UI migration - Zustand store, bridge, components + ToolController_/BottomBar React migration
- Install @tmcw/togeojson dependency for KML-to-GeoJSON conversion
- Add isKmlUrl helper and fetchKmlAsGeoJSON to LayerCapturer.js
- Wrap default URL fetch and dynamic extent fetch with KML detection
- Export isKmlUrl for unit testing
- Create sample KML file with Points, LineString, and Polygon
- Add KML Sample layer to Reference Mission config
- Update configure UI and docs to mention KML support
- Add E2E tests for KML layer loading and toggling
- Add unit tests for isKmlUrl helper function

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- Total layers: 44 -> 45
- Vector layers: 36 -> 37
- GeoJSON Data Features: 19 -> 20
- Update description to mention KML converted to GeoJSON at runtime

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…config

- README: Update layer listings to match reorganized config structure
  - Geometry Types: Replace Time-Enabled/KML Sample with Arrows/Annotations
  - Feature Property Behavior: Remove Arrows/Annotations, add Hotline Gradient 3D (8 layers)
  - Add Miscellaneous section with KML layer
  - Time Tab: Add Time-Enabled (2 layers)
  - Core Settings Tab: Update to new zoom layer names (3 layers)
  - Attachment - Markers Tab: Add second image layer (2 layers)
  - Update all section counts (18 GeoJSON Data Features, 18 Layer Configuration)
- E2E tests: Update layer name 'KML Sample' -> 'KML', group 'Geometry Types' -> 'Miscellaneous'
- LayersTool.js: Add KML support to raw download export path via isKmlUrl/fetchKmlAsGeoJSON
- LayerCapturer.js: Export fetchKmlAsGeoJSON for reuse

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- Add GET /api/utils/fetchProxy endpoint that streams external http/https resources
- Register fetch_proxy in calls.js for client-side use
- Update fetchKmlAsGeoJSON to route absolute URLs through the proxy
- Local/relative KML URLs continue to be fetched directly

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…port

Add KML import support for MMGIS vector layers
Pass ROOT_PATH to adminlogin and login template render calls in server.js.
Prefix all asset hrefs/srcs in adminlogin.pug, login.pug, and resetpassword.pug
with ROOT_PATH. Move background-image and font-face URLs from CSS files to
inline styles in pug templates so they can use the ROOT_PATH variable.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
When ROOT_PATH is set (e.g. /mmgis), visiting the URL without a trailing
slash would not match the main route and assets would fail to load.
This adds a redirect so /mmgis -> /mmgis/ works correctly.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- Update populateCogScale early-return guard to allow layer.type === 'data'
- Skip cogTransform check for data layers (they use shader ramps)
- Add units extraction from variables.shader.units for data layers
- Add min/max extraction from layer minValue/maxValue for data layers
- Add color interpolation from shader ramps for data layer legends
- Add populateCogScale call for data layers with colorize shader
- Generate DEM rgba tiles (zoom 10-12) via gdal2customtiles.py --dem
- Add 'Elevation - RGBA Tiles (URL)' data layer to Reference Mission config

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- Use /public/images/contours.png for adminlogin background (the old path
  /configure/build/contours.png is behind ensureUser middleware, so
  unauthenticated users get the login page HTML instead of the image)
- Add ROOT_PATH prefix to all img src attributes in login.pug,
  adminlogin.pug, and resetpassword.pug

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
The background-color on the body,html selector caused the html element
to paint over the body's background-image. Move background-color to the
inline style on body (alongside background-image) so it doesn't conflict.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Fix ROOT_PATH subpath support for login/admin CSS and asset paths
Add null guard for F_.hexToRGB() results in data layer color
interpolation. Ramp stops like 'transparent' are not valid hex
colors, so hexToRGB returns null. Fall back to 'transparent' color
when either endpoint cannot be parsed.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
devin-ai-integration Bot and others added 23 commits May 5, 2026 18:09
…dropdown

- #timeUI: 10px border-radius on the outer time control bar.
- #mmgisTimeUIActionsLeft / #mmgisTimeUIActionsRight: 10px border-radius
  so the action clusters sit as rounded chips.
- #mmgisTimeUIActionsRight > div (excluding #mmgisTimeUIPresent): 10px
  border-radius on each action button so they match the wrapper.
- #mmgisTimeUIModeDropdown: 40px height + 10px border-radius to align
  with the rest of the bar; clear the dropy default border-color so the
  rounded edge isn't outlined.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Light themes still have outstanding contrast issues, so flag them in the
Color Theme dropdown without changing the saved value.

- Maker dropdown now accepts options as either a plain string (current
  behavior) or { value, label } so the rendered label can differ from
  the persisted value.
- tab-ui-config switches the six light themes to { value, label } form
  with '(experimental)' appended to the label only. Existing mission
  configs that already saved 'Light Default' etc. continue to match.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…505)

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…preview

feat(theming): add 5 new themes, --color-shadow variable, and configure ThemePreview
Clicking Layers -> Time -> Layers -> Time on mobile caused the bottom
panel to render LayersTool content with TimeUI height. The #timeUI DOM
element was destroyed when LayersTool.make() called $('#tools').empty(),
before the async React useEffect in MobileTimeUIToggle could rescue it
to its staging container.

- ToolController_.makeTool: synchronously move #timeUI from #tools back
  to #timeUIMobileStaging (and reset TimeUI store flags) on mobile,
  before invoking the new tool's make().
- MobileTimeUIToggle.handleClick: defensive fallback that re-initializes
  TimeUI if #timeUI no longer exists when the toggle is activated.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
TimeUI.init() on mobile appends the new #timeUI to the hidden
#timeUIMobileStaging container, so the fallback branch must also move
it into #tools — otherwise the user sees an empty tool panel after
the destroyed-element recovery path.

Caught by Devin Review.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
On mobile, opening or closing the Coordinates tool runs
$('#tools').empty() inside interfaceWithMMWebGIS / separateFromMMWebGIS.
After the previous PR commits, clicking Coordinates -> Time still left
the bottom panel empty because:

- Coordinates.make() empties #tools while #timeUI is in staging (fine
  on its own), but the Coordinates teardown that fires after the user
  switches to the Time toggle (via MobileCoordButton's useEffect on
  activeToolName change) calls Coordinates.destroy() ->
  separateFromMMWebGIS(), which empties #tools wholesale and destroys
  the freshly-placed #timeUI.

Add a rescueMobileTimeUI() helper that moves #timeUI from #tools back
to #timeUIMobileStaging before each tools.empty() call in Coordinates,
mirroring the rescue already done in ToolController_.makeTool().

Coordinates -> Time now correctly shows the TimeUI.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…povers)

Devin Review correctly flagged that the safety-net path in
MobileTimeUIToggle.handleClick was producing a partially-broken TimeUI
when it fired:

- TimeUI.init() unconditionally appends a new #timeUIPlayPopover_global
  to <body>, so a second init() left two elements with the same id.
- TimeUI.init() alone does not wire up date pickers or per-button click
  handlers — that's TimeUI.fina()'s job. Without fina(), the recovered
  TimeUI rendered visually but Play / Previous / Next / Fit / Follow /
  Present / Expand were all dead.

Before re-initializing, remove the stale #timeUIPlayPopover_global and
#timeUIQuickSelectPopover_global divs to avoid duplicate ids. After the
new #timeUI is moved into #tools, call TimeUI.fina() to populate the
date pickers, attach the button click handlers, build the histogram,
and populate the expanded mobile rows.

Some delegated body/document handlers in attachEvents() will still be
duplicated on this path; that is acceptable for a degraded recovery
that should never run in practice now that the primary rescues in
ToolController_.makeTool() and Coordinates.js cover all known paths.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
The previous Coordinates fix was racing with itself: after the Time
toggle synchronously moved #timeUI into #tools, MobileCoordButton's
useEffect (triggered by the activeToolName change) ran on the next
React tick and called L_.Coordinates.destroy(). That called
separateFromMMWebGIS(), whose rescue moved #timeUI right back into the
hidden staging div before tools.empty() — so the bottom panel ended up
empty even though the time toggle was 'active'.

Make separateFromMMWebGIS selective: only remove the
Coordinates-specific DOM (#coordUIHeader and #CoordinatesDiv) instead
of wiping all of #tools. Any other content already in #tools (e.g.
#timeUI placed there by the Time toggle) is left alone.

interfaceWithMMWebGIS still keeps the rescue + tools.empty() pattern
on the open path so Coordinates always starts from a clean panel.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…rescue

fix(mobile): rescue #timeUI before tool make() destroys it
…lopment

Upstream commits merged:
- 081c65b Fix clearGradientHoverPoint missing in mockLitho (NASA-AMMOS#957)
- 4f7f143 NASA-AMMOS#955 Fix login pathing for external proxies (NASA-AMMOS#956)

Conflicts resolved:
- package.json, configure/package.json: kept JPL-Devin version (5.0.5-20260505)
- Globe_.js: kept JPL-Devin version (LF endings, TopRight control args),
  added upstream's setGradientHoverPoint/clearGradientHoverPoint to mockLitho

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Sync upstream NASA-AMMOS/MMGIS development into JPL-Devin development
Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
- mmgis-api.spec.js: add form-fill login under AUTH=local; serialize
  describe to avoid concurrent-login race in the session store
- coordinates.spec.js: TimeUI toggle was moved from the coordinates bar
  to the Settings modal; navigate via topbar kebab menu and assert the
  checkbox is rendered
- widgets.spec.js: target .leaflet-control-zoom-in/-out specifically;
  the bare .leaflet-control-zoom class is also used by the home/reset
  control, so the original assertion was always false
- sites.spec.js: scope panel selector to #toolPanel; both the toolbar
  icon and the panel container share id="SitesTool"

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
test(e2e): fix 9 pre-existing failures (test-only changes)
@tariqksoliman tariqksoliman self-assigned this May 6, 2026
@tariqksoliman tariqksoliman added the enhancement For making an existing feature better label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement For making an existing feature better

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant