feat: AddTempLayer plugin (WMS/WMTS/XYZ/GeoJSON) + core layer-add bus - #126
feat: AddTempLayer plugin (WMS/WMTS/XYZ/GeoJSON) + core layer-add bus#126BhattaraiSijan wants to merge 27 commits into
Conversation
…to feat/add-temp-layer-plugin
✅ Version Already UpdatedThis PR includes a manual version update to No automatic version bump needed. |
Update — URL handling reworked (
|
…to feat/add-temp-layer-plugin
…ombie resurrection, hung promise)
🤖 Version Auto-BumpedThe version has been automatically incremented to This commit was added to your PR branch. When you merge this PR, the new version will be included. If you want a different version, update |
The plugin is now only the 'Add layer from URL' form, living hidden in a float-top-right panel. Any plugin reveals it by emitting 'addTempLayer:show'; the close button hides it again. The dotted trigger button is gone — it belongs to whichever host wants to offer it (e.g. LayerManager). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parseWmsUrl previously kept only LAYERS
Summary of fixes
|
| if (ToolController_.activeToolName === 'LayersTool') { | ||
| const layersTool = ToolController_.getTool('LayersTool') | ||
| if (layersTool.destroy && layersTool.make) { | ||
| layersTool.destroy() | ||
| layersTool.make() | ||
| } |
There was a problem hiding this comment.
why did we need to remove this?
| const u = (url || '').trim().toLowerCase() | ||
| if (u.length === 0) return null |
There was a problem hiding this comment.
is there a reason this has to be repeated here? you're calling validateUrl already before passing it to detectLayerType. So you could assume that url has been validated on the latter
| if (u.includes('service=wmts') || u.includes('request=gettile')) { | ||
| return 'wmts' | ||
| } | ||
|
|
||
| // WMS — OGC KVP markers | ||
| if (u.includes('service=wms') || u.includes('request=getmap')) { | ||
| return 'wms' | ||
| } |
There was a problem hiding this comment.
i wonder if these should be and instead of or
| type: TempLayerType, | ||
| url: string, | ||
| ): ValidationResult { | ||
| const u = (url || '').trim().toLowerCase() |
There was a problem hiding this comment.
same comment as above. redundant
| // {s} is Leaflet's pick-a-subdomain placeholder. We never substitute it, | ||
| // and the deck.gl engine sends it to the network literally — every request | ||
| // fails after an apparently successful add. Make the user pick one. | ||
| if (u.includes('{s}')) { | ||
| return { | ||
| ok: false, | ||
| message: `We can’t add this layer — {s} is a subdomain placeholder we don’t fill in. Replace it with a real subdomain, e.g. https://a.tile.host/{z}/{x}/{y}.png`, | ||
| } | ||
| } |
| if (!(u.includes('{z}') && u.includes('{x}') && u.includes('{y}'))) { | ||
| const kind = type === 'wmts' ? 'WMTS' : 'XYZ' | ||
| return { | ||
| ok: false, | ||
| message: `We can’t add this layer — the ${kind} URL needs a {z}/{x}/{y} template. Example: ${SAMPLE_URLS[type]}`, | ||
| } | ||
| } |
There was a problem hiding this comment.
wmts doesnt require {z}/{x}/{y}
| // Notify subscribers (e.g. the modern-layout Layers panel) that the | ||
| // layer list changed, so they rebuild. | ||
| if (window.mmgisAPI) { | ||
| window.mmgisAPI.emit('layers:listChanged') | ||
| } |
…IMPACT/MMGIS into feat/add-temp-layer-plugin
…IMPACT/MMGIS into feat/add-temp-layer-plugin
Purpose
Add an AddTempLayer plugin — "Add layer from URL" — letting users drop an external WMS / WMTS / XYZ / GeoJSON layer onto the map for the current session, plus the core event-bus and rendering support it needs. Built to the monorepo tool pattern: a portable
lib/of presentational React components with all MMGIS coupling isolated inadapters/, communicating with the core over thewindow.mmgisAPIevent bus only.Note on discoverability
The plugin shipping without its own trigger button is intentional, not an
oversight. AddTempLayer follows the framework's decoupled-plugin model: it
exposes a bus contract and leaves when and from where it opens to the app
builder.
addTempLayer:showon the MMGIS bus(
window.mmgisAPI.emit('addTempLayer:show')) opens the form. Any plugin,toolbar button, or host-app code can be the trigger — the plugin does not
care who emits it.
Proposed Changes
AddTempLayerplugin (monorepo pattern):lib/(portable):AddTempLayerPanel(trigger + form state) andAddLayerModal(presentational),utils/url(validateUrl,detectLayerType),utils/icons, BEMblocks-*classes, Path A--theme-*styling.adapters/buildLayerObj(URL → MMGIS layer object),MMGISAddTempLayerAdapter(bus bridge), thinAddTempLayerTool(createRoot),config.jsonwith modern-layoutmetadata.layers:addLayer/layers:removeLayer(Layers_.js), backed bymmgisAPI.addLayer/removeLayer— session-only, in-memory add viaresetConfig+modifyLayer(lost on reload).WMSLayerbranch inDeckGLHelpers(withparseWmsUrl) selected whentileformat === 'wms';tileformatthreaded throughTileLayerOptionsand the deck tile call inMap_.js.WMSColorFilter.{z}/{y}/{x}template so it renders through the standard template-tile path in both engines.layers:listChangedevent replaces the directLayersTooldestroy/make on layer mutation, so any subscriber (modern or classic layout) can react — decoupled.validateUrlrejects internal whitespace, guarding against two URLs pasted into one field.Issues
Testing
npm run typecheck→ 0 errors.Browser (DeckGL engine), verified end-to-end per type — add one URL at a time:
XYZ
WMS (needs a
LAYERSparam)WMTS — REST template
WMTS — KVP (exercises the KVP→template rewrite)
GeoJSON (CORS-enabled host)