TenantAtlas/apps/platform/app/Filament/Widgets/Dashboard/RecentDriftFindings.php
ahmido e64bae9cfc feat: cut over tenant core to managed environments (#335)
## Summary
- replace the legacy Tenant and TenantMembership core models with ManagedEnvironment and ManagedEnvironmentMembership
- propagate the managed environment naming and key changes across Filament resources, pages, controllers, jobs, models, and supporting runtime paths
- add feature 279 spec artifacts and focused managed-environment test coverage for model behavior, route binding, panel context, authorization, and legacy guardrails

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentAuthorizationTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentRouteBindingTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentContextResolverTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentModelTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes
- branch pushed from commit `1123b122`
- browser smoke test file was added but not run in this pass

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #335
2026-05-07 06:38:14 +00:00

95 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Widgets\Dashboard;
use App\Filament\Resources\FindingResource;
use App\Models\Finding;
use App\Models\ManagedEnvironment;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\OpsUx\ActiveRuns;
use Filament\Facades\Filament;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
class RecentDriftFindings extends TableWidget
{
protected int|string|array $columnSpan = 'full';
public function table(Table $table): Table
{
$tenant = Filament::getTenant();
return $table
->heading('Recent Drift Findings')
->query($this->getQuery())
->poll(fn (): ?string => ($tenant instanceof ManagedEnvironment) && ActiveRuns::existForTenant($tenant) ? '10s' : null)
->defaultSort('created_at', 'desc')
->paginated(\App\Support\Filament\TablePaginationProfiles::widget())
->columns([
TextColumn::make('short_id')
->label('ID')
->state(fn (Finding $record): string => '#'.$record->getKey())
->copyable()
->copyableState(fn (Finding $record): string => (string) $record->getKey()),
TextColumn::make('subject_display_name')
->label('Subject')
->placeholder('—')
->limit(40)
->state(fn (Finding $record): ?string => $record->resolvedSubjectDisplayName())
->description(function (Finding $record): ?string {
if (Arr::get($record->evidence_jsonb ?? [], 'summary.kind') !== 'rbac_role_definition') {
return null;
}
return __('findings.drift.rbac_role_definition');
})
->tooltip(fn (Finding $record): ?string => $record->resolvedSubjectDisplayName()),
TextColumn::make('severity')
->badge()
->sortable()
->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingSeverity))
->color(BadgeRenderer::color(BadgeDomain::FindingSeverity))
->icon(BadgeRenderer::icon(BadgeDomain::FindingSeverity))
->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingSeverity)),
TextColumn::make('status')
->badge()
->sortable()
->toggleable(isToggledHiddenByDefault: true)
->formatStateUsing(BadgeRenderer::label(BadgeDomain::FindingStatus))
->color(BadgeRenderer::color(BadgeDomain::FindingStatus))
->icon(BadgeRenderer::icon(BadgeDomain::FindingStatus))
->iconColor(BadgeRenderer::iconColor(BadgeDomain::FindingStatus)),
TextColumn::make('created_at')
->label('Created')
->sortable()
->since(),
])
->recordUrl(fn (Finding $record): ?string => $tenant instanceof ManagedEnvironment
? FindingResource::getUrl('view', ['record' => $record], tenant: $tenant)
: null)
->emptyStateHeading('No drift findings')
->emptyStateDescription('You\'re looking good — no drift findings to review yet.');
}
/**
* @return Builder<Finding>
*/
private function getQuery(): Builder
{
$tenant = Filament::getTenant();
$tenantId = $tenant instanceof ManagedEnvironment ? $tenant->getKey() : null;
return Finding::query()
->withSubjectDisplayName()
->when($tenantId, fn (Builder $query) => $query->where('managed_environment_id', $tenantId))
->where('finding_type', Finding::FINDING_TYPE_DRIFT)
->latest('created_at');
}
}