refactor(system-info): reduce to Stripe-style status page
Reduce admin/system-info to a single focused status view: overall status banner, components list from existing health checks, and an environment meta table. Drops the Modules and Permissions tabs — those were dev-diagnostics already available via CLI. - Remove SystemInfoService + its test; wire the action directly to SystemHealthService and build meta inline - Extend SystemHealthService with per-check label + description so the UI speaks in customer terms while the CLI doctor path stays compatible - Rebuild the view on existing app-stats-table + app-empty-state primitives; add a small app-status-banner component for the headline signal - Align help-center nav label and i18n keys (de/en) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,8 @@ class SystemHealthServiceTest extends TestCase
|
||||
|
||||
self::assertSame('ok', $result['status']);
|
||||
self::assertSame('Database connectivity', $result['name']);
|
||||
self::assertSame('Database', $result['label']);
|
||||
self::assertSame('Connection established', $result['description']);
|
||||
}
|
||||
|
||||
public function testCheckDatabaseReturnsFailWhenDisconnected(): void
|
||||
@@ -39,6 +41,8 @@ class SystemHealthServiceTest extends TestCase
|
||||
$result = $this->service->checkDatabase();
|
||||
|
||||
self::assertSame('fail', $result['status']);
|
||||
self::assertSame('Database', $result['label']);
|
||||
self::assertSame('Database did not return the expected response', $result['description']);
|
||||
}
|
||||
|
||||
public function testCheckDatabaseReturnsFailOnException(): void
|
||||
@@ -190,6 +194,10 @@ class SystemHealthServiceTest extends TestCase
|
||||
self::assertArrayHasKey('status', $check);
|
||||
self::assertArrayHasKey('name', $check);
|
||||
self::assertArrayHasKey('message', $check);
|
||||
self::assertArrayHasKey('label', $check);
|
||||
self::assertArrayHasKey('description', $check);
|
||||
self::assertNotSame('', $check['label']);
|
||||
self::assertNotSame('', $check['description']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Tests\Service\System;
|
||||
|
||||
use MintyPHP\App\Module\ModuleRegistry;
|
||||
use MintyPHP\Repository\System\SystemHealthRepositoryInterface;
|
||||
use MintyPHP\Service\System\SystemHealthService;
|
||||
use MintyPHP\Service\System\SystemInfoService;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SystemInfoServiceTest extends TestCase
|
||||
{
|
||||
private SystemHealthService&MockObject $healthService;
|
||||
private SystemHealthRepositoryInterface&MockObject $healthRepository;
|
||||
private string $fixturesDir;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->healthService = $this->createMock(SystemHealthService::class);
|
||||
$this->healthRepository = $this->createMock(SystemHealthRepositoryInterface::class);
|
||||
$this->fixturesDir = sys_get_temp_dir() . '/system-info-test-' . uniqid();
|
||||
mkdir($this->fixturesDir, 0777, true);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->removeDir($this->fixturesDir);
|
||||
}
|
||||
|
||||
public function testBuildPageDataReturnsExpectedStructure(): void
|
||||
{
|
||||
$service = new SystemInfoService($this->healthService, $this->healthRepository, null);
|
||||
|
||||
$this->healthService->expects($this->once())
|
||||
->method('runAll')
|
||||
->willReturn([
|
||||
['status' => 'ok', 'name' => 'DB', 'message' => 'connected'],
|
||||
]);
|
||||
|
||||
$this->healthRepository->method('countActivePermissions')->willReturn(10);
|
||||
$this->healthRepository->method('countInactivePermissions')->willReturn(2);
|
||||
$this->healthRepository->method('listAllActivePermissionKeys')->willReturn(['users.view', 'settings.view']);
|
||||
|
||||
$data = $service->buildPageData();
|
||||
|
||||
self::assertArrayHasKey('overview', $data);
|
||||
self::assertArrayHasKey('modules', $data);
|
||||
self::assertArrayHasKey('permissions', $data);
|
||||
|
||||
self::assertSame(PHP_VERSION, $data['overview']['php_version']);
|
||||
self::assertIsArray($data['overview']['health_checks']);
|
||||
self::assertCount(1, $data['overview']['health_checks']);
|
||||
}
|
||||
|
||||
public function testModuleInventoryReturnsSortedList(): void
|
||||
{
|
||||
$registry = $this->createRegistryWithModules();
|
||||
$service = new SystemInfoService($this->healthService, $this->healthRepository, $registry);
|
||||
|
||||
$this->healthService->method('runAll')->willReturn([]);
|
||||
$this->healthRepository->method('countActivePermissions')->willReturn(0);
|
||||
$this->healthRepository->method('countInactivePermissions')->willReturn(0);
|
||||
$this->healthRepository->method('listAllActivePermissionKeys')->willReturn([]);
|
||||
|
||||
$data = $service->buildPageData();
|
||||
|
||||
self::assertCount(2, $data['modules']);
|
||||
self::assertSame('alpha', $data['modules'][0]['id']);
|
||||
self::assertSame('beta', $data['modules'][1]['id']);
|
||||
self::assertSame('2.0.0', $data['modules'][1]['version']);
|
||||
self::assertSame(['alpha'], $data['modules'][1]['requires']);
|
||||
}
|
||||
|
||||
public function testPermissionSummaryReturnsCorrectCounts(): void
|
||||
{
|
||||
$service = new SystemInfoService($this->healthService, $this->healthRepository, null);
|
||||
|
||||
$this->healthService->method('runAll')->willReturn([]);
|
||||
$this->healthRepository->expects($this->once())->method('countActivePermissions')->willReturn(42);
|
||||
$this->healthRepository->expects($this->once())->method('countInactivePermissions')->willReturn(3);
|
||||
$this->healthRepository->expects($this->once())->method('listAllActivePermissionKeys')->willReturn([
|
||||
'users.view', 'settings.view',
|
||||
]);
|
||||
|
||||
$data = $service->buildPageData();
|
||||
|
||||
self::assertSame(42, $data['permissions']['active_count']);
|
||||
self::assertSame(3, $data['permissions']['inactive_count']);
|
||||
self::assertSame(['core' => 2], $data['permissions']['by_source']);
|
||||
}
|
||||
|
||||
public function testBuildPageDataWorksWithoutModuleRegistry(): void
|
||||
{
|
||||
$service = new SystemInfoService($this->healthService, $this->healthRepository, null);
|
||||
|
||||
$this->healthService->method('runAll')->willReturn([]);
|
||||
$this->healthRepository->method('countActivePermissions')->willReturn(5);
|
||||
$this->healthRepository->method('countInactivePermissions')->willReturn(0);
|
||||
$this->healthRepository->method('listAllActivePermissionKeys')->willReturn([]);
|
||||
|
||||
$data = $service->buildPageData();
|
||||
|
||||
self::assertSame([], $data['modules']);
|
||||
}
|
||||
|
||||
private function createRegistryWithModules(): ModuleRegistry
|
||||
{
|
||||
mkdir($this->fixturesDir . '/alpha', 0777, true);
|
||||
file_put_contents(
|
||||
$this->fixturesDir . '/alpha/module.php',
|
||||
'<?php return ' . var_export([
|
||||
'id' => 'alpha',
|
||||
'version' => '1.0.0',
|
||||
'enabled_by_default' => true,
|
||||
], true) . ';'
|
||||
);
|
||||
|
||||
mkdir($this->fixturesDir . '/beta', 0777, true);
|
||||
file_put_contents(
|
||||
$this->fixturesDir . '/beta/module.php',
|
||||
'<?php return ' . var_export([
|
||||
'id' => 'beta',
|
||||
'version' => '2.0.0',
|
||||
'enabled_by_default' => false,
|
||||
'requires' => ['alpha'],
|
||||
], true) . ';'
|
||||
);
|
||||
|
||||
return ModuleRegistry::boot($this->fixturesDir, ['alpha', 'beta']);
|
||||
}
|
||||
|
||||
private function removeDir(string $dir): void
|
||||
{
|
||||
if (!is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
$items = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
foreach ($items as $item) {
|
||||
$item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
|
||||
}
|
||||
rmdir($dir);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user