## Summary - introduce a shared enterprise-detail composition layer for Filament detail pages - migrate BackupSet, BaselineSnapshot, EntraGroup, and OperationRun detail screens to the shared summary-first layout - add regression and unit coverage for section hierarchy, related context, degraded states, and duplicate fact/badge presentation ## Scope - adds shared support classes under `app/Support/Ui/EnterpriseDetail` - adds shared enterprise detail Blade partials under `resources/views/filament/infolists/entries/enterprise-detail` - updates touched Filament resources/pages to use the shared detail shell - includes Spec 133 artifacts under `specs/133-detail-page-template` ## Notes - branch: `133-detail-page-template` - base: `dev` - commit: `fd294c7` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #162
82 lines
3.1 KiB
PHP
82 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Support\Ui\EnterpriseDetail\DetailSectionData;
|
|
use App\Support\Ui\EnterpriseDetail\EnterpriseDetailBuilder;
|
|
use App\Support\Ui\EnterpriseDetail\PageActionData;
|
|
use App\Support\Ui\EnterpriseDetail\SummaryHeaderData;
|
|
use App\Support\Ui\EnterpriseDetail\SupportingCardData;
|
|
use App\Support\Ui\EnterpriseDetail\TechnicalDetailData;
|
|
|
|
it('requires a summary header before building a page payload', function (): void {
|
|
expect(fn (): \App\Support\Ui\EnterpriseDetail\EnterpriseDetailPageData => EnterpriseDetailBuilder::make('operation_run', 'workspace-context')
|
|
->build())
|
|
->toThrow(LogicException::class, 'Enterprise detail pages require a summary header.');
|
|
});
|
|
|
|
it('filters invisible and empty sections before returning the page payload', function (): void {
|
|
$page = EnterpriseDetailBuilder::make('operation_run', 'workspace-context')
|
|
->header(new SummaryHeaderData(
|
|
title: 'Policy sync',
|
|
statusBadges: [['label' => 'Completed', 'color' => 'gray']],
|
|
keyFacts: [['label' => 'Run', 'value' => '#44']],
|
|
primaryActions: [
|
|
new PageActionData(label: 'View run', url: '/admin/operations/44'),
|
|
new PageActionData(label: 'Hidden', url: '/admin/operations/hidden', visible: false),
|
|
],
|
|
))
|
|
->addSection(
|
|
new DetailSectionData(
|
|
id: 'counts',
|
|
kind: 'current_status',
|
|
title: 'Counts',
|
|
items: [['label' => 'Processed', 'value' => '10']],
|
|
),
|
|
new DetailSectionData(
|
|
id: 'hidden',
|
|
kind: 'domain_detail',
|
|
title: 'Hidden',
|
|
items: [['label' => 'Ignored', 'value' => '1']],
|
|
visible: false,
|
|
),
|
|
new DetailSectionData(
|
|
id: 'empty',
|
|
kind: 'domain_detail',
|
|
title: 'Empty',
|
|
),
|
|
)
|
|
->addSupportingCard(
|
|
new SupportingCardData(
|
|
kind: 'timestamps',
|
|
title: 'Timing',
|
|
items: [['label' => 'Completed', 'value' => '2026-03-10 09:00']],
|
|
),
|
|
new SupportingCardData(
|
|
kind: 'empty',
|
|
title: 'Ignored',
|
|
),
|
|
)
|
|
->addTechnicalSection(
|
|
new TechnicalDetailData(
|
|
title: 'Context',
|
|
entries: [['label' => 'Hash', 'value' => 'abc123']],
|
|
),
|
|
new TechnicalDetailData(
|
|
title: 'Skipped',
|
|
visible: false,
|
|
entries: [['label' => 'Ignored', 'value' => '1']],
|
|
),
|
|
)
|
|
->build()
|
|
->toArray();
|
|
|
|
expect($page['header']['primaryActions'])->toHaveCount(1)
|
|
->and($page['mainSections'])->toHaveCount(1)
|
|
->and($page['mainSections'][0]['title'])->toBe('Counts')
|
|
->and($page['supportingCards'])->toHaveCount(1)
|
|
->and($page['supportingCards'][0]['title'])->toBe('Timing')
|
|
->and($page['technicalSections'])->toHaveCount(1)
|
|
->and($page['technicalSections'][0]['title'])->toBe('Context');
|
|
});
|