1212use Filament \Schemas \Schema ;
1313use Filament \Tables ;
1414use Filament \Tables \Table ;
15- use Tapp \FilamentLibrary \Forms \Components \UserSearchSelect ;
15+ use Illuminate \Database \Eloquent \Model ;
16+ use Illuminate \Support \Facades \Schema as SchemaFacade ;
17+ use Tapp \FilamentLibrary \Models \LibraryItemPermission ;
18+ use App \Models \User ;
1619
1720class LibraryItemPermissionsRelationManager extends RelationManager
1821{
@@ -24,66 +27,175 @@ class LibraryItemPermissionsRelationManager extends RelationManager
2427
2528 protected static ?string $ pluralModelLabel = 'Permissions ' ;
2629
30+
31+ public static function canAccess (): bool
32+ {
33+ $ user = auth ()->user ();
34+ if (!$ user ) {
35+ return false ;
36+ }
37+
38+ // Admins can always access
39+ if ($ user ->hasRole ('Admin ' )) {
40+ return true ;
41+ }
42+
43+ // For non-admins, check if they have share permission on the current record
44+ $ record = static ::getOwnerRecord ();
45+ if ($ record && $ record ->hasPermission ($ user , 'share ' )) {
46+ return true ;
47+ }
48+
49+ return false ;
50+ }
51+
52+ public static function canViewForRecord (Model $ ownerRecord , string $ pageClass ): bool
53+ {
54+ return $ ownerRecord ->hasPermission (auth ()->user (), 'share ' );
55+ }
56+
57+ /**
58+ * Get the display name for a user, supporting both 'name' and 'first_name/last_name' fields.
59+ */
60+ private function getUserDisplayName ($ user ): string
61+ {
62+ if (!$ user ) {
63+ return 'Unknown User ' ;
64+ }
65+
66+ // Check if user has a name accessor or name field with a value
67+ if ($ user ->name ) {
68+ return $ user ->name . ' ( ' . $ user ->email . ') ' ;
69+ }
70+
71+ // Fall back to first_name/last_name if available
72+ if (SchemaFacade::hasColumn ('users ' , 'first_name ' ) && SchemaFacade::hasColumn ('users ' , 'last_name ' )) {
73+ $ firstName = $ user ->first_name ?? '' ;
74+ $ lastName = $ user ->last_name ?? '' ;
75+ $ fullName = trim ($ firstName . ' ' . $ lastName );
76+
77+ if ($ fullName ) {
78+ return $ fullName . ' ( ' . $ user ->email . ') ' ;
79+ }
80+ }
81+
82+ // Fall back to email only
83+ return $ user ->email ;
84+ }
85+
2786 public function form (Schema $ schema ): Schema
2887 {
2988 return $ schema
3089 ->components ([
31- UserSearchSelect ::make ('user_id ' )
90+ Forms \ Components \Select ::make ('user_id ' )
3291 ->label ('User ' )
33- ->required ()
3492 ->searchable ()
35- ->preload (),
93+ ->preload ()
94+ ->getSearchResultsUsing (fn (string $ search ): array =>
95+ User::where (function ($ query ) use ($ search ) {
96+ // Search first_name and last_name fields if they exist
97+ if (SchemaFacade::hasColumn ('users ' , 'first_name ' ) && SchemaFacade::hasColumn ('users ' , 'last_name ' )) {
98+ $ query ->orWhere ('first_name ' , 'like ' , "% {$ search }% " )
99+ ->orWhere ('last_name ' , 'like ' , "% {$ search }% " );
100+ }
101+ // Search name field if it exists and first/last don't
102+ elseif (SchemaFacade::hasColumn ('users ' , 'name ' )) {
103+ $ query ->orWhere ('name ' , 'like ' , "% {$ search }% " );
104+ }
105+ // Always search email
106+ $ query ->orWhere ('email ' , 'like ' , "% {$ search }% " );
107+ })
108+ ->limit (50 )
109+ ->get ()
110+ ->mapWithKeys (fn ($ user ) => [
111+ $ user ->id => $ this ->getUserDisplayName ($ user )
112+ ])
113+ ->toArray ()
114+ )
115+ ->getOptionLabelUsing (fn ($ value ): ?string =>
116+ $ this ->getUserDisplayName (User::find ($ value ))
117+ )
118+ ->required (),
119+
36120 Forms \Components \Select::make ('role ' )
37121 ->label ('Role ' )
38- ->options (\Tapp \FilamentLibrary \Models \LibraryItemPermission::getRoleOptions ())
39- ->required ()
40- ->default ('viewer ' ),
122+ ->options (LibraryItemPermission::getRoleOptions ())
123+ ->required (),
41124 ]);
42125 }
43126
44127 public function table (Table $ table ): Table
45128 {
46129 return $ table
47- ->recordTitleAttribute ('user.name ' )
130+ ->recordTitleAttribute ('role ' )
48131 ->columns ([
49- Tables \Columns \TextColumn::make ('user.name ' )
132+ Tables \Columns \TextColumn::make ('user ' )
50133 ->label ('User ' )
51- ->searchable ()
52- ->sortable (),
134+ ->formatStateUsing (fn ($ record ) => $ this ->getUserDisplayName ($ record ->user ))
135+ ->searchable (function ($ query , $ search ) {
136+ return $ query ->where (function ($ query ) use ($ search ) {
137+ // Search first_name and last_name fields if they exist
138+ if (SchemaFacade::hasColumn ('users ' , 'first_name ' ) && SchemaFacade::hasColumn ('users ' , 'last_name ' )) {
139+ $ query ->orWhere ('first_name ' , 'like ' , "% {$ search }% " )
140+ ->orWhere ('last_name ' , 'like ' , "% {$ search }% " );
141+ }
142+ // Search name field if it exists and first/last don't
143+ elseif (SchemaFacade::hasColumn ('users ' , 'name ' )) {
144+ $ query ->orWhere ('name ' , 'like ' , "% {$ search }% " );
145+ }
146+ // Always search email
147+ $ query ->orWhere ('email ' , 'like ' , "% {$ search }% " );
148+ });
149+ }),
150+
53151 Tables \Columns \TextColumn::make ('user.email ' )
54152 ->label ('Email ' )
55- ->searchable ()
56- -> sortable (),
153+ ->searchable (),
154+
57155 Tables \Columns \TextColumn::make ('role ' )
58156 ->label ('Role ' )
59157 ->badge ()
60158 ->color (fn (string $ state ): string => match ($ state ) {
61- 'viewer ' => 'info ' ,
62- 'editor ' => 'success ' ,
63- 'owner ' => 'warning ' ,
159+ 'owner ' => 'danger ' ,
160+ 'editor ' => 'warning ' ,
161+ 'viewer ' => 'success ' ,
64162 default => 'gray ' ,
65163 }),
164+
66165 Tables \Columns \TextColumn::make ('created_at ' )
67- ->label ('Granted ' )
166+ ->label ('Added ' )
68167 ->dateTime ()
69168 ->sortable ()
70169 ->toggleable (isToggledHiddenByDefault: true ),
71170 ])
72171 ->filters ([
73172 Tables \Filters \SelectFilter::make ('role ' )
74- ->options (\ Tapp \ FilamentLibrary \ Models \ LibraryItemPermission::getRoleOptions ()),
173+ ->options (LibraryItemPermission::getRoleOptions ()),
75174 ])
76175 ->headerActions ([
77- CreateAction::make (),
176+ CreateAction::make ()
177+ ->visible (fn () => $ this ->ownerRecord ->hasPermission (auth ()->user (), 'share ' )),
78178 ])
179+ ->heading ('User Permissions ' )
180+ ->description ('Owner: Share and edit. Editor/Viewer: Standard permissions. ' )
79181 ->actions ([
80- EditAction::make (),
81- DeleteAction::make (),
182+ EditAction::make ()
183+ ->visible (fn () => $ this ->ownerRecord ->hasPermission (auth ()->user (), 'share ' )),
184+ DeleteAction::make ()
185+ ->visible (fn () => $ this ->ownerRecord ->hasPermission (auth ()->user (), 'share ' )),
82186 ])
83187 ->bulkActions ([
84188 BulkActionGroup::make ([
85- DeleteBulkAction::make (),
189+ DeleteBulkAction::make ()
190+ ->visible (fn () => $ this ->ownerRecord ->hasPermission (auth ()->user (), 'share ' )),
86191 ]),
192+ ])
193+ ->emptyStateHeading ('No permissions assigned ' )
194+ ->emptyStateDescription ('Add users to grant them specific permissions on this item. ' )
195+ ->emptyStateActions ([
196+ CreateAction::make ()
197+ ->label ('Add Permission ' )
198+ ->visible (fn () => $ this ->ownerRecord ->hasPermission (auth ()->user (), 'share ' )),
87199 ]);
88200 }
89201}
0 commit comments