Add BitMap component (#10110)#12360
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
<review_stack_artifact_start /> ✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Pull request overview
Introduces a new generic, provider-pluggable BitMap<TMapProvider> component in Bit.BlazorUI.Extras with seven map backends (Leaflet, MapLibre GL, Mapbox GL, OpenLayers, ArcGIS, Azure Maps, Cesium), exposing a unified imperative API for markers, vector layers, GeoJSON, tile overlays, and view manipulation, plus a full demo page. Closes #10110.
Changes:
- Adds
BitMapRazor component, supporting types (BitMapLatLng,Bounds,Marker,VectorPathStyle,TileOverlay,ViewState, callback args),IBitMapProvider/BitMapProviderBase, and concrete provider classes for each backend. - Adds the corresponding TypeScript providers (
BitMapLeaflet,BitMapGlBase+ MapLibre/Mapbox wrappers,BitMapOpenLayers,BitMapArcGis,BitMapAzureMaps,BitMapCesium) plus shared helpers, and wires SCSS viaextra-components.scss. - Registers the demo page, navigation entry, JS interop extensions, and ignores
.kiro/.cursoreditor folders.
Reviewed changes
Copilot reviewed 33 out of 40 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor[.cs] | New generic component + imperative API and JSInvokable bridge methods. |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap{LatLng,LatLngBounds,Marker,TileOverlay,VectorPathStyle,ViewState,MarkerDragEndArgs}.cs | Shared domain types/payloads. |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cs, BitMapProviderBase.cs | Provider abstraction and common options. |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/Bit*MapProvider.cs | Seven concrete C# provider configurations. |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMap*.ts | TypeScript runtime adapters (Leaflet, GL base + MapLibre/Mapbox, OpenLayers, ArcGIS, AzureMaps, Cesium, shared helpers). |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cs | Provider-agnostic JS interop helpers. |
| src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scss + Styles/extra-components.scss | Component styles and aggregator. |
| src/BlazorUI/Demo/.../Pages/Components/Extras/Map/BitMapDemo.razor[.cs] | Demo page with 13 examples covering all providers. |
| src/BlazorUI/Demo/.../Shared/MainLayout.razor.NavItems.cs | Adds "Map" entry to demo nav. |
| .gitignore | Ignores .kiro and .cursor editor directories. |
Comments suppressed due to low confidence (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts:156
AddMarkerfirst adds the new feature tos.markerSource, then checks if a marker with the same id already exists and removes it. Because the new feature has just been registered with the same id (f.setId(markerId)),s.markerSource.addFeature(f)may throw an "AssertionError: Feature already added to the source" before the previous entry is cleaned up. Removes.markers[markerId]from the source before adding the new feature, mirroring the pattern used in the other providers.
f.setId(markerId);
f.setStyle(BitMapOpenLayers._markerStyle(ol, opts));
s.markerSource.addFeature(f);
const existing = s.markers[markerId];
if (existing) try { s.markerSource.removeFeature(existing); } catch { /* ignore */ }
s.markers[markerId] = f;
}
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (1)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor (1)
203-203: ⚡ Quick winAdd explicit labels for token/key fields.
Line 203 and Line 233 currently rely on placeholders only. Add
Labelto improve screen-reader clarity and form accessibility.Proposed change
- <BitTextField `@bind-Value`="mapboxToken" Placeholder="pk.eyJ1…" Style="margin-bottom:0.5rem;max-width:480px" /> + <BitTextField Label="Mapbox access token" `@bind-Value`="mapboxToken" Placeholder="pk.eyJ1…" Style="margin-bottom:0.5rem;max-width:480px" /> ... - <BitTextField `@bind-Value`="azureMapsKey" Placeholder="Azure Maps subscription key" Style="margin-bottom:0.5rem;max-width:480px" /> + <BitTextField Label="Azure Maps subscription key" `@bind-Value`="azureMapsKey" Placeholder="Azure Maps subscription key" Style="margin-bottom:0.5rem;max-width:480px" />Also applies to: 233-233
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor` at line 203, Add explicit Label attributes to the BitTextField components that currently only use Placeholder so screen readers can announce them; locate the BitTextField instances bound to mapboxToken (BitTextField `@bind-Value`="mapboxToken") and the other token/key field around the second occurrence (the BitTextField at line ~233) and add a meaningful Label (e.g., Label="Mapbox token" and Label="MapTiler key") to each component so they are accessible to assistive tech.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cs`:
- Around line 302-308: OnProviderSet currently returns early when Provider is
null, which prevents reverting to a default provider after initialization;
change OnProviderSet so that when _initialized is true and Provider is null you
create/assign a default TMapProvider (or call ProviderFactory/default factory)
and proceed to call _js.BitMapSync(JsObject, _Id,
Provider.BuildOptionsPayload()) and set _activeProvider = Provider; ensure the
logic still skips work only when nothing changed (e.g., _activeProvider equals
Provider) but handles the "post-init reset to null" case by reinstating the
default provider and resending options.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scss`:
- Around line 9-13: The CSS rule for .bit-map-canvas removes the browser focus
outline (outline: none), which hides keyboard focus for the focusable map
canvas; restore visible keyboard focus by removing the outline: none declaration
(or replace it with a sensible focus style such as outline: auto or add a
:focus/:focus-visible rule to provide an accessible focus ring) so that the
.bit-map-canvas element shows a clear focus indicator when tabbed to.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cs`:
- Around line 35-41: In BuildOptionsPayload, validate the basemap/key combo
before returning the payload: if BasemapId is not "osm" (case-insensitive) and
ApiKey is null/empty, throw a clear ArgumentException (or
InvalidOperationException) with a message explaining that non‑OSM basemaps
require a valid ApiKey; use the existing GetCommonOptions(), BasemapId and
ApiKey symbols to locate where to add the check so invalid combinations fail
fast rather than emitting a runtime JS config error.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cs`:
- Around line 10-37: The SubscriptionKey property is required but currently can
be empty and is passed into BuildOptionsPayload; update the BuildOptionsPayload
method in BitAzureMapsMapProvider to validate SubscriptionKey
(non-empty/non-whitespace) and throw a clear exception (e.g., ArgumentException)
if it's missing before calling GetCommonOptions; then only add
common["subscriptionKey"] = SubscriptionKey after validation so initialization
fails fast and provides a deterministic error.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 232-267: addGeoJson currently only handles Point, LineString, and
Polygon and silently drops MultiPoint, MultiLineString, MultiPolygon and
GeometryCollection; update addGeoJson to recursively expand multi-geometries and
GeometryCollection into their constituent geometries and create graphics for
each piece using the same attribute merge (props) and existing symbol helpers
(_lineSym, _fillSym, Point symbol); for MultiPoint create a Graphic per
coordinate using esri.Point, for MultiLineString create a Polyline per
coordinate array, for MultiPolygon create one or more Polygon graphics using
rings (maintaining spatialReference { wkid: 4326 }), and for GeometryCollection
iterate its geometries and dispatch by type; keep using esri.Graphic and ensure
all created graphics are added to s.view.graphics and included in
s.geoJsonLayers[layerId] so nothing is silently dropped.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`:
- Around line 265-296: When adding a GeoJSON/vector layer (in addGeoJson and the
similar _addVectorLayer code paths referenced around lines 344-356) we currently
overwrite s.geoJsonLayers[layerId] without removing the previously-added map
layers and source, leaking stale layers; update both functions to first check
s.geoJsonLayers[layerId], and if present iterate its layerIds to remove each
layer from s.map.layers (s.map.layers.remove(...)) and remove the previous
source from s.map.sources (and dispose/clear the DataSource if appropriate),
then delete the registry entry before creating and registering the new
DataSource and layers so removeLayer will correctly clean up the latest
instance.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs`:
- Around line 10-41: The BuildOptionsPayload currently forwards StyleUrl and
AccessToken unchanged which allows a "mapbox://" style to be used with an empty
AccessToken; update BitMapboxMapProvider.BuildOptionsPayload to validate and
guard this: detect when StyleUrl starts with "mapbox://" and if
string.IsNullOrWhiteSpace(AccessToken) either throw a clear ArgumentException
(or return/fallback to a non-mapbox CDN style) so consumers get a deterministic
failure instead of runtime errors; modify the method to check
StyleUrl.StartsWith("mapbox://", StringComparison.OrdinalIgnoreCase) and handle
the empty AccessToken case before adding values to the common dictionary.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`:
- Around line 258-273: addGeoJson only sets _bmLayerId on the DataSource, but
the click handler expects metadata on each picked Entity, so GeoJSON features
never trigger OnGeoJsonFeatureClick; update BitMapCesium.addGeoJson (and the
similar routine around lines 381-395) to iterate ds.entities.values and for each
entity set entity._bmLayerId = layerId and entity._bmKind = 'geojson' (or
whatever kind the click handler checks), and also apply any per-entity
style/metadata as needed so the pick logic can detect GeoJSON features; keep the
existing DataSource tagging but ensure every Entity gets the same metadata after
GeoJsonDataSource.load completes and before adding to viewer.
- Around line 150-160: The add/remove order is reversed causing Cesium to throw
on duplicate IDs; locate the marker creation blocks (uses s.viewer.entities.add,
id `bm-marker-${id}-${markerId}`, variables ent, existing and
s.markers[markerId]) and remove any existing entity first (check existing =
s.markers[markerId]; if (existing) try { s.viewer.entities.remove(existing); }
catch {/*ignore*/}) before calling s.viewer.entities.add(...) and then assign
s.markers[markerId] = ent; apply the same change to the other similar blocks
referenced (around the ranges mentioned).
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts`:
- Around line 292-297: The click handlers attached via s.map.on('click', ...)
(the handler created near lines with layerId/fillId/lineId) are never
unregistered, so update the code to store these handler references in the
vectorCatalog entry for the vector (e.g., keep the handler function(s) under
vectorCatalog[layerId].clickHandler or similar) and then, inside _removeVector,
call s.map.off('click', fillId, handler) and s.map.off('click', lineId, handler)
(or the exact stored handler refs) before removing the layers and source; ensure
you reference the same handler function objects when calling map.off so
listeners are fully removed and will not persist when layers are re-added.
- Line 177: The popup content is being injected unsafely via
setHTML(String(opts.popupHtml)) in BitMapGlBase; guard against XSS by checking
the source and type of opts.popupHtml and either (a) use marker.setPopup(new
gl.Popup({ offset: 25 }).setText(String(opts.popupHtml))) for
untrusted/plain-text input or (b) run opts.popupHtml through a
sanitizer/whitelist before calling setHTML; update the code path that constructs
the Popup in BitMapGlBase to choose setText when content is untrusted or
sanitize/validate the HTML first and only call setHTML when it is known-safe.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`:
- Around line 34-48: The provider never maps public interaction toggles
(scrollWheelZoom, dragging, doubleClickZoom, keyboardNavigation) into
OpenLayers, so update the ol.Map creation and the sync path to pass and toggle
ol.interaction.defaults based on the component options object (o) — e.g., set
the map option interactions: ol.interaction.defaults({mouseWheelZoom:
o.scrollWheelZoom !== false, dragPan: o.dragging !== false, doubleClickZoom:
o.doubleClickZoom !== false, keyboard: o.keyboardNavigation !== false}) when
constructing the map in init, and in sync (or the equivalent update handler)
enable/disable those interactions on the existing map instance (map) to reflect
changes to o.scrollWheelZoom, o.dragging, o.doubleClickZoom, and
o.keyboardNavigation.
- Around line 230-238: The style function styleFn currently returns ol.Style({
stroke, fill }) for Point and MultiPoint geometries which doesn't render points;
update styleFn to check for 'Point' and 'MultiPoint' types and return an
ol.Style that includes an image (e.g., ol.style.Circle with radius, fill/stroke)
alongside stroke/fill so point features render; modify the branch where you
create new ol.Style({ stroke, fill }) to instead create new ol.Style({ image: /*
Circle style using fill/stroke */, stroke, fill }) ensuring compatibility with
ol.VectorLayer and the existing features variable.
---
Nitpick comments:
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor`:
- Line 203: Add explicit Label attributes to the BitTextField components that
currently only use Placeholder so screen readers can announce them; locate the
BitTextField instances bound to mapboxToken (BitTextField
`@bind-Value`="mapboxToken") and the other token/key field around the second
occurrence (the BitTextField at line ~233) and add a meaningful Label (e.g.,
Label="Mapbox token" and Label="MapTiler key") to each component so they are
accessible to assistive tech.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7aaa1a15-5612-413b-a9bd-8deefa307b2b
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (35)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs (1)
34-41:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd a null/empty guard for
StyleUrlbeforeStartsWith.Line 36 can throw if
StyleUrlis null at runtime. Validate it first and fail with a deterministic message.Suggested fix
public override object BuildOptionsPayload() { + if (string.IsNullOrWhiteSpace(StyleUrl)) + { + throw new InvalidOperationException("BitMapboxMapProvider: StyleUrl is required."); + } + if (StyleUrl.StartsWith("mapbox://", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(AccessToken)) { throw new InvalidOperationException( $"BitMapboxMapProvider: An AccessToken is required when using a 'mapbox://' style ('{StyleUrl}'). " + "Provide a valid Mapbox access token or use a non-Mapbox style URL."); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs` around lines 34 - 41, In BuildOptionsPayload, guard against null/empty StyleUrl before calling StyleUrl.StartsWith to avoid a NullReferenceException: check string.IsNullOrWhiteSpace(StyleUrl) first and throw a clear InvalidOperationException (similar to the existing AccessToken check) when StyleUrl is null/empty; only then evaluate StartsWith("mapbox://", StringComparison.OrdinalIgnoreCase) and proceed with the current AccessToken validation (reference: BuildOptionsPayload, StyleUrl, AccessToken).src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cs (1)
37-42:⚠️ Potential issue | 🟠 Major | ⚡ Quick winHarden
BasemapIdvalidation and make OSM check case-insensitive.Line 37 treats
"OSM"as non-OSM and may enforceApiKeyincorrectly. Also guard emptyBasemapIdearly.Suggested fix
public override object BuildOptionsPayload() { - if (BasemapId is not "osm" && string.IsNullOrWhiteSpace(ApiKey)) + if (string.IsNullOrWhiteSpace(BasemapId)) + { + throw new InvalidOperationException("BitArcGisMapProvider: BasemapId is required."); + } + + if (!string.Equals(BasemapId, "osm", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(ApiKey)) { throw new InvalidOperationException( $"BitArcGisMapProvider: An ApiKey is required for the '{BasemapId}' basemap. " + "Only the 'osm' basemap works without an API key."); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cs` around lines 37 - 42, Validate BasemapId in BitArcGisMapProvider by first guarding against null/empty/whitespace (throwing a clear InvalidOperationException if missing), then perform the OSM check using a case-insensitive comparison (e.g., compare BasemapId to "osm" with StringComparison.OrdinalIgnoreCase or normalize with ToLowerInvariant/Trim) so values like "OSM" or extra whitespace don't incorrectly require an ApiKey, and only throw the existing ApiKey-required InvalidOperationException when the normalized BasemapId is not "osm" and ApiKey is null/whitespace.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cs`:
- Around line 14-22: The Opacity and FillOpacity properties on
BitMapVectorPathStyle accept any double but are documented as 0–1; clamp their
values to the valid range by implementing bounded setters for Opacity and
FillOpacity (or validate and clamp right before serialization) so any assigned
value <0 becomes 0 and >1 becomes 1; update the property implementations on the
BitMapVectorPathStyle class (the Opacity and FillOpacity members) to enforce
this clamping and preserve existing defaults.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cs`:
- Around line 65-82: In BuildOptionsPayload, enforce Cesium token-dependent
options before returning the payload: check IonAccessToken (in
BuildOptionsPayload) and if it's null/empty disable token-required features (set
TerrainEnabled to false and override any Bing/ion-dependent ImageryStyle to a
safe default) so the payload never enables terrain or Bing imagery when
IonAccessToken is missing; update the logic around the TerrainEnabled,
ImageryStyle and IonAccessToken assignments in BuildOptionsPayload accordingly.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 64-72: BitMapArcGis.sync currently updates
center/zoom/basemap/scale but doesn't reapply interaction flags (e.g.,
scrollWheelZoom, dragging) that init sets, so update BitMapArcGis.sync to read
the same options (o.scrollWheelZoom, o.dragging or their exact names used in
init) and reapply them to the stored map/view instance s (the same
enable/disable logic used in BitMapArcGis.init), ensuring interaction state is
toggled on s.view or s.map the same way as during initialization; reference
BitMapArcGis.sync, BitMapArcGis.init, BitMapArcGis._maps and
BitMapArcGis._ensureScaleBar when making the change.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`:
- Around line 318-327: The addTileOverlay implementation
(BitMapAzureMaps.addTileOverlay) currently overwrites s.tileOverlays[opts.id]
without removing any previous layer; before creating the new TileLayer (tlId),
check s.tileOverlays[opts.id] for an existing layer id, locate that layer in
s.map.layers (by the stored layer id) and remove it from the map (and from the
registry) so you don't leave stale state, then proceed to create and add the new
TileLayer and set s.tileOverlays[opts.id] = tlId.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`:
- Around line 133-143: The SetView and FlyTo methods always default zoom to 4,
causing unintended zoom changes when zoom is omitted; change them to preserve
the current camera altitude when zoom is null by reading the current camera
height (e.g. from s.viewer.camera.positionCartographic.height or equivalent) and
only call BitMapCesium._zoomToAltitude when zoom is provided. Update both
BitMapCesium.setView and BitMapCesium.flyTo to compute altitude = zoom != null ?
BitMapCesium._zoomToAltitude(zoom) : currentCameraHeight and use that altitude
for Cesium.Cartesian3.fromDegrees.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts`:
- Around line 328-344: The addTileOverlay method currently returns early when a
source already exists, so new URL/opacity/maxZoom aren't applied; modify
addTileOverlay (and use the instance from BitMapGlBase._require) to detect
existing tileOverlayCatalog[opts.id] or s.map.getSource(sourceId) and remove the
old layer and source (s.map.removeLayer(layerId) and
s.map.removeSource(sourceId)) before adding the new source and layer, or
alternatively update the existing layer's paint and source options via
s.map.setPaintProperty and by recreating the source with the new tiles/maxzoom;
ensure you keep tileOverlayCatalog[opts.id] in sync with the new
sourceId/layerId after replacing/updating so subsequent calls reflect the new
URL/opacity/maxZoom.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.ts`:
- Around line 90-93: The sync currently forces a hardcoded center by building c
= [o.center?.lat ?? 51.505, o.center?.lng ?? -0.09] and always calling
s.map.setView(c, z), which can jump the map on option-only updates; change sync
so it only calls s.map.setView when options.center is explicitly provided (use
o.center and o.zoom or fall back to current s.map.getZoom for the z argument),
and if only options.zoom is provided call s.map.setZoom(o.zoom, { animate: false
}) instead of rebuilding a default center; reference variables/methods:
function/method sync in BitMapLeaflet.ts, variables o.center, o.zoom, c, z, and
calls s.map.setView / s.map.setZoom.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`:
- Line 181: BitMapOpenLayers.openMarkerPopup currently silently no-ops; change
it to surface a clear failure by throwing a descriptive Error (or at minimum
logging and throwing) so caller code knows OpenLayers doesn't support this
built-in popup behavior; update the method BitMapOpenLayers.openMarkerPopup to
throw an Error that includes context (the passed _id and _markerId and that
OpenLayers requires a custom overlay/implementation) so provider-agnostic
callers receive a visible failure instead of silent no-op.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.ts`:
- Around line 45-53: The circleRingLngLat function can divide by points causing
NaN when points <= 0; add a guard at the start of circleRingLngLat to validate
and normalize points (e.g., if points is not a positive integer, set points =
Math.max(1, Math.floor(points)) or throw a clear error) before using it in the
bearing calculation and loop; ensure the rest of the function uses the
normalized points variable so the division (bearing = (i / points) * 2 *
Math.PI) and loop bounds are safe.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cs`:
- Around line 37-42: Validate BasemapId in BitArcGisMapProvider by first
guarding against null/empty/whitespace (throwing a clear
InvalidOperationException if missing), then perform the OSM check using a
case-insensitive comparison (e.g., compare BasemapId to "osm" with
StringComparison.OrdinalIgnoreCase or normalize with ToLowerInvariant/Trim) so
values like "OSM" or extra whitespace don't incorrectly require an ApiKey, and
only throw the existing ApiKey-required InvalidOperationException when the
normalized BasemapId is not "osm" and ApiKey is null/whitespace.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs`:
- Around line 34-41: In BuildOptionsPayload, guard against null/empty StyleUrl
before calling StyleUrl.StartsWith to avoid a NullReferenceException: check
string.IsNullOrWhiteSpace(StyleUrl) first and throw a clear
InvalidOperationException (similar to the existing AccessToken check) when
StyleUrl is null/empty; only then evaluate StartsWith("mapbox://",
StringComparison.OrdinalIgnoreCase) and proceed with the current AccessToken
validation (reference: BuildOptionsPayload, StyleUrl, AccessToken).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5edad8b8-6807-4608-8452-a84d84564da4
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (35)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs (1)
34-37:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd a null/empty guard for
StyleUrlbeforeStartsWith.
StartsWithon a nullStyleUrlcauses an immediate runtime failure instead of a clear configuration error.Proposed fix
public override object BuildOptionsPayload() { + if (string.IsNullOrWhiteSpace(StyleUrl)) + { + throw new InvalidOperationException("BitMapboxMapProvider: StyleUrl is required."); + } + if (StyleUrl.StartsWith("mapbox://", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(AccessToken)) { throw new InvalidOperationException( $"BitMapboxMapProvider: An AccessToken is required when using a 'mapbox://' style ('{StyleUrl}'). " + "Provide a valid Mapbox access token or use a non-Mapbox style URL."); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs` around lines 34 - 37, In BuildOptionsPayload(), guard StyleUrl for null/empty before calling StyleUrl.StartsWith(...) — e.g., check string.IsNullOrWhiteSpace(StyleUrl) first and handle it (throw a clear configuration exception or return an appropriate error) so the subsequent StartsWith call is never invoked on null; also retain the existing AccessToken check and ensure the error message references StyleUrl and AccessToken for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cs`:
- Around line 67-77: The code treats whitespace-only IonAccessToken as present;
update the token presence check in the BitCesiumMapProvider by replacing
string.IsNullOrEmpty(IonAccessToken) with
string.IsNullOrWhiteSpace(IonAccessToken) (i.e., compute hasToken =
!string.IsNullOrWhiteSpace(IonAccessToken)) so TerrainEnabled/terrainEnabled and
imageryStyle logic correctly treat whitespace tokens as missing, and ensure
common["ionAccessToken"] is only set when hasToken is true (otherwise leave it
null/empty).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cs`:
- Around line 20-21: The TileOpacity property on BitLeafletMapProvider currently
allows any double but is documented as 0–1; update the TileOpacity property
setter (the TileOpacity auto-property) to clamp incoming values to the [0,1]
range (e.g., set to 0 if value < 0, to 1 if value > 1, otherwise keep value) so
the component honors its documented contract and use that clamped value
internally when raising any change notifications or rendering updates.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 323-335: In addTileOverlay (BitMapArcGis.addTileOverlay) remove
any existing tile layer from s.tileOverlays[opts.id] (and call s.map.remove on
it) before creating/adding the new esri.WebTileLayer; use
BitMapArcGis._require(id) to get s, check const existing =
s.tileOverlays[opts.id] and if present call s.map.remove(existing) and clear
s.tileOverlays[opts.id] before instantiating tl and calling s.map.add(tl), then
assign s.tileOverlays[opts.id] = tl.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cs`:
- Around line 19-20: TileOpacity currently allows values outside the documented
0–1 range; change the auto-property to use a private backing field and clamp
assignments in the TileOpacity setter (e.g., use Math.Clamp(value, 0.0, 1.0)) so
any set (including the default) is constrained to 0..1 and keep the default at
1.0; update references to the property if they relied on direct field access.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cs`:
- Around line 34-37: In BuildOptionsPayload(), guard StyleUrl for null/empty
before calling StyleUrl.StartsWith(...) — e.g., check
string.IsNullOrWhiteSpace(StyleUrl) first and handle it (throw a clear
configuration exception or return an appropriate error) so the subsequent
StartsWith call is never invoked on null; also retain the existing AccessToken
check and ensure the error message references StyleUrl and AccessToken for
clarity.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 581b08e6-756e-448c-8bbc-f77f5a867969
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (35)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFix Stylelint violation on Line 7 import path.
@import "../Components/Map/BitMap.scss";violatesscss/load-partial-extension. Remove the.scssextension.🔧 Suggested fix
-@import "../Components/Map/BitMap.scss"; +@import "../Components/Map/BitMap";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The SCSS import for BitMap currently includes the .scss extension which triggers the scss/load-partial-extension Stylelint rule; update the `@import` that references BitMap.scss to remove the .scss extension (i.e. import the partial by name without the extension) so the import follows the linter rule and still resolves the BitMap partial.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts`:
- Around line 465-475: _applyInteractivity currently enables/disables handlers
even when options are unspecified; change it to only modify a given handler when
the corresponding option is present. For each option (scrollWheelZoom,
doubleClickZoom, boxZoom, dragPan/dragging, dragRotate, keyboardNavigation)
check for presence (e.g., o.scrollWheelZoom !== undefined or 'scrollWheelZoom'
in o) before calling map.<handler>?.enable()/disable(); for the dragPan/dragging
case only proceed if either 'dragPan' or 'dragging' exists on o and use the
resolved dp value to decide enable/disable. This prevents partial sync() updates
from unintentionally toggling other interactions.
In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.css`:
- Line 135: The vendored Leaflet CSS is triggering stylelint rules
(value-keyword-case and declaration-empty-line-before) at several spots like the
pointer-events: visiblePainted; declaration and other vendor blocks; fix by
excluding this third-party file from stylelint checks: add a file-level
suppression (e.g., a top-of-file comment to disable the specific rules used by
CI and a closing re-enable comment) so stylelint ignores value-keyword-case and
declaration-empty-line-before for this file, or alternatively normalize
offending keyword tokens to lowercase consistently (e.g., adjust the
pointer-events value) and remove/clear extra empty-line-before declarations;
target the pointer-events: visiblePainted; occurrence and the other flagged
declarations when applying the change.
---
Duplicate comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The SCSS import for BitMap currently includes the .scss extension
which triggers the scss/load-partial-extension Stylelint rule; update the
`@import` that references BitMap.scss to remove the .scss extension (i.e. import
the partial by name without the extension) so the import follows the linter rule
and still resolves the BitMap partial.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b3f0ad8c-0f8b-4c19-ac58-54ad9f5848b0
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (38)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.csssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/Map/BitMapTests.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts (1)
207-239:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDo not silently ignore draggable markers in the Cesium provider.
Line 207 accepts marker options, but draggable behavior is never implemented, and Lines 489–543 never emit
OnMarkerDragEnd. This makesDraggable = truea silent no-op on Cesium.🔧 Minimal safe fix (fail fast until drag support is implemented)
public static addMarker(id: string, markerId: string, opts: any) { const s = BitMapCesium._require(id); const Cesium = s.Cesium; + if (opts?.draggable === true) { + throw new Error('BitMapCesium: draggable markers are not supported yet.'); + } const existing = s.markers[markerId]; if (existing) try { s.viewer.entities.remove(existing); } catch { /* ignore */ }Also applies to: 489-543
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts` around lines 207 - 239, addMarker currently ignores opts.draggable which makes Draggable a silent no-op; modify BitMapCesium.addMarker to detect opts.draggable === true and fail fast (throw a clear Error or call process/console.error and throw) stating "Draggable markers not supported in Cesium provider" so callers get immediate feedback; also add a TODO comment referencing the drag handler block (the code around the existing drag-related logic that should emit OnMarkerDragEnd) so future work implements proper drag behavior and emits OnMarkerDragEnd when complete.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts (1)
134-139: 💤 Low valueConsider sanitizing
popupHtmlbefore rendering in Azure Maps popups.Both
addMarker(line 135) andopenMarkerPopup(line 220) injectpopupHtmldirectly into popup content. Like the OpenLayers provider, this could enable XSS if popup content originates from untrusted sources.This is consistent across providers—if the design intent is to allow arbitrary HTML, consider documenting the security expectation that callers must sanitize input.
Also applies to: 219-220
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts` around lines 134 - 139, addMarker and openMarkerPopup currently inject popupHtml directly into atlas.Popup content which can cause XSS; update both functions (refs: addMarker, openMarkerPopup, popupHtml, popupText, atlas.Popup) to either sanitize HTML input before using it (e.g., run popupHtml through a sanitizer like DOMPurify or a project-approved HTML sanitizer) or disallow raw HTML and only accept escaped text (reuse the escaping logic used for popupText), and add a short comment/doc note explaining the security expectation so callers know they must provide safe HTML if raw HTML is permitted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cs`:
- Around line 65-80: In BuildOptionsPayload validate ImageryStyle and SceneMode
against their documented allowed values before adding them to the payload:
define the allowed-value sets (e.g., allowed imagery styles including
"bing_aerial","bing_labels","osm", etc., and allowed scene modes) and perform
case-insensitive membership checks on ImageryStyle and SceneMode (use trimmed
values similar to IonAccessToken); if a value is not in the allowed set throw an
ArgumentException with a clear message naming the parameter and allowed options,
otherwise use the validated/normalized value when setting common["imageryStyle"]
and common["sceneMode"] so invalid strings are rejected server-side rather than
forwarded to JS.
---
Duplicate comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`:
- Around line 207-239: addMarker currently ignores opts.draggable which makes
Draggable a silent no-op; modify BitMapCesium.addMarker to detect opts.draggable
=== true and fail fast (throw a clear Error or call process/console.error and
throw) stating "Draggable markers not supported in Cesium provider" so callers
get immediate feedback; also add a TODO comment referencing the drag handler
block (the code around the existing drag-related logic that should emit
OnMarkerDragEnd) so future work implements proper drag behavior and emits
OnMarkerDragEnd when complete.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`:
- Around line 134-139: addMarker and openMarkerPopup currently inject popupHtml
directly into atlas.Popup content which can cause XSS; update both functions
(refs: addMarker, openMarkerPopup, popupHtml, popupText, atlas.Popup) to either
sanitize HTML input before using it (e.g., run popupHtml through a sanitizer
like DOMPurify or a project-approved HTML sanitizer) or disallow raw HTML and
only accept escaped text (reuse the escaping logic used for popupText), and add
a short comment/doc note explaining the security expectation so callers know
they must provide safe HTML if raw HTML is permitted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: a4548936-0ba0-487a-8f81-15cd517be5c4
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (38)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.csssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/Map/BitMapTests.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts (1)
568-573:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSanitize popup content before writing to
innerHTML.Line 570 assigns
popupHtmldirectly toinnerHTML, which keeps an XSS path open when popup content is not fully trusted.🔧 Minimal safe patch
- if (html) { - contentEl.innerHTML = html; - } else { - contentEl.textContent = text; - } + // Treat incoming popup content as untrusted by default. + contentEl.textContent = html || text;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts` around lines 568 - 573, The popup content is being assigned directly to innerHTML (contentEl.innerHTML = html) which opens an XSS vector; update the BitMapOpenLayers popup rendering to sanitize the html before writing it to s.popupContentElement (contentEl) — e.g., call a trusted sanitizer (like DOMPurify.sanitize or your app's sanitizer) on the html string and assign the sanitized result to contentEl.innerHTML, or if no sanitizer is available, fall back to using contentEl.textContent = text; ensure the change touches the block that checks if (html) { ... } so all HTML paths are sanitized.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js (1)
15-25: ⚡ Quick winInitialize
__bitMapOlBundleonce to avoid duplicate module fetches.Line 15 always reassigns the global promise. If this loader is injected again, imports can be re-fired unnecessarily. Prefer one-time initialization.
Proposed change
-globalThis.__bitMapOlBundle = Promise.all([ +globalThis.__bitMapOlBundle ??= Promise.all([🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js` around lines 15 - 25, The loader currently always reassigns globalThis.__bitMapOlBundle causing duplicate imports; change the initialization to set globalThis.__bitMapOlBundle only if it is undefined (i.e., guard the Promise.all assignment with a check like if (!globalThis.__bitMapOlBundle) or use logical OR) so repeated injections reuse the same Promise; ensure the existing Promise resolves to the same shape (the then mapping that destructures [ol, olControl, olStyle, olGeom, olSource, olLayer, olFormat, olProj, olInteraction]) remains unchanged and reference the existing globalThis.__bitMapOlBundle when present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cs`:
- Around line 451-453: The early return in OnProviderSet prevents
re-initialization after a failed initial attempt; update the method
(OnProviderSet) to not bail out solely because _initialized is false — only
return when _activeProvider is null — and if _initialized is false then trigger
the initialization/retry path (call the existing initialization routine used
elsewhere or invoke the same logic that sets up scripts and map instance) so
provider changes can retry setup and recover from prior failures.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 351-353: When replacing a layer by id, clear any prior
representation across both storage types so switching types (e.g., polyline →
GeoJSON or vice versa) doesn't leave the old rendering behind; update
BitMapArcGis.addGeoJson (the block that calls BitMapArcGis._removeGeoJsonLayer
and then sets s.geoJsonLayers[layerId]) and the _setLayer/_removeLayer logic so
they each remove both s.geoJsonLayers[layerId] and s.layers[layerId] (and their
associated graphics/graphics layers) before adding the new one, ensuring layerId
replacement is cross-type rather than catalog-specific.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`:
- Around line 380-383: When reusing a layerId you must clear both entity and
GeoJSON state: update addGeoJson() (where s.geoJsonLayers[layerId] is set and ds
added to s.viewer.dataSources) to also remove any existing entity set stored in
s.layers[layerId] (and clear s.layers[layerId]) before adding the new
dataSource; likewise update _setLayer() (which sets s.layers[layerId]) to remove
and clear any existing GeoJSON dataSource in s.geoJsonLayers[layerId] (using the
same remove call pattern as for existingDs) so that reusing a layerId does not
leave the old content rendered alongside the new one.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`:
- Around line 568-573: The popup content is being assigned directly to innerHTML
(contentEl.innerHTML = html) which opens an XSS vector; update the
BitMapOpenLayers popup rendering to sanitize the html before writing it to
s.popupContentElement (contentEl) — e.g., call a trusted sanitizer (like
DOMPurify.sanitize or your app's sanitizer) on the html string and assign the
sanitized result to contentEl.innerHTML, or if no sanitizer is available, fall
back to using contentEl.textContent = text; ensure the change touches the block
that checks if (html) { ... } so all HTML paths are sanitized.
---
Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js`:
- Around line 15-25: The loader currently always reassigns
globalThis.__bitMapOlBundle causing duplicate imports; change the initialization
to set globalThis.__bitMapOlBundle only if it is undefined (i.e., guard the
Promise.all assignment with a check like if (!globalThis.__bitMapOlBundle) or
use logical OR) so repeated injections reuse the same Promise; ensure the
existing Promise resolves to the same shape (the then mapping that destructures
[ol, olControl, olStyle, olGeom, olSource, olLayer, olFormat, olProj,
olInteraction]) remains unchanged and reference the existing
globalThis.__bitMapOlBundle when present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: ad3030ab-509f-4678-bbf5-bc325e92f473
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (38)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.csssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/Map/BitMapTests.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRemove
.scssextension in import to satisfy Stylelint rule.Line 7 violates
scss/load-partial-extension, which can fail CI linting.Suggested fix
-@import "../Components/Map/BitMap.scss"; +@import "../Components/Map/BitMap";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The import statement currently includes the .scss extension which triggers the scss/load-partial-extension rule; update the import "`@import` "../Components/Map/BitMap.scss";" to remove the extension (e.g. "`@import` "../Components/Map/BitMap";") so the stylesheet import for BitMap complies with Stylelint.src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts (1)
233-235:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRaw
setHTMLstill permits XSS for untrusted popup content.Line 234 passes
opts.popupHtmldirectly toPopup.setHTML(...). This remains unsafe for user-provided content; prefersetText(...)unless HTML is explicitly trusted/sanitized.Does MapLibre GL JS Popup.setHTML sanitize input HTML, or must callers sanitize untrusted content themselves?🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts` around lines 233 - 235, The code calls marker.setPopup(new gl.Popup(...).setHTML(String(opts.popupHtml))) which allows raw HTML and risks XSS; change this to use setText for untrusted content (i.e., marker.setPopup(new gl.Popup(...).setText(String(opts.popupHtml)))) or require an explicit trust flag (e.g., opts.popupHtmlTrusted) and only call gl.Popup.setHTML after running a sanitizer (e.g., DOMPurify) when that flag is true; update the BitMapGlBase marker popup creation logic (refs: opts.popupHtml, marker.setPopup, gl.Popup.setHTML, setText) so untrusted user input is not passed directly to setHTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cs`:
- Around line 413-418: The DotNetObjectReference (_dotnetObj created via
DotNetObjectReference.Create(this)) is allocated before calling
_activeProvider.BuildOptionsPayload(), so if BuildOptionsPayload() throws you'll
leak the reference; fix by either moving the DotNetObjectReference.Create(this)
to after successfully obtaining initOptions, or wrap the BuildOptionsPayload()
call in a try/catch that disposes _dotnetObj on exception (call
_dotnetObj.Dispose() and null it) before rethrowing, ensuring no live
DotNetObjectReference remains when payload validation fails.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 623-662: The _esriPromise is permanently memoized on failure
inside BitMapArcGis._loadEsri; change the assignment so that if the inner async
IIFE rejects we clear BitMapArcGis._esriPromise before propagating the error.
Concretely, wrap the async IIFE in a try/catch (or attach .catch) when assigning
BitMapArcGis._esriPromise inside _loadEsri; in the catch handler set
BitMapArcGis._esriPromise = undefined (or null) and rethrow the error so
subsequent calls to _loadEsri will retry the SDK load.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`:
- Around line 134-139: The code currently injects opts.popupHtml directly into
atlas.Popup content (popup variable), which can enable XSS; update the logic in
BitMapAzureMaps where popup is created to either (a) only accept raw HTML when
explicitly marked trusted (e.g., add a new flag like opts.popupHtmlTrusted) and
otherwise escape/sanitize opts.popupHtml before insertion, or (b) prefer the
existing opts.popupText branch by converting untrusted popupHtml into escaped
text like the popupText flow; ensure atlas.Popup creation uses the
sanitized/validated content and keep the pixelOffset and closeButton options
unchanged.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.ts`:
- Around line 254-255: The code in BitMapLeaflet that sets icon dimensions uses
the `||` operator so explicit zeros are treated as falsey and replaced with 32;
change the assignment in the icon creation logic to explicitly check for
undefined/null instead (e.g., use a nullish check or conditional) so
opts.iconWidth and opts.iconHeight values of 0 are honored when computing `w`
and `h` (refer to the variables `w`, `h`, and `opts.iconWidth`/`opts.iconHeight`
in the BitMapLeaflet icon creation code).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`:
- Around line 640-651: The current BitMapOpenLayers._loadOl caches a rejected
BitMapOpenLayers._olLoadPromise so retries never succeed; modify _loadOl so the
created promise clears BitMapOpenLayers._olLoadPromise on any rejection before
rethrowing the error. Concretely, wrap the inner async IIFE (the code that
awaits BitMapHelpers.waitForGlobal and returns globalThis.__bitMapOlBundle) with
a try/catch that sets BitMapOpenLayers._olLoadPromise = undefined in the catch
and then throws the original error, keeping the successful path unchanged.
In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js`:
- Around line 19-29: The current assignment to globalThis.__bitMapOlBundle uses
Promise.all(...).then(...) so if an import() fails the global becomes a
permanently rejected promise; modify the code to capture the created Promise
(e.g. const p = Promise.all([...]).then(...)) and assign p to
globalThis.__bitMapOlBundle, then attach a .catch(err => { if
(globalThis.__bitMapOlBundle === p) delete globalThis.__bitMapOlBundle; throw
err; }) so any import failure clears the global (allowing future retries) and
still rethrows the error; reference the symbols globalThis.__bitMapOlBundle,
Promise.all, import(u()), .then and .catch while making the change.
---
Duplicate comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.ts`:
- Around line 233-235: The code calls marker.setPopup(new
gl.Popup(...).setHTML(String(opts.popupHtml))) which allows raw HTML and risks
XSS; change this to use setText for untrusted content (i.e., marker.setPopup(new
gl.Popup(...).setText(String(opts.popupHtml)))) or require an explicit trust
flag (e.g., opts.popupHtmlTrusted) and only call gl.Popup.setHTML after running
a sanitizer (e.g., DOMPurify) when that flag is true; update the BitMapGlBase
marker popup creation logic (refs: opts.popupHtml, marker.setPopup,
gl.Popup.setHTML, setText) so untrusted user input is not passed directly to
setHTML.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement currently includes the .scss extension which
triggers the scss/load-partial-extension rule; update the import "`@import`
"../Components/Map/BitMap.scss";" to remove the extension (e.g. "`@import`
"../Components/Map/BitMap";") so the stylesheet import for BitMap complies with
Stylelint.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 49355d1a-6d4a-4ec7-b6a4-ea8826ddf73a
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (38)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.csssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/Map/BitMapTests.cs
|
@coderabbitai re-review |
|
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 10
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scss`:
- Line 43: Replace the deprecated CSS property in BitMap.scss: find the rule
containing "word-wrap: break-word;" (near the BitMap component styles) and
change it to use the modern property "overflow-wrap: break-word;" so Stylelint
no longer flags the deprecation; keep the same value and placement to preserve
behavior.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`:
- Around line 531-545: The pointer-down handler currently sets the module-level
active state from the async view.hitTest result (view.on('pointer-down') →
view.hitTest(...)) which can race with release and leave dragPrimary nulled
permanently; change this by deferring activation to the first real drag event
(the drag start handler) instead of assigning active inside the pointer-down
hitTest promise, or add explicit cancellation: on 'pointer-up' and
'pointer-leave' handlers clear active and restore (active as any)._prevDrag to
view.navigation.actionMap.dragPrimary (and restore am.dragPrimary if previously
nulled) so a late hitTest resolution cannot leave active set and panning
disabled. Ensure the same fix is applied to the analogous block around lines
548-568.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`:
- Around line 461-473: The _notifyView function currently checks s.dotnetObj
before scheduling a queueMicrotask, but dispose() can null s.dotnetObj before
the microtask runs; fix this by capturing the .NET handle and necessary camera
values into local constants at the start of _notifyView (e.g., const dotnet =
s.dotnetObj; const cam = s.map.getCamera(); const center = cam.center ?? [0,0];
const bounds = cam.bounds;), return early if dotnet is falsy, and then use
dotnet.invokeMethodAsync(...) inside the queueMicrotask instead of referencing
s.dotnetObj; this ensures invokeMethodAsync is called on a stable handle even if
dispose() runs later.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`:
- Around line 504-507: The callback BitMapCesium._notifyView defers calling
BitMapCesium._readView inside queueMicrotask but only checks s.dotnetObj up
front, so the viewer may have been destroyed by dispose() before the microtask
runs; fix by either capturing the view snapshot synchronously (call _readView
immediately into a local variable and pass that into the microtask) or by
re-checking both s.dotnetObj and s.viewer inside the microtask before calling
_readView, ensuring you never access viewer after dispose(); reference
BitMapCesium._notifyView, BitMapCesium._readView, and the s.dotnetObj/s.viewer
fields when making the change.
- Around line 25-28: Remove the global mutation of Cesium.Ion.defaultAccessToken
in BitMapCesium; instead, when o.ionAccessToken is present pass it as a
per-instance credential to the Cesium ion resource/provider you create (e.g.,
use IonResource.fromAssetId(..., { accessToken: o.ionAccessToken }) or new
Cesium.IonImageryProvider({ ..., accessToken: o.ionAccessToken })) and delete
the assignment to Cesium.Ion.defaultAccessToken so other Viewer instances are
not affected.
- Around line 119-153: BitMapCesium.sync currently only updates camera position;
extend it to apply the other Cesium options sent by BuildOptionsPayload: read
o.imageryStyle, o.terrainEnabled, o.sceneMode, o.shadowsEnabled and any widget
flags and apply them to the existing viewer instance
(BitMapCesium._maps[id].viewer) at runtime instead of ignoring them.
Specifically: update imagery by switching/modifying the base imagery layer or
its provider according to o.imageryStyle, enable/disable terrain by setting
viewer.terrainProvider (or replacing it with a null/ellipsoid terrain) based on
o.terrainEnabled, change scene mode/morph using viewer.scene.mode or
scene.morphTo for o.sceneMode, toggle shadows via viewer.shadows or
viewer.scene.shadowMap.enabled from o.shadowsEnabled, and show/hide UI widgets
using the same viewer widget references used elsewhere in BitMapCesium. Keep
camera updates (fromDegrees/flyTo) but add these runtime updates before or after
the flyTo call so the provider-level options take effect when sync is called
with the same JsObjectName.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.ts`:
- Around line 385-395: L.geoJSON usage in BitMapLeaflet is missing a
pointToLayer handler, so Point/MultiPoint features render as default markers and
ignore BitMapLeaflet._pathStyle(style); update the L.geoJSON options to include
a pointToLayer function that creates vector markers (e.g., use L.circleMarker
with BitMapLeaflet._pathStyle(style)) so point features use the same styling as
other geometries; keep the existing style and onEachFeature (with dn and
layerId) unchanged and ensure pointToLayer receives latlng and returns the
styled layer.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`:
- Around line 24-27: The tile attribution fallback is missing for the built-in
OSM tiles: when BitMapOpenLayers._defaultTileUrl (and values returned by
BitMapOpenLayers._resolveTileUrl) is used but tileAttribution is empty, set
tileAttribution to the OSM attribution string (same logic as BitMapLeaflet).
Update the initialization path in BitMapOpenLayers.init and the update path in
BitMapOpenLayers.sync (and any nearby defaulting code around the _resolveTileUrl
usage at lines referenced) to check if tileAttribution is falsy AND the resolved
tileUrl equals BitMapOpenLayers._defaultTileUrl, then assign the OSM attribution
fallback.
In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js`:
- Around line 57-60: The catch attached to the promise `p` is doing cleanup but
rethrows the error (`throw err`), which can produce an extra unhandled
rejection; update the handler attached via `p.catch(...)` (the block referencing
`globalThis.__bitMapOlBundle` and `p`) to perform only the cleanup (delete
`globalThis.__bitMapOlBundle === p`) and do not rethrow the error or return a
rejected promise so the original promise `p` remains the single source of
rejection.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cs`:
- Line 10: The Description for the OnReady metadata is inaccurate: update the
entry for the OnReady event (new() { Name = "OnReady", Type = "EventCallback",
... }) so it reflects the component contract that OnReady fires not only once
initially but also fires again after a destructive provider swap (i.e., whenever
the map becomes ready following a provider replacement). Modify the Description
text to mention both the initial ready event and subsequent ready events after
provider swaps so it matches the component behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 85035d17-0f3b-42c9-b051-f9fdc4e2b2b7
⛔ Files ignored due to path filters (5)
src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/layers.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon-2x.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-icon.pngis excluded by!**/*.pngsrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/images/marker-shadow.pngis excluded by!**/*.png
📒 Files selected for processing (38)
.gitignoresrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLng.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapLatLngBounds.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarker.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapMarkerDragEndArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapProviderBase.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapTileOverlay.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapVectorPathStyle.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapViewState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/IBitMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitArcGisMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitAzureMapsMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitLeafletMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapGlBase.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLibreMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapLibre.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapMapbox.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapShared.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapboxMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitOpenLayersMapProvider.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.csssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/leaflet/leaflet-1.9.4.jssrc/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.jssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cssrc/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Extras/Map/BitMapTests.cs
| background: #fff; | ||
| border-radius: 6px; | ||
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); | ||
| word-wrap: break-word; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify deprecated property is removed from this stylesheet.
rg -n '\bword-wrap\s*:' src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scss
# Expected: no matchesRepository: bitfoundation/bitplatform
Length of output: 99
Replace deprecated wrapping property
word-wrap: break-word; is still present at line 43. Replace with overflow-wrap to address the Stylelint deprecation.
♻️ Proposed fix
- word-wrap: break-word;
+ overflow-wrap: break-word;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| word-wrap: break-word; | |
| overflow-wrap: break-word; |
🧰 Tools
🪛 Stylelint (17.12.0)
[error] 43-43: Expected "word-wrap" to be "overflow-wrap" (property-no-deprecated)
(property-no-deprecated)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.scss` at line 43,
Replace the deprecated CSS property in BitMap.scss: find the rule containing
"word-wrap: break-word;" (near the BitMap component styles) and change it to use
the modern property "overflow-wrap: break-word;" so Stylelint no longer flags
the deprecation; keep the same value and placement to preserve behavior.
| view.on('pointer-down', (event: any) => { | ||
| view.hitTest(event).then((response: any) => { | ||
| for (const r of response.results) { | ||
| const g = r.graphic; | ||
| const a = g?.attributes; | ||
| if (a && a.markerId && a.draggable && s.markers[a.markerId] === g) { | ||
| active = { graphic: g, markerId: a.markerId }; | ||
| // Disable map panning while dragging this marker. | ||
| try { event.stopPropagation(); } catch { /* ignore */ } | ||
| const am = view.navigation?.actionMap; | ||
| if (am) { (active as any)._prevDrag = am.dragPrimary; am.dragPrimary = null; } | ||
| break; | ||
| } | ||
| } | ||
| }).catch(() => { /* ignore */ }); |
There was a problem hiding this comment.
pointer-down can leave a draggable marker permanently active.
active is assigned from the async pointer-down hit test, but it is only cleared from the drag handler's "end" path. A normal click/tap on a draggable marker, or a late hitTest resolution after release, leaves active set and dragPrimary nulled, so panning stays disabled and the next drag can move the stale marker. This needs a cancellation path (pointer-up/pointer-leave) or, better, activation moved to the first real drag event instead of pointer-down.
Also applies to: 548-568
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapArcGis.ts`
around lines 531 - 545, The pointer-down handler currently sets the module-level
active state from the async view.hitTest result (view.on('pointer-down') →
view.hitTest(...)) which can race with release and leave dragPrimary nulled
permanently; change this by deferring activation to the first real drag event
(the drag start handler) instead of assigning active inside the pointer-down
hitTest promise, or add explicit cancellation: on 'pointer-up' and
'pointer-leave' handlers clear active and restore (active as any)._prevDrag to
view.navigation.actionMap.dragPrimary (and restore am.dragPrimary if previously
nulled) so a late hitTest resolution cannot leave active set and panning
disabled. Ensure the same fix is applied to the analogous block around lines
548-568.
| private static _notifyView(s: any) { | ||
| if (!s.dotnetObj) return; | ||
| const cam = s.map.getCamera(); | ||
| if (!cam) return; | ||
| const c = cam.center ?? [0, 0]; | ||
| const b = cam.bounds; | ||
| queueMicrotask(() => s.dotnetObj.invokeMethodAsync('OnViewChanged', { | ||
| center: { lat: c[1], lng: c[0] }, | ||
| zoom: cam.zoom ?? 0, | ||
| bounds: b | ||
| ? { southWest: { lat: b[1], lng: b[0] }, northEast: { lat: b[3], lng: b[2] } } | ||
| : { southWest: { lat: 0, lng: 0 }, northEast: { lat: 0, lng: 0 } }, | ||
| })); |
There was a problem hiding this comment.
Capture the .NET handle before queueing OnViewChanged.
dispose() nulls s.dotnetObj, but _notifyView() only checks it before queueMicrotask(). A pending move-end callback can therefore queue a microtask that dereferences null during teardown.
🛠️ Minimal hardening
private static _notifyView(s: any) {
- if (!s.dotnetObj) return;
+ const dn = s.dotnetObj;
+ if (!dn) return;
const cam = s.map.getCamera();
if (!cam) return;
const c = cam.center ?? [0, 0];
const b = cam.bounds;
- queueMicrotask(() => s.dotnetObj.invokeMethodAsync('OnViewChanged', {
+ const payload = {
center: { lat: c[1], lng: c[0] },
zoom: cam.zoom ?? 0,
bounds: b
? { southWest: { lat: b[1], lng: b[0] }, northEast: { lat: b[3], lng: b[2] } }
: { southWest: { lat: 0, lng: 0 }, northEast: { lat: 0, lng: 0 } },
- }));
+ };
+ queueMicrotask(() => { void dn.invokeMethodAsync('OnViewChanged', payload).catch(() => {}); });
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapAzureMaps.ts`
around lines 461 - 473, The _notifyView function currently checks s.dotnetObj
before scheduling a queueMicrotask, but dispose() can null s.dotnetObj before
the microtask runs; fix this by capturing the .NET handle and necessary camera
values into local constants at the start of _notifyView (e.g., const dotnet =
s.dotnetObj; const cam = s.map.getCamera(); const center = cam.center ?? [0,0];
const bounds = cam.bounds;), return early if dotnet is falsy, and then use
dotnet.invokeMethodAsync(...) inside the queueMicrotask instead of referencing
s.dotnetObj; this ensures invokeMethodAsync is called on a stable handle even if
dispose() runs later.
| // Default to OSM imagery if no ion token | ||
| if (o.ionAccessToken) { | ||
| Cesium.Ion.defaultAccessToken = o.ionAccessToken; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In CesiumJS, is Ion.defaultAccessTokenshared globally across allViewer instances, and what per-viewer or per-asset authentication APIs are recommended instead of mutating the global default token?
💡 Result:
Yes—CesiumJS’s Ion.defaultAccessToken is effectively a global singleton setting shared across all Viewer instances, because it is defined as a static default token for “default settings for accessing the Cesium ion API” (Cesium.Ion.defaultAccessToken). [1][2] Recommended alternatives (avoid mutating the global default token): 1) Pass a token per asset/resource when creating Cesium ion resources. - IonResource.fromAssetId(assetId, options) supports an accessToken option (defaults to Ion.defaultAccessToken). Provide options.accessToken to scope auth per asset. [3][4] 2) Pass a token per imagery provider (per-viewer layer/provider instance). - Cesium.IonImageryProvider (and also resource-based imagery providers) support an accessToken option; it is documented as defaulting to Ion.defaultAccessToken. Pass a token directly to the provider instead of changing the global default. [5][6] 3) For CesiumJS token hygiene, rely on your own ion token(s) rather than the built-in demo/default token. - Cesium notes that a default access token is provided for evaluation only, and you should replace it with your own ion access token for production use. [2] Why this answers your “shared globally” question: - The only official per-Viewer/per-asset mechanism shown in the API docs is the per-call/per-instance accessToken option on specific ion resource/provider constructors (IonResource / IonImageryProvider). [5][3] - Cesium.Ion.defaultAccessToken is a single static default value, which applies wherever APIs fall back to “defaultAccessToken” instead of an explicit per-instance accessToken. [1][2] Example patterns (conceptual): - Per-asset: Cesium.IonResource.fromAssetId(assetId, { accessToken: userToken }) then use that resource for tiles/CZML. [3][4] - Per-imagery-provider: new Cesium.IonImageryProvider({ assetId, accessToken: userToken }) then attach it to a specific Viewer (or to a specific base layer for that Viewer). [5][6]
Citations:
- 1: https://cesium.com/downloads/cesiumjs/releases/1.46/Build/Documentation/Ion.html
- 2: https://cesium.com/learn/cesiumjs/ref-doc/Ion.html
- 3: https://cesium.com/docs/cesiumjs-ref-doc/IonResource.html
- 4: https://cesium.com/downloads/cesiumjs/releases/1.72/Build/Documentation/IonResource.html
- 5: https://cesium.com/downloads/cesiumjs/releases/1.44/Build/Documentation/IonImageryProvider.html
- 6: https://cesium.com/learn/cesiumjs/ref-doc/IonImageryProvider.html
Avoid mutating Cesium.Ion.defaultAccessToken per BitMapCesium instance (src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts, lines 25-28).
Cesium.Ion.defaultAccessToken is effectively process-global (static “default settings”), so setting it when one BitMapCesium initializes can affect other Viewer instances and later “tokenless” maps.
Use per-instance/per-asset auth instead: pass accessToken: o.ionAccessToken directly to the ion resource/provider you create (e.g., IonResource.fromAssetId(..., { accessToken }) / new Cesium.IonImageryProvider({ ..., accessToken })) and remove the global assignment.
// Default to OSM imagery if no ion token
if (o.ionAccessToken) {
Cesium.Ion.defaultAccessToken = o.ionAccessToken;
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`
around lines 25 - 28, Remove the global mutation of
Cesium.Ion.defaultAccessToken in BitMapCesium; instead, when o.ionAccessToken is
present pass it as a per-instance credential to the Cesium ion resource/provider
you create (e.g., use IonResource.fromAssetId(..., { accessToken:
o.ionAccessToken }) or new Cesium.IonImageryProvider({ ..., accessToken:
o.ionAccessToken })) and delete the assignment to Cesium.Ion.defaultAccessToken
so other Viewer instances are not affected.
| public static sync(id: string, options: any) { | ||
| const s = BitMapCesium._maps[id]; | ||
| if (!s) return; | ||
| const o = options || {}; | ||
|
|
||
| let lat: number, lng: number, altitude: number; | ||
|
|
||
| const currentCartographic = s.Cesium.Cartographic.fromCartesian(s.viewer.camera.position); | ||
|
|
||
| if (o.center !== undefined && o.center !== null) { | ||
| lat = o.center.lat; | ||
| lng = o.center.lng; | ||
| } else if (currentCartographic) { | ||
| lat = s.Cesium.Math.toDegrees(currentCartographic.latitude); | ||
| lng = s.Cesium.Math.toDegrees(currentCartographic.longitude); | ||
| } else { | ||
| lat = 51.505; | ||
| lng = -0.09; | ||
| } | ||
|
|
||
| if (o.altitude !== undefined && o.altitude !== null) { | ||
| altitude = o.altitude; | ||
| } else if (o.zoom !== undefined && o.zoom !== null) { | ||
| altitude = BitMapCesium._zoomToAltitude(o.zoom); | ||
| } else if (currentCartographic) { | ||
| altitude = currentCartographic.height; | ||
| } else { | ||
| altitude = BitMapCesium._zoomToAltitude(4); | ||
| } | ||
|
|
||
| s.viewer.camera.flyTo({ | ||
| destination: s.Cesium.Cartesian3.fromDegrees(lng, lat, altitude), | ||
| duration: 0, | ||
| }); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For a CesiumJS Viewer, which of these can be updated after construction without recreating the viewer: imagery layer, terrain provider, scene mode, shadow map enabled, and the animation/timeline/baseLayerPicker/navigation/fullscreen/geocoder/infoBox widgets?
💡 Result:
Answer (for a CesiumJS Viewer): 1) imagery layer: Yes (update by adding/removing/reordering imagery layers via viewer.imageryLayers; you can also modify properties like show/alpha/brightness/contrast on an ImageryLayer, without recreating the Viewer). [1][2] 2) terrain provider: Yes (set viewer.terrainProvider / use viewer.terrain; Cesium supports updating terrain and the Viewer constructor can take terrain as an option). [3][4] 3) scene mode: Yes (scene.mode can be changed programmatically; SceneModePicker updates the widget when the specified Scene is used to perform the change, implying the scene mode is mutable after construction). [5][6] 4) shadow map enabled: Yes (Viewer exposes a shadowMap; ShadowMap has an enabled property you can toggle after construction). [7][8] 5) widgets you listed: - animation: Yes (viewer.animation is controllable as an exposed widget; enabling/disabling construction is separate, but you can interact with it after construction). - timeline: Yes (viewer.timeline is controllable). - baseLayerPicker: Yes (base layer selection can be changed after construction through the underlying selectedImageryProviderViewModel / imagery layer). [3] - navigation: Yes (navigation widget is interactive after construction). - fullscreen: Yes (full-screen widget is interactive after construction). - geocoder: Yes (geocoder widget is interactive after construction). - infoBox: Yes (infoBox can be shown/hidden after construction). If you want, I can provide a concise code snippet demonstrating each update (imagery swap, terrain swap, scene.mode switch, and viewer.shadowMap.enabled toggle) for current CesiumJS.
Citations:
- 1: https://cesium.com/learn/cesiumjs-learn/cesiumjs-imagery
- 2: https://cesium.com/learn/ion-sdk/ref-doc/ImageryLayer.html
- 3: https://cesium.com/learn/cesiumjs/ref-doc/Viewer.html
- 4: https://cesium.com/learn/cesiumjs-learn/cesiumjs-terrain/
- 5: https://gis.stackexchange.com/questions/261777/change-the-scene-mode-in-cesium-every-interval
- 6: https://cesium.com/downloads/cesiumjs/releases/b28/Documentation/SceneModePicker.html
- 7: https://cesium.com/docs/cesiumjs-ref-doc/Viewer.html
- 8: https://cesium.com/learn/cesiumjs/ref-doc/ShadowMap.html
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Focus search on the Cesium provider implementation area
rg -n "BuildOptionsPayload\\(" src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers -S || true
rg -n "OnProviderSet\\(" src/BlazorUI/Bit.BlazorUI.Extras/Components/Map -S || true
rg -n "class BitCesiumMapProvider|BitCesiumMapProvider" src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers -S || true
rg -n "BitMapCesium\\.sync\\(|sync\\(id: string, options: any\\)" src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers -S || true
# Show the exact sync implementation around the reported lines
sed -n '1,220p' src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts | nl -ba | sed -n '100,190p'Repository: bitfoundation/bitplatform
Length of output: 2396
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE_TS="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts"
FILE_PROVIDER="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitCesiumMapProvider.cs"
FILE_RAZOR="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cs"
echo "== BitMapCesium.ts sync() (around ~119-180) =="
awk 'NR>=90 && NR<=190 {printf "%6d\t%s\n", NR, $0}' "$FILE_TS" | sed -n '1,120p'
echo
echo "== BitCesiumMapProvider.cs BuildOptionsPayload() (around method) =="
# Print a window around the method definition
LINE=$(rg -n "BuildOptionsPayload\\(" "$FILE_PROVIDER" | head -n 1 | cut -d: -f1)
START=$((LINE-40))
END=$((LINE+120))
awk -v s="$START" -v e="$END" 'NR>=s && NR<=e {printf "%6d\t%s\n", NR, $0}' "$FILE_PROVIDER"
echo
echo "== BitMap.razor.cs OnProviderSet() (around method) =="
LINE2=$(rg -n "OnProviderSet\\(" "$FILE_RAZOR" | head -n 1 | cut -d: -f1)
START2=$((LINE2-60))
END2=$((LINE2+140))
awk -v s="$START2" -v e="$END2" 'NR>=s && NR<=e {printf "%6d\t%s\n", NR, $0}' "$FILE_RAZOR"Repository: bitfoundation/bitplatform
Length of output: 19090
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE_TS="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts"
# show start area and BitMapCesium.init / viewerOptions construction
awk 'NR<=140 {printf "%6d\t%s\n", NR, $0}' "$FILE_TS" | sed -n '1,140p'Repository: bitfoundation/bitplatform
Length of output: 7572
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate BitMapSync definition / interop wiring in JS/TS
fd -a "BitMap.*(sync|Sync).*\\.(ts|js)$" . | head -n 50 || true
rg -n "BitMapSync\\b" src -S || true
rg -n "function BitMapSync|BitMapSync\\s*=" src -S || true
rg -n "BitMapCesium\\.sync\\b|\\.sync\\(id: string, options: any\\)" src -S || true
# If there's a central interop file, print likely match region
FILE=$(rg -n "BitMapSync\\b" src -S --files-with-matches | head -n 1 || true)
if [[ -n "${FILE}" ]]; then
echo "== showing ${FILE} around BitMapSync =="
rg -n "BitMapSync\\b" -n "${FILE}" -S
# print a small window around first occurrence
LINE=$(rg -n "BitMapSync\\b" "${FILE}" -S | head -n 1 | cut -d: -f1)
START=$((LINE-40)); END=$((LINE+80))
sed -n "${START},${END}p" "${FILE}"
fiRepository: bitfoundation/bitplatform
Length of output: 2474
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE_TS="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts"
FILE_CSPROV="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMap.razor.cs"
FILE_EXT="src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/BitMapJsRuntimeExtensions.cs"
echo "== BitMapCesium.ts: full sync() method =="
LINE=$(rg -n "public static sync\\(id: string, options: any\\)" "$FILE_TS" | head -n1 | cut -d: -f1)
START=$LINE
END=$((LINE+60))
awk -v s="$START" -v e="$END" 'NR>=s && NR<=e {print NR "\t" $0}' "$FILE_TS"
echo
echo "== BitMapJsRuntimeExtensions.cs: BitMapSync =="
awk 'NR>=1 && NR<=140 {print NR "\t" $0}' "$FILE_EXT"
echo
echo "== BitMap.razor.cs: OnProviderSet sync call =="
LINE2=$(rg -n "await _js\\.BitMapSync\\(" "$FILE_CSPROV" | head -n1 | cut -d: -f1)
START2=$((LINE2-30)); if (( START2 < 1 )); then START2=1; fi
END2=$((LINE2+20))
awk -v s="$START2" -v e="$END2" 'NR>=s && NR<=e {print NR "\t" $0}' "$FILE_CSPROV"
echo
echo "== JS/TS-side: where BitMapSync dispatches to provider sync =="
# Look for the JS entry point named "BitMapSync" and provider sync usage.
rg -n "BitMapSync\\b" . -S --glob='*.js' --glob='*.ts' --glob='*.mjs' --glob='*.cjs' || true
rg -n "BitMapCesium\\.sync\\b" . -S --glob='*.js' --glob='*.ts' --glob='*.mjs' --glob='*.cjs' || trueRepository: bitfoundation/bitplatform
Length of output: 12255
Fix Cesium option updates on same-provider sync (currently camera-only)
BitCesiumMapProvider.BuildOptionsPayload() sends imageryStyle, terrainEnabled, sceneMode, shadowsEnabled, and widget flags, but BitMapCesium.sync() (119-153) only computes center/altitude/zoom and calls viewer.camera.flyTo(). With the same JsObjectName, BitMap.razor.cs routes updates through BitMapSync (which calls BitMapCesium.sync), so changes to those Cesium options become a no-op.
Cesium’s Viewer supports runtime updates for imagery layers/base imagery, terrain provider, scene.mode/morph, and shadowMap.enabled, so this should be mirrored in sync() (or the component should re-init when these settings change).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`
around lines 119 - 153, BitMapCesium.sync currently only updates camera
position; extend it to apply the other Cesium options sent by
BuildOptionsPayload: read o.imageryStyle, o.terrainEnabled, o.sceneMode,
o.shadowsEnabled and any widget flags and apply them to the existing viewer
instance (BitMapCesium._maps[id].viewer) at runtime instead of ignoring them.
Specifically: update imagery by switching/modifying the base imagery layer or
its provider according to o.imageryStyle, enable/disable terrain by setting
viewer.terrainProvider (or replacing it with a null/ellipsoid terrain) based on
o.terrainEnabled, change scene mode/morph using viewer.scene.mode or
scene.morphTo for o.sceneMode, toggle shadows via viewer.shadows or
viewer.scene.shadowMap.enabled from o.shadowsEnabled, and show/hide UI widgets
using the same viewer widget references used elsewhere in BitMapCesium. Keep
camera updates (fromDegrees/flyTo) but add these runtime updates before or after
the flyTo call so the provider-level options take effect when sync is called
with the same JsObjectName.
| private static _notifyView(s: any) { | ||
| if (!s.dotnetObj) return; | ||
| queueMicrotask(() => s.dotnetObj.invokeMethodAsync('OnViewChanged', BitMapCesium._readView(s))); | ||
| } |
There was a problem hiding this comment.
Don't defer _readView against a viewer that may already be destroyed.
dispose() nulls dotnetObj and destroys viewer, but this callback reads both inside a queued microtask. A pending move-end can therefore fail during teardown even after the map has been disposed.
🛠️ Minimal hardening
private static _notifyView(s: any) {
- if (!s.dotnetObj) return;
- queueMicrotask(() => s.dotnetObj.invokeMethodAsync('OnViewChanged', BitMapCesium._readView(s)));
+ const dn = s.dotnetObj;
+ if (!dn) return;
+ const payload = BitMapCesium._readView(s);
+ queueMicrotask(() => { void dn.invokeMethodAsync('OnViewChanged', payload).catch(() => {}); });
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapCesium.ts`
around lines 504 - 507, The callback BitMapCesium._notifyView defers calling
BitMapCesium._readView inside queueMicrotask but only checks s.dotnetObj up
front, so the viewer may have been destroyed by dispose() before the microtask
runs; fix by either capturing the view snapshot synchronously (call _readView
immediately into a local variable and pass that into the microtask) or by
re-checking both s.dotnetObj and s.viewer inside the microtask before calling
_readView, ensuring you never access viewer after dispose(); reference
BitMapCesium._notifyView, BitMapCesium._readView, and the s.dotnetObj/s.viewer
fields when making the change.
| const layer = L.geoJSON(gj, { | ||
| style: () => BitMapLeaflet._pathStyle(style), | ||
| onEachFeature(feature: any, lyr: any) { | ||
| if (dn) { | ||
| lyr.on('click', (e: any) => { | ||
| L.DomEvent.stopPropagation(e); | ||
| dn.invokeMethodAsync('OnGeoJsonFeatureClick', layerId, feature?.properties || {}); | ||
| }); | ||
| } | ||
| }, | ||
| }).addTo(s.map); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Leaflet 1.9.4, does the styleoption passed toL.geoJSON(...)apply toPointandMultiPointfeatures, or ispointToLayer required to style them?
💡 Result:
Leaflet 1.9.4: the style option passed to L.geoJSON(...) can apply to GeoJSON Point and MultiPoint features, but only when those points are created as vector layers that support path styling (e.g., L.CircleMarker). If you use the default Point handling (simple L.Marker), style won’t affect marker appearance and you must use pointToLayer to create a styled marker type. Evidence: Leaflet’s GeoJSON example explains that Points are handled differently from polylines/polygons, and that the default is “simple markers.” It also notes you can change point rendering by providing pointToLayer. In the same example, Leaflet states that you can “also set the style property” because “Leaflet is smart enough to apply styles to GeoJSON points” if you create the point as a vector layer inside pointToLayer (e.g., a circle). [1]
Citations:
Fix Leaflet GeoJSON Point/MultiPoint styling (missing pointToLayer)
The current L.geoJSON call only provides style and omits pointToLayer, so Leaflet falls back to its default “simple marker” rendering for GeoJSON Point/MultiPoint, which won’t apply BitMapLeaflet._pathStyle(style) consistently.
const layer = L.geoJSON(gj, {
style: () => BitMapLeaflet._pathStyle(style),
onEachFeature(feature: any, lyr: any) {
if (dn) {
lyr.on('click', (e: any) => {
L.DomEvent.stopPropagation(e);
dn.invokeMethodAsync('OnGeoJsonFeatureClick', layerId, feature?.properties || {});
});
}
},
}).addTo(s.map);Add a pointToLayer callback that returns a vector layer (e.g., L.circleMarker(latlng, BitMapLeaflet._pathStyle(style))) so point features honor the supplied style like the other providers in this PR.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapLeaflet.ts`
around lines 385 - 395, L.geoJSON usage in BitMapLeaflet is missing a
pointToLayer handler, so Point/MultiPoint features render as default markers and
ignore BitMapLeaflet._pathStyle(style); update the L.geoJSON options to include
a pointToLayer function that creates vector markers (e.g., use L.circleMarker
with BitMapLeaflet._pathStyle(style)) so point features use the same styling as
other geometries; keep the existing style and onEachFeature (with dn and
layerId) unchanged and ensure pointToLayer receives latlng and returns the
styled layer.
| private static readonly _defaultTileUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; | ||
|
|
||
| private static _resolveTileUrl(o: any): string { | ||
| return (o.tileUrl || BitMapOpenLayers._defaultTileUrl).replace('{s}', 'a'); |
There was a problem hiding this comment.
Mirror the OSM attribution fallback here as well.
This provider defaults to the built-in OSM tile URL, but tileAttribution still falls back to '', so the default map renders with no attribution and partial syncs preserve that empty value. BitMapLeaflet already special-cases the same built-in URL in this PR; OpenLayers should apply the same URL-keyed fallback in both init and sync so provider behavior stays consistent.
Also applies to: 37-40, 176-180
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/Map/Providers/BitMapOpenLayers.ts`
around lines 24 - 27, The tile attribution fallback is missing for the built-in
OSM tiles: when BitMapOpenLayers._defaultTileUrl (and values returned by
BitMapOpenLayers._resolveTileUrl) is used but tileAttribution is empty, set
tileAttribution to the OSM attribution string (same logic as BitMapLeaflet).
Update the initialization path in BitMapOpenLayers.init and the update path in
BitMapOpenLayers.sync (and any nearby defaulting code around the _resolveTileUrl
usage at lines referenced) to check if tileAttribution is falsy AND the resolved
tileUrl equals BitMapOpenLayers._defaultTileUrl, then assign the OSM attribution
fallback.
| p.catch((err) => { | ||
| if (globalThis.__bitMapOlBundle === p) delete globalThis.__bitMapOlBundle; | ||
| throw err; | ||
| }); |
There was a problem hiding this comment.
Avoid rethrowing inside the fire-and-forget cleanup catch.
The throw err here can create an additional unhandled rejection from the catch chain, while callers still observe rejection from p itself. Keep this handler cleanup-only.
🔧 Proposed fix
p.catch((err) => {
if (globalThis.__bitMapOlBundle === p) delete globalThis.__bitMapOlBundle;
- throw err;
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| p.catch((err) => { | |
| if (globalThis.__bitMapOlBundle === p) delete globalThis.__bitMapOlBundle; | |
| throw err; | |
| }); | |
| p.catch((err) => { | |
| if (globalThis.__bitMapOlBundle === p) delete globalThis.__bitMapOlBundle; | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/wwwroot/openlayers/bit-map-ol-loader.js`
around lines 57 - 60, The catch attached to the promise `p` is doing cleanup but
rethrows the error (`throw err`), which can produce an extra unhandled
rejection; update the handler attached via `p.catch(...)` (the block referencing
`globalThis.__bitMapOlBundle` and `p`) to perform only the cleanup (delete
`globalThis.__bitMapOlBundle === p`) and do not rethrow the error or return a
rejected promise so the original promise `p` remains the single source of
rejection.
| new() { Name = "TMapProvider", Type = "Type (generic)", DefaultValue = "", Description = "The map provider type. One of: BitLeafletMapProvider, BitMapLibreMapProvider, BitMapboxMapProvider, BitOpenLayersMapProvider, BitArcGisMapProvider, BitAzureMapsMapProvider, BitCesiumMapProvider." }, | ||
| new() { Name = "Provider", Type = "TMapProvider?", DefaultValue = "null", Description = "Provider configuration instance (center, zoom, tokens, etc.). When null a default instance is created." }, | ||
| new() { Name = "ChildContent", Type = "RenderFragment?", DefaultValue = "null", Description = "Optional content rendered above the map canvas." }, | ||
| new() { Name = "OnReady", Type = "EventCallback", DefaultValue = "", Description = "Fires once after the map is ready for imperative calls." }, |
There was a problem hiding this comment.
Update the OnReady docs to match the component contract.
The component now raises OnReady again after a destructive provider swap, but this metadata still says it fires only once.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/Map/BitMapDemo.razor.cs`
at line 10, The Description for the OnReady metadata is inaccurate: update the
entry for the OnReady event (new() { Name = "OnReady", Type = "EventCallback",
... }) so it reflects the component contract that OnReady fires not only once
initially but also fires again after a destructive provider swap (i.e., whenever
the map becomes ready following a provider replacement). Modify the Description
text to mention both the initial ready event and subsequent ready events after
provider swaps so it matches the component behavior.
closes #10110
Summary by CodeRabbit
New Features
Documentation / Demos
Style
Tests
Chores