1313use Filament \Facades \Filament ;
1414use Filament \Notifications \Notification ;
1515use Filament \Pages \Page ;
16+ use Filament \Resources \Concerns \HasTabs ;
1617use Filament \Schemas \Components \EmbeddedTable ;
18+ use Filament \Schemas \Components \Tabs \Tab ;
1719use Filament \Schemas \Schema ;
1820use Filament \Support \Facades \FilamentView ;
1921use Filament \Tables \Columns \ImageColumn ;
2325use Filament \Tables \Contracts \HasTable ;
2426use Filament \Tables \Table ;
2527use Illuminate \Pagination \LengthAwarePaginator ;
28+ use Livewire \Attributes \Url ;
2629
2730class PlayersPage extends Page implements HasTable
2831{
2932 use BlockAccessInConflict;
33+ use HasTabs;
3034 use InteractsWithTable;
3135
3236 protected static string |\BackedEnum |null $ navigationIcon = 'tabler-users-group ' ;
@@ -35,6 +39,20 @@ class PlayersPage extends Page implements HasTable
3539
3640 protected static ?int $ navigationSort = 30 ;
3741
42+ #[Url(as: 'tab ' )]
43+ public ?string $ activeTab = null ;
44+
45+ public bool $ isMinecraft = false ;
46+
47+ /** @var array<string, mixed> */
48+ public array $ players = [];
49+
50+ /** @var string[] */
51+ public array $ whitelist = [];
52+
53+ /** @var string[] */
54+ public array $ ops = [];
55+
3856 public static function canAccess (): bool
3957 {
4058 /** @var Server $server */
@@ -72,57 +90,67 @@ public function getTitle(): string
7290 return static ::getNavigationLabel ();
7391 }
7492
75- /**
76- * @throws Exception
77- */
78- public function table (Table $ table ): Table
93+ public function mount (): void
94+ {
95+ $ this ->loadPlayersData ();
96+
97+ $ this ->loadDefaultActiveTab ();
98+ }
99+
100+ protected function loadPlayersData (): void
79101 {
80102 /** @var Server $server */
81103 $ server = Filament::getTenant ();
82104
83105 /** @var ?GameQuery $gameQuery */
84106 $ gameQuery = $ server ->egg ->gameQuery ; // @phpstan-ignore property.notFound
85107
86- $ isMinecraft = $ gameQuery ?->query_type === 'minecraft_java ' ;
108+ $ this -> isMinecraft = $ gameQuery ?->query_type === 'minecraft_java ' ;
87109
88- $ whitelist = [];
89- $ ops = [];
110+ $ this -> whitelist = [];
111+ $ this -> ops = [];
90112
91- if ($ isMinecraft ) {
113+ if ($ this -> isMinecraft ) {
92114 $ fileRepository = (new DaemonFileRepository ())->setServer ($ server );
93115
94116 try {
95117 $ whitelist = json_decode ($ fileRepository ->getContent ('whitelist.json ' ), true , 512 , JSON_THROW_ON_ERROR );
96- $ whitelist = array_unique (array_map (fn ($ data ) => $ data ['name ' ], $ whitelist ));
118+ $ this -> whitelist = array_unique (array_map (fn ($ data ) => $ data ['name ' ], $ whitelist ));
97119 } catch (Exception $ exception ) {
98120 report ($ exception );
99121 }
100122
101123 try {
102124 $ ops = json_decode ($ fileRepository ->getContent ('ops.json ' ), true , 512 , JSON_THROW_ON_ERROR );
103- $ ops = array_unique (array_map (fn ($ data ) => $ data ['name ' ], $ ops ));
125+ $ this -> ops = array_unique (array_map (fn ($ data ) => $ data ['name ' ], $ ops ));
104126 } catch (Exception $ exception ) {
105127 report ($ exception );
106128 }
107129 }
108130
109- return $ table
110- ->records (function (?string $ search , int $ page , int $ recordsPerPage ) {
111- /** @var Server $server */
112- $ server = Filament::getTenant ();
113-
114- $ players = [];
131+ $ this ->players = [];
115132
116- /** @var ?GameQuery $gameQuery */
117- $ gameQuery = $ server -> egg -> gameQuery ; // @phpstan-ignore property.notFound
133+ if ( $ gameQuery) {
134+ $ data = $ gameQuery -> runQuery ( $ server );
118135
119- if ($ gameQuery ) {
120- $ data = $ gameQuery ->runQuery ($ server );
136+ if ($ data ) {
137+ $ this ->players = $ data ['players ' ] ?? [];
138+ }
139+ }
140+ }
121141
122- if ($ data ) {
123- $ players = $ data ['players ' ] ?? [];
124- }
125- }
142+ /**
143+ * @throws Exception
144+ */
145+ public function table (Table $ table ): Table
146+ {
147+ return $ table
148+ ->records (function (?string $ search , int $ page , int $ recordsPerPage ) {
149+ $ players = match ($ this ->activeTab ) {
150+ 'whitelist ' => array_map (fn ($ player ) => ['name ' => $ player ], $ this ->whitelist ),
151+ 'ops ' => array_map (fn ($ player ) => ['name ' => $ player ], $ this ->ops ),
152+ default => $ this ->players ,
153+ };
126154
127155 if ($ search ) {
128156 $ players = array_filter ($ players , fn ($ player ) => str ($ player ['name ' ])->contains ($ search , true ));
@@ -134,38 +162,38 @@ public function table(Table $table): Table
134162 ->contentGrid ([
135163 'default ' => 1 ,
136164 'lg ' => 2 ,
137- 'xl ' => $ isMinecraft ? 2 : 3 ,
165+ 'xl ' => $ this -> isMinecraft ? 2 : 3 ,
138166 ])
139167 ->columns ([
140168 Split::make ([
141169 ImageColumn::make ('avatar ' )
142- ->visible (fn () => $ isMinecraft )
143- ->state (fn (array $ record ) => 'https://cravatar.eu/helmhead/ ' . $ record ['id ' ] . '/256.png ' )
170+ ->visible (fn () => $ this -> isMinecraft )
171+ ->state (fn (array $ record ) => 'https://cravatar.eu/helmhead/ ' . ( array_key_exists ( ' id ' , $ record) ? $ record ['id ' ] : $ record [ ' name ' ]) . '/256.png ' )
144172 ->grow (false ),
145173 TextColumn::make ('name ' )
146174 ->label ('Name ' )
147175 ->tooltip (fn (array $ record ) => array_key_exists ('id ' , $ record ) ? $ record ['id ' ] : null )
148176 ->searchable (),
149177 TextColumn::make ('is_whitelisted ' )
150- ->visible (fn () => $ isMinecraft )
178+ ->visible (fn () => $ this -> isMinecraft )
151179 ->badge ()
152180 ->grow (false )
153- ->state (fn (array $ record ) => in_array ($ record ['name ' ], $ whitelist ) ? trans ('player-counter::query.whitelisted ' ) : null ),
181+ ->state (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> whitelist ) ? trans ('player-counter::query.whitelisted ' ) : null ),
154182 TextColumn::make ('is_op ' )
155- ->visible (fn () => $ isMinecraft )
183+ ->visible (fn () => $ this -> isMinecraft )
156184 ->badge ()
157185 ->grow (false )
158- ->state (fn (array $ record ) => in_array ($ record ['name ' ], $ ops ) ? trans ('player-counter::query.op ' ) : null ),
186+ ->state (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> ops ) ? trans ('player-counter::query.op ' ) : null ),
159187 TextColumn::make ('time ' )
160- ->hidden (fn () => $ isMinecraft )
188+ ->hidden (fn () => $ this -> isMinecraft )
161189 ->badge ()
162190 ->grow (false )
163191 ->formatStateUsing (fn ($ state ) => $ state ? CarbonInterval::seconds ($ state )->cascade ()->forHumans () : null ),
164192 ]),
165193 ])
166194 ->recordActions ([
167195 Action::make ('exclude_kick ' )
168- ->visible (fn () => $ isMinecraft )
196+ ->visible (fn () => ! $ this -> activeTab || $ this -> activeTab === ' online ' )
169197 ->label (trans ('player-counter::query.kick ' ))
170198 ->icon ('tabler-door-exit ' )
171199 ->color ('danger ' )
@@ -194,7 +222,7 @@ public function table(Table $table): Table
194222 }
195223 }),
196224 Action::make ('exclude_ban ' )
197- ->visible (fn () => $ isMinecraft )
225+ ->visible (fn () => ! $ this -> activeTab || $ this -> activeTab === ' online ' )
198226 ->label (trans ('player-counter::query.ban ' ))
199227 ->icon ('tabler-hammer ' )
200228 ->color ('danger ' )
@@ -224,16 +252,16 @@ public function table(Table $table): Table
224252 }
225253 }),
226254 Action::make ('exclude_whitelist ' )
227- ->visible (fn () => $ isMinecraft )
228- ->label (fn (array $ record ) => in_array ($ record ['name ' ], $ whitelist ) ? trans ('player-counter::query.remove_from_whitelist ' ) : trans ('player-counter::query.add_to_whitelist ' ))
229- ->icon (fn (array $ record ) => in_array ($ record ['name ' ], $ whitelist ) ? 'tabler-playlist-x ' : 'tabler-playlist-add ' )
230- ->color (fn (array $ record ) => in_array ($ record ['name ' ], $ whitelist ) ? 'danger ' : 'success ' )
231- ->action (function (array $ record ) use ( $ whitelist ) {
255+ ->visible (fn () => $ this -> isMinecraft )
256+ ->label (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> whitelist ) ? trans ('player-counter::query.remove_from_whitelist ' ) : trans ('player-counter::query.add_to_whitelist ' ))
257+ ->icon (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> whitelist ) ? 'tabler-playlist-x ' : 'tabler-playlist-add ' )
258+ ->color (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> whitelist ) ? 'danger ' : 'success ' )
259+ ->action (function (array $ record ) {
232260 /** @var Server $server */
233261 $ server = Filament::getTenant ();
234262
235263 try {
236- $ action = in_array ($ record ['name ' ], $ whitelist ) ? 'remove ' : 'add ' ;
264+ $ action = in_array ($ record ['name ' ], $ this -> whitelist ) ? 'remove ' : 'add ' ;
237265
238266 $ server ->send ('whitelist ' . $ action . ' ' . $ record ['name ' ]);
239267
@@ -255,16 +283,16 @@ public function table(Table $table): Table
255283 }
256284 }),
257285 Action::make ('exclude_op ' )
258- ->visible (fn () => $ isMinecraft )
259- ->label (fn (array $ record ) => in_array ($ record ['name ' ], $ ops ) ? trans ('player-counter::query.remove_from_ops ' ) : trans ('player-counter::query.add_to_ops ' ))
260- ->icon (fn (array $ record ) => in_array ($ record ['name ' ], $ ops ) ? 'tabler-shield-minus ' : 'tabler-shield-plus ' )
261- ->color (fn (array $ record ) => in_array ($ record ['name ' ], $ ops ) ? 'warning ' : 'success ' )
262- ->action (function (array $ record ) use ( $ ops ) {
286+ ->visible (fn () => $ this -> isMinecraft )
287+ ->label (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> ops ) ? trans ('player-counter::query.remove_from_ops ' ) : trans ('player-counter::query.add_to_ops ' ))
288+ ->icon (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> ops ) ? 'tabler-shield-minus ' : 'tabler-shield-plus ' )
289+ ->color (fn (array $ record ) => in_array ($ record ['name ' ], $ this -> ops ) ? 'warning ' : 'success ' )
290+ ->action (function (array $ record ) {
263291 /** @var Server $server */
264292 $ server = Filament::getTenant ();
265293
266294 try {
267- $ action = in_array ($ record ['name ' ], $ ops ) ? 'deop ' : 'op ' ;
295+ $ action = in_array ($ record ['name ' ], $ this -> ops ) ? 'deop ' : 'op ' ;
268296
269297 $ server ->send ($ action . ' ' . $ record ['name ' ]);
270298
@@ -287,6 +315,10 @@ public function table(Table $table): Table
287315 }),
288316 ])
289317 ->emptyStateHeading (function () {
318+ if ($ this ->activeTab && $ this ->activeTab !== 'online ' ) {
319+ return trans ('player-counter::query.table.no_players ' );
320+ }
321+
290322 /** @var Server $server */
291323 $ server = Filament::getTenant ();
292324
@@ -297,6 +329,10 @@ public function table(Table $table): Table
297329 return trans ('player-counter::query.table.no_players ' );
298330 })
299331 ->emptyStateDescription (function () {
332+ if ($ this ->activeTab && $ this ->activeTab !== 'online ' ) {
333+ return null ;
334+ }
335+
300336 /** @var Server $server */
301337 $ server = Filament::getTenant ();
302338
@@ -308,10 +344,32 @@ public function table(Table $table): Table
308344 });
309345 }
310346
347+ public function getTabs (): array
348+ {
349+ if (!$ this ->isMinecraft ) {
350+ return [];
351+ }
352+
353+ return [
354+ 'online ' => Tab::make ('online ' )
355+ ->label ('Online ' )
356+ ->badge (fn () => count ($ this ->players )),
357+
358+ 'whitelist ' => Tab::make ('whitelist ' )
359+ ->label ('Whitelist ' )
360+ ->badge (fn () => count ($ this ->whitelist )),
361+
362+ 'ops ' => Tab::make ('ops ' )
363+ ->label ('OPs ' )
364+ ->badge (fn () => count ($ this ->ops )),
365+ ];
366+ }
367+
311368 public function content (Schema $ schema ): Schema
312369 {
313370 return $ schema
314371 ->components ([
372+ $ this ->getTabsContentComponent (),
315373 EmbeddedTable::make (),
316374 ]);
317375 }
0 commit comments