TenantAtlas/app/Filament/Pages/ManagedTenants/Index.php
2026-02-01 10:49:19 +01:00

147 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Pages\ManagedTenants;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Rbac\UiEnforcement;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Pages\Page;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use UnitEnum;
class Index extends Page implements HasTable
{
use InteractsWithTable;
protected static bool $isDiscovered = false;
protected static bool $shouldRegisterNavigation = true;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-building-office-2';
protected static string|UnitEnum|null $navigationGroup = 'Managed tenants';
protected static ?string $navigationLabel = 'Managed tenants';
protected static ?string $slug = 'managed-tenants';
protected static ?string $title = 'Managed tenants';
protected string $view = 'filament.pages.managed-tenants.index';
public function mount(): void
{
$user = auth()->user();
if (! $user instanceof User) {
abort(403);
}
if (! $user->tenantMemberships()->exists()) {
abort(404);
}
/** @var CapabilityResolver $resolver */
$resolver = app(CapabilityResolver::class);
$canViewAny = Tenant::query()
->whereIn('id', $user->tenants()->withTrashed()->pluck('tenants.id'))
->cursor()
->contains(fn (Tenant $tenant): bool => $resolver->can($user, $tenant, Capabilities::TENANT_MANAGED_TENANTS_VIEW));
if (! $canViewAny) {
abort(403);
}
}
/**
* @return array<Action>
*/
protected function getHeaderActions(): array
{
return [
Action::make('add_managed_tenant')
->label('Add managed tenant')
->icon('heroicon-o-plus')
->url('/admin/managed-tenants/onboarding'),
];
}
public function table(Table $table): Table
{
return $table
->query($this->managedTenantsQuery())
->columns([
TextColumn::make('name')->searchable(),
TextColumn::make('tenant_id')->label('Tenant ID')->copyable()->searchable(),
TextColumn::make('environment')->badge()->sortable(),
TextColumn::make('status')->badge()->sortable(),
])
->actions([
UiEnforcement::forTableAction(
Action::make('open')
->label('Open')
->icon('heroicon-o-arrow-top-right-on-square')
->url(fn (Tenant $record): string => "/admin/managed-tenants/{$record->getKey()}/open"),
fn () => Filament::getTenant(),
)
->requireCapability(Capabilities::TENANT_MANAGED_TENANTS_VIEW)
->apply(),
UiEnforcement::forTableAction(
Action::make('view')
->label('View')
->url(fn (Tenant $record): string => ViewManagedTenant::getUrl(['managedTenant' => $record])),
fn () => Filament::getTenant(),
)
->requireCapability(Capabilities::TENANT_MANAGED_TENANTS_VIEW)
->apply(),
UiEnforcement::forTableAction(
Action::make('edit')
->label('Edit')
->url(fn (Tenant $record): string => EditManagedTenant::getUrl(['managedTenant' => $record])),
fn () => Filament::getTenant(),
)
->requireCapability(Capabilities::TENANT_MANAGED_TENANTS_MANAGE)
->apply(),
])
->emptyStateHeading('No managed tenants')
->emptyStateDescription('Add your first managed tenant to begin onboarding.')
->emptyStateActions([
Action::make('empty_add_managed_tenant')
->label('Add managed tenant')
->icon('heroicon-o-plus')
->url('/admin/managed-tenants/onboarding'),
]);
}
private function managedTenantsQuery(): Builder
{
$user = auth()->user();
if (! $user instanceof User) {
return Tenant::query()->whereRaw('1 = 0');
}
$tenantIds = $user->tenants()
->withTrashed()
->pluck('tenants.id');
return Tenant::query()
->withTrashed()
->whereIn('id', $tenantIds);
}
}