components([ Section::make('Run')->columns(3)->schema([ TextEntry::make('model_version')->columnSpanFull(), TextEntry::make('directional_accuracy') ->label('Accuracy') ->state(fn (Backtest $record): string => $record->directional_accuracy === null ? '—' : round((float) $record->directional_accuracy, 1).'%'), TextEntry::make('mae_pence') ->label('MAE') ->state(fn (Backtest $record): string => $record->mae_pence === null ? '—' : number_format((float) $record->mae_pence, 2).'p'), IconEntry::make('leak_suspected') ->label('Leak suspected') ->boolean() ->trueColor('danger'), TextEntry::make('train_start')->date('d M Y'), TextEntry::make('train_end')->date('d M Y'), TextEntry::make('eval_start')->date('d M Y'), TextEntry::make('eval_end')->date('d M Y'), TextEntry::make('ran_at')->dateTime('d M Y H:i'), ]), Section::make('Calibration table') ->description('Empirical hit rate per magnitude bin from the eval window.') ->schema([ KeyValueEntry::make('calibration_table') ->hiddenLabel() ->keyLabel('Magnitude bin') ->valueLabel('Empirical hit rate') ->state(fn (Backtest $record): array => collect($record->calibration_table ?? []) ->mapWithKeys(fn ($value, $key) => [$key => round((float) $value * 100, 1).'%']) ->all()) ->columnSpanFull(), ]), Section::make('Feature spec')->schema([ KeyValueEntry::make('features_json') ->hiddenLabel() ->state(fn (Backtest $record): array => self::flattenForKeyValue($record->features_json)) ->columnSpanFull(), ]), Section::make('Coefficients') ->visible(fn (Backtest $record) => $record->coefficients_json !== null) ->collapsed() ->schema([ TextEntry::make('coefficients_json') ->hiddenLabel() ->state(fn (Backtest $record): string => json_encode( $record->coefficients_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ?: '') ->columnSpanFull(), ]), ]); } /** * KeyValueEntry expects a flat string-keyed map, so collapse nested arrays * into JSON strings rather than dropping them. * * @param array|null $features * @return array */ protected static function flattenForKeyValue(?array $features): array { return collect($features ?? []) ->mapWithKeys(fn ($value, $key) => [ (string) $key => is_scalar($value) ? (string) $value : (json_encode($value, JSON_UNESCAPED_SLASHES) ?: ''), ]) ->all(); } }