*/ final class PipelineArchiveCrudController extends AbstractCrudController { public static function getEntityFqcn(): string { return AIPipelineJob::class; } public function configureCrud(Crud $crud): Crud { return $crud ->setEntityLabelInSingular('Pipeline Job') ->setEntityLabelInPlural('AI Pipeline — Archive') ->setDefaultSort(['completedAt' => 'DESC']) ->showEntityActionsInlined(); } public function configureActions(Actions $actions): Actions { return $actions ->add(Crud::PAGE_INDEX, Action::DETAIL) ->disable(Action::NEW, Action::EDIT, Action::DELETE); } public function configureFields(string $pageName): iterable { yield IdField::new('id')->hideOnIndex(); yield TextField::new('inventoryNumber', 'Inventory #') ->hideOnForm() ->formatValue(static fn ($v, AIPipelineJob $job): string => (string) ($job->getInputData()['inventoryNumber'] ?? '—')); yield TextField::new('statusLabel', 'Status') ->hideOnForm(); yield IntegerField::new('attemptCount', 'Attempts')->hideOnForm(); yield DateTimeField::new('createdAt', 'Started')->hideOnForm(); yield DateTimeField::new('completedAt', 'Completed')->hideOnForm(); yield TextField::new('articleId', 'Article') ->hideOnForm() ->formatValue(static fn ($v, AIPipelineJob $job): string => $job->getArticleId()?->toRfc4122() ?? '—'); yield TextareaField::new('aiResults', 'AI Results') ->onlyOnDetail() ->formatValue(static fn ($v, AIPipelineJob $job): string => self::formatStepResults($job)); } public function createIndexQueryBuilder( SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters, ): QueryBuilder { $qb = $this->container->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters); $qb->andWhere('entity.status = :completed') ->setParameter('completed', AIPipelineJobStatus::Completed); return $qb; } private static function formatStepResults(AIPipelineJob $job): string { $output = $job->getOutputData(); if ([] === $output) { return '(none)'; } $lines = []; $labels = [ 'vision' => 'Vision', 'specs_research' => 'Specs Research', 'json_coding' => 'JSON Coding', 'validation' => 'Validation', ]; foreach ($labels as $key => $label) { if (!isset($output[$key])) { continue; } $data = $output[$key]; $lines[] = "=== {$label} ==="; foreach ($data as $k => $v) { if (\is_array($v)) { $lines[] = "{$k}: ".json_encode($v, \JSON_UNESCAPED_UNICODE | \JSON_PRETTY_PRINT); } else { $lines[] = "{$k}: {$v}"; } } $lines[] = ''; } return implode("\n", $lines); } }