Files
fuel-price/app/Filament/Resources/OilPredictionResource.php
Ovidiu U 3ccdc28763
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
prediction with context
2026-04-05 17:08:16 +01:00

142 lines
5.7 KiB
PHP

<?php
namespace App\Filament\Resources;
use App\Enums\PredictionSource;
use App\Enums\TrendDirection;
use App\Filament\NavigationGroup;
use App\Filament\Resources\OilPredictionResource\Pages\ListOilPredictions;
use App\Filament\Resources\OilPredictionResource\Pages\ViewOilPrediction;
use App\Models\PricePrediction;
use Filament\Actions\ViewAction;
use Filament\Forms\Components\DatePicker;
use Filament\Infolists\Components\TextEntry;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
class OilPredictionResource extends Resource
{
protected static ?string $model = PricePrediction::class;
protected static string|\UnitEnum|null $navigationGroup = NavigationGroup::Data;
protected static ?string $navigationLabel = 'Oil Predictions';
protected static ?int $navigationSort = 3;
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('predicted_for')
->date('d M Y')
->sortable(),
TextColumn::make('source')
->badge()
->formatStateUsing(fn (PredictionSource $state) => match ($state) {
PredictionSource::Llm => 'LLM',
PredictionSource::LlmWithContext => 'LLM + Context',
PredictionSource::Ewma => 'EWMA',
})
->color(fn (PredictionSource $state) => match ($state) {
PredictionSource::Llm => 'success',
PredictionSource::LlmWithContext => 'warning',
PredictionSource::Ewma => 'info',
}),
TextColumn::make('direction')
->badge()
->color(fn (TrendDirection $state) => match ($state) {
TrendDirection::Rising => 'danger',
TrendDirection::Falling => 'success',
TrendDirection::Flat => 'gray',
}),
TextColumn::make('confidence')
->suffix('%')
->sortable(),
TextColumn::make('reasoning')
->limit(60)
->placeholder('—'),
TextColumn::make('generated_at')
->dateTime('d M Y H:i')
->sortable(),
])
->defaultSort('predicted_for', 'desc')
->filters([
SelectFilter::make('source')
->options([
PredictionSource::Llm->value => 'LLM',
PredictionSource::LlmWithContext->value => 'LLM + Context',
PredictionSource::Ewma->value => 'EWMA',
]),
SelectFilter::make('direction')
->options([
TrendDirection::Rising->value => 'Rising',
TrendDirection::Falling->value => 'Falling',
TrendDirection::Flat->value => 'Flat',
]),
Filter::make('predicted_for')
->schema([
DatePicker::make('from')->label('From'),
DatePicker::make('until')->label('Until'),
])
->query(function (Builder $query, array $data) {
$query
->when($data['from'], fn ($q, $d) => $q->whereDate('predicted_for', '>=', $d))
->when($data['until'], fn ($q, $d) => $q->whereDate('predicted_for', '<=', $d));
}),
])
->recordActions([
ViewAction::make(),
]);
}
public static function infolist(Schema $schema): Schema
{
return $schema->components([
Section::make('Prediction')->schema([
TextEntry::make('predicted_for')->date('d M Y'),
TextEntry::make('source')
->badge()
->formatStateUsing(fn (PredictionSource $state) => match ($state) {
PredictionSource::Llm => 'LLM',
PredictionSource::LlmWithContext => 'LLM + Context',
PredictionSource::Ewma => 'EWMA',
})
->color(fn (PredictionSource $state) => match ($state) {
PredictionSource::Llm => 'success',
PredictionSource::LlmWithContext => 'warning',
PredictionSource::Ewma => 'info',
}),
TextEntry::make('direction')
->badge()
->color(fn (TrendDirection $state) => match ($state) {
TrendDirection::Rising => 'danger',
TrendDirection::Falling => 'success',
TrendDirection::Flat => 'gray',
}),
TextEntry::make('confidence')->suffix('%'),
TextEntry::make('generated_at')->dateTime('d M Y H:i:s'),
])->columns(3),
Section::make('Reasoning')->schema([
TextEntry::make('reasoning')
->columnSpanFull()
->placeholder('No reasoning recorded'),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ListOilPredictions::route('/'),
'view' => ViewOilPrediction::route('/{record}'),
];
}
}