Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ jobs:
if (pr) {
const body = (pr.body || '')
.replace(/##\s*Summary by CodeRabbit[\s\S]*/i, '')
.replace(/Pull Request Description/gi, 'Summary')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restrict the replacement to the section heading.

Line 146 rewrites every occurrence in the PR body, including prose and code blocks. Match only the intended Markdown heading so release-note content is preserved.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/dotnet.yml at line 146, Update the replacement in the
workflow’s PR-body transformation to match only the Markdown section heading
“Pull Request Description,” including its heading syntax, rather than every
case-insensitive occurrence. Preserve prose and code-block content while still
renaming the intended heading to “Summary.”

.trim() || 'No release notes provided.';
fs.writeFileSync('release_notes.md', body);
} else {
Expand Down
4 changes: 1 addition & 3 deletions Core/Resgrid.Model/CommandDefinitionRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ public class CommandDefinitionRole : IEntity

public virtual ICollection<CommandDefinitionRoleUnitType> RequiredUnitTypes { get; set; }

public virtual ICollection<CommandDefinitionRoleCert> RequiredCerts { get; set; }

public virtual ICollection<CommandDefinitionRolePersonnelRole> RequiredRoles { get; set; }

[NotMapped]
Expand All @@ -70,6 +68,6 @@ public object IdValue
public int IdType => 0;

[NotMapped]
public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName", "Command", "RequiredUnitTypes", "RequiredCerts", "RequiredRoles" };
public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName", "Command", "RequiredUnitTypes", "RequiredRoles" };
}
}
48 changes: 0 additions & 48 deletions Core/Resgrid.Model/CommandDefinitionRoleCert.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Resgrid.Model
{
/// <summary>
/// Thrown when a resource assignment (or move) targets a command board lane whose source template
/// role has <c>ForceRequirements</c> enabled and the resource does not satisfy the lane's required
/// unit types / personnel roles. The message is safe to surface to the caller.
/// </summary>
public class CommandRequirementsNotMetException : Exception
{
public CommandRequirementsNotMetException(string message) : base(message)
{
}
}
}
10 changes: 10 additions & 0 deletions Core/Resgrid.Model/IncidentCommand/CommandStructureNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ public class ResourceAssignment : IEntity, IChangeTracked

public DateTime? ReleasedOn { get; set; }

/// <summary>
/// True when the resource does not satisfy the target lane's template requirements but the lane
/// does NOT force them (advisory). The IC app renders this as a warning outline on the resource
/// chip. Recomputed on every assign/move; false when compliant or when requirements don't apply.
/// </summary>
public bool RequirementsWarning { get; set; }

/// <summary>Human-readable reason for <see cref="RequirementsWarning"/>; null when no warning.</summary>
public string RequirementsWarningMessage { get; set; }

/// <summary>Change cursor for offline delta sync + last-write-wins; stamped on every write.</summary>
public DateTime? ModifiedOn { get; set; }

Expand Down
10 changes: 9 additions & 1 deletion Core/Resgrid.Model/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ public class Message : IEntity
[ProtoMember(14)]
public virtual ICollection<MessageRecipient> MessageRecipients { get; set; }

/// <summary>
/// Optional subtitle for push/inbox notifications; not persisted. When set, delivery
/// uses this instead of the generic "Msg from ..." subtitle.
/// </summary>
[NotMapped]
[JsonIgnore]
public string PushSubTitle { get; set; }

[NotMapped]
[JsonIgnore]
public object IdValue
Expand All @@ -86,7 +94,7 @@ public object IdValue
public int IdType => 0;

[NotMapped]
public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName", "SendingUser", "ReceivingUser", "MessageRecipients" };
public IEnumerable<string> IgnoredProperties => new string[] { "IdValue", "IdType", "TableName", "IdName", "SendingUser", "ReceivingUser", "MessageRecipients", "PushSubTitle" };

public List<string> GetRecipients()
{
Expand Down
3 changes: 2 additions & 1 deletion Core/Resgrid.Model/MessageTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public enum MessageTypes
{
Normal = 0,
Callback = 1,
Poll = 2
Poll = 2,
WeatherAlert = 3
}
}
50 changes: 49 additions & 1 deletion Core/Resgrid.Model/Repositories/ICommandDefinitionRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Resgrid.Model.Repositories
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Resgrid.Model.Repositories
{
/// <summary>
/// Interface ICommandDefinitionRepository
Expand All @@ -8,4 +11,49 @@
public interface ICommandDefinitionRepository: IRepository<CommandDefinition>
{
}

/// <summary>
/// Repository for the lanes/assignments (<see cref="CommandDefinitionRole"/>) of a command definition template.
/// </summary>
public interface ICommandDefinitionRoleRepository : IRepository<CommandDefinitionRole>
{
/// <summary>
/// Gets all lanes/assignments for a command definition template.
/// </summary>
/// <param name="commandDefinitionId">The command definition identifier.</param>
/// <returns>Task&lt;IEnumerable&lt;CommandDefinitionRole&gt;&gt;.</returns>
Task<IEnumerable<CommandDefinitionRole>> GetRolesByCommandDefinitionIdAsync(int commandDefinitionId);
}

/// <summary>
/// Repository for a lane's required unit types (<see cref="CommandDefinitionRoleUnitType"/>).
/// </summary>
public interface ICommandDefinitionRoleUnitTypeRepository : IRepository<CommandDefinitionRoleUnitType>
{
/// <summary>
/// Gets the required unit types for every lane of a command definition template.
/// </summary>
Task<IEnumerable<CommandDefinitionRoleUnitType>> GetUnitTypesByCommandDefinitionIdAsync(int commandDefinitionId);

/// <summary>
/// Gets the required unit types for a single lane.
/// </summary>
Task<IEnumerable<CommandDefinitionRoleUnitType>> GetUnitTypesByRoleIdAsync(int commandDefinitionRoleId);
}

/// <summary>
/// Repository for a lane's required personnel roles (<see cref="CommandDefinitionRolePersonnelRole"/>).
/// </summary>
public interface ICommandDefinitionRolePersonnelRoleRepository : IRepository<CommandDefinitionRolePersonnelRole>
{
/// <summary>
/// Gets the required personnel roles for every lane of a command definition template.
/// </summary>
Task<IEnumerable<CommandDefinitionRolePersonnelRole>> GetPersonnelRolesByCommandDefinitionIdAsync(int commandDefinitionId);

/// <summary>
/// Gets the required personnel roles for a single lane.
/// </summary>
Task<IEnumerable<CommandDefinitionRolePersonnelRole>> GetPersonnelRolesByRoleIdAsync(int commandDefinitionRoleId);
}
}
8 changes: 8 additions & 0 deletions Core/Resgrid.Model/Services/ICommandsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public interface ICommandsService
/// <returns>Task&lt;CommandDefinition&gt;.</returns>
Task<CommandDefinition> GetCommandForCallTypeAsync(int departmentId, int? callTypeId);

/// <summary>
/// Gets a single lane (role) with its requirement sets (RequiredUnitTypes/RequiredRoles) hydrated.
/// Used to enforce lane requirements when assigning resources on the live command board.
/// </summary>
/// <param name="commandDefinitionRoleId">The lane (command definition role) identifier.</param>
/// <returns>Task&lt;CommandDefinitionRole&gt;.</returns>
Task<CommandDefinitionRole> GetRoleWithRequirementsAsync(int commandDefinitionRoleId);

Comment on lines +39 to +46

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add a bypassCache parameter to GetRoleWithRequirementsAsync.

Per coding guidelines, service methods should expose a bypassCache (default false) parameter so callers can force fresh data. This method drives live enforcement/warning decisions on every resource assign/move (IncidentCommandService.EvaluateNodeRequirementsAsync); without a bypass option, a lane-requirement edit could be enforced against stale cached data until the cache expires. As per coding guidelines: "Service methods should include a bypassCache parameter (default: false) to allow callers to skip cache retrieval when fresh data is required."

♻️ Suggested signature change
-		Task<CommandDefinitionRole> GetRoleWithRequirementsAsync(int commandDefinitionRoleId);
+		Task<CommandDefinitionRole> GetRoleWithRequirementsAsync(int commandDefinitionRoleId, bool bypassCache = false);
📝 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.

Suggested change
/// <summary>
/// Gets a single lane (role) with its requirement sets (RequiredUnitTypes/RequiredRoles) hydrated.
/// Used to enforce lane requirements when assigning resources on the live command board.
/// </summary>
/// <param name="commandDefinitionRoleId">The lane (command definition role) identifier.</param>
/// <returns>Task&lt;CommandDefinitionRole&gt;.</returns>
Task<CommandDefinitionRole> GetRoleWithRequirementsAsync(int commandDefinitionRoleId);
/// <summary>
/// Gets a single lane (role) with its requirement sets (RequiredUnitTypes/RequiredRoles) hydrated.
/// Used to enforce lane requirements when assigning resources on the live command board.
/// </summary>
/// <param name="commandDefinitionRoleId">The lane (command definition role) identifier.</param>
/// <returns>Task&lt;CommandDefinitionRole&gt;.</returns>
Task<CommandDefinitionRole> GetRoleWithRequirementsAsync(int commandDefinitionRoleId, bool bypassCache = false);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/Resgrid.Model/Services/ICommandsService.cs` around lines 39 - 46, Update
ICommandsService.GetRoleWithRequirementsAsync to accept an optional bool
bypassCache parameter defaulting to false, and propagate this parameter through
its implementation and callers, especially
IncidentCommandService.EvaluateNodeRequirementsAsync, so live requirement
evaluation can request fresh data when needed.

Source: Coding guidelines

/// <summary>
/// Deletes the specified command definition.
/// </summary>
Expand Down
Loading
Loading