feat(anomalies): filter the feed by detector kind
Adds a detector-kind chip row to the anomaly feed (SuspensionFlip / SteamMove / SuspensionFreeze / OverroundCompression), multi-select like the sport filter — so with four detectors live you can slice the feed to a single signal type. The kind set lives on AnomalyFilter and filters in-memory alongside severity/sport, persisted via AnomalyBrowsingState like the other filters. - AnomalyFilter.Kinds + AnomalyBrowsingService in-memory Where clause; feed chip row + ToggleKind/KindLabel; en/ru resx (Anomaly.Filter.Kind). - 2 tests: kind-filtered subset + no-filter returns all kinds.
This commit is contained in:
@@ -82,6 +82,23 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="m-list-toolbar__row m-list-toolbar__chips">
|
||||
<span class="m-list-toolbar__label">@L["Anomaly.Filter.Kind"]</span>
|
||||
@foreach (var kind in _kindOptions)
|
||||
{
|
||||
var localKind = kind;
|
||||
var active = _filter.Kinds is { Count: > 0 } ks && ks.Contains(localKind);
|
||||
<button type="button"
|
||||
class="m-chip @(active ? "is-active" : null)"
|
||||
aria-pressed="@active"
|
||||
data-test="kind-chip"
|
||||
data-kind="@localKind"
|
||||
@onclick="() => ToggleKind(localKind)">
|
||||
@KindLabel(localKind)
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="m-list-toolbar__row">
|
||||
<div class="m-list-toolbar__group">
|
||||
<label class="m-list-toolbar__label">@L["Anomaly.Filter.From"]</label>
|
||||
@@ -178,6 +195,9 @@
|
||||
private static readonly AnomalySeverity[] _severityOptions =
|
||||
{ AnomalySeverity.Low, AnomalySeverity.Medium, AnomalySeverity.High };
|
||||
|
||||
private static readonly AnomalyKind[] _kindOptions =
|
||||
{ AnomalyKind.SuspensionFlip, AnomalyKind.SteamMove, AnomalyKind.SuspensionFreeze, AnomalyKind.OverroundCompression };
|
||||
|
||||
private List<AnomalyListItem> _items = new();
|
||||
private IReadOnlyList<int> _availableSports = Array.Empty<int>();
|
||||
private bool _loading = true;
|
||||
@@ -251,6 +271,22 @@
|
||||
return UpdateFilter(_filter with { SportCodes = existing.Count == 0 ? null : existing });
|
||||
}
|
||||
|
||||
private Task ToggleKind(AnomalyKind kind)
|
||||
{
|
||||
var existing = _filter.Kinds?.ToList() ?? new List<AnomalyKind>();
|
||||
if (!existing.Remove(kind)) existing.Add(kind);
|
||||
return UpdateFilter(_filter with { Kinds = existing.Count == 0 ? null : existing });
|
||||
}
|
||||
|
||||
private string KindLabel(AnomalyKind kind) => kind switch
|
||||
{
|
||||
AnomalyKind.SuspensionFlip => L["Anomaly.Kind.SuspensionFlip"],
|
||||
AnomalyKind.SteamMove => L["Anomaly.Kind.SteamMove"],
|
||||
AnomalyKind.SuspensionFreeze => L["Anomaly.Kind.SuspensionFreeze"],
|
||||
AnomalyKind.OverroundCompression => L["Anomaly.Kind.OverroundCompression"],
|
||||
_ => kind.ToString(),
|
||||
};
|
||||
|
||||
private async Task OnFromChanged(ChangeEventArgs e)
|
||||
{
|
||||
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
|
||||
|
||||
Reference in New Issue
Block a user