Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork73
Develop#234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Thanks for opening this, but we'd appreciate a little more information. Could you update it with more details? |
coderabbitaibot commentedAug 12, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Note Currently processing new changes in this PR. This may take a few minutes, please wait... 📒 Files selected for processing (8)
WalkthroughAdds analytics exporter selection and config fields; introduces “On Unit” action logging with DB migrations and UI handling; adds a new department setting gating unit-linked personnel status updates; updates UnitStatus save flow to create linked action logs; enhances Twilio voice menus with new endpoints; adjusts RabbitMQ retry behavior; various UI/localization and validation updates. Changes
Sequence Diagram(s)sequenceDiagram participant Client participant UnitStatusController participant UnitsService participant DepartmentSettingsService participant ActionLogsService Client->>UnitStatusController: SaveUnitStatus(input, cancellationToken) UnitStatusController->>UnitsService: Save unit state (+roles) UnitsService-->>UnitStatusController: saved state + roles UnitStatusController->>DepartmentSettingsService: GetPersonnelOnUnitSetUnitStatusAsync(deptId) DepartmentSettingsService-->>UnitStatusController: flag alt flag == true and roles exist loop for each role user UnitStatusController->>ActionLogsService: CreateUnitLinkedStatus(userId, deptId, unitStateId, unitName, ct) ActionLogsService-->>UnitStatusController: ActionLog end end UnitStatusController-->>Client: SaveUnitStatusResultsequenceDiagram participant Caller participant Twilio participant TwilioController participant CustomStateService participant ActionLogsService participant UserStateService Caller->>Twilio: Incoming Call Twilio->>TwilioController: InboundVoice GET TwilioController-->>Twilio: TwiML (repeated Gather prompts) alt user selects status Twilio->>TwilioController: InboundVoiceActionStatus (digit) TwilioController->>ActionLogsService: Log status change ActionLogsService-->>TwilioController: Result TwilioController-->>Twilio: TwiML response else user selects staffing Twilio->>TwilioController: InboundVoiceActionStaffing (digit) TwilioController->>UserStateService: Update staffing UserStateService-->>TwilioController: Result TwilioController-->>Twilio: TwiML response endsequenceDiagram participant Client participant ConfigController participant TelemetryConfig Client->>ConfigController: GetConfig() ConfigController->>TelemetryConfig: GetAnalyticsKey() TelemetryConfig-->>ConfigController: analytics key ConfigController->>TelemetryConfig: ExporterType TelemetryConfig-->>ConfigController: exporter enum ConfigController-->>Client: AnalyticsApiKey, AnalyticsHost, EventingUrlEstimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
Tip You can disable sequence diagrams in the walkthrough.Disable the ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat withCodeRabbit:
SupportNeed help? Create a ticket on oursupport page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 21
🔭 Outside diff range comments (4)
Web/Resgrid.Web/Views/Account/LogOn.cshtml (1)
97-97:Rename ‘SetLanugage’ to ‘SetLanguage’The action and all its references are misspelled as “SetLanugage.” To prevent confusion and future bugs, rename the action method and update the view bindings:
• AccountController (Web/Resgrid.Web/Controllers/AccountController.cs, line 507)
– Changepublic IActionResult SetLanugage(string culture, string returnUrl)
– Topublic IActionResult SetLanguage(string culture, string returnUrl)• LogOn.cshtml (Web/Resgrid.Web/Views/Account/LogOn.cshtml, line 97)
– Change<form … asp-action="SetLanugage" …>
– To<form … asp-action="SetLanguage" …>• _TopNavbar.cshtml (Web/Resgrid.Web/Areas/User/Views/Shared/_TopNavbar.cshtml, line 53)
– Change<form … asp-action="SetLanugage" …>
– To<form … asp-action="SetLanguage" …>Ensure any route tests or JavaScript calls referencing this endpoint are updated accordingly.
Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs (2)
75-83:Bug: Using current user instead of requested user when loading state
GetLastUserStateByUserIdAsyncis called withUserId(the caller) instead of theuserIdparameter after it’s normalized. This returns the wrong person’s staffing for requests querying another user.Fix the call to use the
userIdvariable:- var userState = await _userStateService.GetLastUserStateByUserIdAsync(UserId);+ var userState = await _userStateService.GetLastUserStateByUserIdAsync(userId);
187-191:Harden parsing of input.Type before looping over UserIdsTo prevent a
FormatException(e.g. wheninput.Typeis whitespace), parse once up‐front withint.TryParseand return a 400 if invalid. Then use the parsed value in bothCreateUserStatecalls:• File: Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs
Lines: around 187–191Suggested diff:
- // inside SavePersonsStaffings, before looping- List<string> logIds = new List<string>();+ // Validate and parse Type once+ if (!int.TryParse(input.Type, out var typeVal))+ return BadRequest("`Type` must be a valid integer.");+ var logIds = new List<string>(); foreach (var userId in input.UserIds) {@@- if (String.IsNullOrWhiteSpace(input.Note))- savedState = await _userStateService.CreateUserState(userToSetStatusFor.UserId, DepartmentId, int.Parse(input.Type), cancellationToken);- else- savedState = await _userStateService.CreateUserState(userToSetStatusFor.UserId, DepartmentId, int.Parse(input.Type), input.Note, cancellationToken);+ if (string.IsNullOrWhiteSpace(input.Note))+ savedState = await _userStateService.CreateUserState(userToSetStatusFor.UserId, DepartmentId, typeVal, cancellationToken);+ else+ savedState = await _userStateService.CreateUserState(userToSetStatusFor.UserId, DepartmentId, typeVal, input.Note, cancellationToken);Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs (1)
579-582:Header parsing is brittle; Rabbit header values are often byte[] or longea.BasicProperties.Headers values are AMQP field tables and commonly arrive as byte[] or integer types. To avoid parse errors (e.g., "System.Byte[]" string), handle multiple types.
Apply this diff:
-int currentDeliveryCount = 0;--if (ea.BasicProperties != null && ea.BasicProperties.Headers != null && ea.BasicProperties.Headers.Count > 0 &&- ea.BasicProperties.Headers.ContainsKey("x-redelivered-count"))- currentDeliveryCount = int.Parse(ea.BasicProperties.Headers["x-redelivered-count"].ToString());+int currentDeliveryCount = 0;+if (ea.BasicProperties?.Headers != null &&+ ea.BasicProperties.Headers.TryGetValue("x-redelivered-count", out var hdrVal))+{+ switch (hdrVal)+ {+ case byte b: currentDeliveryCount = b; break;+ case sbyte sb: currentDeliveryCount = sb; break;+ case short s: currentDeliveryCount = s; break;+ case int i: currentDeliveryCount = i; break;+ case long l: currentDeliveryCount = (int)l; break;+ case byte[] bytes:+ if (int.TryParse(Encoding.UTF8.GetString(bytes), out var parsedBytes))+ currentDeliveryCount = parsedBytes;+ break;+ default:+ int.TryParse(hdrVal?.ToString(), out currentDeliveryCount);+ break;+ }+}
🧹 Nitpick comments (19)
Web/Resgrid.Web/wwwroot/js/ng/vendor.js (1)
124644-124647:No-op async handler registered on ReconnectedThis is an async no-op: function* () {}. Consider omitting the handler to reduce noise, unless used as a future hook.
Web/Resgrid.Web/Views/Account/Register.cshtml (2)
120-120:Possible typo in localization key: "Resgister".The button uses@localizer["Resgister"]. If this is a misspelling, update to@localizer["Register"] and the corresponding resource keys. If “Resgister” is the intentional key in your resource files, ignore this.
94-94:Invalid CSS value: vertical-align: central;“central” isn’t a valid value for vertical-align, and vertical-align doesn’t apply to block-level elements in this context. Consider removing it or using a flexbox layout for the label/select alignment.
Core/Resgrid.Model/DepartmentSettingTypes.cs (1)
39-39:Enum value added correctly; consider documenting the setting intent
PersonnelOnUnitSetUnitStatus = 35is consistent with sequencing. Consider adding an XML summary to capture the behavior (gates creating unit-linked action logs and optionally personnel status updates).Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs (1)
71-71:Rename the action method to the correct spellingThe action name is still misspelled (
GetCurrentStatffing). Rename the method to reduce confusion and improve API docs, while keeping both route attributes for compatibility.- public async Task<ActionResult<GetCurrentStaffingResult>> GetCurrentStatffing(string userId)+ public async Task<ActionResult<GetCurrentStaffingResult>> GetCurrentStaffing(string userId)Core/Resgrid.Model/ActionLog.cs (1)
54-59:Persisting Unit linkage: consider constraining UnitName length and indexing strategyAdding UnitStateId and UnitName looks good. Recommend:
- Add a [MaxLength] constraint on UnitName to match expected lengths and avoid unbounded strings in SQL (e.g., 128–256 chars).
- If UnitName will be searched/filtered, consider adding an index at the DB level in the migration.
Example annotation:
[ProtoMember(13)]-public string UnitName { get; set; }+[MaxLength(256)]+public string UnitName { get; set; }If you’d prefer a different max length, I can update the migration(s) accordingly.
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0035_UpdatingContactsTableAgain.cs (1)
9-17:Empty migration body with non-empty name/numberThis no-op migration upgrades the version but does nothing. If intentional (to reconcile numbering across providers), add a brief comment explaining why to avoid confusion; otherwise, either implement the intended change or remove this migration.
Example:
// Intentionally left blank to align migration numbering across providers.Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs (1)
597-598:Consider excluding raw exception messages from headers"x-previous-error" may leak sensitive info to consumers/logs. Prefer an error code or truncated/sanitized message.
Apply this diff to reduce exposure:
-props.Headers.Add("x-previous-error", mex.Message);+props.Headers.Add("x-previous-error", string.IsNullOrWhiteSpace(mex.Message) ? "UnhandledError" : mex.Message.Substring(0, Math.Min(256, mex.Message.Length)));Or use a known error code map.
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs (1)
11-12:Nit: avoid repeated ToLower() calls on identical literals.Minor readability refactor: store the normalized identifiers in locals to avoid repetition.
-Alter.Table("ActionLogs".ToLower()).AddColumn("UnitStateId".ToLower()).AsInt32().Nullable();-Alter.Table("ActionLogs".ToLower()).AddColumn("UnitName".ToLower()).AsCustom("citext").Nullable();+var table = "actionlogs";+Alter.Table(table).AddColumn("unitstateid").AsInt32().Nullable();+Alter.Table(table).AddColumn("unitname").AsCustom("citext").Nullable();Web/Resgrid.Web.Services/Resgrid.Web.Services.xml (1)
3978-3984:Fix method XML docs: wrong summary and missing parameter.The summary refers to “current user”, but this is UnitStatusController.SaveUnitStatus; it should describe saving a unit’s status. Also, the new CancellationToken parameter lacks documentation, and the param name/type reference says “StatusInput” instead of “UnitStatusInput”.
Proposed doc correction:
- <member name="M:Resgrid.Web.Services.Controllers.v4.UnitStatusController.SaveUnitStatus(Resgrid.Web.Services.Models.v4.UnitStatus.UnitStatusInput,System.Threading.CancellationToken)">- <summary>- Sets the status/action for the current user.- </summary>- <param name="statusInput">StatusInput object with the Status/Action to set.</param>- <returns>Returns HttpStatusCode Created if successful, BadRequest otherwise.</returns>- </member>+ <member name="M:Resgrid.Web.Services.Controllers.v4.UnitStatusController.SaveUnitStatus(Resgrid.Web.Services.Models.v4.UnitStatus.UnitStatusInput,System.Threading.CancellationToken)">+ <summary>+ Sets the status/state for the specified unit.+ </summary>+ <param name="statusInput">UnitStatusInput object with the state to set.</param>+ <param name="cancellationToken">The cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>+ <returns>Returns HttpStatusCode Created if successful, BadRequest otherwise.</returns>+ </member>Core/Resgrid.Config/TelemetryConfig.cs (1)
19-26:Clarify multi-client analytics key selection and avoid dual source of truth.
- GetAnalyticsKey() always returns AptabaseWebApiKey for Aptabase. You added multiple Aptabase keys (Services/Responder/Unit/BigBoard/Dispatch), but they’re unused here. If GetConfig serves multiple client apps, this may leak the wrong key. Consider a keyed selector, e.g., GetAnalyticsKeyFor(string client).
- Exporter (string) and ExporterType (enum) can drift. Provide a single setter to keep them in sync.
Suggested additions:
public static string GetAnalyticsKey() { if (ExporterType == TelemetryExporters.PostHog) return PostHogApiKey; else if (ExporterType == TelemetryExporters.Aptabase) return AptabaseWebApiKey; return string.Empty; }++// Optional: centralize host selection alongside key selection+public static string GetAnalyticsHost() =>+ExporterType == TelemetryExporters.PostHog ? PostHogUrl :+ExporterType == TelemetryExporters.Aptabase ? AptabaseUrl : string.Empty;++// Optional: keep Exporter and ExporterType in sync+public static void SetExporter(string exporter)+{+Exporter = exporter ?? string.Empty;+switch (exporter?.Trim().ToLowerInvariant())+{+case "posthog": ExporterType = TelemetryExporters.PostHog; break;+case "aptabase": ExporterType = TelemetryExporters.Aptabase; break;+default: ExporterType = TelemetryExporters.None; break;+}+}Alternatively, extend GetAnalyticsKey(client) to map Aptabase keys per client (web/services/responder/unit/bigboard/dispatch).
Core/Resgrid.Services/DepartmentSettingsService.cs (1)
718-726:Consider caching this hot-path setting and invalidate on updatesThis flag will be checked on SaveUnitStatus requests; adding caching will reduce DB load. Also ensure cache invalidation when the setting changes.
Apply this diff to introduce caching for the getter:
-public async Task<bool> GetPersonnelOnUnitSetUnitStatusAsync(int departmentId)-{-var settingValue = await GetSettingByDepartmentIdType(departmentId, DepartmentSettingTypes.PersonnelOnUnitSetUnitStatus);--if (settingValue != null)-return bool.Parse(settingValue.Setting);--return false;-}+public async Task<bool> GetPersonnelOnUnitSetUnitStatusAsync(int departmentId)+{+async Task<string> getSetting()+{+var s = await GetSettingByDepartmentIdType(departmentId, DepartmentSettingTypes.PersonnelOnUnitSetUnitStatus);+return s?.Setting ?? "false";+}++if (Config.SystemBehaviorConfig.CacheEnabled)+{+var cachedValue = await _cacheProvider.RetrieveAsync<string>(+string.Format(PersonnelOnUnitSetUnitStatusCacheKey, departmentId),+getSetting,+LongCacheLength);+return bool.Parse(cachedValue);+}++return bool.Parse(await getSetting());+}Add these outside the selected range:
// Near other cache keys at the topprivatestaticstringPersonnelOnUnitSetUnitStatusCacheKey="DSetOnUnitSetUnitStatus_{0}";And invalidate on update in SaveOrUpdateSettingAsync’s switch:
caseDepartmentSettingTypes.PersonnelOnUnitSetUnitStatus:_cacheProvider.Remove(string.Format(PersonnelOnUnitSetUnitStatusCacheKey,departmentId));break;Web/Resgrid.Web.Services/Controllers/v4/CallFilesController.cs (2)
128-130:Good defensive validation, but consider logging or monitoring.The validation correctly prevents processing when attachment data is invalid. However, since this is a change in behavior (previously it might have thrown an exception downstream), consider adding logging to track when these conditions occur.
if (String.IsNullOrWhiteSpace(attachment.FileName) || attachment.Data == null || attachment.Data.Length == 0)+{+ Logging.LogWarning($"GetFile: Invalid attachment data for attachment ID {id} - FileName: {!String.IsNullOrWhiteSpace(attachment.FileName)}, DataLength: {attachment.Data?.Length ?? 0}"); return NotFound();+}
171-173:Inconsistent validation pattern with GetFile method.This method has the same validation as
GetFile, which is good. However, the validation logic is duplicated. Consider extracting this to a helper method to maintain DRY principles.Add a private helper method to reduce duplication:
privateboolIsValidAttachment(CallAttachmentattachment){return!String.IsNullOrWhiteSpace(attachment?.FileName)&&attachment.Data!=null&&attachment.Data.Length>0;}Then use it in both methods:
-if (String.IsNullOrWhiteSpace(attachment.FileName) || attachment.Data == null || attachment.Data.Length == 0)+if (!IsValidAttachment(attachment)) return NotFound();Web/Resgrid.Web.Services/Controllers/TwilioController.cs (5)
478-488:Duplicate Gather blocks may confuse callersCreating two identical Gather blocks in sequence could lead to poor user experience. If the user doesn't respond to the first prompt, they'll hear the exact same prompt again, which may be confusing. Consider adding a variation or escalation in the second prompt.
for (int repeat = 0; repeat < 2; repeat++) { var gatherResponse1 = new Gather(numDigits: 1, action: new Uri(string.Format("{0}/api/Twilio/VoiceCallAction?userId={1}&callId={2}", Config.SystemBehaviorConfig.ResgridApiBaseUrl, userId, callId)), method: "GET") { BargeIn = true };- gatherResponse1.Append(new Say(sb1.ToString()));+ if (repeat == 0)+ gatherResponse1.Append(new Say(sb1.ToString()));+ else+ gatherResponse1.Append(new Say("I didn't catch that. " + sb1.ToString())); gatherResponse1.Append(playResponse); response.Append(gatherResponse1); }
537-545:Duplicate Gather blocks may confuse callersSimilar to the previous comment, having two identical prompts in sequence without variation could confuse users who don't respond to the first prompt.
for (int repeat = 0; repeat < 2; repeat++) { var gatherResponse = new Gather(numDigits: 1, action: new Uri(string.Format("{0}/api/Twilio/VoiceCallAction?userId={1}&callId={2}", Config.SystemBehaviorConfig.ResgridApiBaseUrl, userId, callId)), method: "GET") { BargeIn = true };- gatherResponse.Append(new Say(sb.ToString()));+ if (repeat == 0)+ gatherResponse.Append(new Say(sb.ToString()));+ else+ gatherResponse.Append(new Say("I didn't catch that. " + sb.ToString())); response.Append(gatherResponse); }
638-646:Duplicate Gather blocks may confuse callersThe main menu also uses duplicate identical prompts. Consider adding variation for better user experience.
for (int repeat = 0; repeat < 2; repeat++) { var gatherResponse = new Gather(numDigits: 1, action: new Uri(string.Format("{0}/api/Twilio/InboundVoiceAction?userId={1}", Config.SystemBehaviorConfig.ResgridApiBaseUrl, profile.UserId)), method: "GET") { BargeIn = true };- gatherResponse.Append(new Say(sb.ToString()));+ if (repeat == 0)+ gatherResponse.Append(new Say(sb.ToString()));+ else+ gatherResponse.Append(new Say("I didn't catch that. " + sb.ToString())); response.Append(gatherResponse); }
832-836:Duplicate Gather blocks in dynamic menu generationThe pattern of duplicate identical Gather blocks continues here. Consider adding variation for consistency with other suggested improvements.
for (int repeat = 0; repeat < 2; repeat++) {- gatherResponse.Append(new Say(sb.ToString()));+ if (repeat == 0)+ gatherResponse.Append(new Say(sb.ToString()));+ else+ gatherResponse.Append(new Say("I didn't catch that. " + sb.ToString())); response.Append(gatherResponse); }
781-822:Consider extracting option building logicThe status and staffing option building logic is very similar. Consider extracting this into a helper method to reduce duplication and improve maintainability.
Would you like me to generate a helper method that consolidates the option building logic for both status and staffing selections?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
Core/Resgrid.Config/TelemetryConfig.cs(1 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.en.resx(1 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.resx(1 hunks)Core/Resgrid.Model/ActionLog.cs(4 hunks)Core/Resgrid.Model/ActionTypes.cs(1 hunks)Core/Resgrid.Model/DepartmentSettingTypes.cs(1 hunks)Core/Resgrid.Model/Services/IActionLogsService.cs(1 hunks)Core/Resgrid.Model/Services/IDepartmentSettingsService.cs(1 hunks)Core/Resgrid.Services/ActionLogsService.cs(2 hunks)Core/Resgrid.Services/CustomStateService.cs(2 hunks)Core/Resgrid.Services/DepartmentSettingsService.cs(1 hunks)Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs(2 hunks)Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs(1 hunks)Providers/Resgrid.Providers.MigrationsPg/Migrations/M0035_UpdatingContactsTableAgain.cs(1 hunks)Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs(1 hunks)Web/Resgrid.Web.Services/Controllers/TwilioController.cs(5 hunks)Web/Resgrid.Web.Services/Controllers/v4/CallFilesController.cs(4 hunks)Web/Resgrid.Web.Services/Controllers/v4/ConfigController.cs(3 hunks)Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs(1 hunks)Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs(5 hunks)Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs(1 hunks)Web/Resgrid.Web.Services/Models/v4/Configs/GetConfigResult.cs(2 hunks)Web/Resgrid.Web.Services/Resgrid.Web.Services.xml(3 hunks)Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs(2 hunks)Web/Resgrid.Web/Areas/User/Controllers/ReportsController.cs(1 hunks)Web/Resgrid.Web/Areas/User/Models/Departments/DispatchSettingsView.cs(1 hunks)Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/Api.cshtml(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/CallSettings.cshtml(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml(2 hunks)Web/Resgrid.Web/Areas/User/Views/Department/MappingSettings.cshtml(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/ModuleSettings.cshtml(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/ShiftSettings.cshtml(3 hunks)Web/Resgrid.Web/Areas/User/Views/Home/_UserStatusTableRowPartial.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/LogOn.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/Register.cshtml(1 hunks)Web/Resgrid.Web/wwwroot/js/ng/vendor.js(33 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs (1)
Core/Resgrid.Model/ActionLog.cs (1)
GetActionText(94-120)
Web/Resgrid.Web/Areas/User/Controllers/ReportsController.cs (1)
Core/Resgrid.Model/ActionLog.cs (1)
GetActionText(94-120)
Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs (1)
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs (3)
Migration(6-19)Up(9-13)Down(15-18)
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0035_UpdatingContactsTableAgain.cs (2)
Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs (3)
Migration(6-19)Up(9-13)Down(15-18)Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs (3)
Migration(6-19)Up(9-13)Down(15-18)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
Core/Resgrid.Model/ActionLog.cs (1)
GetActionText(94-120)
Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs (1)
Web/Resgrid.Web.Services/Controllers/v4/CallFilesController.cs (2)
HttpGet(49-91)HttpGet(98-138)
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs (1)
Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs (3)
Migration(6-19)Up(9-13)Down(15-18)
Web/Resgrid.Web.Services/Controllers/v4/ConfigController.cs (2)
Core/Resgrid.Config/SystemBehaviorConfig.cs (1)
SystemBehaviorConfig(11-204)Core/Resgrid.Config/TelemetryConfig.cs (2)
TelemetryConfig(3-27)GetAnalyticsKey(19-26)
Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs (3)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
Task(78-318)Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs (1)
Task(102-342)Core/Resgrid.Model/Services/IDepartmentSettingsService.cs (1)
Task(18-18)
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (2)
Core/Resgrid.Config/SystemBehaviorConfig.cs (1)
SystemBehaviorConfig(11-204)Core/Resgrid.Model/Call.cs (1)
GetPriorityText(251-276)
🔇 Additional comments (67)
Web/Resgrid.Web/wwwroot/js/ng/vendor.js (34)
15393-15402:Check getISOWeek DST behavior (rounding by milliseconds)The implementation uses Math.round(diff / 604800000). This is sensitive to DST transitions; behavior differs from difference-in-calendar-weeks approaches. If this is intentional, add tests around DST boundaries to confirm expected outcomes.
16034-16080:startOfISOWeekYear implementation looks correctThis matches the canonical algorithm: compute Monday of the week containing Jan 4 of the ISO week-year.
16084-16124:startOfISOWeek implementation looks correctDelegating to startOfWeek with weekStartsOn: 1 is correct for ISO weeks.
16043-16044:AI summary appears inconsistent with the code (no export swap in these modules)The summary mentions swapped default exports between startOfISOWeekYear and startOfISOWeek. The code here shows startOfISOWeekYear default-exported from startOfISOWeekYear/index.js and startOfISOWeek default-exported from startOfISOWeek/index.js, which is correct.
Also applies to: 16093-16094
72374-72377:Non-functional import alias change (Babel helper)Renaming the asyncToGenerator helper import alias has no functional impact. Ensure these changes originate from a consistent build rather than a manual edit in vendor.js.
73897-73900:Async wrapper import usage looks fineThis is a standard asyncToGenerator wrapping. No logic change beyond build-time transformation.
73951-73954:Async wrapper inside runOutsideAngular is fineNo functional change; just the compiled async generator wrapper.
75987-75990:Non-functional alias import change (Babel helper)Same pattern as above; no functional impact.
123077-123080:Non-functional alias import changeNo logic change; ensure this comes from a reproducible build.
123891-123894:Async wrapper for storage read is fineNo functional change beyond async compilation.
123907-123910:Async wrapper for storage write is fineNo functional change.
123916-123919:Async wrapper for storage remove is fineNo functional change.
123925-123928:Async wrapper for storage clear is fineNo functional change.
123997-124000:Async wrapper for logout looks fineNo functional change.
124031-124034:Token storage flow looks unchangedWrapper only; no functional change.
124042-124045:Token retrieval wrapper is fineNo functional change.
124052-124054:Token removal wrapper is fineNo functional change.
124200-124203:Auth header interception wrapper is fineNo functional change here.
124264-124267:Cache provider initialize wrapper is fineNo functional change.
124277-124280:Cache put wrapper is fineNo functional change.
124288-124291:Cache get wrapper is fineNo functional change.
124320-124323:Cache delete/HTTP response put wrappers are fineNo functional change.
Also applies to: 124328-124331
124338-124341:HTTP response get wrapper is fineNo functional change.
124351-124354:HTTP response delete wrapper is fineNo functional change.
124597-124600:LiveKit connect wrapper is fineNo functional change.
124634-124637:LiveKit prepareConnection wrapper is fineNo functional change.
124683-124686:SignalConnected handler wrapper is fineNo functional change; comment lines clarify intent.
124957-124960:toggleAudio wrapper is fineAssuming isMicrophoneEnabled is a boolean accessor, this is OK.
124965-124968:toggleVideo wrapper is fineNo functional change.
124975-124978:disconnect wrapper is fineNo functional change.
124999-125004:Device change handler wrapper is fineNo functional change.
125110-125113:toggleTransmitting wrapper is fineNo functional change.
125120-125121:start/stop transmitting and channel change wrappers are fineNo functional changes.
Also applies to: 125126-125127, 125133-125136
128200-128203:SignalR Channel start wrapper is fineNo functional changes.
Core/Resgrid.Model/ActionTypes.cs (1)
50-56:New ActionType 'OnUnit' is well-introduced and consistent with existing enum usage
- Display attribute and XML summary are aligned with existing entries.
- Value 7 fits the contiguous range and matches downstream handling referenced in related files (UI styling, text, weighting).
No issues from a serialization or persistence standpoint given the enum is additive.
Web/Resgrid.Web/Areas/User/Models/Departments/DispatchSettingsView.cs (1)
18-19:Property addition looks good; ensure UI binding and defaults are intentionalAdding
PersonnelOnUnitSetUnitStatusas a bool is consistent with other toggles and will default to false when not posted. Verify the view uses the typical checkbox + hidden input pattern so false binds correctly when unchecked.Core/Resgrid.Model/Services/IDepartmentSettingsService.cs (1)
275-276:Interface addition is fine; ensure implementation handles invalid persisted values safelyAdding
GetPersonnelOnUnitSetUnitStatusAsync(int departmentId)is consistent with other getters. In the implementation, avoidbool.Parseon persisted values (throws on invalid); preferbool.TryParse(setting.Value, out var enabled)with a false fallback.Web/Resgrid.Web.Services/Controllers/v4/PersonnelStaffingController.cs (1)
68-69:Good: Added corrected route alias while preserving the legacy misspellingKeeping both
[HttpGet("GetCurrentStatffing")]and[HttpGet("GetCurrentStaffing")]preserves backward compatibility and fixes discoverability.Core/Resgrid.Localization/Areas/User/Department/Department.en.resx (1)
492-506:English localizations added correctly and match UI usageThe added strings look consistent with the new setting and shift UI. Ensure the neutral resx provides sane defaults (see comment in Department.resx) to avoid blank labels for non-en cultures.
Core/Resgrid.Model/ActionLog.cs (3)
112-116:Action text for OnUnit is sensible; keep an eye on localizationThe new OnUnit text logic is fine and aligns with other cases. If/when we localize ActionLog strings, we’ll want to route this through localization like the UI does.
Would you like this to be localized now or tracked for later?
140-141:Consistent styling for OnUnitReturning "label-success" for OnUnit aligns with Responding and related states. Looks good.
193-194:Weight mapping for OnUnitWeight 2 for OnUnit makes sense alongside OnScene. Good addition.
Web/Resgrid.Web/Areas/User/Controllers/ReportsController.cs (1)
179-182:OnUnit handling: reuse ActionLog text helperUsing l.GetActionText() for ActionTypeId == 7 is correct and keeps logic centralized.
Web/Resgrid.Web/Areas/User/Views/Home/_UserStatusTableRowPartial.cshtml (1)
149-152:OnUnit rendering is consistent with model helpersUsing al.GetActionCss() and al.GetActionText() is the right approach; keeps UI logic DRY and aligned.
Web/Resgrid.Web.Services/Models/v4/Configs/GetConfigResult.cs (1)
34-38:New EventingUrl fieldAdding EventingUrl is straightforward; confirm the controller sets it for all code paths.
If not already done, ensure ConfigController populates EventingUrl for all environments.
Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs (2)
599-603:mandatory publish without BasicReturn handler may drop messages silentlyWith mandatory: true, undeliverable messages are returned via BasicReturn. No handler is attached here, so returns are ignored.
Options:
- Handle BasicReturn on the channel to log and decide on next steps, or
- Set mandatory: false if you expect the same binding to re-route reliably.
Do you want me to wire a BasicReturn handler?
586-606:Connection/channel lifecycle and call-site semantics
A new channel is opened per retry and disposed. That’s OK if RabbitConnection pools the connection, but verify CreateConnection(_clientName) doesn’t open a new connection each time (or dispose it later) to avoid leaks.
RetryQueueItem returns true to indicate “don’t retry the original”; however, call sites handle this inconsistently:
- CallQueueReceived: Nack(requeue: false)
- Others: Ack()
If queues are DLX-enabled, Nack(false) may route to a dead-letter queue while Ack() simply drops it. Suggest standardizing behavior depending on your retry/DLX strategy.
I can normalize the call sites to all Ack() on successful republish. Would you like a follow-up patch?
Web/Resgrid.Web/Areas/User/Views/Department/ShiftSettings.cshtml (1)
12-12:commonLocalizer injection and resource keys verified
- The
@inject IStringLocalizer<Resgrid.Localization.Common> commonLocalizeris declared in Web/Resgrid.Web/Areas/User/Views/_ViewImports.cshtml (line 14).- All view-specific keys (ShiftSettingsHeader, DepartmentSettingsHeader, SaveShiftSettingsText, ShiftSignupSettingsHeader, ShiftSignupsMultipleGroupsHeader) exist in Core/Resgrid.Localization/Areas/User/Department/Department*.resx.
- Common keys (HomeModule, Cancel, Save) are defined in Core/Resgrid.Localization/Common.{en,es}.resx.
No changes required.
Web/Resgrid.Web.Services/Resgrid.Web.Services.xml (2)
5453-5457:EventingUrl doc addition looks good.The new EventingUrl field is documented with a clear description and aligns with the config controller behavior.
5533-5542:AnalyticsApiKey/AnalyticsHost renaming doc looks correct.Docs reflect the telemetry exporter change and new field names. Ensure any old PostHog-specific doc entries (e.g., PostHogHost/PostHogApiKey) have been removed to avoid confusion.
Web/Resgrid.Web.Services/Controllers/v4/ConfigController.cs (1)
71-71:EventingUrl surfaced in API response — LGTMAdding EventingUrl mapped from SystemBehaviorConfig aligns the config shape with eventing needs.
Web/Resgrid.Web/Areas/User/Views/Department/CallSettings.cshtml (1)
18-20:Added Department Settings breadcrumb — LGTMBreadcrumb structure and localization usage are consistent with parallel views.
Web/Resgrid.Web/Areas/User/Views/Department/ModuleSettings.cshtml (1)
15-15:Switch to DepartmentSettingsHeader in breadcrumb — LGTMLocalization source and key are appropriate and consistent across the Department views.
Web/Resgrid.Web/Areas/User/Views/Department/Api.cshtml (1)
14-16:Added Department Settings breadcrumb — LGTMConsistent with other pages and correctly routes to Department/Settings.
Core/Resgrid.Services/CustomStateService.cs (1)
351-351:Default personnel status “On Unit” added — LGTMMatches ActionTypes.OnUnit addition and the new ActionLog behavior. Defaults and styling align with existing statuses.
Web/Resgrid.Web/Areas/User/Views/Department/MappingSettings.cshtml (1)
14-16:Added Department Settings breadcrumb — LGTMNavigation and localization are in line with the broader UI updates.
Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml (1)
14-16:Added Department Settings breadcrumb — LGTMMatches the breadcrumb pattern in related settings views.
Core/Resgrid.Model/Services/IActionLogsService.cs (1)
228-229:LGTM! Clean interface addition for unit-linked status tracking.The new
CreateUnitLinkedStatusmethod follows the established async pattern and naming conventions, properly positioned after the related methods and maintaining backward compatibility with the optionalCancellationTokenparameter.Core/Resgrid.Services/ActionLogsService.cs (2)
411-422:LGTM! Well-implemented unit-linked status creation method.The method correctly creates an
ActionLogwith theOnUnitaction type and properly associates it with the unit state information.
1-12:Clean up duplicate and unused imports.The imports section contains duplicates and an unused import:
Amazon.SimpleEmail.Modelis imported but not used- Multiple System.* imports appear to be duplicated
-using Amazon.SimpleEmail.Model; using Resgrid.Model; using Resgrid.Model.Events; using Resgrid.Model.Providers; using Resgrid.Model.Repositories; using Resgrid.Model.Services; using Resgrid.Providers.Bus; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks;Likely an incorrect or invalid review comment.
Web/Resgrid.Web.Services/Controllers/v4/CallFilesController.cs (1)
214-216:Good defensive programming with explicit base64 validation.The addition of input validation and try-catch for base64 decoding improves robustness. The error handling properly returns BadRequest for invalid input.
Also applies to: 229-236
Web/Resgrid.Web/Areas/User/Controllers/DepartmentController.cs (1)
1645-1645:LGTM! Clean integration of the new PersonnelOnUnitSetUnitStatus setting.The implementation correctly follows the existing pattern for department settings, properly retrieving and persisting the new setting.
Also applies to: 1687-1689
Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs (4)
39-40:LGTM! Dependencies properly injected following established patterns.The new service dependencies are correctly added and follow the existing naming conventions.
Also applies to: 47-48, 55-56
191-191:Good addition of CancellationToken support.The method signature properly supports cancellation with a default parameter value, maintaining backward compatibility while enabling proper async cancellation support.
Also applies to: 196-196, 199-199
273-273:Fixed extraneous semicolon.Good catch on removing the duplicate semicolon from the property assignment.
298-308:VerifyUnit.Namenullability and error-handling in unit-linked status creationWe weren’t able to find any
[Required]attribute or EF configuration enforcing non-null on theNameproperty inCore/Resgrid.Model/Unit, so please confirm:
- Can
unit.Nameever benullat runtime?
If it can, consider coalescing or guarding before calling:- await _actionLogsService.CreateUnitLinkedStatus(role.UserId, DepartmentId, savedState.UnitStateId, unit.Name, cancellationToken);+ await _actionLogsService.CreateUnitLinkedStatus(+ role.UserId,+ DepartmentId,+ savedState.UnitStateId,+ unit.Name ?? string.Empty,+ cancellationToken+ );- What should happen if one of these
CreateUnitLinkedStatuscalls fails?
Should the loop abort and roll back all previous entries (e.g., via a transaction), or continue/ retry on error?File: Web/Resgrid.Web.Services/Controllers/v4/UnitStatusController.cs (lines 298–308)
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (1)
689-690:GatherResponse initialization is safe due to fallback assignment
Theif (gatherResponse == null)block (lines 824–830) guarantees a non-nullGatherinstance before it’s ever used in the loop, covering all cases whereDigitsisn’t “0” or “7.” No null-reference risk remains—no changes required.Likely an incorrect or invalid review comment.
| <dataname="ShiftSettingsHeader"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="SaveShiftSettingsText"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="ShiftSignupSettingsHeader"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="ShiftSignupsMultipleGroupsHeader"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="PersonnelOnUnitSetUnitStatusLabel"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| </root> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
Empty neutral-resx entries may render blank UI for non-English cultures
All five new keys have empty values in the neutral resource. Unless you’re guaranteeing culture fallback to Department.en.resx for all deployments, these may appear blank. Prefer providing default English strings here to ensure sane fallback.
Apply this diff to populate values:
- <data name="ShiftSettingsHeader" xml:space="preserve">- <value />- </data>+ <data name="ShiftSettingsHeader" xml:space="preserve">+ <value>Shift Settings</value>+ </data>- <data name="SaveShiftSettingsText" xml:space="preserve">- <value />- </data>+ <data name="SaveShiftSettingsText" xml:space="preserve">+ <value>Successfully saved Shift Settings.</value>+ </data>- <data name="ShiftSignupSettingsHeader" xml:space="preserve">- <value />- </data>+ <data name="ShiftSignupSettingsHeader" xml:space="preserve">+ <value>Shift Signup Settings</value>+ </data>- <data name="ShiftSignupsMultipleGroupsHeader" xml:space="preserve">- <value />- </data>+ <data name="ShiftSignupsMultipleGroupsHeader" xml:space="preserve">+ <value>Allow Signups For Multiple Groups</value>+ </data>- <data name="PersonnelOnUnitSetUnitStatusLabel" xml:space="preserve">- <value />- </data>+ <data name="PersonnelOnUnitSetUnitStatusLabel" xml:space="preserve">+ <value>Personnel on Unit Set Unit Status</value>+ </data>
🏁 Script executed:
#!/bin/bash# Locate the neutral and English resources for Departmentecho"Searching for Department.resx and Department.en.resx..."find Core/Resgrid.Localization/Areas/User/Department -type f\( -name"Department.resx" -o -name"Department.en.resx"\)echo -e"\nChecking English-specific entries in Department.en.resx if present..."EN_FILE="Core/Resgrid.Localization/Areas/User/Department/Department.en.resx"if [-f"$EN_FILE" ];thenforkeyin ShiftSettingsHeader SaveShiftSettingsText ShiftSignupSettingsHeader ShiftSignupsMultipleGroupsHeader PersonnelOnUnitSetUnitStatusLabel;doecho"Key:$key" rg -n"<data name=\"$key\"" -A1"$EN_FILE"||echo" → Not found"doneelseecho"Department.en.resx not found."fi
Length of output: 2989
🏁 Script executed:
#!/bin/bash# Search for NeutralResourcesLanguage attribute in the codebaserg -n"NeutralResourcesLanguage" -H.
Length of output: 37
Populate default English values in the neutral resource or specify a fallback culture
The neutralDepartment.resx currently has empty<value/> entries for these five keys. Without an assembly-level[NeutralResourcesLanguage("en")] attribute, non-English UI cultures will fall back to this empty file—resulting in blank labels. To resolve:
• Option A: Populate the English defaults in Core/Resgrid.Localization/Areas/User/Department/Department.resx
• Option B: Add[assembly: NeutralResourcesLanguage("en")] (e.g. in your Localization project’s AssemblyInfo.cs) to force fallback to Department.en.resx
Suggested diff for Option A:
--- a/Core/Resgrid.Localization/Areas/User/Department/Department.resx+++ b/Core/Resgrid.Localization/Areas/User/Department/Department.resx@@ -177,7 +177,7 @@ <data name="ShiftSettingsHeader" xml:space="preserve">- <value />+ <value>Shift Settings</value> </data>@@ -180,7 +180,7 @@ <data name="SaveShiftSettingsText" xml:space="preserve">- <value />+ <value>Successfully saved Shift Settings.</value> </data>@@ -183,7 +183,7 @@ <data name="ShiftSignupSettingsHeader" xml:space="preserve">- <value />+ <value>Shift Signup Settings</value> </data>@@ -186,7 +186,7 @@ <data name="ShiftSignupsMultipleGroupsHeader" xml:space="preserve">- <value />+ <value>Allow Signups For Multiple Groups</value> </data>@@ -189,7 +189,7 @@ <data name="PersonnelOnUnitSetUnitStatusLabel" xml:space="preserve">- <value />+ <value>Personnel on Unit Set Unit Status</value> </data>
📝 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.
| <dataname="ShiftSettingsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="SaveShiftSettingsText"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="ShiftSignupSettingsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="ShiftSignupsMultipleGroupsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="PersonnelOnUnitSetUnitStatusLabel"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| </root> | |
| <dataname="ShiftSettingsHeader"xml:space="preserve"> | |
| <value>Shift Settings</value> | |
| </data> | |
| <dataname="SaveShiftSettingsText"xml:space="preserve"> | |
| <value>Successfully saved Shift Settings.</value> | |
| </data> | |
| <dataname="ShiftSignupSettingsHeader"xml:space="preserve"> | |
| <value>Shift Signup Settings</value> | |
| </data> | |
| <dataname="ShiftSignupsMultipleGroupsHeader"xml:space="preserve"> | |
| <value>Allow Signups For Multiple Groups</value> | |
| </data> | |
| <dataname="PersonnelOnUnitSetUnitStatusLabel"xml:space="preserve"> | |
| <value>Personnel on Unit Set Unit Status</value> | |
| </data> | |
| </root> |
🤖 Prompt for AI Agents
In Core/Resgrid.Localization/Areas/User/Department/Department.resx around lines177 to 192, five resource entries (ShiftSettingsHeader, SaveShiftSettingsText,ShiftSignupSettingsHeader, ShiftSignupsMultipleGroupsHeader,PersonnelOnUnitSetUnitStatusLabel) have empty <value/> elements; populate thesewith the English default text in this neutral .resx (e.g., "Shift Settings","Save Shift Settings", "Shift Signup Settings", "Multiple Group Signups", "SetUnit Status for Personnel") OR, if you prefer to keep English inDepartment.en.resx, add an assembly-level NeutralResourcesLanguage("en")attribute (e.g., in the Localization project’s AssemblyInfo.cs) so non-Englishcultures fall back to Department.en.resx; choose one approach and apply itconsistently.Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
| Alter.Table("ActionLogs").AddColumn("UnitStateId").AsInt32().Nullable(); | ||
| Alter.Table("ActionLogs").AddColumn("UnitName").AsString().Nullable(); | ||
| } | ||
| publicoverridevoidDown() | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
Implement Down() and consider explicit length for UnitName for SQL Server parity
- Provide a reversible migration so rollbacks don’t get stuck.
- For SQL Server,
AsString()defaults may vary; set an explicit reasonable length (e.g., 256) to align expectations and avoid unintended nvarchar(max)/length mismatches with PG’s citext usage.
Apply this diff:
- Alter.Table("ActionLogs").AddColumn("UnitStateId").AsInt32().Nullable();- Alter.Table("ActionLogs").AddColumn("UnitName").AsString().Nullable();+ Alter.Table("ActionLogs").AddColumn("UnitStateId").AsInt32().Nullable();+ Alter.Table("ActionLogs").AddColumn("UnitName").AsString(256).Nullable();
And implement Down():
public override void Down() {-+ Delete.Column("UnitName").FromTable("ActionLogs");+ Delete.Column("UnitStateId").FromTable("ActionLogs"); }🏁 Script executed:
#!/bin/bashset -e# Locate the migration file for M0036echo"=== Migration file path ==="rg -l"M0036_AddingUnitStateToActionLogs" -t cs# Show the Up() methodecho -e"\n=== Up() method content ==="rg -n"public override void Up" -A5 -B2 Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs# Show the Down() methodecho -e"\n=== Down() method content ==="rg -n"public override void Down" -A3 -B2 Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs# List other migrations using AsString() without an explicit lengthecho -e"\n=== Other AsString() usages without length ==="rg -n"AsString\\(\\)" -A1 -t cs Providers/Resgrid.Providers.Migrations/Migrations
Length of output: 19647
🏁 Script executed:
#!/bin/bashset -e# Show the full content of the PG version of the migrationecho"=== PG Migration file content ==="sed -n'1,200p' Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs
Length of output: 641
Add reversible Down() methods and specify SQL Server string length
- Implement the
Down()override in both SQL and PG migrations so rollbacks remove the new columns. - In the SQL-Server migration (
Providers/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.cs), set an explicit length onUnitName(e.g. 256) to avoid default NVARCHAR(MAX) and stay in line with PG’s citext expectations. - The PG migration (
Providers/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.cs) correctly usescitext; just add the correspondingDown()cleanup for the lowercase names.
SQL Server migration diff:
public override void Up() {- Alter.Table("ActionLogs").AddColumn("UnitStateId").AsInt32().Nullable();- Alter.Table("ActionLogs").AddColumn("UnitName").AsString().Nullable();+ Alter.Table("ActionLogs").AddColumn("UnitStateId").AsInt32().Nullable();+ Alter.Table("ActionLogs").AddColumn("UnitName").AsString(256).Nullable(); } public override void Down()-{-}+{+ Delete.Column("UnitName").FromTable("ActionLogs");+ Delete.Column("UnitStateId").FromTable("ActionLogs");+}PG migration diff:
public override void Down()-{-}+{+ Delete.Column("unitname").FromTable("actionlogs");+ Delete.Column("unitstateid").FromTable("actionlogs");+}
🤖 Prompt for AI Agents
InProviders/Resgrid.Providers.Migrations/Migrations/M0036_AddingUnitStateToActionLogs.csaround lines 11-16, implement the Down() override to remove the two columnsadded in Up() and change the Up() call for UnitName to use AsString(256) so SQLServer creates NVARCHAR(256) instead of NVARCHAR(MAX); inProviders/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.csadd a Down() override that drops the citext column and the unit state int columnusing the lowercased column names used in the PG Up(), ensuring rollbacks removethe same columns each migration added.| Alter.Table("ActionLogs".ToLower()).AddColumn("UnitStateId".ToLower()).AsInt32().Nullable(); | ||
| Alter.Table("ActionLogs".ToLower()).AddColumn("UnitName".ToLower()).AsCustom("citext").Nullable(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Ensure citext extension exists before adding a citext column.
PostgreSQL requires the citext extension to be installed. Without it, this migration will fail on environments where the extension hasn’t been enabled.
Consider executing CREATE EXTENSION IF NOT EXISTS citext prior to altering the table:
public override void Up() {+// Ensure citext extension is available (idempotent)+Execute.Sql("CREATE EXTENSION IF NOT EXISTS citext;"); Alter.Table("ActionLogs".ToLower()).AddColumn("UnitStateId".ToLower()).AsInt32().Nullable(); Alter.Table("ActionLogs".ToLower()).AddColumn("UnitName".ToLower()).AsCustom("citext").Nullable(); }📝 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.
| Alter.Table("ActionLogs".ToLower()).AddColumn("UnitStateId".ToLower()).AsInt32().Nullable(); | |
| Alter.Table("ActionLogs".ToLower()).AddColumn("UnitName".ToLower()).AsCustom("citext").Nullable(); | |
| } | |
| publicoverridevoidUp() | |
| { | |
| // Ensure citext extension is available (idempotent) | |
| Execute.Sql("CREATE EXTENSION IF NOT EXISTS citext;"); | |
| Alter.Table("ActionLogs".ToLower()) | |
| .AddColumn("UnitStateId".ToLower()).AsInt32().Nullable(); | |
| Alter.Table("ActionLogs".ToLower()) | |
| .AddColumn("UnitName".ToLower()).AsCustom("citext").Nullable(); | |
| } |
🤖 Prompt for AI Agents
InProviders/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.csaround lines 11 to 13 you add a citext column but don’t ensure the citextextension exists; add a statement at the start of the Up() migration to execute"CREATE EXTENSION IF NOT EXISTS citext" (or the FluentMigrator equivalent)before calling Alter.Table(...). Ensure this extension-creation runs prior toadding the citext column so the migration succeeds on databases where citext isnot yet enabled.| publicoverridevoidDown() | ||
| { | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🛠️ Refactor suggestion
Implement Down() to support rollback.
Down() is empty; rollbacks should drop the added columns to keep migrations reversible.
public override void Down() {-+Delete.Column("unitname").FromTable("actionlogs");+Delete.Column("unitstateid").FromTable("actionlogs"); }📝 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.
| publicoverridevoidDown() | |
| { | |
| } | |
| publicoverridevoidDown() | |
| { | |
| Delete.Column("unitname").FromTable("actionlogs"); | |
| Delete.Column("unitstateid").FromTable("actionlogs"); | |
| } |
🤖 Prompt for AI Agents
InProviders/Resgrid.Providers.MigrationsPg/Migrations/M0036_AddingUnitStateToActionLogs.csaround lines 15-18, the Down() method is empty so the migration is notreversible; implement Down() to revert the Up() changes by removing thecolumn(s) and any associated index/constraint added for UnitState on theActionLogs table (e.g., drop the UnitState column and any FK/index created)using the same migration API your project uses so rollbacks restore the schemato its previous state.Uh oh!
There was an error while loading.Please reload this page.
| <divclass="col-md-3"> | ||
| Resgrid, LLC. | ||
| </div> | ||
| <divclass="col-md-6 text-right"> | ||
| <divclass="col-md-3"> | ||
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | ||
| </div> | ||
| <divclass="col-md-3 text-right"> | ||
| <small>©@DateTime.Now.Year</small> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Mirror fixes: localize the new footer string, add a11y, and consider 12-column layout.
- The “Made with … in Lake Tahoe” string should be localized to match the rest of the page.
- Add aria-hidden to the icon and provide a visually hidden label for screen readers.
- Three col-md-3 columns only use 9/12 columns. Consider col-md-4 across all three for balanced layout (if 9/12 isn’t intentional).
Apply this diff:
- <div>- Resgrid, LLC.- </div>- <div>- Made with <i></i> in Lake Tahoe- </div>- <div>+ <div>+ Resgrid, LLC.+ </div>+ <div>+ @localizer["MadeWith"] <span>@localizer["Love"]</span><i aria-hidden="true"></i> @localizer["InLakeTahoe"]+ </div>+ <div> <small>© @DateTime.Now.Year</small> </div>
- If you implement a shared footer partial in Register.cshtml, reuse it here for consistency.
📝 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.
| <divclass="col-md-3"> | |
| Resgrid, LLC. | |
| </div> | |
| <divclass="col-md-6 text-right"> | |
| <divclass="col-md-3"> | |
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | |
| </div> | |
| <divclass="col-md-3 text-right"> | |
| <small>©@DateTime.Now.Year</small> | |
| <divclass="col-md-4"> | |
| Resgrid, LLC. | |
| </div> | |
| <divclass="col-md-4"> | |
| @localizer["MadeWith"] <spanclass="sr-only">@localizer["Love"]</span><iclass="fa fa-heart text-danger"aria-hidden="true"></i>@localizer["InLakeTahoe"] | |
| </div> | |
| <divclass="col-md-4 text-right"> | |
| <small>©@DateTime.Now.Year</small> | |
| </div> |
🤖 Prompt for AI Agents
In Web/Resgrid.Web/Views/Account/LogOn.cshtml around lines 118-125, the footerneeds three fixes: localize the "Made with … in Lake Tahoe" string using theexisting localization mechanism (e.g., resource lookup), add accessibility bymarking the heart icon aria-hidden="true" and include a visually-hidden textlabel for screen readers (e.g., span with sr-only or aria-label) describing thephrase or heart, and adjust layout from three col-md-3 to three col-md-4 forbalanced 12-column layout (unless the 9/12 width is intentional). If a sharedfooter partial was implemented in Register.cshtml, replace this block with thatpartial to reuse the same footer.| <divclass="col-md-3"> | ||
| Resgrid, LLC. | ||
| </div> | ||
| <divclass="col-md-6 text-right"> | ||
| <divclass="col-md-3"> | ||
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | ||
| </div> | ||
| <divclass="col-md-3 text-right"> | ||
| <small>©@DateTime.Now.Year</small> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
Localize the new footer text, add a11y for the icon, and consider using full 12-column layout.
- The new “Made with … in Lake Tahoe” string is hard-coded and not localized, unlike the rest of the page. This regresses i18n. Please move it to the localization resources.
- Add aria-hidden to the heart icon and include a visually hidden “love” for screen readers.
- Three col-md-3 columns only consume 9/12 grid columns. Consider making them col-md-4 to avoid ragged spacing on md+ breakpoints (unless the 9/12 is intentional).
Apply this diff:
- <div>- Resgrid, LLC.- </div>- <div>- Made with <i></i> in Lake Tahoe- </div>- <div>+ <div>+ Resgrid, LLC.+ </div>+ <div>+ @localizer["MadeWith"] <span>@localizer["Love"]</span><i aria-hidden="true"></i> @localizer["InLakeTahoe"]+ </div>+ <div> <small>© @DateTime.Now.Year</small> </div>
- Alternatively, use a single key like@localizer["MadeWithLoveInLakeTahoe"] and place the heart icon as purely decorative after the text.
- Since the same footer appears in LogOn.cshtml, consider extracting this into a shared partial (e.g., _AccountFooter.cshtml) to keep things DRY and consistent across pages.
To confirm Font Awesome is available on these pages (for the heart icon), run:
🏁 Script executed:
#!/bin/bash# Locate style partial(s) and check for Font Awesome referencesfd -a _StylePartial.cshtmlrg -n"font-awesome|fontawesome|fa-" -S
Length of output: 309423
Localize Footer Text, Improve A11y, Use 12-Column Layout & Extract to Partial
- Move the hard-coded “Made with … in Lake Tahoe” string into your localization resources (e.g. Resources.Account.Footer):
- @localizer["MadeWithLoveInLakeTahoe"] (or two keys: “MadeWith” and “InLakeTahoe” plus a “Love” screen-reader key)
- Add
aria-hidden="true"to the<i>and include a visually hidden label:<span>@localizer["Love"]</span>
- Change the three
col-md-3tocol-md-4so they fill the full 12-column grid: <div>Resgrid, LLC.</div><div>Made with <i></i> in Lake Tahoe</div><div>
<div>Resgrid, LLC.</div><div>@localizer["MadeWith"] <span>@localizer["Love"]</span><i aria-hidden="true"></i> @localizer["InLakeTahoe"]</div><div> <small>© @DateTime.Now.Year</small> </div>
- Extract the footer into a shared partial (e.g.
_AccountFooter.cshtml) and include it in both Register.cshtml and LogOn.cshtml to keep layouts DRY. - confirmed: Font Awesome is available via libman under
wwwroot/lib/font-awesome/
📝 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.
| <divclass="col-md-3"> | |
| Resgrid, LLC. | |
| </div> | |
| <divclass="col-md-6 text-right"> | |
| <divclass="col-md-3"> | |
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | |
| </div> | |
| <divclass="col-md-3 text-right"> | |
| <small>©@DateTime.Now.Year</small> | |
| <divclass="col-md-4"> | |
| Resgrid, LLC. | |
| </div> | |
| <divclass="col-md-4"> | |
| @localizer["MadeWith"] <spanclass="sr-only">@localizer["Love"]</span><iclass="fa fa-heart text-danger"aria-hidden="true"></i>@localizer["InLakeTahoe"] | |
| </div> | |
| <divclass="col-md-4 text-right"> | |
| <small>©@DateTime.Now.Year</small> | |
| </div> |
🤖 Prompt for AI Agents
In Web/Resgrid.Web/Views/Account/Register.cshtml around lines 132–139 the footercontains hard-coded text, incorrect column widths, missing a11y markup, andshould be shared across pages; move the “Made with … in Lake Tahoe” string intolocalization (e.g. use @localizer["MadeWithLoveInLakeTahoe"] or separate keyslike "MadeWith", "Love", "InLakeTahoe"), add aria-hidden="true" to the <iclass="fa fa-heart"> icon and include a visually-hidden label for screen readers(e.g. a sr-only span with @localizer["Love"]), change the three col-md-3 classesto col-md-4 so they total 12 columns, and extract this block into a sharedpartial (e.g. Views/Shared/_AccountFooter.cshtml) then include that partial inboth Register.cshtml and LogOn.cshtml so the footer is localized, accessible,and DRY.| /***/ 8355: | ||
| /*!*******************************************************!*\ | ||
| !*** ./node_modules/date-fns/esm/getISOWeek/index.js ***! | ||
| \*******************************************************/ | ||
| /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { | ||
| "use strict"; | ||
| __webpack_require__.r(__webpack_exports__); | ||
| /* harmony export */ __webpack_require__.d(__webpack_exports__, { | ||
| /* harmony export */ "default": () => (/* binding */ getISOWeek) | ||
| /* harmony export */ }); | ||
| /* harmony import */ var _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../toDate/index.js */ 9103); | ||
| /* harmony import */ var _startOfISOWeek_index_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../startOfISOWeek/index.js */ 5556); | ||
| /* harmony import */ var _startOfISOWeekYear_index_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../startOfISOWeekYear/index.js */ 2781); | ||
| /* harmony import */ var _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_lib/requiredArgs/index.js */ 4507); | ||
| var MILLISECONDS_IN_WEEK = 604800000; | ||
| /** | ||
| * @name getISOWeek | ||
| * @category ISO Week Helpers | ||
| * @summary Get the ISO week of the given date. | ||
| * | ||
| * @description | ||
| * Get the ISO week of the given date. | ||
| * | ||
| * ISO week-numbering year: http://en.wikipedia.org/wiki/ISO_week_date | ||
| * | ||
| * @param {Date|Number} date - the given date | ||
| * @returns {Number} the ISO week | ||
| * @throws {TypeError} 1 argument required | ||
| * | ||
| * @example | ||
| * // Which week of the ISO-week numbering year is 2 January 2005? | ||
| * const result = getISOWeek(new Date(2005, 0, 2)) | ||
| * //=> 53 | ||
| */ | ||
| function getISOWeek(dirtyDate) { | ||
| (0,_lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__["default"])(1, arguments); | ||
| var date = (0,_toDate_index_js__WEBPACK_IMPORTED_MODULE_1__["default"])(dirtyDate); | ||
| var diff = (0,_startOfISOWeek_index_js__WEBPACK_IMPORTED_MODULE_2__["default"])(date).getTime() - (0,_startOfISOWeekYear_index_js__WEBPACK_IMPORTED_MODULE_3__["default"])(date).getTime(); | ||
| // Round the number of days to the nearest integer | ||
| // because the number of milliseconds in a week is not constant | ||
| // (e.g. it's different in the week of the daylight saving time clock shift) | ||
| return Math.round(diff / MILLISECONDS_IN_WEEK) + 1; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do not hand-edit bundled vendor.js; update dependencies and rebuild instead
This file appears to have been manually modified to add/alter date-fns modules (e.g., getISOWeek). Compiled vendor assets should be generated by the build toolchain (webpack) from package sources to ensure reproducibility, correct sourcemaps, and avoid future drift. Please revert direct edits to vendor.js, adjust the dependency (e.g., update date-fns), and rebuild.
If the intent was to introduce getISOWeek, add/upgrade date-fns in package.json and re-run the build.
I can propose the package.json changes and expected build steps if you confirm your target date-fns version. Do you want me to open an issue to track removing manual edits from vendor assets?
🤖 Prompt for AI Agents
In Web/Resgrid.Web/wwwroot/js/ng/vendor.js around lines 15353–15402, the bundledvendor file was manually edited to add/alter date-fns modules (e.g.,getISOWeek); revert these manual edits and restore vendor.js from the last cleanbuild artifact or from source control, then update package.json to the desireddate-fns version that includes getISOWeek (or add the correct package), run npminstall to update package-lock.json/yarn.lock, rebuild the frontend bundle usingthe project build script (e.g., npm run build or the project's webpack task),verify the generated vendor.js contains the expected date-fns exports, andcommit only the dependency changes and regenerated artifacts (not hand edits) sofuture builds remain reproducible.| return (0,G_Resgrid_Resgrid_Web_Resgrid_Web_Areas_User_Apps_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function* () { | ||
| const timeout = new Promise(resolve => setTimeout(resolve)); | ||
| const rAF = typeof _global['requestAnimationFrame'] === 'function' ? new Promise(resolve => requestAnimationFrame(() => resolve())) : null; | ||
| yield Promise.race([timeout, rAF]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Bug: Promise.race includes a non-promise (null) resulting in immediate resolution
When requestAnimationFrame is unavailable, rAF is null, and Promise.race([timeout, rAF]) resolves immediately (non-thenables are wrapped by Promise.resolve). This defeats the intended wait behavior.
Apply this diff to safely handle the absence of rAF:
- const rAF = typeof _global['requestAnimationFrame'] === 'function' ? new Promise(resolve => requestAnimationFrame(() => resolve())) : null;- yield Promise.race([timeout, rAF]);+ const rAF = typeof _global['requestAnimationFrame'] === 'function'+ ? new Promise(resolve => requestAnimationFrame(() => resolve()))+ : undefined;+ yield Promise.race([timeout, rAF].filter(Boolean));
Note: Please make the change in the source TS/JS before bundling, not directly in vendor.js.
📝 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.
| return(0,G_Resgrid_Resgrid_Web_Resgrid_Web_Areas_User_Apps_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0__["default"])(function*(){ | |
| consttimeout=newPromise(resolve=>setTimeout(resolve)); | |
| constrAF=typeof_global['requestAnimationFrame']==='function' ?newPromise(resolve=>requestAnimationFrame(()=>resolve())) :null; | |
| yieldPromise.race([timeout,rAF]); | |
| constrAF=typeof_global['requestAnimationFrame']==='function' | |
| ?newPromise(resolve=>requestAnimationFrame(()=>resolve())) | |
| :undefined; | |
| yieldPromise.race([timeout,rAF].filter(Boolean)); |
🤖 Prompt for AI Agents
In Web/Resgrid.Web/wwwroot/js/ng/vendor.js around lines 109667 to 109670 thePromise.race call includes rAF which can be null when requestAnimationFrame isunavailable, causing Promise.race to immediately resolve; update the originalsource TS/JS (not vendor bundle) to only include a thenable: either push rAFinto the race array only if it's truthy, or replace a missing rAF with anon-resolving Promise (e.g. new Promise(()=>{})) so the timeout remainseffective; make the change in the source file and rebuild the bundle.Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 7
🔭 Outside diff range comments (3)
Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (3)
41-43:Add rel="noopener noreferrer" to external links opened in a new tabPrevents window.opener vulnerabilities and improves performance when using.
- @localizer["SignUpTerms1"] Resgrid's <a asp-controller="Public" asp-action="Terms">@localizer["TermsOfUse"]</a> &- <a asp-controller="Public" asp-action="Privacy">@localizer["PrivacyPolicy"]</a>+ @localizer["SignUpTerms1"] Resgrid's <a asp-controller="Public" asp-action="Terms" rel="noopener noreferrer">@localizer["TermsOfUse"]</a> &+ <a asp-controller="Public" asp-action="Privacy" rel="noopener noreferrer">@localizer["PrivacyPolicy"]</a>
26-26:Add alt text to the logo for accessibilityImages used as branding should have an alt description so screen readers convey context.
- <a href="@Resgrid.Config.UrlsConfig.HomeUrl"><img src="~/images/Resgrid_JustText.png" /></a>+ <a href="@Resgrid.Config.UrlsConfig.HomeUrl"><img src="~/images/Resgrid_JustText.png" alt="Resgrid" /></a>
80-80:Fix typo “Resgister” → “Register” in views and resource filesThe key “Resgister” is consistently used in two Razor views and two
.resxfiles—this will render the typo at runtime. Please update the key and its value as follows:• Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (line 80)
Change@localizer["Resgister"]
to@localizer["Register"]• Web/Resgrid.Web/Views/Account/Register.cshtml (line 120)
Change@localizer["Resgister"]
to@localizer["Register"]• Core/Resgrid.Localization/Account/Login.en.resx (≈lines 243–244)
– Rename<data name="Resgister" …>→<data name="Register" …>
– Update<value>Resgister</value>→<value>Register</value>• Core/Resgrid.Localization/Account/Login.es.resx (≈line 243)
– Rename key as above
– Update the<value>to the correct Spanish translation (e.g. “Registrarse”) per your localization guidelinesSuggested diff:
--- before --- after- @localizer["Resgister"] + @localizer["Register"]- <data name="Resgister" xml:space="preserve"> + <data name="Register" xml:space="preserve">- <value>Resgister</value> + <value>Register</value> (or proper Spanish text)
🧹 Nitpick comments (5)
Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (3)
94-96:Optional: match typography with the year usingTo visually balance the left/right columns, wrap the company name in small text like the year column.
- <div>- Resgrid, LLC.- </div>+ <div>+ <small>Resgrid, LLC.</small>+ </div>
101-101:Use HTML entity for the copyright symbolUsing © avoids encoding surprises across locales and editors.
- <small>© @DateTime.Now.Year</small>+ <small>© @DateTime.Now.Year</small>
51-52:Form/JS mismatch: IDs referenced in JS don’t exist; reCAPTCHA line should be guardedThe submit handler targets #registrationForm and #registerButton, but the markup lacks these IDs. Also, reCAPTCHA fields may not exist on this page; guard the code to avoid no-op confusion.
Apply these diffs:
Add IDs to form and button so the JS can bind and disable the button on submit:
- <form role="form" asp-controller="Account" asp-action="CompleteInvite" method="post">+ <form role="form" asp-controller="Account" asp-action="CompleteInvite" method="post">...- <button type="submit">@localizer["Resgister"]</button>+ <button type="submit">@localizer["Resgister"]</button>Guard the reCAPTCHA assignment so it only runs if fields exist:
- $(document).on('submit', '#registrationForm', function () {- var crep = $('#g-recaptcha-response').val();- $('#GoogleReCaptchaResponse').val(crep);+ $(document).on('submit', '#registrationForm', function () {+ var $crep = $('#g-recaptcha-response');+ if ($crep.length) {+ $('#GoogleReCaptchaResponse').val($crep.val());+ }If this page doesn’t use reCAPTCHA, consider removing those lines entirely.
Also applies to: 80-80, 117-120
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (2)
630-637:Polish the IVR prompt phrasing and punctuationMinor grammatical nit: standardize casing and insert commas to aid TTS clarity.
Apply this diff to refine the wording:
- sb.Append($@"Hello {profile.FirstName}, this is the Resgrid Automated Voice System for {department.Name}. Please select from the following options.-To list current active calls press 1,-To list current user statuses press 2,-To list current unit statuses press 3,-To list upcoming Calendar events press 4,-To list upcoming Shifts press 5,-To Set your current status press 6,-To set your current staffing level press 7");+ sb.Append($@"Hello {profile.FirstName}, this is the Resgrid automated voice system for {department.Name}. Please select from the following options.+To list current active calls, press 1.+To list current user statuses, press 2.+To list current unit statuses, press 3.+To list upcoming calendar events, press 4.+To list upcoming shifts, press 5.+To set your current status, press 6.+To set your current staffing level, press 7.");
709-715:Risk of overly long TTS prompts; consider limiting or chunking resultsReading all calls, all users with status/staffing, and all units can produce extremely long prompts, hurting UX and risking Twilio timeouts.
Consider:
- Limit items (e.g., top 10) and end with “For more, use the mobile app or website.”
- Or paginate/chunk and redirect to a follow-up menu.
- For calls/units, summarize counts and only read brief highlights (e.g., counts by priority/status) to reduce verbosity.
Also applies to: 727-737, 748-756
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
Core/Resgrid.Localization/Areas/User/Department/Department.en.resx(2 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.es.resx(2 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.resx(1 hunks)Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs(2 hunks)Web/Resgrid.Web.Services/Controllers/TwilioController.cs(5 hunks)Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs(1 hunks)Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml(3 hunks)Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/LogOn.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/Register.cshtml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
- Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs
- Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml
- Core/Resgrid.Localization/Areas/User/Department/Department.en.resx
- Web/Resgrid.Web/Views/Account/Register.cshtml
- Core/Resgrid.Localization/Areas/User/Department/Department.resx
- Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs
- Web/Resgrid.Web/Views/Account/LogOn.cshtml
- Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs
🧰 Additional context used
🧬 Code Graph Analysis (1)
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (2)
Core/Resgrid.Config/SystemBehaviorConfig.cs (1)
SystemBehaviorConfig(11-204)Core/Resgrid.Model/Call.cs (1)
GetPriorityText(251-276)
🔇 Additional comments (4)
Core/Resgrid.Localization/Areas/User/Department/Department.es.resx (1)
123-134:Don’t remove these dispatch localization keysThe grep results show that all four keys are still referenced in
Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml
and are present in both the neutral (Department.resx) and English (Department.en.resx) resource files. Removing them fromDepartment.es.resxwould break the localization calls.Likely an incorrect or invalid review comment.
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (3)
478-490:Good use of Gather with barge-in and audio playback for call dispatchCreating two Gather prompts with BargeIn and embedding Play + Say is appropriate for improving input responsiveness during audio playback.
537-548:LGTM: Consistent Gather loop for non-audio branchThe repeated Gather prompts with BargeIn and explicit Hangup look correct and consistent with the audio branch.
638-647:LGTM: Main menu gathers properly configuredTwo Gather prompts with BargeIn and an explicit Hangup afterwards are appropriate for the main menu.
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | ||
| <value /> | ||
| </data> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🛠️ Refactor suggestion
Add the missing label key for the new PersonnelOnUnitSetUnitStatus setting
UI relies on both the Label and Help resources; es.resx currently contains only the Help key. Add the Label key to keep parity and avoid fallback to the default language.
Apply this diff to add the missing label adjacent to the help entry:
<data name="DeleteDepartmentSettingsHeader" xml:space="preserve"> <value /> </data>+ <data name="PersonnelOnUnitSetUnitStatusLabel" xml:space="preserve">+ <value />+ </data> <data name="PersonnelOnUnitSetUnitStatusHelp" xml:space="preserve"> <value /> </data>
If you want, I can propose Spanish copy for both Label/Help once the final English strings are confirmed.
📝 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.
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="DeleteDepartmentSettingsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="PersonnelOnUnitSetUnitStatusLabel"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | |
| <value /> | |
| </data> |
🤖 Prompt for AI Agents
In Core/Resgrid.Localization/Areas/User/Department/Department.es.resx aroundlines 393 to 395, the resource file contains only the Help entry forPersonnelOnUnitSetUnitStatus; add a matching Label entry named"PersonnelOnUnitSetUnitStatus" immediately adjacent to the existing Help <data>block so the UI has both Label and Help keys (use an empty <value /> for now oradd the Spanish label text once confirmed).Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
| <divclass="col-md-6 text-center"> | ||
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
🛠️ Refactor suggestion
Localize the new footer sentence and make the heart icon accessible
The hardcoded string isn’t localized, and the icon lacks accessible text. Use the localizer and provide screen-reader text for “love,” while hiding the icon from AT.
Apply this diff:
- <div>- Made with <i></i> in Lake Tahoe- </div>+ <div>+ @localizer["MadeWith"] <span>@localizer["Love"]</span><i aria-hidden="true"></i> @localizer["In"] Lake Tahoe+ </div>
Follow-up:
- Add the resource keys “MadeWith”, “Love”, and “In” to the localization resource used by this view.
📝 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.
| <divclass="col-md-6 text-center"> | |
| Made with <iclass="fa fa-heart text-danger"></i>in Lake Tahoe | |
| </div> | |
| <divclass="col-md-6 text-center"> | |
| @localizer["MadeWith"] <spanclass="sr-only">@localizer["Love"]</span><iclass="fa fa-heart text-danger"aria-hidden="true"></i>@localizer["In"] Lake Tahoe | |
| </div> |
🤖 Prompt for AI Agents
In Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml around lines 97-99, thefooter string is hardcoded and the heart icon lacks accessible text; replace theliteral sentence with localized fragments using the view's IViewLocalizer (e.g.,@Localizer["MadeWith"], @Localizer["In"]) and render the heart icon asdecorative (aria-hidden="true") with a screen-reader-only span containing thelocalized "Love" text (e.g., <span>@Localizer["Love"]</span>),and add the resource keys "MadeWith", "Love", and "In" to the localizationresource used by this view.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (3)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
291-297:Guard against null roles to avoid NREroles can be null; wrap the loop to prevent a runtime exception.
Apply this diff:
-foreach (var role in roles)-{-if (newRoles.Length > 0)-newRoles.Append(", " + role.Name);-else-newRoles.Append(role.Name);-}+if (roles != null)+{+foreach (var role in roles)+{+if (newRoles.Length > 0)+newRoles.Append(", " + role.Name);+else+newRoles.Append(role.Name);+}+}Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (2)
106-128:JavaScript selectors reference non-existent element IDs (form/button)The script binds to
#registrationFormand disables#registerButtonon submit, but:
- The
<form>at Line 51 has no id.- The submit
<button>at Line 80 has no id.Result: no handler is attached; the disable-on-submit safeguard never runs.
Add stable IDs to match the selectors (or update the selectors). Suggested fix:
@@- <form role="form" asp-controller="Account" asp-action="CompleteInvite" method="post">+ <form role="form" asp-controller="Account" asp-action="CompleteInvite" method="post">@@- <button type="submit">@localizer["Resgister"]</button>+ <button type="submit">@localizer["Resgister"]</button>If you adopt the typo fix above, also update the button label accordingly.
80-80:Fix typo in localization key “Resgister” → “Register”Update resource entries and cshtml references:
Core/Resgrid.Localization/Account/Login.en.resx
– <data name="Resgister" xml:space="preserve">– <value>Resgister</value>+ <data name="Register" xml:space="preserve">+ <value>Register</value>Core/Resgrid.Localization/Account/Login.es.resx
– <data name="Resgister" xml:space="preserve">– <value>Registrarse</value>+ <data name="Register" xml:space="preserve">+ <value>Registrarse</value>Web/Resgrid.Web/Views/Account/Register.cshtml
–<button type="submit">@localizer["Resgister"]</button>+<button type="submit">@localizer["Register"]</button>Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml
–<button type="submit">@localizer["Resgister"]</button>+<button type="submit">@localizer["Register"]</button>
♻️ Duplicate comments (1)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
484-497:Add OnUnit to ActionTypes.ToCss() for consistency with new helper/stateExtend the local mapping so callers using CssExtensions also get the correct class for OnUnit.
Apply this diff:
switch (type) { case ActionTypes.StandingBy: return ""; case ActionTypes.NotResponding: return "label-important"; case ActionTypes.Responding: return "label-success"; case ActionTypes.OnScene: return "label-inverse"; case ActionTypes.AvailableStation: return ""; case ActionTypes.RespondingToStation: return "label-success"; case ActionTypes.RespondingToScene: return "label-success";+case ActionTypes.OnUnit: return "label-success"; default: return ""; }
🧹 Nitpick comments (6)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (2)
249-253:Consider capturing coordinates for OnUnit (if present)Other “responding” states persist GeoLocationData to map pins; if OnUnit actions can include coordinates, mirror that behavior for parity.
Apply this diff if OnUnit may include GeoLocationData:
- statusCss = actionLog.GetActionCss();- status = actionLog.GetActionText();+ statusCss = actionLog.GetActionCss();+ status = actionLog.GetActionText();+ if (!String.IsNullOrWhiteSpace(actionLog.GeoLocationData))+ {+ var cords = actionLog.GetCoordinates();+ latitude = cords.Latitude;+ longitude = cords.Longitude;+ }
299-317:Set CallNumber on the returned view model (currently unused property)CallNumber is a property but isn’t populated. If intended for UI, assign it during initialization.
Apply this diff:
-DestinationType = destinationType+DestinationType = destinationType,+CallNumber = callNumberWeb/Resgrid.Web.Services/Controllers/TwilioController.cs (4)
689-691:Unnecessary variable initializationThe
gatherResponsevariable is initialized tonullon line 690 but is conditionally assigned later. Consider initializing it only where needed to improve clarity.StringBuilder sb = new StringBuilder();-Gather gatherResponse = null;
871-879:Consider consolidating error handling logicThe error handling for invalid digits and empty input could be consolidated since they both redirect to the same endpoint with similar messages.
-else-{- response.Say("Invalid status selection, goodbye.").Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET");-}} else {- response.Say("No status selection made, goodbye.").Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET");+ var message = String.IsNullOrWhiteSpace(twilioRequest.Digits)+ ? "No status selection made, goodbye."+ : "Invalid status selection, goodbye.";+ response.Say(message).Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET"); }
911-919:Apply same error handling consolidationSimilar to the status endpoint, the error handling here could be consolidated.
-else-{- response.Say("Invalid staffing selection, goodbye.").Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET");-}} else {- response.Say("No staffing selection made, goodbye.").Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET");+ var message = String.IsNullOrWhiteSpace(twilioRequest.Digits)+ ? "No staffing selection made, goodbye."+ : "Invalid staffing selection, goodbye.";+ response.Say(message).Redirect(new Uri($"{Config.SystemBehaviorConfig.ResgridApiBaseUrl}/api/Twilio/InboundVoice"), "GET"); }
930-936:Consider proper namespace for TwilioMessage classThe
TwilioMessageclass is defined at the bottom of the controller file. Consider moving it to a separate file in the Models namespace for better organization and maintainability.Would you like me to help create a separate model file for the
TwilioMessageclass to improve code organization?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
Core/Resgrid.Localization/Areas/User/Department/Department.en.resx(2 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.es.resx(2 hunks)Core/Resgrid.Localization/Areas/User/Department/Department.resx(1 hunks)Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs(2 hunks)Web/Resgrid.Web.Services/Controllers/TwilioController.cs(5 hunks)Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs(1 hunks)Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs(1 hunks)Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml(3 hunks)Web/Resgrid.Web/Areas/User/Views/Department/ShiftSettings.cshtml(3 hunks)Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/LogOn.cshtml(1 hunks)Web/Resgrid.Web/Views/Account/Register.cshtml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
- Web/Resgrid.Web/Areas/User/Views/Department/ShiftSettings.cshtml
- Web/Resgrid.Web/Areas/User/Models/Home/BigBoardModel.cs
- Web/Resgrid.Web/Views/Account/LogOn.cshtml
- Core/Resgrid.Localization/Areas/User/Department/Department.resx
- Web/Resgrid.Web/Views/Account/Register.cshtml
- Providers/Resgrid.Providers.Bus.Rabbit/RabbitInboundQueueProvider.cs
- Web/Resgrid.Web/Areas/User/Views/Department/DispatchSettings.cshtml
- Core/Resgrid.Localization/Areas/User/Department/Department.en.resx
🧰 Additional context used
🧬 Code Graph Analysis (2)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
Core/Resgrid.Model/ActionLog.cs (2)
GetActionCss(122-145)GetActionText(94-120)
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (1)
Core/Resgrid.Config/SystemBehaviorConfig.cs (1)
SystemBehaviorConfig(11-204)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (8)
Web/Resgrid.Web.Services/Models/v3/BigBoard/BigBoardModel.cs (1)
249-253:Good fix: OnUnit now uses centralized helpersUsing actionLog.GetActionCss() and GetActionText() keeps styling/text consistent across the app and aligns with recent model updates.
Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (1)
94-103:Three-column footer restructure reads well and improves balanceThe new 3-column layout with left brand, centered message, and right © year is a clean improvement.
Web/Resgrid.Web.Services/Controllers/TwilioController.cs (6)
478-488:Good improvement to the Gather flowThe refactored approach with the loop creating two Gather blocks, each containing both the Say and Play elements, provides better user experience with BargeIn support and repeated prompts.
537-547:Consistent implementation of dual Gather promptsThe same pattern is correctly applied here for voice calls without attachments, maintaining consistency across the voice call flows.
638-648:Well-structured main menu implementationThe dual Gather implementation for the main menu with BargeIn enabled provides a better interactive experience, allowing users to interrupt and make selections immediately.
781-822:Status and staffing menu generation looks goodThe dynamic menu generation for status (digit 6) and staffing (digit 7) options is well-implemented, correctly routing to the appropriate action endpoints.
849-887:Good error handling in status endpointThe new
InboundVoiceActionStatusendpoint properly validates input and provides appropriate feedback for invalid selections. The implementation correctly handles edge cases.
889-927:Consistent implementation for staffing endpointThe
InboundVoiceActionStaffingendpoint follows the same pattern as the status endpoint with proper validation and error handling.
| <dataname="GroupDispatchSettingsHeader"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="UnitDispatchSettingsHeader"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="UnitDispatchAlsoDispatchToAssignedPersonnelLabel"xml:space="preserve"> | ||
| <value /> | ||
| </data> | ||
| <dataname="UnitDispatchAlsoDispatchToGroupLabel"xml:space="preserve"> | ||
| <value /> | ||
| </data> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
Empty Spanish values will render blank UI; remove to enable fallback or populate with text
Including keys with<value /> in a localized .resx overrides fallback to the neutral/English resource. These four entries will show as empty strings in the Spanish UI. Either remove them (so ResourceManager falls back to English) or populate with text (Spanish or English placeholders).
Also, the PR summary claims these entries were later removed in this file, but they are still present here. Please reconcile to avoid drift.
Option A — remove to enable fallback:
- <data name="GroupDispatchSettingsHeader" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchSettingsHeader" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchAlsoDispatchToAssignedPersonnelLabel" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchAlsoDispatchToGroupLabel" xml:space="preserve">- <value />- </data>
Option B — populate with English placeholders to avoid blanks (until Spanish translations are ready):
<data name="GroupDispatchSettingsHeader" xml:space="preserve">- <value />+ <value>Group Dispatch Settings</value> </data> <data name="UnitDispatchSettingsHeader" xml:space="preserve">- <value />+ <value>Unit Dispatch Settings</value> </data> <data name="UnitDispatchAlsoDispatchToAssignedPersonnelLabel" xml:space="preserve">- <value />+ <value>Also dispatch to assigned personnel</value> </data> <data name="UnitDispatchAlsoDispatchToGroupLabel" xml:space="preserve">- <value />+ <value>Also dispatch to group</value> </data>
🏁 Script executed:
#!/bin/bashgrep -n -E"GroupDispatchSettingsHeader|UnitDispatchSettingsHeader|UnitDispatchAlsoDispatchToAssignedPersonnelLabel|UnitDispatchAlsoDispatchToGroupLabel" Core/Resgrid.Localization/Areas/User/Department/Department.es.resx||echo"No matches found"
Length of output: 527
Empty Spanish entries in Department.es.resx will render blank UI—please remove or populate
The following keys inCore/Resgrid.Localization/Areas/User/Department/Department.es.resx still have empty<value/>, which overrides fallback to English and leads to blank labels in the Spanish UI. Additionally, the PR summary states these were removed, but they remain in this file. Please reconcile and then either:
• Remove them so ResourceManager falls back to English
• Populate them with placeholder text (Spanish or English) until translations are available
Affected locations:
- Department.es.resx: lines 123, 126, 129, 132
Option A — remove entries to enable fallback:
- <data name="GroupDispatchSettingsHeader" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchSettingsHeader" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchAlsoDispatchToAssignedPersonnelLabel" xml:space="preserve">- <value />- </data>- <data name="UnitDispatchAlsoDispatchToGroupLabel" xml:space="preserve">- <value />- </data>
Option B — add English placeholders until Spanish copy is ready:
<data name="GroupDispatchSettingsHeader" xml:space="preserve">- <value />+ <value>Group Dispatch Settings</value> </data> <data name="UnitDispatchSettingsHeader" xml:space="preserve">- <value />+ <value>Unit Dispatch Settings</value> </data> <data name="UnitDispatchAlsoDispatchToAssignedPersonnelLabel" xml:space="preserve">- <value />+ <value>Also dispatch to assigned personnel</value> </data> <data name="UnitDispatchAlsoDispatchToGroupLabel" xml:space="preserve">- <value />+ <value>Also dispatch to group</value> </data>
📝 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.
| <dataname="GroupDispatchSettingsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="UnitDispatchSettingsHeader"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="UnitDispatchAlsoDispatchToAssignedPersonnelLabel"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="UnitDispatchAlsoDispatchToGroupLabel"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="GroupDispatchSettingsHeader"xml:space="preserve"> | |
| <value>Group Dispatch Settings</value> | |
| </data> | |
| <dataname="UnitDispatchSettingsHeader"xml:space="preserve"> | |
| <value>Unit Dispatch Settings</value> | |
| </data> | |
| <dataname="UnitDispatchAlsoDispatchToAssignedPersonnelLabel"xml:space="preserve"> | |
| <value>Also dispatch to assigned personnel</value> | |
| </data> | |
| <dataname="UnitDispatchAlsoDispatchToGroupLabel"xml:space="preserve"> | |
| <value>Also dispatch to group</value> | |
| </data> |
🤖 Prompt for AI Agents
In Core/Resgrid.Localization/Areas/User/Department/Department.es.resx aroundlines 123-134 the keys GroupDispatchSettingsHeader, UnitDispatchSettingsHeader,UnitDispatchAlsoDispatchToAssignedPersonnelLabel andUnitDispatchAlsoDispatchToGroupLabel have empty <value/> entries which overridefallback and produce blank UI; either remove these <data> entries so theResourceManager falls back to the default English resources, or populate each<value> with a temporary placeholder (e.g., English text) until proper Spanishtranslations are available, and then commit the file reflecting the chosenoption.| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | ||
| <value /> | ||
| </data> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
“PersonnelOnUnitSetUnitStatusHelp” is empty; will display as blank in Spanish
Same issue: an empty localized value prevents fallback to neutral/English. Either remove this entry to inherit the English string or populate it.
Option A — remove to enable fallback:
- <data name="PersonnelOnUnitSetUnitStatusHelp" xml:space="preserve">- <value />- </data>
Option B — populate with the English help text (from en.resx) for now:
<data name="PersonnelOnUnitSetUnitStatusHelp" xml:space="preserve">- <value />+ <value>When a unit submits a status and users are setup on roles, the users status will be set to On Unit.</value> </data>
If you prefer, I can also add the Spanish translation in a follow-up, or add a<comment> marker to flag it for translators.
🏁 Script executed:
#!/bin/bash# Search for the key across all .resx files to verify English fallback valuerg -n'PersonnelOnUnitSetUnitStatusHelp' -n --glob'*.resx'
Length of output: 479
🏁 Script executed:
#!/bin/bash# Extract the English help text for the key from Department.en.resxrg -A2 -n'PersonnelOnUnitSetUnitStatusHelp' --glob'*.resx' Core/Resgrid.Localization/Areas/User/Department/Department.en.resx
Length of output: 338
Empty Spanish localization entry prevents fallback
The<value /> in Department.es.resx will return an empty string instead of falling back to the default (English) text. Please either remove the Spanish entry or supply at least a placeholder so users don’t see a blank field.
• File: Core/Resgrid.Localization/Areas/User/Department/Department.es.resx (lines 393–395)
• Reference English text in Core/Resgrid.Localization/Areas/User/Department/Department.en.resx (line 508)
Option A — remove the empty entry to enable fallback:
- <data name="PersonnelOnUnitSetUnitStatusHelp" xml:space="preserve">- <value />- </data>
Option B — add the English text as a temporary placeholder:
<data name="PersonnelOnUnitSetUnitStatusHelp" xml:space="preserve">- <value />+ <value>When a unit submits a status and users are setup on roles, the users status will be set to On Unit.</value> </data>
If you prefer, add a<comment> marker or follow up with the actual Spanish translation later.
📝 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.
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | |
| <value /> | |
| </data> |
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | |
| <value /> | |
| </data> | |
| <dataname="PersonnelOnUnitSetUnitStatusHelp"xml:space="preserve"> | |
| <value>When a unit submits a status and users are setup on roles, the users status will be set to On Unit.</value> | |
| </data> |
🤖 Prompt for AI Agents
In Core/Resgrid.Localization/Areas/User/Department/Department.es.resx aroundlines 393–395 the PersonnelOnUnitSetUnitStatusHelp entry has an empty <value/>,which returns an empty string instead of falling back to English; fix by eitherremoving this Spanish <data> element so the resource system falls back toCore/Resgrid.Localization/Areas/User/Department/Department.en.resx (see line 508for the English text), or populate the <value> with a placeholder (e.g., theEnglish text or a <comment> marker) until a proper Spanish translation isavailable.Uh oh!
There was an error while loading.Please reload this page.
| <divclass="col-md-6 text-center"> | ||
| Made with <iclass="fa fa-heart text-danger"></i> in Lake Tahoe | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
💡 Verification agent
🧩 Analysis chain
Localize and make the “Made with ♥” message accessible
- The phrase is hardcoded and not localized, unlike the rest of the page.
- Screen readers won’t announce “love” because the heart is an icon; they’ll read “Made with in Lake Tahoe”.
Consider localizing the text and ensuring SR users hear a full sentence. Minimal change below keeps the icon decorative and adds SR-only “love”:
- <div>- Made with <i></i> in Lake Tahoe- </div>+ <div>+ @localizer["MadeWith"] <i aria-hidden="true"></i><span>@localizer["Love"]</span> @localizer["In"] Lake Tahoe+ </div>
Alternatively, prefer a single localized string so translators control word order: e.g.,@localizer["MadeWithLoveIn", "Lake Tahoe"] and keep the icon purely decorative after/before the text.
To verify whether the localization keys already exist (or where to add them), run:
🏁 Script executed:
#!/bin/bash# Search for existing localization keys or similar phrases across the reporg -n --hidden --glob'!**/bin/**' --glob'!**/obj/**'$'MadeWith|Love|In|MadeWithLoveIn|Made with|Lake Tahoe'# Inspect localization resources (resx/json)fd -a -e resx -e json| xargs -I{} sh -c'echo "### {}"; rg -n $'\''MadeWith|Love|In|MadeWithLoveIn|Lake Tahoe'\'' "{}" || true'
Length of output: 281011
Add new localization entries and update for accessibility
No existing resource keys (MadeWith, Love, In, MadeWithLoveIn, “Lake Tahoe”) were found in any .resx/.json files, so you’ll need to add them. Then update the view to use localized text and expose “love” to screen readers:
• Create localization entries (CommonResources.resx or similar):
– Key=”MadeWith” Value=”Made with”
– Key=”Love” Value=”love”
– Key=”In” Value=”in”
– (Or a combined key) Key=”MadeWithLoveIn” Value=”Made with love in {0}”
• Update Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml (around line 97):
- <div>- Made with <i></i> in Lake Tahoe- </div>+ <div>+ @localizer["MadeWith"] <i aria-hidden="true"></i><span>@localizer["Love"]</span> @localizer["In"] Lake Tahoe+ </div>
• Alternatively, if you add a single key (MadeWithLoveIn), you can write:
@localizer["MadeWithLoveIn","Lake Tahoe"]<i class="fa fa-heart text-danger"aria-hidden="true"></i>
🤖 Prompt for AI Agents
In Web/Resgrid.Web/Views/Account/CompleteInvite.cshtml around lines 97-99, thestatic footer text "Made with <heart> in Lake Tahoe" lacks localization andaccessibility for the heart icon; add resource entries (e.g.,CommonResources.resx or equivalent) for MadeWith ("Made with"), Love ("love"),In ("in") or a single composite key MadeWithLoveIn ("Made with love in {0}") andupdate the view to use the localizer to render the localized string with "LakeTahoe" as the parameter, render the heart icon with aria-hidden="true" andinclude the word "love" for screen readers (e.g., a visually hidden span oraria-label) so the phrase is localized and accessible.Approve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This PR is approved.
3fac2b4 intomasterUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes