## Summary - collapse secondary and diagnostic operation-run sections by default to reduce page density - visually emphasize the primary next step while keeping counts readable but secondary - keep failures and other actionable detail available without dominating the default reading path ## Testing - vendor/bin/sail artisan test --compact tests/Feature/Filament/OperationRunBaselineTruthSurfaceTest.php tests/Feature/Filament/OperationRunEnterpriseDetailPageTest.php tests/Feature/Filament/EnterpriseDetailTemplateRegressionTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php - vendor/bin/sail bin pint --dirty --format agent Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #194
89 lines
3.5 KiB
PHP
89 lines
3.5 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),
|
|
],
|
|
))
|
|
->decisionZone([
|
|
'title' => 'Decision',
|
|
'facts' => [['label' => 'Outcome', 'value' => 'Succeeded']],
|
|
'primaryNextStep' => ['text' => 'No action needed.', 'source' => 'none_required'],
|
|
])
|
|
->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['decisionZone'])->not->toBeNull()
|
|
->and($page['decisionZone']['title'])->toBe('Decision')
|
|
->and($page['mainSections'])->toHaveCount(1)
|
|
->and($page['mainSections'][0]['title'])->toBe('Counts')
|
|
->and($page['supportingGroups'])->toHaveCount(1)
|
|
->and($page['supportingGroups'][0]['title'])->toBe('Timing')
|
|
->and($page['technicalSections'])->toHaveCount(1)
|
|
->and($page['technicalSections'][0]['title'])->toBe('Context');
|
|
});
|