TenantAtlas/apps/platform/app/Filament/Pages/Monitoring/Operations.php
ahmido aeef285d1d feat: implement spec 286 UI copy, IA & localization neutralization (#345)
## Summary

Implements feature branch `286-ui-copy-ia-localization-neutralization`.

This change set:
- aligns chooser, managed-environment landing, dashboard, shell, and workspace context copy to environment-first terminology
- neutralizes the bounded policy and baseline helper copy called out by Spec 286
- adds focused feature, guard, and browser coverage plus the complete Spec 286 artifact set
- records the discovered `Capture snapshot` modal issue as out-of-scope runtime debt in the Spec 286 close-out notes

## Validation

- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization/EnvironmentContextTerminologyTest.php tests/Feature/Filament/EnvironmentContextSurfaceCopyTest.php tests/Feature/Filament/Localization/PolicyInventoryLocalizationTest.php tests/Feature/Guards/EnvironmentCopyNeutralizationGuardTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec286EnvironmentCopyNeutralizationSmokeTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes

- Target branch: `platform-dev`
- Filament remains on v5 with Livewire v4.
- Provider registration remains unchanged in `apps/platform/bootstrap/providers.php`.
- No new destructive actions, asset strategy changes, or global-search posture changes are introduced in this slice.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #345
2026-05-09 23:29:11 +00:00

523 lines
19 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Pages\Monitoring;
use App\Filament\Resources\OperationRunResource;
use App\Filament\Widgets\Operations\OperationsKpiHeader;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Support\Filament\CanonicalAdminTenantFilterState;
use App\Support\Navigation\CanonicalNavigationContext;
use App\Support\OperateHub\OperateHubShell;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Operations\OperationLifecyclePolicy;
use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration;
use App\Support\Ui\ActionSurface\ActionSurfaceDefaults;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceType;
use App\Support\Workspaces\WorkspaceContext;
use App\Models\User;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Pages\Page;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use UnitEnum;
class Operations extends Page implements HasForms, HasTable
{
use InteractsWithForms;
use InteractsWithTable;
protected const MONITORING_PAGE_STATE_CONTRACT = [
'surfaceKey' => 'operations',
'surfaceType' => 'simple_monitoring',
'stateFields' => [
[
'stateKey' => 'managed_environment_id',
'stateClass' => 'contextual_prefilter',
'carrier' => 'query_param',
'queryRole' => 'durable_restorable',
'shareable' => true,
'restorableOnRefresh' => true,
'tenantSensitive' => true,
'invalidFallback' => 'discard_and_continue',
],
[
'stateKey' => 'tenant_scope',
'stateClass' => 'contextual_prefilter',
'carrier' => 'query_param',
'queryRole' => 'durable_restorable',
'shareable' => true,
'restorableOnRefresh' => true,
'tenantSensitive' => true,
'invalidFallback' => 'reset_to_default_scope',
],
[
'stateKey' => 'problemClass',
'stateClass' => 'contextual_prefilter',
'carrier' => 'query_param',
'queryRole' => 'scoped_deeplink',
'shareable' => true,
'restorableOnRefresh' => true,
'tenantSensitive' => false,
'invalidFallback' => 'discard_and_continue',
],
[
'stateKey' => 'activeTab',
'stateClass' => 'active',
'carrier' => 'livewire_property',
'queryRole' => 'durable_restorable',
'shareable' => true,
'restorableOnRefresh' => true,
'tenantSensitive' => false,
'invalidFallback' => 'discard_and_continue',
],
[
'stateKey' => 'tableFilters',
'stateClass' => 'shareable_restorable',
'carrier' => 'session',
'queryRole' => 'unsupported',
'shareable' => false,
'restorableOnRefresh' => true,
'tenantSensitive' => true,
'invalidFallback' => 'discard_and_continue',
],
],
'hydrationRule' => [
'precedenceOrder' => ['query', 'session', 'default'],
'appliesOnInitialMountOnly' => true,
'activeStateBecomesAuthoritativeAfterMount' => true,
'clearsOnTenantSwitch' => ['managed_environment_id', 'type', 'initiator_name'],
'invalidRequestedStateFallback' => 'discard_and_continue',
],
'inspectContract' => [
'primaryModel' => 'none',
'selectedStateKey' => null,
'openedBy' => [],
'presentation' => 'none',
'shareable' => false,
'invalidSelectionFallback' => 'discard_and_continue',
],
'shareableStateKeys' => ['managed_environment_id', 'tenant_scope', 'problemClass', 'activeTab'],
'localOnlyStateKeys' => [],
];
public string $activeTab = 'all';
/**
* @var array<string, mixed>|null
*/
public ?array $navigationContextPayload = null;
protected static bool $isDiscovered = false;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-queue-list';
protected static string|UnitEnum|null $navigationGroup = 'Monitoring';
protected static ?string $title = 'Operations';
// Must be non-static
protected string $view = 'filament.pages.monitoring.operations';
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
{
return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::RunLog, ActionSurfaceType::ReadOnlyRegistryReport)
->withDefaults(new ActionSurfaceDefaults(
moreGroupLabel: 'More',
exportIsDefaultBulkActionForReadOnly: false,
))
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions preserve scope context and return navigation for the monitoring operations list.')
->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'Operation runs remain immutable on the monitoring list and intentionally omit bulk actions.')
->satisfy(ActionSurfaceSlot::ListEmptyState, 'The empty state explains when no operation runs exist for the active workspace scope.')
->exempt(ActionSurfaceSlot::DetailHeader, 'Row navigation opens the canonical tenantless operation detail page, which owns header actions.');
}
/**
* @return array<string, mixed>
*/
public static function monitoringPageStateContract(): array
{
return self::MONITORING_PAGE_STATE_CONTRACT;
}
public function mount(): void
{
$this->navigationContextPayload = is_array(request()->query('nav')) ? request()->query('nav') : null;
$this->applyRequestedTenantScope();
app(CanonicalAdminTenantFilterState::class)->sync(
$this->getTableFiltersSessionKey(),
['type', 'initiator_name'],
request(),
);
$this->mountInteractsWithTable();
$this->applyRequestedDashboardPrefilter();
}
protected function getHeaderWidgets(): array
{
return [
OperationsKpiHeader::class,
];
}
/**
* @return array<Action>
*/
protected function getHeaderActions(): array
{
$operateHubShell = app(OperateHubShell::class);
$navigationContext = $this->navigationContext();
$actions = [
Action::make('operate_hub_scope_operations')
->label($operateHubShell->scopeLabel(request()))
->color('gray')
->disabled(),
];
$activeTenant = $operateHubShell->activeEntitledTenant(request());
if ($navigationContext?->backLinkLabel !== null && $navigationContext->backLinkUrl !== null) {
$actions[] = Action::make('operate_hub_back_to_origin_operations')
->label($navigationContext->backLinkLabel)
->icon('heroicon-o-arrow-left')
->color('gray')
->url($navigationContext->backLinkUrl);
} elseif ($activeTenant instanceof ManagedEnvironment) {
$actions[] = Action::make('operate_hub_back_to_tenant_operations')
->label('Back to '.$activeTenant->name)
->icon('heroicon-o-arrow-left')
->color('gray')
->url(\App\Filament\Pages\TenantDashboard::getUrl(tenant: $activeTenant));
}
if ($activeTenant instanceof ManagedEnvironment) {
$actions[] = Action::make('operate_hub_show_all_tenants')
->label(__('localization.shell.show_all_environments'))
->color('gray')
->action(function (): void {
Filament::setTenant(null, true);
app(WorkspaceContext::class)->clearLastTenantId(request());
$this->removeTableFilter('managed_environment_id');
$this->redirect(OperationRunLinks::index(allTenants: true));
});
}
return $actions;
}
/**
* @return array{
* scope_label: string,
* scope_body: string,
* return_label: ?string,
* return_body: ?string,
* scope_reset_label: ?string,
* scope_reset_body: ?string,
* inspect_body: string
* }
*/
public function landingHierarchySummary(): array
{
$operateHubShell = app(OperateHubShell::class);
$navigationContext = $this->navigationContext();
$activeTenant = $operateHubShell->activeEntitledTenant(request());
$returnLabel = null;
$returnBody = null;
if ($navigationContext?->backLinkLabel !== null && $navigationContext->backLinkUrl !== null) {
$returnLabel = $navigationContext->backLinkLabel;
$returnBody = 'Return to the originating monitoring surface without competing with the current tab, filters, or row inspection flow.';
} elseif ($activeTenant instanceof ManagedEnvironment) {
$returnLabel = 'Back to '.$activeTenant->name;
$returnBody = 'Return to the tenant dashboard when you need tenant-specific context outside this workspace monitoring landing.';
}
return [
'scope_label' => $operateHubShell->scopeLabel(request()),
'scope_body' => $activeTenant instanceof ManagedEnvironment
? 'The landing is currently narrowed to one environment inside the active workspace.'
: 'The landing is currently showing workspace-wide monitoring across all entitled environments.',
'return_label' => $returnLabel,
'return_body' => $returnBody,
'scope_reset_label' => $activeTenant instanceof ManagedEnvironment ? __('localization.shell.show_all_environments') : null,
'scope_reset_body' => $activeTenant instanceof ManagedEnvironment
? 'Reset the landing back to workspace-wide monitoring when environment-specific context is no longer needed.'
: null,
'inspect_body' => 'Open a run from the table to enter the canonical monitoring detail viewer.',
];
}
public function tabUrl(string $tab): string
{
$normalizedTab = in_array($tab, self::supportedTabs(), true) ? $tab : 'all';
return $this->operationsUrl([
'activeTab' => $normalizedTab !== 'all' ? $normalizedTab : null,
'problemClass' => in_array($normalizedTab, self::problemClassTabs(), true) ? $normalizedTab : null,
]);
}
private function navigationContext(): ?CanonicalNavigationContext
{
if (! is_array($this->navigationContextPayload)) {
return CanonicalNavigationContext::fromRequest(request());
}
return CanonicalNavigationContext::fromPayload($this->navigationContextPayload);
}
public function updatedActiveTab(): void
{
$this->resetPage();
}
public function table(Table $table): Table
{
return OperationRunResource::table($table)
->query(function (): Builder {
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
$tenantFilter = $this->currentTenantFilterId();
$query = OperationRun::query()
->with('user')
->latest('id')
->when(
$workspaceId,
fn (Builder $query): Builder => $query->where('workspace_id', (int) $workspaceId),
)
->when(
! $workspaceId,
fn (Builder $query): Builder => $query->whereRaw('1 = 0'),
)
->when(
$tenantFilter !== null,
fn (Builder $query): Builder => $query->where('managed_environment_id', $tenantFilter),
);
return $this->applyActiveTab($query);
});
}
private function applyRequestedTenantScope(): void
{
if (! $this->shouldForceWorkspaceWideTenantScope()) {
return;
}
Filament::setTenant(null, true);
app(WorkspaceContext::class)->clearLastTenantId(request());
}
/**
* @return array{likely_stale:int,reconciled:int}
*/
public function lifecycleVisibilitySummary(): array
{
$baseQuery = $this->scopedSummaryQuery();
if (! $baseQuery instanceof Builder) {
return [
'likely_stale' => 0,
'reconciled' => 0,
];
}
$reconciled = (clone $baseQuery)
->whereNotNull('context->reconciliation->reconciled_at')
->count();
$policy = app(OperationLifecyclePolicy::class);
$likelyStale = (clone $baseQuery)
->likelyStale($policy)
->count();
return [
'likely_stale' => $likelyStale,
'reconciled' => $reconciled,
];
}
private function applyActiveTab(Builder $query): Builder
{
return match ($this->activeTab) {
'active' => $query->healthyActive(),
OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION => $query->activeStaleAttention(),
OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP => $query->terminalFollowUp(),
'blocked' => $query->dashboardNeedsFollowUp(),
'succeeded' => $query
->where('status', OperationRunStatus::Completed->value)
->where('outcome', OperationRunOutcome::Succeeded->value),
'partial' => $query
->where('status', OperationRunStatus::Completed->value)
->where('outcome', OperationRunOutcome::PartiallySucceeded->value),
'failed' => $query
->where('status', OperationRunStatus::Completed->value)
->where('outcome', OperationRunOutcome::Failed->value),
default => $query,
};
}
private function scopedSummaryQuery(): ?Builder
{
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
if (! $workspaceId) {
return null;
}
$tenantFilter = $this->currentTenantFilterId();
return OperationRun::query()
->where('workspace_id', (int) $workspaceId)
->when(
$tenantFilter !== null,
fn (Builder $query): Builder => $query->where('managed_environment_id', $tenantFilter),
);
}
private function applyRequestedDashboardPrefilter(): void
{
if (! $this->shouldForceWorkspaceWideTenantScope()) {
$requestedTenantId = $this->normalizeEntitledTenantFilter(request()->query('managed_environment_id'));
if ($requestedTenantId !== null) {
$tenantId = (string) $requestedTenantId;
$this->tableFilters['managed_environment_id']['value'] = $tenantId;
$this->tableDeferredFilters['managed_environment_id']['value'] = $tenantId;
}
}
$requestedProblemClass = request()->query('problemClass');
if (in_array($requestedProblemClass, self::problemClassTabs(), true)) {
$this->activeTab = (string) $requestedProblemClass;
return;
}
$requestedTab = request()->query('activeTab');
if (in_array($requestedTab, self::supportedTabs(), true)) {
$this->activeTab = (string) $requestedTab;
}
}
private function shouldForceWorkspaceWideTenantScope(): bool
{
return request()->query('tenant_scope') === 'all';
}
private function operationsUrl(array $overrides = []): string
{
$parameters = array_merge(
['workspace' => app(WorkspaceContext::class)->currentWorkspace(request())],
$this->navigationContext()?->toQuery() ?? [],
[
'tenant_scope' => $this->shouldForceWorkspaceWideTenantScope() ? 'all' : null,
'managed_environment_id' => $this->shouldForceWorkspaceWideTenantScope() ? null : $this->currentTenantFilterId(),
'activeTab' => $this->activeTab !== 'all' ? $this->activeTab : null,
'problemClass' => in_array($this->activeTab, self::problemClassTabs(), true) ? $this->activeTab : null,
],
$overrides,
);
return route(
'admin.operations.index',
array_filter($parameters, static fn (mixed $value): bool => $value !== null && $value !== '' && $value !== []),
);
}
private function currentTenantFilterId(): ?int
{
$tenantFilter = app(CanonicalAdminTenantFilterState::class)->currentFilterValue(
$this->getTableFiltersSessionKey(),
$this->tableFilters ?? [],
request(),
);
return $this->normalizeEntitledTenantFilter($tenantFilter);
}
private function normalizeEntitledTenantFilter(mixed $value): ?int
{
if (! is_numeric($value)) {
return null;
}
$tenantId = (int) $value;
return in_array($tenantId, $this->authorizedTenantIds(), true)
? $tenantId
: null;
}
/**
* @return list<int>
*/
private function authorizedTenantIds(): array
{
$user = auth()->user();
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
if (! $user instanceof User || ! is_int($workspaceId)) {
return [];
}
return collect($user->getTenants(Filament::getCurrentOrDefaultPanel()))
->filter(static fn (ManagedEnvironment $tenant): bool => (int) $tenant->workspace_id === $workspaceId)
->filter(static fn (ManagedEnvironment $tenant): bool => $tenant->isActive())
->map(static fn (ManagedEnvironment $tenant): int => (int) $tenant->getKey())
->values()
->all();
}
/**
* @return list<string>
*/
private static function supportedTabs(): array
{
return [
'all',
'active',
'blocked',
'succeeded',
'partial',
'failed',
...self::problemClassTabs(),
];
}
/**
* @return list<string>
*/
private static function problemClassTabs(): array
{
return [
OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
];
}
}