fix(ui): carry SourceNode on SiteCallDetail + NotificationDetail records
The Site Calls and Notifications detail modals were reading SourceNode from the summary record (d.SourceNode) while every other field read from the detail record (det.X). The pattern works today because the modal always opens via a row click that pre-loads the summary, but a future drill-in from a deep link or refresh path could leave the summary stale or null and the field would render blank or wrong. Add SourceNode to both detail records, project it through the actor's ToDetail mapping, and switch the razor markup to read det.SourceNode. Now the modal binds uniformly to the detail record across all fields.
This commit is contained in:
@@ -266,7 +266,7 @@
|
||||
<dd class="col-sm-9">@SiteName(d.SourceSiteId)</dd>
|
||||
|
||||
<dt class="col-sm-3">Source node</dt>
|
||||
<dd class="col-sm-9">@(string.IsNullOrEmpty(d.SourceNode) ? "—" : d.SourceNode)</dd>
|
||||
<dd class="col-sm-9">@(string.IsNullOrEmpty(_detail?.SourceNode) ? "—" : _detail.SourceNode)</dd>
|
||||
|
||||
<dt class="col-sm-3">Source instance</dt>
|
||||
<dd class="col-sm-9">@(string.IsNullOrEmpty(d.SourceInstanceId) ? "—" : d.SourceInstanceId)</dd>
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
<dd class="col-sm-9">@SiteName(det.SourceSite)</dd>
|
||||
|
||||
<dt class="col-sm-3">Source node</dt>
|
||||
<dd class="col-sm-9">@(string.IsNullOrEmpty(d.SourceNode) ? "—" : d.SourceNode)</dd>
|
||||
<dd class="col-sm-9">@(string.IsNullOrEmpty(det.SourceNode) ? "—" : det.SourceNode)</dd>
|
||||
|
||||
<dt class="col-sm-3">Channel</dt>
|
||||
<dd class="col-sm-9">@det.Channel</dd>
|
||||
|
||||
@@ -119,7 +119,8 @@ public sealed record SiteCallDetail(
|
||||
DateTime CreatedAtUtc,
|
||||
DateTime UpdatedAtUtc,
|
||||
DateTime? TerminalAtUtc,
|
||||
DateTime IngestedAtUtc);
|
||||
DateTime IngestedAtUtc,
|
||||
string? SourceNode = null);
|
||||
|
||||
/// <summary>
|
||||
/// Site Calls UI -> Central: request for the global <c>SiteCalls</c> KPI summary.
|
||||
|
||||
@@ -119,7 +119,8 @@ public record NotificationDetail(
|
||||
DateTimeOffset CreatedAt,
|
||||
DateTimeOffset? LastAttemptAt,
|
||||
DateTimeOffset? NextAttemptAt,
|
||||
DateTimeOffset? DeliveredAt);
|
||||
DateTimeOffset? DeliveredAt,
|
||||
string? SourceNode = null);
|
||||
|
||||
/// <summary>
|
||||
/// Outbox UI -> Central: request for the notification outbox KPI summary.
|
||||
|
||||
@@ -749,7 +749,8 @@ public class NotificationOutboxActor : ReceiveActor, IWithTimers
|
||||
notification.CreatedAt,
|
||||
notification.LastAttemptAt,
|
||||
notification.NextAttemptAt,
|
||||
notification.DeliveredAt);
|
||||
notification.DeliveredAt,
|
||||
notification.SourceNode);
|
||||
|
||||
return new NotificationDetailResponse(
|
||||
request.CorrelationId, Success: true, ErrorMessage: null, detail);
|
||||
|
||||
@@ -652,7 +652,8 @@ public class SiteCallAuditActor : ReceiveActor
|
||||
CreatedAtUtc: row.CreatedAtUtc,
|
||||
UpdatedAtUtc: row.UpdatedAtUtc,
|
||||
TerminalAtUtc: row.TerminalAtUtc,
|
||||
IngestedAtUtc: row.IngestedAtUtc);
|
||||
IngestedAtUtc: row.IngestedAtUtc,
|
||||
SourceNode: row.SourceNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -354,6 +354,7 @@ public class NotificationOutboxActorQueryTests : TestKit
|
||||
row.ResolvedTargets = "[\"ops@example.com\",\"oncall@example.com\"]";
|
||||
row.TypeData = "{\"priority\":\"high\"}";
|
||||
row.SourceScript = "HighLevelAlarm.csx";
|
||||
row.SourceNode = "node-a";
|
||||
row.SiteEnqueuedAt = DateTimeOffset.UtcNow.AddMinutes(-5);
|
||||
row.DeliveredAt = DateTimeOffset.UtcNow;
|
||||
_repository.GetByIdAsync(row.NotificationId, Arg.Any<CancellationToken>()).Returns(row);
|
||||
@@ -377,6 +378,10 @@ public class NotificationOutboxActorQueryTests : TestKit
|
||||
Assert.Equal("instance-42", detail.SourceInstanceId);
|
||||
Assert.Equal(2, detail.RetryCount);
|
||||
Assert.Equal("transient blip", detail.LastError);
|
||||
// SourceNode flows through the detail projection so the report detail
|
||||
// modal binds uniformly to the detail record (was previously read off
|
||||
// the summary).
|
||||
Assert.Equal("node-a", detail.SourceNode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -402,7 +402,8 @@ public class SiteCallAuditActorTests : TestKit, IClassFixture<MsSqlMigrationFixt
|
||||
var repo = new SiteCallAuditRepository(context);
|
||||
var actor = CreateActor(repo);
|
||||
|
||||
await repo.UpsertAsync(NewRow(id, siteId, status: "Attempted", retryCount: 2, lastError: "503"));
|
||||
await repo.UpsertAsync(NewRow(
|
||||
id, siteId, status: "Attempted", retryCount: 2, lastError: "503", sourceNode: "node-a"));
|
||||
|
||||
actor.Tell(new SiteCallDetailRequest("corr-d1", id.Value), TestActor);
|
||||
|
||||
@@ -414,6 +415,9 @@ public class SiteCallAuditActorTests : TestKit, IClassFixture<MsSqlMigrationFixt
|
||||
Assert.Equal(2, response.Detail.RetryCount);
|
||||
Assert.Equal("503", response.Detail.LastError);
|
||||
Assert.Equal(siteId, response.Detail.SourceSite);
|
||||
// SourceNode flows through ToDetail so the report detail modal binds
|
||||
// uniformly to the detail record (was previously read off the summary).
|
||||
Assert.Equal("node-a", response.Detail.SourceNode);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
|
||||
Reference in New Issue
Block a user