sourceGroupId = $sourceGroupId; $this->sourceGroupDisplayName = filled($sourceGroupDisplayName) ? $sourceGroupDisplayName : null; $this->tenantId = is_int($tenantId) && $tenantId > 0 ? $tenantId : null; $tenant = $this->resolveTenantContext(); if ($tenant instanceof ManagedEnvironment) { $this->tenantId = (int) $tenant->getKey(); $this->hasCachedGroups = EntraGroup::query() ->where('managed_environment_id', $tenant->getKey()) ->exists(); $this->groupSyncUrl = EntraGroupResource::getUrl('index', tenant: $tenant); $this->groupSyncOperationsUrl = OperationRunLinks::index($tenant, operationType: 'directory.groups.sync'); } } public function table(Table $table): Table { $tenantId = $this->tenantId ?? $this->resolveTenantContext()?->getKey(); $query = EntraGroup::query(); if ($tenantId) { $query->where('managed_environment_id', $tenantId); } else { $query->whereRaw('1 = 0'); } $stalenessDays = (int) config('directory_groups.staleness_days', 30); $cutoff = now('UTC')->subDays(max(1, $stalenessDays)); return $table ->queryStringIdentifier('entraGroupCachePicker') ->query($query) ->defaultSort('display_name') ->paginated(\App\Support\Filament\TablePaginationProfiles::picker()) ->defaultPaginationPageOption(25) ->searchable() ->searchPlaceholder('Search groups…') ->deferLoading(! app()->runningUnitTests()) ->columns([ TextColumn::make('display_name') ->label('Name') ->searchable() ->sortable() ->wrap() ->limit(60), TextColumn::make('type') ->label('Type') ->badge() ->state(fn (EntraGroup $record): string => $this->groupTypeLabel($this->groupType($record))) ->color(fn (EntraGroup $record): string => $this->groupTypeColor($this->groupType($record))) ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('entra_id') ->label('ID') ->formatStateUsing(fn (?string $state): string => filled($state) ? ('…'.substr($state, -8)) : '—') ->extraAttributes(['class' => 'font-mono']) ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('last_seen_at') ->label('Last seen') ->since() ->sortable(), ]) ->filters([ SelectFilter::make('stale') ->label('Stale') ->options([ '1' => 'Stale', '0' => 'Fresh', ]) ->query(function (Builder $query, array $data) use ($cutoff): Builder { $value = $data['value'] ?? null; if ($value === null || $value === '') { return $query; } if ((string) $value === '1') { return $query->where(function (Builder $q) use ($cutoff): void { $q->whereNull('last_seen_at') ->orWhere('last_seen_at', '<', $cutoff); }); } return $query->where('last_seen_at', '>=', $cutoff); }), SelectFilter::make('group_type') ->label('Type') ->options([ 'security' => 'Security', 'microsoft365' => 'Microsoft 365', 'mail' => 'Mail-enabled', 'unknown' => 'Unknown', ]) ->query(function (Builder $query, array $data): Builder { $value = (string) ($data['value'] ?? ''); if ($value === '') { return $query; } return match ($value) { 'microsoft365' => $query->whereJsonContains('group_types', 'Unified'), 'security' => $query ->where('security_enabled', true) ->where(function (Builder $q): void { $q->whereNull('group_types') ->orWhereJsonDoesntContain('group_types', 'Unified'); }), 'mail' => $query ->where('mail_enabled', true) ->where(function (Builder $q): void { $q->whereNull('group_types') ->orWhereJsonDoesntContain('group_types', 'Unified'); }), 'unknown' => $query ->where(function (Builder $q): void { $q->whereNull('group_types') ->orWhereJsonDoesntContain('group_types', 'Unified'); }) ->where('security_enabled', false) ->where('mail_enabled', false), default => $query, }; }), ]) ->actions([ Action::make('select') ->label('Select') ->icon('heroicon-o-check') ->color('primary') ->action(function (EntraGroup $record): void { $this->dispatch('entra-group-cache-picked', sourceGroupId: $this->sourceGroupId, entraId: (string) $record->entra_id); }), ]) ->emptyStateHeading('No cached directory groups match your search') ->emptyStateDescription('Try a broader search, or sync directory groups if the cache is incomplete for this environment.') ->emptyStateActions([]); } public function render(): View { return view('livewire.entra-group-cache-picker-table'); } private function groupType(EntraGroup $record): string { $groupTypes = $record->group_types; if (is_array($groupTypes) && in_array('Unified', $groupTypes, true)) { return 'microsoft365'; } if ($record->security_enabled) { return 'security'; } if ($record->mail_enabled) { return 'mail'; } return 'unknown'; } private function groupTypeLabel(string $type): string { return match ($type) { 'microsoft365' => 'Microsoft 365', 'security' => 'Security', 'mail' => 'Mail-enabled', default => 'Unknown', }; } private function groupTypeColor(string $type): string { return match ($type) { 'microsoft365' => 'info', 'security' => 'success', 'mail' => 'warning', default => 'gray', }; } private function resolveTenantContext(): ?ManagedEnvironment { if ($this->tenantId !== null) { $tenant = ManagedEnvironment::query()->find($this->tenantId); if ($tenant instanceof ManagedEnvironment) { return $tenant; } } $tenant = app(OperateHubShell::class)->tenantOwnedPanelContext(request()); if ($tenant instanceof ManagedEnvironment) { return $tenant; } $tenant = ManagedEnvironment::current(); return $tenant instanceof ManagedEnvironment ? $tenant : null; } }