Add sortable columns to all bench result tables (scenario detail + run detail)
This commit is contained in:
parent
504b9e1322
commit
6f6f43c5ec
3 changed files with 99 additions and 53 deletions
|
|
@ -116,7 +116,7 @@ public function depthsweepResults(): HasMany
|
|||
* an empty collection for suites this run does not have. An optional
|
||||
* level filter narrows to one thinking level (depthsweep drill-in).
|
||||
*/
|
||||
public function suiteResults(?string $level = null): Collection
|
||||
public function suiteResults(?string $level = null, ?string $sortBy = null, ?string $sortDir = null): Collection
|
||||
{
|
||||
$model = Suites::modelFor($this->suite);
|
||||
|
||||
|
|
@ -126,11 +126,13 @@ public function suiteResults(?string $level = null): Collection
|
|||
|
||||
$relation = Suites::runRelation($this->suite);
|
||||
|
||||
$orderCol = $this->suite === 'scenariobench' ? 'scenario' : 'task';
|
||||
$defaultOrder = $this->suite === 'scenariobench' ? 'scenario' : 'task';
|
||||
$orderCol = $sortBy ?? $defaultOrder;
|
||||
$direction = $sortDir === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
return $this->{$relation}()
|
||||
->when($level !== null && $level !== '', fn ($q) => $q->where('level', $level))
|
||||
->orderBy($orderCol)
|
||||
->orderBy($orderCol, $direction)
|
||||
->orderBy('id')
|
||||
->get();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Livewire\IncludesSorting;
|
||||
use App\Models\BenchmarkRun;
|
||||
use Flux\Flux;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
|
|
@ -8,6 +9,24 @@
|
|||
use Livewire\Component;
|
||||
|
||||
new #[Layout('components.layouts.app')] class extends Component {
|
||||
use IncludesSorting;
|
||||
|
||||
private const SORTABLE_SCENARIO = [
|
||||
'scenario', 'level', 'ok', 'outcome',
|
||||
'wall', 'turns', 'commands', 'submissions', 'rejected',
|
||||
't_first_sub', 't_pass', 'gen_tokens',
|
||||
];
|
||||
|
||||
private const SORTABLE_DEPTHSWEEP = [
|
||||
'section', 'task', 'level', 'ok', 'ttft', 'wall', 'visible',
|
||||
];
|
||||
|
||||
private const SORTABLE_METRIC = [
|
||||
'section', 'task', 'level', 'ok', 'checks_passed',
|
||||
'kind', 'user_tps', 'decode', 'ttft', 't_answer',
|
||||
'wall', 'reasoning', 'visible', 'finish',
|
||||
];
|
||||
|
||||
public ?string $notes = null;
|
||||
|
||||
public ?string $runId = null;
|
||||
|
|
@ -67,6 +86,16 @@ private function authorizeOwner(): void
|
|||
throw new AuthorizationException;
|
||||
}
|
||||
}
|
||||
|
||||
private function sortColumn(array $allowed): string
|
||||
{
|
||||
return in_array($this->sortBy, $allowed, true) ? $this->sortBy : $allowed[0];
|
||||
}
|
||||
|
||||
private function sortDir(): string
|
||||
{
|
||||
return $this->sortDirection === 'asc' ? 'asc' : 'desc';
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
|
|
@ -137,24 +166,25 @@ private function authorizeOwner(): void
|
|||
<flux:heading size="md">{{ $this->run->suite === 'scenariobench' ? __('Scenario results') : ($this->run->suite === 'depthsweep' ? __('Depth sweep results') : __('Task results')) }}</flux:heading>
|
||||
<div class="mt-3">
|
||||
@if ($this->run->suite === 'scenariobench')
|
||||
@php($sortCol = $this->sortColumn(self::SORTABLE_SCENARIO))
|
||||
<flux:table>
|
||||
<flux:table.columns>
|
||||
<flux:table.column>{{ __('Scenario') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Pass') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Outcome') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Wall (s)') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Turns') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Commands') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Submissions') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Rejected') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('t first sub') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('t pass') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Gen tokens') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'scenario'" :direction="$sortDirection" wire:click="sort('scenario')">{{ __('Scenario') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'level'" :direction="$sortDirection" wire:click="sort('level')">{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ok'" :direction="$sortDirection" wire:click="sort('ok')">{{ __('Pass') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'outcome'" :direction="$sortDirection" wire:click="sort('outcome')">{{ __('Outcome') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'wall'" :direction="$sortDirection" wire:click="sort('wall')" class="text-center">{{ __('Wall (s)') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'turns'" :direction="$sortDirection" wire:click="sort('turns')" class="text-center">{{ __('Turns') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'commands'" :direction="$sortDirection" wire:click="sort('commands')" class="text-center">{{ __('Commands') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'submissions'" :direction="$sortDirection" wire:click="sort('submissions')" class="text-center">{{ __('Submissions') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'rejected'" :direction="$sortDirection" wire:click="sort('rejected')" class="text-center">{{ __('Rejected') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 't_first_sub'" :direction="$sortDirection" wire:click="sort('t_first_sub')" class="text-center">{{ __('t first sub') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 't_pass'" :direction="$sortDirection" wire:click="sort('t_pass')" class="text-center">{{ __('t pass') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'gen_tokens'" :direction="$sortDirection" wire:click="sort('gen_tokens')" class="text-center">{{ __('Gen tokens') }}</flux:table.column>
|
||||
</flux:table.columns>
|
||||
|
||||
<flux:table.rows>
|
||||
@foreach ($this->run->suiteResults() as $result)
|
||||
@foreach ($this->run->suiteResults($this->level, $sortCol, $this->sortDir()) as $result)
|
||||
<flux:table.row :key="$result->id">
|
||||
<flux:table.cell>{{ $result->scenario }}</flux:table.cell>
|
||||
<flux:table.cell>{{ $result->level ?? '—' }}</flux:table.cell>
|
||||
|
|
@ -188,20 +218,21 @@ private function authorizeOwner(): void
|
|||
<flux:button size="xs" variant="ghost" icon="x-mark" href="{{ route('runs.show', $this->run->run_id) }}" wire:navigate>{{ __('show all levels') }}</flux:button>
|
||||
</div>
|
||||
@endif
|
||||
@php($sortCol = $this->sortColumn(self::SORTABLE_DEPTHSWEEP))
|
||||
<flux:table>
|
||||
<flux:table.columns>
|
||||
<flux:table.column>{{ __('Depth') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Task') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Found') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'section'" :direction="$sortDirection" wire:click="sort('section')">{{ __('Depth') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'task'" :direction="$sortDirection" wire:click="sort('task')">{{ __('Task') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'level'" :direction="$sortDirection" wire:click="sort('level')">{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ok'" :direction="$sortDirection" wire:click="sort('ok')">{{ __('Found') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Needle') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('TTFT') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Wall') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Visible') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ttft'" :direction="$sortDirection" wire:click="sort('ttft')" class="text-center">{{ __('TTFT') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'wall'" :direction="$sortDirection" wire:click="sort('wall')" class="text-center">{{ __('Wall') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'visible'" :direction="$sortDirection" wire:click="sort('visible')" class="text-center">{{ __('Visible') }}</flux:table.column>
|
||||
</flux:table.columns>
|
||||
|
||||
<flux:table.rows>
|
||||
@foreach ($this->run->suiteResults($this->level) as $result)
|
||||
@foreach ($this->run->suiteResults($this->level, $sortCol, $this->sortDir()) as $result)
|
||||
<flux:table.row :key="$result->id">
|
||||
<flux:table.cell><flux:badge size="xs" color="sky">{{ $result->section }}</flux:badge></flux:table.cell>
|
||||
<flux:table.cell>{{ $result->task }}</flux:table.cell>
|
||||
|
|
@ -222,32 +253,33 @@ private function authorizeOwner(): void
|
|||
</flux:table.rows>
|
||||
</flux:table>
|
||||
@else
|
||||
@php($sortCol = $this->sortColumn(self::SORTABLE_METRIC))
|
||||
<flux:table>
|
||||
<flux:table.columns>
|
||||
@if (in_array($this->run->suite, ['softbench', 'prosebench', 'psychbench']))
|
||||
<flux:table.column>{{ __('Section') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'section'" :direction="$sortDirection" wire:click="sort('section')">{{ __('Section') }}</flux:table.column>
|
||||
@endif
|
||||
<flux:table.column>{{ __('Task') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Pass') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'task'" :direction="$sortDirection" wire:click="sort('task')">{{ __('Task') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'level'" :direction="$sortDirection" wire:click="sort('level')">{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ok'" :direction="$sortDirection" wire:click="sort('ok')">{{ __('Pass') }}</flux:table.column>
|
||||
@if (in_array($this->run->suite, ['prosebench', 'psychbench']))
|
||||
<flux:table.column class="text-center">{{ __('Checks') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'checks_passed'" :direction="$sortDirection" wire:click="sort('checks_passed')" class="text-center">{{ __('Checks') }}</flux:table.column>
|
||||
@endif
|
||||
@if ($this->run->suite === 'infrabench')
|
||||
<flux:table.column>{{ __('Kind') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'kind'" :direction="$sortDirection" wire:click="sort('kind')">{{ __('Kind') }}</flux:table.column>
|
||||
@endif
|
||||
<flux:table.column class="text-center">{{ __('User tok/s') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Decode') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('TTFT') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('t_answer') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Wall') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Reasoning') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Visible') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Finish') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'user_tps'" :direction="$sortDirection" wire:click="sort('user_tps')" class="text-center">{{ __('User tok/s') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'decode'" :direction="$sortDirection" wire:click="sort('decode')" class="text-center">{{ __('Decode') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ttft'" :direction="$sortDirection" wire:click="sort('ttft')" class="text-center">{{ __('TTFT') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 't_answer'" :direction="$sortDirection" wire:click="sort('t_answer')" class="text-center">{{ __('t_answer') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'wall'" :direction="$sortDirection" wire:click="sort('wall')" class="text-center">{{ __('Wall') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'reasoning'" :direction="$sortDirection" wire:click="sort('reasoning')" class="text-center">{{ __('Reasoning') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'visible'" :direction="$sortDirection" wire:click="sort('visible')" class="text-center">{{ __('Visible') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'finish'" :direction="$sortDirection" wire:click="sort('finish')">{{ __('Finish') }}</flux:table.column>
|
||||
</flux:table.columns>
|
||||
|
||||
<flux:table.rows>
|
||||
@foreach ($this->run->suiteResults() as $result)
|
||||
@foreach ($this->run->suiteResults(null, $sortCol, $this->sortDir()) as $result)
|
||||
<flux:table.row :key="$result->id">
|
||||
@if (in_array($this->run->suite, ['softbench', 'prosebench', 'psychbench']))
|
||||
<flux:table.cell>{{ $result->section ?? '—' }}</flux:table.cell>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Livewire\IncludesSorting;
|
||||
use App\Models\BenchmarkRun;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Attributes\Computed;
|
||||
|
|
@ -7,6 +8,14 @@
|
|||
use Livewire\Component;
|
||||
|
||||
new #[Layout('components.layouts.app')] class extends Component {
|
||||
use IncludesSorting;
|
||||
|
||||
private const SORTABLE = [
|
||||
'scenario', 'level', 'ok', 'outcome',
|
||||
'wall', 'turns', 'commands', 'submissions', 'rejected',
|
||||
't_first_sub', 't_pass', 'gen_tokens',
|
||||
];
|
||||
|
||||
public ?int $sessionId = null;
|
||||
|
||||
public function mount(int $session): void
|
||||
|
|
@ -66,10 +75,13 @@ public function results()
|
|||
{
|
||||
$runIds = $this->runs->pluck('id');
|
||||
|
||||
$column = in_array($this->sortBy, self::SORTABLE, true) ? $this->sortBy : 'scenario';
|
||||
$direction = $this->sortDirection === 'asc' ? 'asc' : 'desc';
|
||||
|
||||
return DB::table('scenario_runs')
|
||||
->whereIn('benchmark_run_id', $runIds)
|
||||
->orderBy('scenario')
|
||||
->orderBy('benchmark_run_id')
|
||||
->orderBy($column, $direction)
|
||||
->orderBy('id')
|
||||
->get();
|
||||
}
|
||||
};
|
||||
|
|
@ -96,18 +108,18 @@ public function results()
|
|||
|
||||
<flux:table>
|
||||
<flux:table.columns>
|
||||
<flux:table.column>{{ __('Scenario') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Pass') }}</flux:table.column>
|
||||
<flux:table.column>{{ __('Outcome') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Wall (s)') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Turns') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Commands') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Submissions') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Rejected') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('t first sub') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('t pass') }}</flux:table.column>
|
||||
<flux:table.column class="text-center">{{ __('Gen tokens') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'scenario'" :direction="$sortDirection" wire:click="sort('scenario')">{{ __('Scenario') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'level'" :direction="$sortDirection" wire:click="sort('level')">{{ __('Level') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'ok'" :direction="$sortDirection" wire:click="sort('ok')">{{ __('Pass') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'outcome'" :direction="$sortDirection" wire:click="sort('outcome')">{{ __('Outcome') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'wall'" :direction="$sortDirection" wire:click="sort('wall')" class="text-center">{{ __('Wall (s)') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'turns'" :direction="$sortDirection" wire:click="sort('turns')" class="text-center">{{ __('Turns') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'commands'" :direction="$sortDirection" wire:click="sort('commands')" class="text-center">{{ __('Commands') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'submissions'" :direction="$sortDirection" wire:click="sort('submissions')" class="text-center">{{ __('Submissions') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'rejected'" :direction="$sortDirection" wire:click="sort('rejected')" class="text-center">{{ __('Rejected') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 't_first_sub'" :direction="$sortDirection" wire:click="sort('t_first_sub')" class="text-center">{{ __('t first sub') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 't_pass'" :direction="$sortDirection" wire:click="sort('t_pass')" class="text-center">{{ __('t pass') }}</flux:table.column>
|
||||
<flux:table.column sortable :sorted="$sortBy === 'gen_tokens'" :direction="$sortDirection" wire:click="sort('gen_tokens')" class="text-center">{{ __('Gen tokens') }}</flux:table.column>
|
||||
</flux:table.columns>
|
||||
|
||||
<flux:table.rows>
|
||||
|
|
|
|||
Loading…
Reference in a new issue