schema([ Section::make('Group') ->schema([ TextEntry::make('display_name')->label('Name'), TextEntry::make('entra_id')->label('Entra ID')->copyable(), TextEntry::make('type') ->badge() ->state(fn (EntraGroup $record): string => static::groupTypeLabel(static::groupType($record))), TextEntry::make('security_enabled')->label('Security')->badge(), TextEntry::make('mail_enabled')->label('Mail')->badge(), TextEntry::make('last_seen_at')->label('Last seen')->dateTime()->placeholder('—'), ]) ->columns(2) ->columnSpanFull(), Section::make('Raw groupTypes') ->schema([ ViewEntry::make('group_types') ->label('') ->view('filament.infolists.entries.snapshot-json') ->state(fn (EntraGroup $record) => $record->group_types ?? []) ->columnSpanFull(), ]) ->columnSpanFull(), ]); } public static function table(Table $table): Table { return $table ->defaultSort('display_name') ->modifyQueryUsing(function (Builder $query): Builder { $tenantId = Tenant::current()?->getKey(); return $query->when($tenantId, fn (Builder $q) => $q->where('tenant_id', $tenantId)); }) ->columns([ Tables\Columns\TextColumn::make('display_name')->label('Name')->searchable(), Tables\Columns\TextColumn::make('entra_id')->label('Entra ID')->copyable()->toggleable(), Tables\Columns\TextColumn::make('type') ->label('Type') ->badge() ->state(fn (EntraGroup $record): string => static::groupTypeLabel(static::groupType($record))) ->color(fn (EntraGroup $record): string => static::groupTypeColor(static::groupType($record))), Tables\Columns\TextColumn::make('last_seen_at')->since()->label('Last seen'), ]) ->filters([ SelectFilter::make('stale') ->label('Stale') ->options([ '1' => 'Stale', '0' => 'Fresh', ]) ->query(function (Builder $query, array $data): Builder { $value = $data['value'] ?? null; if ($value === null || $value === '') { return $query; } $stalenessDays = (int) config('directory_groups.staleness_days', 30); $cutoff = now('UTC')->subDays(max(1, $stalenessDays)); 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([ Actions\ViewAction::make(), ]) ->bulkActions([]); } public static function getEloquentQuery(): Builder { return parent::getEloquentQuery()->latest('id'); } public static function getPages(): array { return [ 'index' => Pages\ListEntraGroups::route('/'), 'view' => Pages\ViewEntraGroup::route('/{record}'), ]; } private static 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 static function groupTypeLabel(string $type): string { return match ($type) { 'microsoft365' => 'Microsoft 365', 'security' => 'Security', 'mail' => 'Mail-enabled', default => 'Unknown', }; } private static function groupTypeColor(string $type): string { return match ($type) { 'microsoft365' => 'info', 'security' => 'success', 'mail' => 'warning', default => 'gray', }; } }