Skip to content

Commit 76fcd11

Browse files
committed
RE1-T114 Mapbox update, react change, call file and image fix
1 parent d1a991b commit 76fcd11

94 files changed

Lines changed: 5478 additions & 182063 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,4 @@ Web/Resgrid.WebCore/wwwroot/lib/*
274274
.dual-graph/
275275
.claude/settings.local.json
276276
.claude/settings.local.json
277+
/Web/Resgrid.Web/wwwroot/js/ng/chunks

Core/Resgrid.Config/MappingConfig.cs

Lines changed: 244 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
namespace Resgrid.Config
1+
using System;
2+
3+
namespace Resgrid.Config
24
{
35
public static class MappingConfig
46
{
7+
public const string LeafletMapProvider = "leaflet";
8+
public const string MapboxMapProvider = "mapbox";
9+
510
public static int PersonnelLocationStaleSeconds = 30;
611
public static int UnitLocationStaleSeconds = 30;
712
public static int PersonnelLocationMinMeters = 20;
@@ -53,64 +58,279 @@ public static class MappingConfig
5358
public static string BigBoardOSMKey = "";
5459

5560
public static string DispatchAppMapboxKey = "";
61+
public static string WebsiteMapboxKey = "";
62+
public static string WebsiteMapboxAccessToken = "";
63+
public static string WebsiteMapMode = LeafletMapProvider;
5664

5765
public static string LeafletTileUrl = "https://api.maptiler.com/maps/streets/{{z}}/{{x}}/{{y}}.png?key={0}";
5866
public static string MapBoxTileUrl = "";
67+
public static string MapBoxStyleUrl = "";
5968

6069
public static string LeafletAttribution = "© OpenStreetMap contributors CC-BY-SA";
70+
public static string MapBoxAttribution = "© Mapbox © OpenStreetMap contributors";
6171

6272
/***********************************
6373
* Geocoding and Routing Service URLs
6474
***********************************/
6575
public static string NominatimUrl = "https://nominatim.openstreetmap.org";
6676
public static string OsrmUrl = "https://router.project-osrm.org";
6777

78+
public static ResolvedMapConfig GetMapConfig(string key)
79+
{
80+
var surfaceKey = string.IsNullOrWhiteSpace(key) ? InfoConfig.WebsiteKey : key;
81+
var mapProvider = GetPreferredMapProvider(surfaceKey);
82+
83+
if (mapProvider == MapboxMapProvider)
84+
{
85+
var mapboxAccessToken = GetSystemMapboxAccessToken(surfaceKey);
86+
87+
if (TryCreateMapboxConfig(MapBoxStyleUrl, mapboxAccessToken, false, out var mapboxConfig))
88+
return mapboxConfig;
89+
90+
if (!string.IsNullOrWhiteSpace(mapboxAccessToken) && !string.IsNullOrWhiteSpace(MapBoxTileUrl))
91+
{
92+
return new ResolvedMapConfig
93+
{
94+
MapProvider = MapboxMapProvider,
95+
TileUrl = ReplaceTileKey(MapBoxTileUrl, mapboxAccessToken),
96+
StyleUrl = MapBoxStyleUrl,
97+
AccessToken = mapboxAccessToken,
98+
Attribution = MapBoxAttribution,
99+
IsDepartmentOverride = false
100+
};
101+
}
102+
}
103+
104+
return new ResolvedMapConfig
105+
{
106+
MapProvider = LeafletMapProvider,
107+
TileUrl = GetLegacyLeafletUrl(surfaceKey),
108+
StyleUrl = string.Empty,
109+
AccessToken = string.Empty,
110+
Attribution = LeafletAttribution,
111+
IsDepartmentOverride = false
112+
};
113+
}
114+
115+
public static bool TryCreateMapboxConfig(string styleUrl, string accessToken, bool isDepartmentOverride, out ResolvedMapConfig mapConfig)
116+
{
117+
mapConfig = null;
118+
119+
if (string.IsNullOrWhiteSpace(styleUrl) || string.IsNullOrWhiteSpace(accessToken))
120+
return false;
121+
122+
var styleId = GetMapboxStyleId(styleUrl);
123+
124+
if (string.IsNullOrWhiteSpace(styleId))
125+
return false;
126+
127+
mapConfig = new ResolvedMapConfig
128+
{
129+
MapProvider = MapboxMapProvider,
130+
TileUrl = $"https://api.mapbox.com/styles/v1/{styleId}/tiles/256/{{z}}/{{x}}/{{y}}@2x?access_token={accessToken}",
131+
StyleUrl = NormalizeMapboxStyleUrl(styleUrl, styleId),
132+
AccessToken = accessToken,
133+
Attribution = MapBoxAttribution,
134+
IsDepartmentOverride = isDepartmentOverride
135+
};
136+
137+
return true;
138+
}
139+
140+
public static bool IsSupportedMapboxStyleUrl(string styleUrl)
141+
{
142+
return !string.IsNullOrWhiteSpace(GetMapboxStyleId(styleUrl));
143+
}
144+
68145
public static string GetWebsiteOSMUrl()
69146
{
70-
if (!string.IsNullOrWhiteSpace(WebsiteOSMKey))
71-
return string.Format(MapBoxTileUrl, WebsiteOSMKey);
72-
else
73-
return LeafletTileUrl;
147+
return GetMapConfig(InfoConfig.WebsiteKey).TileUrl;
74148
}
75149

76150
public static string GetApiOSMUrl()
77151
{
78-
if (!string.IsNullOrWhiteSpace(ApiOSMKey))
79-
return string.Format(LeafletTileUrl, ApiOSMKey);
80-
else
81-
return LeafletTileUrl;
152+
return GetMapConfig(InfoConfig.ApiKey).TileUrl;
82153
}
83154

84155
public static string GetResponderAppOSMUrl()
85156
{
86-
if (!string.IsNullOrWhiteSpace(ResponderAppOSMKey))
87-
return string.Format(LeafletTileUrl, ResponderAppOSMKey);
88-
else
89-
return LeafletTileUrl;
157+
return GetMapConfig(InfoConfig.ResponderAppKey).TileUrl;
90158
}
91159

92160
public static string GetUnitAppOSMUrl()
93161
{
94-
if (!string.IsNullOrWhiteSpace(UnitAppOSMKey))
95-
return string.Format(LeafletTileUrl, UnitAppOSMKey);
96-
else
97-
return LeafletTileUrl;
162+
return GetMapConfig(InfoConfig.UnitAppKey).TileUrl;
98163
}
99164

100165
public static string GetBigBoardAppOSMUrl()
101166
{
102-
if (!string.IsNullOrWhiteSpace(BigBoardOSMKey))
103-
return string.Format(LeafletTileUrl, BigBoardOSMKey);
104-
else
105-
return LeafletTileUrl;
167+
return GetMapConfig(InfoConfig.BigBoardKey).TileUrl;
106168
}
107169

108170
public static string GetDispatchAppOSMUrl()
109171
{
110-
if (!string.IsNullOrWhiteSpace(DispatchAppMapboxKey))
111-
return string.Format(MapBoxTileUrl, DispatchAppMapboxKey);
112-
else
172+
return GetMapConfig(InfoConfig.DispatchAppKey).TileUrl;
173+
}
174+
175+
private static string GetLegacyLeafletUrl(string key)
176+
{
177+
if (key == InfoConfig.WebsiteKey)
178+
{
179+
if (!string.IsNullOrWhiteSpace(WebsiteOSMKey))
180+
return ReplaceTileKey(LeafletTileUrl, WebsiteOSMKey);
181+
182+
return LeafletTileUrl;
183+
}
184+
185+
if (key == InfoConfig.ApiKey)
186+
{
187+
if (!string.IsNullOrWhiteSpace(ApiOSMKey))
188+
return ReplaceTileKey(LeafletTileUrl, ApiOSMKey);
189+
190+
return LeafletTileUrl;
191+
}
192+
193+
if (key == InfoConfig.ResponderAppKey)
194+
{
195+
if (!string.IsNullOrWhiteSpace(ResponderAppOSMKey))
196+
return ReplaceTileKey(LeafletTileUrl, ResponderAppOSMKey);
197+
198+
return LeafletTileUrl;
199+
}
200+
201+
if (key == InfoConfig.UnitAppKey)
202+
{
203+
if (!string.IsNullOrWhiteSpace(UnitAppOSMKey))
204+
return ReplaceTileKey(LeafletTileUrl, UnitAppOSMKey);
205+
206+
return LeafletTileUrl;
207+
}
208+
209+
if (key == InfoConfig.BigBoardKey)
210+
{
211+
if (!string.IsNullOrWhiteSpace(BigBoardOSMKey))
212+
return ReplaceTileKey(LeafletTileUrl, BigBoardOSMKey);
213+
214+
return LeafletTileUrl;
215+
}
216+
217+
if (key == InfoConfig.DispatchAppKey)
218+
{
219+
if (!string.IsNullOrWhiteSpace(DispatchAppOSMKey))
220+
return ReplaceTileKey(LeafletTileUrl, DispatchAppOSMKey);
221+
113222
return LeafletTileUrl;
223+
}
224+
225+
return LeafletTileUrl;
226+
}
227+
228+
private static string GetPreferredMapProvider(string key)
229+
{
230+
if (key == InfoConfig.WebsiteKey)
231+
return NormalizeMapProvider(WebsiteMapMode);
232+
233+
if (key == InfoConfig.DispatchAppKey && !string.IsNullOrWhiteSpace(DispatchAppMapboxKey))
234+
return MapboxMapProvider;
235+
236+
if (key == InfoConfig.UnitAppKey && !string.IsNullOrWhiteSpace(UnitAppMapBoxKey))
237+
return MapboxMapProvider;
238+
239+
return LeafletMapProvider;
240+
}
241+
242+
private static string GetSystemMapboxAccessToken(string key)
243+
{
244+
if (key == InfoConfig.WebsiteKey)
245+
{
246+
if (!string.IsNullOrWhiteSpace(WebsiteMapboxAccessToken))
247+
return WebsiteMapboxAccessToken;
248+
249+
if (!string.IsNullOrWhiteSpace(WebsiteMapboxKey))
250+
return WebsiteMapboxKey;
251+
252+
return WebsiteOSMKey;
253+
}
254+
255+
if (key == InfoConfig.DispatchAppKey)
256+
return DispatchAppMapboxKey;
257+
258+
if (key == InfoConfig.UnitAppKey)
259+
return UnitAppMapBoxKey;
260+
261+
return string.Empty;
262+
}
263+
264+
private static string NormalizeMapProvider(string provider)
265+
{
266+
if (string.IsNullOrWhiteSpace(provider))
267+
return LeafletMapProvider;
268+
269+
return provider.Trim().Equals(MapboxMapProvider, StringComparison.InvariantCultureIgnoreCase)
270+
? MapboxMapProvider
271+
: LeafletMapProvider;
272+
}
273+
274+
private static string ReplaceTileKey(string tileUrl, string key)
275+
{
276+
if (string.IsNullOrWhiteSpace(tileUrl))
277+
return tileUrl;
278+
279+
var normalizedTileUrl = tileUrl
280+
.Replace("{{", "{", StringComparison.InvariantCulture)
281+
.Replace("}}", "}", StringComparison.InvariantCulture);
282+
283+
if (string.IsNullOrWhiteSpace(key))
284+
return normalizedTileUrl;
285+
286+
return normalizedTileUrl.Replace("{0}", key, StringComparison.InvariantCulture);
287+
}
288+
289+
private static string NormalizeMapboxStyleUrl(string styleUrl, string styleId)
290+
{
291+
if (styleUrl.StartsWith("mapbox://styles/", StringComparison.InvariantCultureIgnoreCase))
292+
return styleUrl;
293+
294+
return $"mapbox://styles/{styleId}";
295+
}
296+
297+
private static string GetMapboxStyleId(string styleUrl)
298+
{
299+
if (string.IsNullOrWhiteSpace(styleUrl))
300+
return null;
301+
302+
var trimmedStyleUrl = styleUrl.Trim();
303+
304+
if (trimmedStyleUrl.StartsWith("mapbox://styles/", StringComparison.InvariantCultureIgnoreCase))
305+
return ExtractMapboxStyleId(trimmedStyleUrl.Substring("mapbox://styles/".Length));
306+
307+
if (Uri.TryCreate(trimmedStyleUrl, UriKind.Absolute, out var mapboxStyleUri))
308+
{
309+
var path = mapboxStyleUri.AbsolutePath.Trim('/');
310+
var stylesIndex = path.IndexOf("styles/v1/", StringComparison.InvariantCultureIgnoreCase);
311+
312+
if (stylesIndex >= 0)
313+
{
314+
var stylePath = path.Substring(stylesIndex + "styles/v1/".Length);
315+
return ExtractMapboxStyleId(stylePath);
316+
}
317+
}
318+
319+
return null;
320+
}
321+
322+
private static string ExtractMapboxStyleId(string stylePath)
323+
{
324+
if (string.IsNullOrWhiteSpace(stylePath))
325+
return null;
326+
327+
var normalizedPath = stylePath.Trim('/');
328+
var pathSegments = normalizedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
329+
330+
if (pathSegments.Length < 2)
331+
return null;
332+
333+
return $"{pathSegments[0]}/{pathSegments[1]}";
114334
}
115335
}
116336
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Resgrid.Config
2+
{
3+
public class ResolvedMapConfig
4+
{
5+
public string MapProvider { get; set; }
6+
7+
public string TileUrl { get; set; }
8+
9+
public string StyleUrl { get; set; }
10+
11+
public string AccessToken { get; set; }
12+
13+
public string Attribution { get; set; }
14+
15+
public bool IsDepartmentOverride { get; set; }
16+
}
17+
}

Core/Resgrid.Framework/FileHelper.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ namespace Resgrid.Framework
66
{
77
public static class FileHelper
88
{
9+
public static string GetFileExtensionWithoutDot(string fileName)
10+
{
11+
var extension = Path.GetExtension(fileName);
12+
13+
if (string.IsNullOrWhiteSpace(extension))
14+
return string.Empty;
15+
16+
return extension.TrimStart('.').ToLowerInvariant();
17+
}
18+
919
public static string GetContentTypeByExtension(string strExtension)
1020
{
1121
switch (strExtension)

Core/Resgrid.Model/DepartmentSettingTypes.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,8 @@ public enum DepartmentSettingTypes
4747
WeatherAlertCacheMinutes = 43,
4848
WeatherAlertAutoMessageSchedule = 44,
4949
WeatherAlertExcludedEvents = 45,
50+
MappingUseMapboxOverride = 46,
51+
MappingMapboxStyleUrl = 47,
52+
MappingMapboxAccessToken = 48,
5053
}
5154
}

Core/Resgrid.Model/Services/IDepartmentSettingsService.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Threading;
44
using System.Threading.Tasks;
5+
using Resgrid.Config;
56

67
namespace Resgrid.Model.Services
78
{
@@ -266,6 +267,14 @@ public interface IDepartmentSettingsService
266267

267268
Task<bool> GetMappingUnitAllowStatusWithNoLocationToOverwriteAsync(int departmentId);
268269

270+
Task<bool> GetMappingUseMapboxOverrideAsync(int departmentId);
271+
272+
Task<string> GetMappingMapboxStyleUrlAsync(int departmentId);
273+
274+
Task<string> GetMappingMapboxAccessTokenAsync(int departmentId);
275+
276+
Task<ResolvedMapConfig> GetMapConfigForDepartmentAsync(int departmentId, string key = null);
277+
269278
Task<DepartmentModuleSettings> GetDepartmentModuleSettingsAsync(int departmentId, bool bypassCache = false);
270279

271280
Task<bool> GetUnitDispatchAlsoDispatchToAssignedPersonnelAsync(int departmentId);

0 commit comments

Comments
 (0)