modifyQueryUsing(fn (Builder $query) => $query->with('user')) ->columns([ Tables\Columns\TextColumn::make('user.email') ->label(__('User')) ->searchable(), Tables\Columns\TextColumn::make('user_domain') ->label(__('Domain')) ->getStateUsing(function (TenantMembership $record): ?string { $email = $record->user?->email; if (! is_string($email) || $email === '' || ! str_contains($email, '@')) { return null; } return (string) str($email)->after('@')->lower(); }), Tables\Columns\TextColumn::make('user.name') ->label(__('Name')) ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('role') ->badge() ->sortable(), Tables\Columns\TextColumn::make('source') ->badge() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_at')->since(), ]) ->headerActions([ UiEnforcement::forTableAction( Action::make('add_member') ->label(__('Add member')) ->icon('heroicon-o-plus') ->form([ Forms\Components\Select::make('user_id') ->label(__('User')) ->required() ->searchable() ->options(fn () => User::query() ->orderBy('email') ->get(['id', 'name', 'email']) ->mapWithKeys(fn (User $user): array => [ (string) $user->id => trim((string) ($user->name ? "{$user->name} ({$user->email})" : $user->email)), ]) ->all()), Forms\Components\Select::make('role') ->label(__('Role')) ->required() ->options([ 'owner' => __('Owner'), 'manager' => __('Manager'), 'operator' => __('Operator'), 'readonly' => __('Readonly'), ]), ]) ->action(function (array $data, TenantMembershipManager $manager): void { $tenant = $this->getOwnerRecord(); if (! $tenant instanceof Tenant) { abort(404); } $actor = auth()->user(); if (! $actor instanceof User) { abort(403); } $member = User::query()->find((int) $data['user_id']); if (! $member) { Notification::make()->title(__('User not found'))->danger()->send(); return; } try { $manager->addMember( tenant: $tenant, actor: $actor, member: $member, role: (string) $data['role'], source: 'manual', ); } catch (\Throwable $throwable) { Notification::make() ->title(__('Failed to add member')) ->body($throwable->getMessage()) ->danger() ->send(); return; } Notification::make()->title(__('Member added'))->success()->send(); $this->resetTable(); }), fn () => $this->getOwnerRecord(), ) ->requireCapability(Capabilities::TENANT_MEMBERSHIP_MANAGE) ->tooltip('You do not have permission to manage tenant memberships.') ->apply(), ]) ->actions([ UiEnforcement::forTableAction( Action::make('change_role') ->label(__('Change role')) ->icon('heroicon-o-pencil') ->requiresConfirmation() ->form([ Forms\Components\Select::make('role') ->label(__('Role')) ->required() ->options([ 'owner' => __('Owner'), 'manager' => __('Manager'), 'operator' => __('Operator'), 'readonly' => __('Readonly'), ]), ]) ->action(function (TenantMembership $record, array $data, TenantMembershipManager $manager): void { $tenant = $this->getOwnerRecord(); if (! $tenant instanceof Tenant) { abort(404); } $actor = auth()->user(); if (! $actor instanceof User) { abort(403); } try { $manager->changeRole( tenant: $tenant, actor: $actor, membership: $record, newRole: (string) $data['role'], ); } catch (\Throwable $throwable) { Notification::make() ->title(__('Failed to change role')) ->body($throwable->getMessage()) ->danger() ->send(); return; } Notification::make()->title(__('Role updated'))->success()->send(); $this->resetTable(); }), fn () => $this->getOwnerRecord(), ) ->requireCapability(Capabilities::TENANT_MEMBERSHIP_MANAGE) ->tooltip('You do not have permission to manage tenant memberships.') ->apply(), UiEnforcement::forTableAction( Action::make('remove') ->label(__('Remove')) ->color('danger') ->icon('heroicon-o-x-mark') ->requiresConfirmation() ->action(function (TenantMembership $record, TenantMembershipManager $manager): void { $tenant = $this->getOwnerRecord(); if (! $tenant instanceof Tenant) { abort(404); } $actor = auth()->user(); if (! $actor instanceof User) { abort(403); } try { $manager->removeMember($tenant, $actor, $record); } catch (\Throwable $throwable) { Notification::make() ->title(__('Failed to remove member')) ->body($throwable->getMessage()) ->danger() ->send(); return; } Notification::make()->title(__('Member removed'))->success()->send(); $this->resetTable(); }), fn () => $this->getOwnerRecord(), ) ->requireCapability(Capabilities::TENANT_MEMBERSHIP_MANAGE) ->tooltip('You do not have permission to manage tenant memberships.') ->destructive() ->apply(), ]) ->bulkActions([]); } }