fixed custom format page filtering

This commit is contained in:
Flaminel
2026-03-22 21:50:19 +02:00
parent 8659d35235
commit 2ea8cbe2b5
4 changed files with 75 additions and 4 deletions

View File

@@ -25,7 +25,8 @@ public sealed class CustomFormatScoreController : ControllerBase
public async Task<IActionResult> GetCustomFormatScores(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 50,
[FromQuery] Guid? instanceId = null)
[FromQuery] Guid? instanceId = null,
[FromQuery] string? search = null)
{
if (page < 1) page = 1;
if (pageSize < 1) pageSize = 50;
@@ -40,6 +41,11 @@ public sealed class CustomFormatScoreController : ControllerBase
query = query.Where(e => e.ArrInstanceId == instanceId.Value);
}
if (!string.IsNullOrWhiteSpace(search))
{
query = query.Where(e => e.Title.Contains(search));
}
int totalCount = await query.CountAsync();
var items = await query
@@ -151,6 +157,29 @@ public sealed class CustomFormatScoreController : ControllerBase
});
}
[HttpGet("instances")]
public async Task<IActionResult> GetInstances()
{
var instances = await _dataContext.CustomFormatScoreEntries
.AsNoTracking()
.Select(e => new { e.ArrInstanceId, e.ItemType })
.Distinct()
.Join(
_dataContext.ArrInstances.AsNoTracking(),
e => e.ArrInstanceId,
a => a.Id,
(e, a) => new
{
Id = e.ArrInstanceId,
a.Name,
e.ItemType,
})
.OrderBy(x => x.Name)
.ToListAsync();
return Ok(new { Instances = instances });
}
/// <summary>
/// Gets summary statistics for CF score tracking.
/// </summary>

View File

@@ -63,6 +63,12 @@ export interface CfScoreHistoryResponse {
entries: CfScoreHistoryEntry[];
}
export interface CfScoreInstance {
id: string;
name: string;
itemType: string;
}
@Injectable({ providedIn: 'root' })
export class CfScoreApi {
private http = inject(HttpClient);
@@ -77,12 +83,17 @@ export class CfScoreApi {
});
}
getScores(page = 1, pageSize = 50, search?: string): Observable<CfScoreEntriesResponse> {
getScores(page = 1, pageSize = 50, search?: string, instanceId?: string): Observable<CfScoreEntriesResponse> {
const params: Record<string, string | number> = { page, pageSize };
if (search) params['search'] = search;
if (instanceId) params['instanceId'] = instanceId;
return this.http.get<CfScoreEntriesResponse>('/api/seeker/cf-scores', { params });
}
getInstances(): Observable<{ instances: CfScoreInstance[] }> {
return this.http.get<{ instances: CfScoreInstance[] }>('/api/seeker/cf-scores/instances');
}
getItemHistory(instanceId: string, itemId: number, episodeId = 0): Observable<CfScoreHistoryResponse> {
return this.http.get<CfScoreHistoryResponse>(
`/api/seeker/cf-scores/${instanceId}/${itemId}/history`,

View File

@@ -7,6 +7,12 @@
<!-- Toolbar -->
<div class="toolbar">
<div class="toolbar__filters">
<app-select
placeholder="All Instances"
[options]="instanceOptions()"
[value]="selectedInstanceId()"
(valueChange)="onInstanceFilterChange($any($event))"
/>
<app-input
placeholder="Search by title..."
type="search"

View File

@@ -4,8 +4,9 @@ import { NgIcon } from '@ng-icons/core';
import { PageHeaderComponent } from '@layout/page-header/page-header.component';
import {
CardComponent, BadgeComponent, ButtonComponent, InputComponent,
PaginatorComponent, EmptyStateComponent,
PaginatorComponent, EmptyStateComponent, SelectComponent,
} from '@ui';
import type { SelectOption } from '@ui';
import { AnimatedCounterComponent } from '@ui/animated-counter/animated-counter.component';
import {
CfScoreApi, CfScoreEntry, CfScoreStats, CfScoreHistoryEntry,
@@ -25,6 +26,7 @@ const POLL_INTERVAL_MS = 10_000;
BadgeComponent,
ButtonComponent,
InputComponent,
SelectComponent,
PaginatorComponent,
EmptyStateComponent,
AnimatedCounterComponent,
@@ -46,12 +48,15 @@ export class CfScoresComponent implements OnInit, OnDestroy {
readonly currentPage = signal(1);
readonly pageSize = signal(50);
readonly searchQuery = signal('');
readonly selectedInstanceId = signal<string>('');
readonly instanceOptions = signal<SelectOption[]>([]);
readonly expandedId = signal<string | null>(null);
readonly historyEntries = signal<CfScoreHistoryEntry[]>([]);
readonly historyLoading = signal(false);
ngOnInit(): void {
this.loadInstances();
this.loadScores();
this.loadStats();
this.pollTimer = setInterval(() => {
@@ -68,7 +73,7 @@ export class CfScoresComponent implements OnInit, OnDestroy {
loadScores(): void {
this.loading.set(true);
this.api.getScores(this.currentPage(), this.pageSize(), this.searchQuery() || undefined).subscribe({
this.api.getScores(this.currentPage(), this.pageSize(), this.searchQuery() || undefined, this.selectedInstanceId() || undefined).subscribe({
next: (result) => {
this.items.set(result.items);
this.totalRecords.set(result.totalCount);
@@ -81,6 +86,26 @@ export class CfScoresComponent implements OnInit, OnDestroy {
});
}
private loadInstances(): void {
this.api.getInstances().subscribe({
next: (result) => {
this.instanceOptions.set([
{ label: 'All Instances', value: '' },
...result.instances.map(i => ({
label: `${i.name} (${i.itemType})`,
value: i.id,
})),
]);
},
});
}
onInstanceFilterChange(value: string): void {
this.selectedInstanceId.set(value);
this.currentPage.set(1);
this.loadScores();
}
private loadStats(): void {
this.api.getStats().subscribe({
next: (stats) => this.stats.set(stats),