feat(anomalies): sort the feed (newest / top score / longest gap)
Adds a sort chip row to the anomaly feed — newest (default), highest score, or longest suspension gap — replacing the fixed newest-first order. DetectedAt is the tiebreak so order stays stable. - AnomalySort enum + AnomalyFilter.Sort (default Newest, so existing constructions are unaffected); AnomalyBrowsingService applies it; feed sort chips + SetSort/SortLabel; en/ru resx. - 2 tests: default newest-first + highest-score ordering.
This commit is contained in:
@@ -29,8 +29,8 @@ public sealed class AnomalyBrowsingServiceTests
|
||||
private AnomalyBrowsingService CreateSut() => new(_anomalies, _events);
|
||||
|
||||
private int _seq;
|
||||
private Anomaly Make(AnomalyKind kind) =>
|
||||
new(Guid.NewGuid(), new EventId($"evt-{_seq++}"), T0, kind, 0.70m, Evidence);
|
||||
private Anomaly Make(AnomalyKind kind, decimal score = 0.70m, DateTimeOffset? detectedAt = null) =>
|
||||
new(Guid.NewGuid(), new EventId($"evt-{_seq++}"), detectedAt ?? T0, kind, score, Evidence);
|
||||
|
||||
/// <summary>Stubs the anomaly query AND a matching event per anomaly (events exist via FK).</summary>
|
||||
private void Setup(params Anomaly[] anomalies)
|
||||
@@ -74,4 +74,30 @@ public sealed class AnomalyBrowsingServiceTests
|
||||
|
||||
items.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListAsync_DefaultSort_IsNewestFirst()
|
||||
{
|
||||
Setup(
|
||||
Make(AnomalyKind.SuspensionFlip, detectedAt: T0.AddHours(-2)),
|
||||
Make(AnomalyKind.SteamMove, detectedAt: T0));
|
||||
|
||||
var items = await CreateSut().ListAsync(new AnomalyFilter(), CancellationToken.None);
|
||||
|
||||
items.First().DetectedAt.Should().Be(T0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListAsync_SortsByHighestScore()
|
||||
{
|
||||
Setup(
|
||||
Make(AnomalyKind.SuspensionFlip, score: 0.40m),
|
||||
Make(AnomalyKind.SteamMove, score: 0.80m),
|
||||
Make(AnomalyKind.SuspensionFlip, score: 0.60m));
|
||||
|
||||
var items = await CreateSut().ListAsync(
|
||||
new AnomalyFilter(Sort: AnomalySort.HighestScore), CancellationToken.None);
|
||||
|
||||
items.Select(i => i.Score).Should().ContainInOrder(0.80m, 0.60m, 0.40m);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user