Conversation
|
Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details? |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 1 minutes and 14 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (36)
📝 WalkthroughWalkthroughThis PR introduces map configuration with per-department Mapbox overrides, adds personnel check-in timer functionality for dispatched calls, implements Twilio voice verification for contact verification, and migrates client-side apps from Angular to React using Vite, plus updates numerous Razor views to use department-specific map configuration. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes The PR spans multiple architectural layers (config, domain, services, repositories, controllers, views, client-side) with heterogeneous changes including new feature implementation (check-in timers, voice verification, map overrides), a complete client-side framework migration (Angular → React), and extensive view updates. While individual components follow established patterns, the breadth, depth, and diversity of changes across the codebase require careful multi-faceted review. Possibly related PRs
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 4
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
Web/Resgrid.Web/Areas/User/Controllers/DispatchController.cs (1)
2488-2490:⚠️ Potential issue | 🟠 MajorMissing authorization on
AttachCallFile.Unlike the sibling flag/update endpoints, this POST has no
[Authorize(Policy = ResgridResources.Call_Update)]and no_authorizationService.CanUserEditCallAsync(UserId, model.CallId)check before writing the attachment. Any authenticated user can attach a file to any call whose id they know (andDepartmentIdisn't validated either). Pre-existing, but worth fixing while in the area.🛡️ Suggested guard
[HttpPost] +[Authorize(Policy = ResgridResources.Call_Update)] public async Task<IActionResult> AttachCallFile(FileAttachInput model, IFormFile fileToUpload, CancellationToken cancellationToken) { + if (!await _authorizationService.CanUserEditCallAsync(UserId, model.CallId)) + return Unauthorized(); + if (fileToUpload == null || fileToUpload.Length <= 0)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/DispatchController.cs` around lines 2488 - 2490, The POST action AttachCallFile lacks authorization checks and allows any authenticated user to attach files to arbitrary calls; add the [Authorize(Policy = ResgridResources.Call_Update)] attribute to AttachCallFile and, inside the method, call _authorizationService.CanUserEditCallAsync(UserId, model.CallId) (or equivalent) and return Forbid/Unauthorized if it fails, and additionally validate that model.DepartmentId matches the call's DepartmentId before proceeding to save the attachment to ensure the caller is permitted to modify that department's call.Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs (3)
782-782:⚠️ Potential issue | 🟡 MinorFix grammar in user-facing error message.
The message reads "must be smaller then 10MB" but should use "than" instead of "then".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs` at line 782, Update the user-facing error message passed to ModelState.AddModelError for "fileToUpload" to correct the grammar from "must be smaller then 10MB." to "must be smaller than 10MB." — locate the call to ModelState.AddModelError("fileToUpload", ...) in ProfileController (around the file upload/validation logic) and replace "then" with "than".
851-862: 🛠️ Refactor suggestion | 🟠 MajorExtract duplicated file validation logic into a shared method.
The file upload validation logic (lines 851-862) is duplicated from
AddCertification(lines 772-783). This violates the DRY principle and makes maintenance more difficult. Changes to validation rules must be synchronized across both methods.♻️ Proposed refactor to eliminate duplication
Extract the validation into a private method:
private void ValidateCertificationFile(IFormFile file, ModelStateDictionary modelState) { if (file == null || file.Length == 0) return; var extension = FileHelper.GetFileExtensionWithoutDot(file.FileName); var allowedExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "jpg", "jpeg", "png", "gif", "pdf", "doc", "docx", "ppt", "pptx", "pps", "ppsx", "odt", "xls", "xlsx", "txt" }; if (!allowedExtensions.Contains(extension)) modelState.AddModelError("fileToUpload", $"File type ({extension}) is not importable."); if (file.Length > 10_000_000) modelState.AddModelError("fileToUpload", "Document is too large, must be smaller than 10MB."); }Then in both methods:
- if (fileToUpload != null && fileToUpload.Length > 0) - { - var extenion = FileHelper.GetFileExtensionWithoutDot(fileToUpload.FileName); - - if (extenion != "jpg" && extenion != "jpeg" && extenion != "png" && extenion != "gif" && extenion != "gif" && extenion != "pdf" && extenion != "doc" - && extenion != "docx" && extenion != "ppt" && extenion != "pptx" && extenion != "pps" && extenion != "ppsx" && extenion != "odt" - && extenion != "xls" && extenion != "xlsx" && extenion != "txt") - ModelState.AddModelError("fileToUpload", string.Format("File type ({0}) is not importable.", extenion)); - - if (fileToUpload.Length > 10000000) - ModelState.AddModelError("fileToUpload", "Document is too large, must be smaller then 10MB."); - } + ValidateCertificationFile(fileToUpload, ModelState);Note: This also addresses the typo (
extenion), duplicate "gif" check, and grammar error ("then" → "than") mentioned in theAddCertificationreview.As per coding guidelines: "Design for testability; avoid hidden dependencies inside methods and prefer explicit, pure functions" and the principle of not repeating yourself (DRY).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs` around lines 851 - 862, The file upload validation block in ProfileController (duplicated between the current method and AddCertification) should be extracted to a single private helper to follow DRY and fix typos; create a private method (e.g., ValidateCertificationFile(IFormFile file, ModelStateDictionary modelState)) that returns early for null/zero-length, checks extension against a case-insensitive set of allowed extensions (remove duplicate "gif" and correct "extenion" to "extension"), and enforces the 10MB size limit with the corrected message ("smaller than 10MB"); then call ValidateCertificationFile(...) from both AddCertification and the current controller action, keeping ModelState error keys consistent ("fileToUpload").
774-779:⚠️ Potential issue | 🟠 MajorAdd explicit guard against null or empty file extensions.
FileHelper.GetFileExtensionWithoutDotreturnsstring.Emptyfor files without extensions but will throwArgumentNullExceptioniffileNameis null. Add an explicit null/empty check on the returned extension before the validation block:var extenion = FileHelper.GetFileExtensionWithoutDot(fileToUpload.FileName); if (string.IsNullOrEmpty(extenion) || (extenion != "jpg" && extenion != "jpeg" && extenion != "png" && extenion != "gif" && extenion != "pdf" && extenion != "doc" && extenion != "docx" && extenion != "ppt" && extenion != "pptx" && extenion != "pps" && extenion != "ppsx" && extenion != "odt" && extenion != "xls" && extenion != "xlsx" && extenion != "txt")) ModelState.AddModelError("fileToUpload", string.Format("File type ({0}) is not importable.", extenion ?? "unknown"));Additionally, this validation pattern is duplicated across multiple controllers (ProfileController, FilesController, DocumentsController, DispatchController, etc.) with varying allowed extensions. Consider extracting this into a reusable validation method or use a collection-based approach (e.g.,
!allowedExtensions.Contains(extension)) to reduce repetition and maintenance burden.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs` around lines 774 - 779, The file-extension validation in ProfileController uses FileHelper.GetFileExtensionWithoutDot (assigned to extenion) but lacks an explicit null/empty guard; update the validation so it first checks string.IsNullOrEmpty(extenion) and treats that as invalid (calling ModelState.AddModelError with a safe message, e.g., showing "unknown" if extension is null/empty), and replace the long chained != checks with a collection-based check like !allowedExtensions.Contains(extenion) for clarity; also extract this logic into a reusable helper/validator used by ProfileController, FilesController, DocumentsController, DispatchController, etc., to avoid duplication and ensure consistent allowed-extension lists.Core/Resgrid.Model/Services/IContactVerificationService.cs (1)
6-10:⚠️ Potential issue | 🟡 MinorStale interface-level XML doc — home is now voice, not SMS.
The summary still reads "email, mobile SMS, home SMS" even though this PR switches home verification to a Twilio voice call. Consider updating to match the per-method docs on line 28-31.
✏️ Proposed doc update
/// <summary> /// Service responsible for generating, sending, and confirming contact-method - /// verification codes (email, mobile SMS, home SMS). Enforces configurable - /// expiry, daily attempt caps, and hourly send rate limits. + /// verification codes (email, mobile SMS, home voice call). Enforces configurable + /// expiry, daily attempt caps, and hourly send rate limits. /// </summary>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Core/Resgrid.Model/Services/IContactVerificationService.cs` around lines 6 - 10, Update the stale XML summary on the IContactVerificationService interface to reflect that verification supports email, mobile SMS, and home voice calls (Twilio) instead of "home SMS"; edit the interface-level <summary> text in IContactVerificationService to match the per-method descriptions (email, mobile SMS, home voice) so documentation is accurate and consistent with the voice-call implementation.Core/Resgrid.Services/ContactVerificationService.cs (1)
108-120:⚠️ Potential issue | 🔴 CriticalAdd [ValidateTwilioRequest] to VoiceVerification endpoint.
The
VoiceVerificationendpoint correctly retrieves and decrypts the stored code from the profile, so the design is sound. However, the endpoint has no Twilio signature validation. Line 630 shows only[HttpGet("VoiceVerification")]with no[ValidateTwilioRequest]attribute, despiteTwilio.AspNet.Commonbeing imported and available. This allows any unauthenticated HTTP request to call the endpoint with arbitraryuserIdandcontactTypeparameters, retrieve the encrypted code from the database, and expose it in the TwiML response. Apply the[ValidateTwilioRequest]filter to cryptographically validate that requests originate from Twilio, mirroring the security used for other Twilio callbacks.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Core/Resgrid.Services/ContactVerificationService.cs` around lines 108 - 120, The VoiceVerification endpoint lacks Twilio signature validation—add the [ValidateTwilioRequest] attribute to the VoiceVerification action (the method currently annotated with [HttpGet("VoiceVerification")]) so incoming callbacks are cryptographically validated as originating from Twilio; ensure the project imports/uses Twilio.AspNet.Common and apply the attribute to the same method that reads/decrypts the profile verification code so it mirrors other Twilio callbacks' protection.Web/Resgrid.Web/Areas/User/Views/Mapping/NewLayer.cshtml (1)
168-177:⚠️ Potential issue | 🟠 MajorHTML-encoded tile URL / attribution in JS literals, plus duplicate helper calls.
Two issues here:
- Encoding bug.
@SettingsHelper.GetDepartmentMapConfig(...).TileUrland.Attributionare HTML-encoded by Razor before being placed inside single-quoted JS strings. Tile URLs with&become&(breaks tile fetches for Mapbox-style URLs), and the typical Leaflet attribution HTML (© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>) will be rendered as literal escaped markup in the attribution control instead of a working link. A value containing'would also break the script.- Duplicate resolution.
GetDepartmentMapConfigis invoked twice on this page (and twice more inEditLayer.cshtml). Other views in this PR cache the result into amapConfigRazor local — please follow the same pattern here for consistency and to avoid doing the lookup work twice per render.🔧 Suggested fix
@{ ViewBag.Title = "Resgrid | " + localizer["NewLayerPageTitle"]; + var mapConfig = SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey); } @@ const tiles1 = L.tileLayer( - '@SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey).TileUrl', + `@Html.Raw`(Json.Serialize(mapConfig.TileUrl)), { maxZoom: 19, attribution: - '@SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey).Attribution', + `@Html.Raw`(Json.Serialize(mapConfig.Attribution)), } );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Mapping/NewLayer.cshtml` around lines 168 - 177, Call SettingsHelper.GetDepartmentMapConfig once and store it in a Razor local (e.g., mapConfig) instead of calling it twice; then render the tile URL into the JS safely by serializing it into a JS string (use Json.Encode(mapConfig.TileUrl) so quotes and ampersands are escaped correctly) and render the attribution as unencoded HTML for Leaflet (use Html.Raw(mapConfig.Attribution)) so links are not HTML-escaped; update the L.tileLayer/tiles1 and map initialization (tiles1, mapContainer) to use these two prepared values.Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs (1)
1958-1994:⚠️ Potential issue | 🟠 MajorValidate token shape and bound input sizes.
Two small hardening gaps in the Mapbox override path:
- The access token is accepted as-is. Mapbox distinguishes public (
pk.*) vs secret (sk.*) tokens; saving a secret token here would ship it to every client rendering a map. Since the UI labels this field "Mapbox Public Access Token", explicitly reject non-pk.values.- No max-length check on
MapboxStyleUrl/MapboxAccessToken— consider adding[StringLength]on the view-model or bounding here before persisting to avoid oversized settings.🛡️ Suggested validation
if (String.IsNullOrWhiteSpace(model.MapboxAccessToken)) ModelState.AddModelError(nameof(model.MapboxAccessToken), "A Mapbox public access token is required when the department override is enabled for website and mobile map rendering."); + + if (!String.IsNullOrWhiteSpace(model.MapboxAccessToken) + && !model.MapboxAccessToken.Trim().StartsWith("pk.", StringComparison.Ordinal)) + ModelState.AddModelError(nameof(model.MapboxAccessToken), "Only Mapbox public access tokens (pk.*) are allowed; secret tokens (sk.*) must not be used.");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs` around lines 1958 - 1994, When handling model.UseMapboxOverride, validate MapboxAccessToken and MapboxStyleUrl more strictly: ensure MapboxAccessToken (model.MapboxAccessToken) is non-empty and begins with the public prefix "pk." (reject values starting with "sk." or anything not prefixed with "pk.") and add max-length checks for both MapboxAccessToken and MapboxStyleUrl (e.g., enforce a reasonable limit such as 255 chars) before calling _departmentSettingsService.SaveOrUpdateSettingAsync; if validations fail, call ModelState.AddModelError for the relevant field names so code does not reach SaveOrUpdateSettingAsync/DeleteSettingAsync for MappingMapboxStyleUrl or MappingMapboxAccessToken or persist oversized/secret tokens.
♻️ Duplicate comments (4)
Web/Resgrid.Web/Areas/User/Views/Mapping/LiveRouting.cshtml (1)
63-64:⚠️ Potential issue | 🟠 MajorSame HTML-encoding hazard; corrupts
L.tileLayerURL and attribution.These values are consumed directly by
L.tileLayer(osmTileUrl, { ..., attribution: osmTileAttribution })below, so any&in the tile URL or HTML in the attribution will be broken by Razor's HTML encoding. Same fix as the other map views:🔧 Suggested fix
- var osmTileUrl = '@mapConfig.TileUrl'; - var osmTileAttribution = '@mapConfig.Attribution'; + var osmTileUrl = `@Html.Raw`(Json.Serialize(mapConfig.TileUrl)); + var osmTileAttribution = `@Html.Raw`(Json.Serialize(mapConfig.Attribution));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Mapping/LiveRouting.cshtml` around lines 63 - 64, The osmTileUrl and osmTileAttribution Razor interpolations are being HTML-encoded which corrupts values passed into L.tileLayer; replace the plain '@mapConfig.TileUrl' and '@mapConfig.Attribution' injections with properly JSON-encoded/raw output so JavaScript receives correct strings (e.g. emit mapConfig.TileUrl and mapConfig.Attribution via Json.Encode and Html.Raw) and then pass those variables into L.tileLayer(osmTileUrl, { attribution: osmTileAttribution }) to avoid HTML-encoding issues.Web/Resgrid.Web/Areas/User/Views/Mapping/EditLayer.cshtml (1)
170-177:⚠️ Potential issue | 🟠 MajorHTML-encoded tile URL / attribution plus duplicate helper calls (see
NewLayer.cshtmlcomment).Razor
@HTML-encodes the interpolated values:&in the tile URL becomes&(breaks Mapbox-style tile fetches), and the attribution's<a>markup ends up rendered as literal escaped text in Leaflet's attribution control. Additionally,GetDepartmentMapConfigis invoked twice — the other updated views in this PR cache it into amapConfiglocal; please mirror that.🔧 Suggested fix
@{ ViewBag.Title = "Resgrid | " + localizer["EditLayerPageTitle"]; + var mapConfig = SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey); } @@ const tiles1 = L.tileLayer( - '@SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey).TileUrl', + `@Html.Raw`(Json.Serialize(mapConfig.TileUrl)), { maxZoom: 19, attribution: - '@SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey).Attribution', + `@Html.Raw`(Json.Serialize(mapConfig.Attribution)), } );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Mapping/EditLayer.cshtml` around lines 170 - 177, The tile URL and attribution are being HTML-encoded and GetDepartmentMapConfig is called twice; fix by caching SettingsHelper.GetDepartmentMapConfig(Resgrid.Config.InfoConfig.WebsiteKey) into a local mapConfig variable (as done in NewLayer.cshtml), then pass the raw/unencoded strings to Leaflet by using the unencoded values for L.tileLayer (e.g., use the mapConfig.TileUrl without Razor escaping) and for attribution use the unescaped HTML (e.g., mapConfig.Attribution rendered without HTML-encoding) so tiles1/L.tileLayer and its attribution receive the correct, unescaped strings.Web/Resgrid.Web/Areas/User/Views/Mapping/ViewType.cshtml (1)
125-126:⚠️ Potential issue | 🟠 MajorSame HTML-encoding hazard for tile URL and attribution.
See the consolidated note on the other map views — Razor HTML-encodes these values, which breaks URLs containing
&and corrupts attribution HTML. Use@Html.Raw(Json.Serialize(...))(without surrounding quotes) instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Mapping/ViewType.cshtml` around lines 125 - 126, Replace the Razor-encoded string assignments for osmTileUrl and osmTileAttribution so they are emitted as raw JSON (not HTML-encoded) by using Html.Raw(Json.Serialize(...)) instead of embedding '@mapConfig.TileUrl' and '@mapConfig.Attribution' in quotes; update the assignments that set osmTileUrl and osmTileAttribution to use Html.Raw(Json.Serialize(mapConfig.TileUrl)) and Html.Raw(Json.Serialize(mapConfig.Attribution)) respectively (without surrounding quotes) to avoid &-encoding and broken attribution HTML.Web/Resgrid.Web/Areas/User/Views/Dispatch/AddArchivedCall.cshtml (1)
411-412:⚠️ Potential issue | 🟠 MajorSame HTML-encoding hazard as other map views.
@mapConfig.TileUrl/@mapConfig.Attributionare HTML-encoded by Razor before being placed into single-quoted JS strings, corrupting&-containing tile URLs and attribution HTML. Suggested fix:🔧 Suggested fix
- var osmTileUrl = '@mapConfig.TileUrl'; - var osmTileAttribution = '@mapConfig.Attribution'; + var osmTileUrl = `@Html.Raw`(Json.Serialize(mapConfig.TileUrl)); + var osmTileAttribution = `@Html.Raw`(Json.Serialize(mapConfig.Attribution));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Dispatch/AddArchivedCall.cshtml` around lines 411 - 412, The Razor view is HTML-encoding mapConfig.TileUrl and mapConfig.Attribution before placing them into JS strings (osmTileUrl, osmTileAttribution), corrupting values with & and HTML; fix by emitting safe JSON/string literals instead of raw Razor-encoded text—replace the single-quoted '@mapConfig.TileUrl' and '@mapConfig.Attribution' usages with JSON-encoded/raw output (e.g., use Json.Encode wrapped with Html.Raw) so var osmTileUrl and var osmTileAttribution receive properly escaped JS string literals.
🟡 Minor comments (8)
.claude/settings.local.json-9-15 (1)
9-15:⚠️ Potential issue | 🟡 MinorMalformed allowlist entries likely won't match intended commands.
A few of these Bash allowlist patterns look broken and will never match the commands you actually run:
- Line 9:
\\\\\\(-name *mobile*— missing a space between\(and-name. The shell tokenizer will see\(-nameas a single token, so this pattern won't match a normalfind … \( -name *mobile* -o … \)invocation.- Line 12:
find G:ResgridResgridWebResgrid.WebAreasUserViews -type f -name *.cshtml— the path has no separators (/or\) betweenG:,Resgrid,Resgrid,Web,Resgrid.Web,Areas,User,Views. This is not a valid filesystem path and almost certainly a copy/paste artifact.- Line 15:
find /g/Resgrid/Resgrid -type f -name *.swift -o -name *.kt -o -name *.java— due to-oprecedence vs. the implicit*.javafiles will actually be printed. If the intent is to allow a command that finds all three extensions, it needs grouping:\( -name *.swift -o -name *.kt -o -name *.java \).Also worth considering:
.claude/settings.local.jsonis typically a per-developer local file and probably shouldn't be committed to the repo (consider.gitignore-ing it and keeping a sharedsettings.jsonwith only team-wide entries).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/settings.local.json around lines 9 - 15, Fix the malformed Bash allowlist entries in .claude/settings.local.json: add the missing space after the escaped paren in the find pattern (change "\\\\\\(-name" to "\\\\( -name" so the token becomes "\( -name"), correct the garbled Windows path token "G:ResgridResgridWebResgrid.WebAreasUserViews" to a proper path with separators like "G:/Resgrid/ResgridWeb/Resgrid.Web/Areas/User/Views" (or use backslashes), and group the multiple -name tests in the last find entry so all extensions match (wrap the name tests in an escaped group like "\\( -name *.swift -o -name *.kt -o -name *.java \\)" rather than relying on -o precedence); optionally remove or add .claude/settings.local.json to .gitignore if this is meant to be local-only.Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs-776-776 (1)
776-776:⚠️ Potential issue | 🟡 MinorRemove duplicate "gif" check.
The extension "gif" is checked twice in the same condition on Line 776, which is redundant.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs` at line 776, The conditional in ProfileController.cs that checks the file extension (variable extenion) redundantly tests "gif" twice; remove the duplicate "gif" comparison from the if statement (the check that compares extenion against "jpg","jpeg","png","gif","gif","pdf","doc") so each extension appears only once (or replace the chain with a single collection membership test) to eliminate the redundant condition.Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs-774-774 (1)
774-774:⚠️ Potential issue | 🟡 MinorFix the variable name typo.
The variable is misspelled as
extenioninstead ofextension. While this doesn't affect functionality, it reduces code clarity and could confuse future maintainers.📝 Proposed fix
- var extenion = FileHelper.GetFileExtensionWithoutDot(fileToUpload.FileName); + var extension = FileHelper.GetFileExtensionWithoutDot(fileToUpload.FileName); - if (extenion != "jpg" && extenion != "jpeg" && extenion != "png" && extenion != "gif" && extenion != "gif" && extenion != "pdf" && extenion != "doc" - && extenion != "docx" && extenion != "ppt" && extenion != "pptx" && extenion != "pps" && extenion != "ppsx" && extenion != "odt" - && extenion != "xls" && extenion != "xlsx" && extenion != "txt") - ModelState.AddModelError("fileToUpload", string.Format("File type ({0}) is not importable.", extenion)); + if (extension != "jpg" && extension != "jpeg" && extension != "png" && extension != "gif" && extension != "pdf" && extension != "doc" + && extension != "docx" && extension != "ppt" && extension != "pptx" && extension != "pps" && extension != "ppsx" && extension != "odt" + && extension != "xls" && extension != "xlsx" && extension != "txt") + ModelState.AddModelError("fileToUpload", string.Format("File type ({0}) is not importable.", extension));As per coding guidelines: "Use meaningful, descriptive names for types, methods, and parameters; avoid unclear abbreviations".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Controllers/ProfileController.cs` at line 774, In ProfileController, rename the local variable extenion to extension for clarity wherever it is assigned from FileHelper.GetFileExtensionWithoutDot(fileToUpload.FileName) and update any subsequent references within the method to use extension instead of extenion so the code reads correctly and matches naming conventions.Web/Resgrid.Web/Areas/User/Views/Department/MappingSettings.cshtml-89-114 (1)
89-114:⚠️ Potential issue | 🟡 MinorLocalize the new Mapbox settings text.
This page is localized elsewhere, but the new header, labels, placeholders, and help text are hard-coded English strings.
🌐 Suggested direction
- <h3>Department Mapbox Override</h3> + <h3>@localizer["DepartmentMapboxOverrideHeader"]</h3> ... - <label class="col-sm-3 control-label">Use Department Mapbox Map</label> + <label class="col-sm-3 control-label">@localizer["UseDepartmentMapboxMapLabel"]</label> ... - <span class="help-block m-b-none">Use a public Mapbox token intended for website and mobile client-side map rendering for this department.</span> + <span class="help-block m-b-none">@localizer["MapboxPublicAccessTokenHelp"]</span>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Department/MappingSettings.cshtml` around lines 89 - 114, Replace all hard-coded English strings in MappingSettings.cshtml with localized resources: inject IViewLocalizer (e.g., `@inject` IViewLocalizer Localizer) at the top of the view and change the header, labels, placeholders and help-block texts to use Localizer[...] calls (use keys like "DepartmentMapboxOverrideHeader", "UseDepartmentMapboxMap", "MapboxStyleUrlLabel", "MapboxStylePlaceholder", "MapboxStyleHelp", "MapboxAccessTokenLabel", "MapboxAccessTokenPlaceholder", "MapboxAccessTokenHelp"). Update the markup surrounding the inputs bound to UseMapboxOverride, MapboxStyleUrl and MapboxAccessToken to use those Localizer keys for text and placeholder attributes, and add the corresponding entries to the view/resource .resx files for translations.Web/Resgrid.Web/Areas/User/Views/Dispatch/ViewCall.cshtml-951-952 (1)
951-952:⚠️ Potential issue | 🟡 MinorUse
Html.Raw()to prevent Razor HTML encoding in JavaScript string context.Razor's default behavior HTML-encodes output, converting
&to&. While current tile URLs only have single query parameters (not affected), if configuration ever adds multiple parameters with ampersands, the URL would break. UseHtml.Raw()to preserve the values as-is:- var osmTileUrl = '@mapConfig.TileUrl'; - var osmTileAttribution = '@mapConfig.Attribution'; + var osmTileUrl = '@Html.Raw(mapConfig.TileUrl)'; + var osmTileAttribution = '@Html.Raw(mapConfig.Attribution)';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web/Areas/User/Views/Dispatch/ViewCall.cshtml` around lines 951 - 952, Razor is HTML-encoding mapConfig values causing '&' to become '&' in JavaScript strings; update the JavaScript assignments for osmTileUrl and osmTileAttribution to output the raw, unencoded values by using Html.Raw when rendering mapConfig.TileUrl and mapConfig.Attribution so the URL and attribution are preserved exactly in the osmTileUrl and osmTileAttribution variables.Tests/Resgrid.Tests/Services/DepartmentSettingsServiceMapConfigTests.cs-37-43 (1)
37-43:⚠️ Potential issue | 🟡 MinorRestore
MappingConfigafter tests mutate it.These static assignments can leak into unrelated tests or race with parallel fixtures. Capture the original values and restore them in
[TearDown]/[OneTimeTearDown]; consider marking the fixture[NonParallelizable]if shared config cannot be isolated.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Tests/Resgrid.Tests/Services/DepartmentSettingsServiceMapConfigTests.cs` around lines 37 - 43, The test mutates the global MappingConfig static properties (e.g., MappingConfig.MapBoxStyleUrl, MapBoxTileUrl, WebsiteOSMKey, WebsiteMapboxKey, WebsiteMapboxAccessToken, WebsiteMapMode, LeafletTileUrl) which can leak into other tests; update the test class to capture the original values before modification and restore them in a teardown method (use [TearDown] or [OneTimeTearDown] that resets those MappingConfig properties to the saved originals), and if isolation cannot be ensured add the NUnit [NonParallelizable] attribute to the fixture to prevent parallel test interference.Web/Resgrid.Web.Services/Resgrid.Web.Services.xml-427-438 (1)
427-438:⚠️ Potential issue | 🟡 MinorAlign the endpoint summary with the
NoTimerresult contract.The endpoint summary states that only active calls "with personnel check-in timers enabled" are returned, but the response model explicitly documents
HasPersonnelTimer=false, zero timer durations, andStatus="NoTimer"as valid values. The source code directly mapsHasPersonnelTimerwithout filtering, confirming the endpoint returns calls both with and without active timers.📝 Proposed doc fix
- Returns a check-in timer status summary for every active call (with - personnel check-in timers enabled) that <paramref name="userId"/> has been - dispatched on. If the caller is querying a different user they must hold + Returns a check-in timer status summary for every active call that + <paramref name="userId"/> has been dispatched on, including calls without + an active personnel timer reported as <c>NoTimer</c>. If the caller is querying a different user they must hold🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web.Services/Resgrid.Web.Services.xml` around lines 427 - 438, Update the XML doc summary for member M:Resgrid.Web.Services.Controllers.v4.CheckInTimersController.GetUserCallCheckInStatuses(System.String) to reflect that the endpoint returns dispatched calls both with and without personnel check-in timers enabled (i.e., it may return items with HasPersonnelTimer=false, zero durations, and Status="NoTimer"), rather than claiming it only returns calls "with personnel check-in timers enabled"; reference the response contract semantics (HasPersonnelTimer, timer durations, and Status="NoTimer") and ensure the permission note about Personnel_View vs Call_View remains unchanged.Web/Resgrid.Web.Services/Resgrid.Web.Services.xml-5803-5852 (1)
5803-5852:⚠️ Potential issue | 🟡 MinorFix the unresolved XML documentation cross-references.
Lines 5805 and 5851 have
cref="!:..."which indicates unresolved links. Generated API docs will render these as broken references. Since this appears to be generated documentation, apply the fix in the source XML comments.Proposed fix
- Response wrapper for <see cref="!:GetUserCallCheckInStatuses"/>. + Response wrapper for <see cref="M:Resgrid.Web.Services.Controllers.v4.CheckInTimersController.GetUserCallCheckInStatuses(System.String)"/>. @@ - Response wrapper for <see cref="!:GetCallPersonnelCheckInStatuses"/>. + Response wrapper for <see cref="M:Resgrid.Web.Services.Controllers.v4.CheckInTimersController.GetCallPersonnelCheckInStatuses(System.Int32)"/>.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Web/Resgrid.Web.Services/Resgrid.Web.Services.xml` around lines 5803 - 5852, The XML doc has unresolved cross-refs: change the invalid cref attributes (cref="!:GetUserCallCheckInStatuses" and cref="!:GetCallPersonnelCheckInStatuses") in the XML comments for the types Resgrid.Web.Services.Models.v4.CheckInTimers.UserCallCheckInStatusResult and CallPersonnelCheckInStatusResult to valid references — either replace "!:" with the correct member-kind prefix and fully-qualified member name (e.g., "M:Namespace.ControllerClass.GetUserCallCheckInStatuses" and "M:Namespace.ControllerClass.GetCallPersonnelCheckInStatuses") matching the actual controller/method symbols, or replace the cref with plain text summaries if you cannot determine the exact fully-qualified member signature; update the source XML comments (where these types are documented) so the generated docs no longer contain broken cref links.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7789b963-ca0a-4acc-bf01-34326731f306
⛔ Files ignored due to path filters (3)
Core/Resgrid.Localization/Areas/User/Home/EditProfile.en.resxis excluded by!**/*.resxWeb/Resgrid.Web/Areas/User/Apps/package-lock.jsonis excluded by!**/package-lock.jsonWeb/Resgrid.Web/wwwroot/js/ng/favicon.icois excluded by!**/*.ico
📒 Files selected for processing (116)
.claude/settings.local.json.gitignoreCore/Resgrid.Config/MappingConfig.csCore/Resgrid.Config/NumberProviderConfig.csCore/Resgrid.Config/ResolvedMapConfig.csCore/Resgrid.Framework/FileHelper.csCore/Resgrid.Model/DepartmentSettingTypes.csCore/Resgrid.Model/PersonnelCallCheckInStatus.csCore/Resgrid.Model/Providers/IOutboundVoiceProvider.csCore/Resgrid.Model/Repositories/ICallsRepository.csCore/Resgrid.Model/Services/ICallsService.csCore/Resgrid.Model/Services/ICheckInTimerService.csCore/Resgrid.Model/Services/IContactVerificationService.csCore/Resgrid.Model/Services/IDepartmentSettingsService.csCore/Resgrid.Model/UserCallCheckInSummary.csCore/Resgrid.Services/CallsService.csCore/Resgrid.Services/CheckInTimerService.csCore/Resgrid.Services/ContactVerificationService.csCore/Resgrid.Services/DepartmentSettingsService.csProviders/Resgrid.Providers.Number/OutboundVoiceProvider.csRepositories/Resgrid.Repositories.DataRepository/CallsRepository.csRepositories/Resgrid.Repositories.DataRepository/Configs/SqlConfiguration.csRepositories/Resgrid.Repositories.DataRepository/Queries/Calls/SelectActiveCallsWithCheckInTimersForUserQuery.csRepositories/Resgrid.Repositories.DataRepository/Servers/PostgreSql/PostgreSqlConfiguration.csRepositories/Resgrid.Repositories.DataRepository/Servers/SqlServer/SqlServerConfiguration.csTests/Resgrid.Tests/Framework/FileHelperTests.csTests/Resgrid.Tests/Services/ContactVerificationServiceTests.csTests/Resgrid.Tests/Services/DepartmentSettingsServiceMapConfigTests.csWeb/Resgrid.Web.Services/Controllers/TwilioController.csWeb/Resgrid.Web.Services/Controllers/v4/CheckInTimersController.csWeb/Resgrid.Web.Services/Controllers/v4/ConfigController.csWeb/Resgrid.Web.Services/Models/v4/CheckInTimers/CheckInTimerModels.csWeb/Resgrid.Web.Services/Models/v4/Configs/GetConfigResult.csWeb/Resgrid.Web.Services/Resgrid.Web.Services.xmlWeb/Resgrid.Web/Areas/User/Apps/README.mdWeb/Resgrid.Web/Areas/User/Apps/package.jsonWeb/Resgrid.Web/Areas/User/Apps/src/components/map/LeafletMapView.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/map/MapElement.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/map/MapboxMapView.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/map/map.cssWeb/Resgrid.Web/Areas/User/Apps/src/components/map/mapTypes.tsWeb/Resgrid.Web/Areas/User/Apps/src/components/omnibar/OmnibarElement.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/omnibar/omnibar.cssWeb/Resgrid.Web/Areas/User/Apps/src/components/shared/LoadingIndicator.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/shifts/ShiftsCalendarElement.tsxWeb/Resgrid.Web/Areas/User/Apps/src/components/shifts/shifts.cssWeb/Resgrid.Web/Areas/User/Apps/src/elements.tsWeb/Resgrid.Web/Areas/User/Apps/src/runtime/api.tsWeb/Resgrid.Web/Areas/User/Apps/src/runtime/auth.tsWeb/Resgrid.Web/Areas/User/Apps/src/runtime/browserConfig.tsWeb/Resgrid.Web/Areas/User/Apps/src/runtime/customElement.tsxWeb/Resgrid.Web/Areas/User/Apps/src/runtime/events.tsWeb/Resgrid.Web/Areas/User/Apps/src/runtime/signalr.tsWeb/Resgrid.Web/Areas/User/Apps/src/styles/base.cssWeb/Resgrid.Web/Areas/User/Apps/src/vite-env.d.tsWeb/Resgrid.Web/Areas/User/Apps/tsconfig.jsonWeb/Resgrid.Web/Areas/User/Apps/vite.config.tsWeb/Resgrid.Web/Areas/User/Controllers/DepartmentController.csWeb/Resgrid.Web/Areas/User/Controllers/DispatchController.csWeb/Resgrid.Web/Areas/User/Controllers/DocumentsController.csWeb/Resgrid.Web/Areas/User/Controllers/FilesController.csWeb/Resgrid.Web/Areas/User/Controllers/ProfileController.csWeb/Resgrid.Web/Areas/User/Controllers/ProtocolsController.csWeb/Resgrid.Web/Areas/User/Controllers/TrainingsController.csWeb/Resgrid.Web/Areas/User/Models/Departments/MappingSettingsView.csWeb/Resgrid.Web/Areas/User/Views/CustomMaps/Edit.cshtmlWeb/Resgrid.Web/Areas/User/Views/CustomMaps/New.cshtmlWeb/Resgrid.Web/Areas/User/Views/CustomMaps/RegionEditor.cshtmlWeb/Resgrid.Web/Areas/User/Views/Department/MappingSettings.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/AddArchivedCall.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/CallExportEx.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/Dashboard.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/NewCall.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/UpdateCall.cshtmlWeb/Resgrid.Web/Areas/User/Views/Dispatch/ViewCall.cshtmlWeb/Resgrid.Web/Areas/User/Views/Files/Upload.cshtmlWeb/Resgrid.Web/Areas/User/Views/Groups/Geofence.cshtmlWeb/Resgrid.Web/Areas/User/Views/Home/EditUserProfile.cshtmlWeb/Resgrid.Web/Areas/User/Views/IndoorMaps/Edit.cshtmlWeb/Resgrid.Web/Areas/User/Views/IndoorMaps/New.cshtmlWeb/Resgrid.Web/Areas/User/Views/IndoorMaps/ZoneEditor.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/EditLayer.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/Index.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/LiveRouting.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/NewLayer.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/StationRouting.cshtmlWeb/Resgrid.Web/Areas/User/Views/Mapping/ViewType.cshtmlWeb/Resgrid.Web/Areas/User/Views/Personnel/ViewEvents.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/ArchivedView.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/Directions.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/Edit.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/InstanceDetail.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/New.cshtmlWeb/Resgrid.Web/Areas/User/Views/Routes/View.cshtmlWeb/Resgrid.Web/Areas/User/Views/Shared/_UserLayout.cshtmlWeb/Resgrid.Web/Areas/User/Views/Units/ViewEvents.cshtmlWeb/Resgrid.Web/Helpers/SettingsHelper.csWeb/Resgrid.Web/Resgrid.Web.csprojWeb/Resgrid.Web/wwwroot/js/app/internal/home/resgrid.home.edituserprofile.jsWeb/Resgrid.Web/wwwroot/js/ng/3rdpartylicenses.txtWeb/Resgrid.Web/wwwroot/js/ng/index.htmlWeb/Resgrid.Web/wwwroot/js/ng/main.226d4053d1364245.jsWeb/Resgrid.Web/wwwroot/js/ng/main.41cf6e57a0ec9523.jsWeb/Resgrid.Web/wwwroot/js/ng/main.de531c90083e84ba.jsWeb/Resgrid.Web/wwwroot/js/ng/main.jsWeb/Resgrid.Web/wwwroot/js/ng/polyfills.23572fc657073556.jsWeb/Resgrid.Web/wwwroot/js/ng/polyfills.jsWeb/Resgrid.Web/wwwroot/js/ng/react-elements.cssWeb/Resgrid.Web/wwwroot/js/ng/react-elements.jsWeb/Resgrid.Web/wwwroot/js/ng/runtime.1a4e2ecd996ea63f.jsWeb/Resgrid.Web/wwwroot/js/ng/runtime.6b3b18976611456e.jsWeb/Resgrid.Web/wwwroot/js/ng/runtime.jsWeb/Resgrid.Web/wwwroot/js/ng/styles.6e462343e310d4b8.cssWeb/Resgrid.Web/wwwroot/js/ng/styles.cssWeb/Resgrid.Web/wwwroot/js/ng/styles.f0de54956caa9d30.cssWeb/Resgrid.Web/wwwroot/js/ng/vendor.js
💤 Files with no reviewable changes (10)
- Web/Resgrid.Web/wwwroot/js/ng/index.html
- Web/Resgrid.Web/wwwroot/js/ng/styles.f0de54956caa9d30.css
- Web/Resgrid.Web/wwwroot/js/ng/styles.6e462343e310d4b8.css
- Web/Resgrid.Web/wwwroot/js/ng/runtime.6b3b18976611456e.js
- Web/Resgrid.Web/wwwroot/js/ng/runtime.js
- Web/Resgrid.Web/wwwroot/js/ng/runtime.1a4e2ecd996ea63f.js
- Web/Resgrid.Web/wwwroot/js/ng/polyfills.23572fc657073556.js
- Web/Resgrid.Web/wwwroot/js/ng/styles.css
- Web/Resgrid.Web/wwwroot/js/ng/main.js
- Web/Resgrid.Web/wwwroot/js/ng/3rdpartylicenses.txt
| .dual-graph/ | ||
| .claude/settings.local.json | ||
| .claude/settings.local.json | ||
| /Web/Resgrid.Web/wwwroot/js/ng/chunks |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether generated entries reference chunk paths.
rg -n --glob '!**/node_modules/**' 'chunks/|js/ng/chunks|react-elements\.js' Web/Resgrid.Web Web/Resgrid.Web/Areas/User/Apps 2>/dev/null || true
# Confirm git ignores the new chunk directory.
git check-ignore -v Web/Resgrid.Web/wwwroot/js/ng/chunks/example.js || true
# Inspect build/publish config for copying Vite output into wwwroot/js/ng.
fd -i '^(vite\.config\.(ts|js)|package\.json|.*\.csproj|.*\.targets|.*\.props|Directory\.Build\.(props|targets))$' \
-x sh -c '
printf "\n--- %s ---\n" "$1"
rg -n "Areas/User/Apps|wwwroot/js/ng|react-elements|vite|chunks|outDir" "$1" || true
' sh {}Repository: Resgrid/Core
Length of output: 50370
🏁 Script executed:
#!/bin/bash
# Read the vite.config.ts to see output configuration
echo "=== vite.config.ts ==="
cat Web/Resgrid.Web/Areas/User/Apps/vite.config.ts
echo ""
echo "=== Contents of wwwroot/js/ng/ ==="
ls -la Web/Resgrid.Web/wwwroot/js/ng/ 2>/dev/null || echo "Directory not found"
echo ""
echo "=== Contents of wwwroot/js/ng/chunks/ ==="
ls -la Web/Resgrid.Web/wwwroot/js/ng/chunks/ 2>/dev/null || echo "Chunks directory not found or empty"
echo ""
echo "=== Check if chunks directory is listed in .gitignore ==="
grep -n "chunks" .gitignore || echo "No explicit chunks entry in .gitignore"Repository: Resgrid/Core
Length of output: 1810
🏁 Script executed:
#!/bin/bash
# Search for build/publish configuration that copies dist/core to wwwroot
echo "=== Searching for build scripts/targets ==="
fd -i '\.(csproj|targets|props|json)$' Web/Resgrid.Web Web/Resgrid.Web/Areas/User/Apps \
| head -20 | xargs rg -l 'dist/core|wwwroot|copy|build.*chunk' 2>/dev/null
echo ""
echo "=== Check .csproj for publish/build configuration ==="
find Web/Resgrid.Web -name "*.csproj" -type f | head -1 | xargs rg -A5 -B5 'dist|www|publish|copy' 2>/dev/null | head -50
echo ""
echo "=== Check package.json for build/publish scripts ==="
rg -A20 '"scripts"' Web/Resgrid.Web/Areas/User/Apps/package.json 2>/dev/null || echo "Not found"
echo ""
echo "=== Verify if dist/core exists and has chunks ==="
ls -la Web/Resgrid.Web/Areas/User/Apps/dist/ 2>/dev/null || echo "dist/ not found"
ls -la Web/Resgrid.Web/Areas/User/Apps/dist/core/ 2>/dev/null || echo "dist/core/ not found"
ls -la Web/Resgrid.Web/Areas/User/Apps/dist/core/chunks/ 2>/dev/null || echo "dist/core/chunks/ not found"Repository: Resgrid/Core
Length of output: 3097
Confirm the build/publish pipeline copies chunks from dist/core/ to wwwroot/js/ng/.
The vite config outputs chunks to dist/core/chunks/, but the entry point react-elements.js in wwwroot/js/ng/ imports them with relative paths (import "./chunks/elements-BnCXm89z.js"). The chunks directory is not present in wwwroot and is correctly ignored by git as a generated artifact. However, no build step in the .csproj or npm scripts explicitly copies the compiled chunks to the deployed location. Without this copy step, the entry file will fail at runtime with 404 errors when browsers attempt to load the chunk files.
Ensure the ASP.NET publish or build process includes a step that copies dist/core/chunks/ to wwwroot/js/ng/chunks/ (or verify this happens in your CI/CD pipeline).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.gitignore at line 277, The Vite-generated chunk files in dist/core/chunks
are not being copied to the deployed wwwroot/js/ng/chunks so react-elements.js
imports will 404; fix by adding an explicit copy step either in the project
build or npm pipeline: update the .csproj to include an MSBuild Target (e.g.,
AfterPublish or BeforePublish) that copies dist/core/chunks/** to
wwwroot/js/ng/chunks/**, or add a npm script (postbuild) that copies
dist/core/chunks to wwwroot/js/ng/chunks before publish; reference the artifact
paths (dist/core/chunks, wwwroot/js/ng/chunks) and the entry file
react-elements.js so the copy happens as part of the build/publish for CI/CD.
|
Approve |
Summary by CodeRabbit
New Features
Improvements