id > 1; } public static function scopeEloquentQueryToTenant(Builder $query, ?Model $tenant): Builder { return $query->where('team_id', Filament::getTenant()->id)->orWhereNull('team_id'); } public static function getNavigationIcon(): ?string { return config('filament-spatie-roles-permissions.icons.role_navigation'); } public static function shouldRegisterNavigation(): bool { return true; } public static function getModel(): string { return config('permission.models.role', Role::class); } public static function getLabel(): string { return __('filament-spatie-roles-permissions::filament-spatie.section.role'); } public static function getNavigationGroup(): ?string { return __(config('filament-spatie-roles-permissions.navigation_section_group', 'filament-spatie-roles-permissions::filament-spatie.section.roles_and_permissions')); } public static function getNavigationSort(): ?int { return config('filament-spatie-roles-permissions.sort.role_navigation'); } public static function getPluralLabel(): string { return __('filament-spatie-roles-permissions::filament-spatie.section.roles'); } public function isReadOnly(): bool { return false; } public static function form(Form $form): Form { // Find all the permissions, group by the value after the first space in the permissions name $permissionsGroup = Permission::all()->groupBy(fn ($permission) => explode(' ', $permission->name, 2)[1]); // Build the Fields Groups $fieldGroups = []; foreach ($permissionsGroup as $group => $permissions) { $fieldGroups[] = Section::make($group) ->columnSpan(4) ->extraAttributes(['class' => 'compact-gap']) ->columns(12) ->schema( // array_merge( // [ // ToggleButtons::make('select_all_'.$group) // ->columnSpanFull() // ->hiddenLabel() // ->extraAttributes(['class' => 'select-all -mt-4']) // ->inline() // ->live() // ->options([ // true => 'Select All', // false => 'Deselect All', // ]) // ->afterStateUpdated(function ($record, $state, $set) use ($permissions) { // foreach ($permissions as $permission) { // $set("permissions.{$permission->id}", (bool) $state); // } // }), // ], $permissions->map(fn ($permission) => Checkbox::make("permissions.{$permission->id}") ->columnspan(4) ->label( trim(str_replace($group, '', $permission->name)) ) )->toArray() // ) ) ->headerActions([ Action::make('select_all') ->size('sm') ->label('All') ->action(function (callable $set) use ($permissions) { // Pass $set and use $permissions foreach ($permissions as $permission) { $set("permissions.{$permission->id}", true); } }), Action::make('deselect_all') ->size('sm') ->label('None') ->color('danger') ->action(function (callable $set) use ($permissions) { // Pass $set and use $permissions foreach ($permissions as $permission) { $set("permissions.{$permission->id}", false); } }), ]) ->heading(ucwords(preg_replace('/(?label(ucwords(preg_replace('/(?schema([ Section::make() ->schema([ Grid::make(12) ->schema([ TextInput::make('name') ->columnSpan(4) ->label(__('filament-spatie-roles-permissions::filament-spatie.field.name')) ->required() ->unique(ignoreRecord: true, modifyRuleUsing: function (Unique $rule) { // If using teams and Tenancy, ensure uniqueness against current tenant if (config('permission.teams', false) && Filament::hasTenancy()) { // Check uniqueness against current user/team $rule->where(config('permission.column_names.team_foreign_key', 'team_id'), Filament::getTenant()->id); } return $rule; }), Select::make('guard_name') ->columnSpan(4) ->label(__('filament-spatie-roles-permissions::filament-spatie.field.guard_name')) ->options(config('filament-spatie-roles-permissions.guard_names')) ->default('web') ->required(), Select::make(config('permission.column_names.team_foreign_key', 'team_id')) ->columnSpan(4) ->label('Vessel') // ->hidden(fn () => ! config('permission.teams', false) || Filament::hasTenancy()) ->options( fn () => config('filament-spatie-roles-permissions.team_model', \App\Models\Team::class)::pluck('name', 'id') ) ->dehydrated(fn ($state) => (int) $state > 0) ->dehydrateStateUsing(function ($state) { return (int) $state > 0 ? $state : null; }) ->default(null) ->nullable() ->placeholder(__('filament-spatie-roles-permissions::filament-spatie.select-team')) ->hint(__('filament-spatie-roles-permissions::filament-spatie.select-team-hint')), ]), ]), Group::make($fieldGroups) ->columnSpanFull() ->columns(12), ]); } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('id') ->label('ID') ->searchable(), TextColumn::make('name') ->label(__('filament-spatie-roles-permissions::filament-spatie.field.name')) ->searchable(), TextColumn::make('guard_name') ->toggleable(isToggledHiddenByDefault: config('filament-spatie-roles-permissions.toggleable_guard_names.roles.isToggledHiddenByDefault', true)) ->label(__('filament-spatie-roles-permissions::filament-spatie.field.guard_name')) ->searchable(), TextColumn::make('team.name')->label('Vessel'), TextColumn::make('permissions_count') ->width('100px') ->counts('permissions') ->label(__('filament-spatie-roles-permissions::filament-spatie.field.permissions_count')) ->alignCenter() ->toggleable(), TextColumn::make('users_count') ->width('100px') ->counts('users') ->label('Users Assigned') ->alignCenter() ->toggleable(), ]) ->filters([ // Tables\Filters\Filter::make('team') // ->label('Vessel') // ->query(fn (Builder $query, array $data) => $query->where('team_id', (int) $data['team_id'] > 0 ? $data['team_id'] : null)) // ->form([ // Select::make('team_id') // ->label('Vessel') // ->options( // fn () => config('filament-spatie-roles-permissions.team_model', \App\Models\Team::class)::pluck('name', 'id') // ) // ->dehydrated(fn ($state) => (int) $state > 0) // ->dehydrateStateUsing(function ($state) { // return (int) $state > 0 ? $state : null; // }) // ->default(null) // ->nullable() // ->placeholder('- Global Roles -'), // ]), ]) ->actions([ Tables\Actions\EditAction::make()->disabled(fn ($record) => $record->team_id <= 1 && Filament::getTenant()->id > 1), Tables\Actions\ViewAction::make(), Tables\Actions\ReplicateAction::make() ->fillForm(fn ($record) => $record->toArray()) ->form([ Grid::make(2)->schema([ TextInput::make('name') ->label('Role Name') ->unique(), Select::make('team_id') ->label('Vessel') ->options( fn () => config('filament-spatie-roles-permissions.team_model', \App\Models\Team::class)::pluck('name', 'id') ) ->dehydrated(fn ($state) => (int) $state > 0) ->dehydrateStateUsing(function ($state) { return (int) $state > 0 ? $state : null; }) ->default(null) ->nullable() ->placeholder(__('filament-spatie-roles-permissions::filament-spatie.select-team')) ->hint(__('filament-spatie-roles-permissions::filament-spatie.select-team-hint')), Toggle::make('assign_same_users') ->label('Assign Users from Original Role') ->dehydrated(false) ->default(false), ]), ]) ->beforeReplicaSaved(function ($record, $replica, $data) { $replica->name = Arr::get($data, 'name', $replica->name); }) ->excludeAttributes(['users_count', 'permissions_count']) ->after(function ($record, $replica, $data) { $replica->syncPermissions($record->permissions->pluck('id')); if (Arr::get($data, 'assign_same_users', false)) { foreach ($record->users as $user) { foreach ($user->teams as $team) { $replica->users()->syncWithoutDetaching([$user->id => ['team_id' => $team->id]]); } } } }), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]) ->emptyStateActions([ Tables\Actions\CreateAction::make(), ]) ->defaultSort('order_id', 'asc') ->reorderable('order_id'); } public static function getRelations(): array { return [ // PermissionRelationManager::class, UserRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => ListRoles::route('/'), 'create' => CreateRole::route('/create'), 'edit' => EditRole::route('/{record}/edit'), 'view' => ViewRole::route('/{record}'), ]; } }