user(); if (! $user instanceof User) { return false; } /** @var WorkspaceCapabilityResolver $resolver */ $resolver = app(WorkspaceCapabilityResolver::class); $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request()); if (is_int($workspaceId)) { $workspace = Workspace::query()->whereKey($workspaceId)->first(); if ($workspace instanceof Workspace) { return $resolver->isMember($user, $workspace) && $resolver->can($user, $workspace, Capabilities::WORKSPACE_MANAGE); } } foreach ($user->workspaces()->get() as $workspace) { if (! $workspace instanceof Workspace) { continue; } if ($resolver->can($user, $workspace, Capabilities::WORKSPACE_MANAGE)) { return true; } } return false; } public static function canEdit(Model $record): bool { $user = auth()->user(); if (! $user instanceof User || ! $record instanceof Workspace) { return false; } /** @var WorkspaceCapabilityResolver $resolver */ $resolver = app(WorkspaceCapabilityResolver::class); return $resolver->isMember($user, $record) && $resolver->can($user, $record, Capabilities::WORKSPACE_MANAGE); } public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration { return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView) ->satisfy(ActionSurfaceSlot::ListHeader, 'List page provides a capability-gated create action.') ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ViewAction->value) ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Workspace list intentionally uses only primary View/Edit row actions.') ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'Workspace list intentionally omits bulk actions.') ->satisfy(ActionSurfaceSlot::ListEmptyState, 'List page defines a capability-gated empty-state create CTA.') ->satisfy(ActionSurfaceSlot::DetailHeader, 'Workspace view page exposes a capability-gated edit action.'); } public static function getEloquentQuery(): Builder { $query = parent::getEloquentQuery(); $user = auth()->user(); if (! $user instanceof User) { return $query->whereRaw('1 = 0'); } return $query ->whereNull('archived_at') ->whereIn('id', function ($subQuery) use ($user): void { $subQuery->from('workspace_memberships') ->select('workspace_id') ->where('user_id', $user->getKey()); }); } public static function form(Schema $schema): Schema { return $schema ->schema([ Forms\Components\TextInput::make('name') ->required() ->maxLength(255), Forms\Components\TextInput::make('slug') ->required() ->maxLength(255) ->unique(ignoreRecord: true), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('name') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('slug') ->searchable() ->sortable(), ]) ->actions([ Actions\ViewAction::make(), WorkspaceUiEnforcement::forTableAction( Actions\EditAction::make(), fn (): ?Workspace => null, ) ->requireCapability(Capabilities::WORKSPACE_MANAGE) ->apply(), ]); } public static function getPages(): array { return [ 'index' => Pages\ListWorkspaces::route('/'), 'create' => Pages\CreateWorkspace::route('/create'), 'view' => Pages\ViewWorkspace::route('/{record}'), 'edit' => Pages\EditWorkspace::route('/{record}/edit'), ]; } public static function getRelations(): array { return [ WorkspaceMembershipsRelationManager::class, ]; } }