3636use Illuminate \Database \Eloquent \Builder ;
3737use Illuminate \Http \Request ;
3838use Illuminate \Pagination \LengthAwarePaginator ;
39+ use Illuminate \Support \Arr ;
3940use Illuminate \Support \Collection ;
4041use Illuminate \Support \Facades \Auth ;
4142use Illuminate \Support \Facades \Validator ;
@@ -49,10 +50,6 @@ class PortsController implements DeviceTab
4950 'perPage ' => 32 ,
5051 'sort ' => 'ifIndex ' ,
5152 'order ' => 'asc ' ,
52- 'disabled ' => false ,
53- 'ignored ' => false ,
54- 'admin ' => 'up ' ,
55- 'status ' => 'any ' ,
5653 ];
5754
5855 public function visible (Device $ device ): bool
@@ -82,14 +79,11 @@ public function data(Device $device, Request $request): array
8279 'perPage ' => ['regex:/^(\d+|all)$/ ' ],
8380 'sort ' => 'in:media,mac,port,traffic,speed,index ' ,
8481 'order ' => 'in:asc,desc ' ,
85- 'disabled ' => 'in:0,1 ' ,
86- 'ignored ' => 'in:0,1 ' ,
87- 'admin ' => 'in:up,down,testing,any ' ,
88- 'status ' => 'in:up,down,testing,unknown,dormant,notPresent,lowerLayerDown,any ' ,
89- 'type ' => 'in:bits,upkts,nupkts,errors,etherlike ' ,
9082 'from ' => ['regex:/^(int|[+-]\d+[hdmy])$/ ' ],
9183 'to ' => ['regex:/^(int|[+-]\d+[hdmy])$/ ' ],
92- 'searchPort ' => 'nullable|string|max:255 ' ,
84+ 'filter ' => ['nullable ' , 'array ' ],
85+ 'filter.* ' => ['array ' ],
86+ 'filter.*.* ' => ['nullable ' , 'max:255 ' ],
9387 ]);
9488
9589 $ this ->loadSettings ($ request );
@@ -107,11 +101,13 @@ public function data(Device $device, Request $request): array
107101 return array_merge ([
108102 'tab ' => $ tab ,
109103 'details ' => $ this ->detail ,
104+ 'filterFields ' => $ this ->filterFields ($ device ->device_id ),
110105 'submenu ' => [
111106 $ this ->getTabs ($ device ),
112107 __ ('Graphs ' ) => $ this ->getGraphLinks (),
113108 ],
114- 'dropdownLinks ' => $ this ->pageLinks ($ request ),
109+ 'dropdownLinks ' => [],
110+ 'filter ' => UserPref::getPref ($ request ->user (), 'filters.device.ports ' ) ?: [],
115111 'perPage ' => $ this ->settings ['perPage ' ],
116112 'sort ' => $ this ->settings ['sort ' ],
117113 'next_order ' => $ this ->settings ['order ' ] == 'asc ' ? 'desc ' : 'asc ' ,
@@ -139,8 +135,7 @@ private function portData(Device $device, Request $request): array
139135 /** @var Collection<int, Port>|LengthAwarePaginator<Port> $ports */
140136 $ ports = $ this ->getFilteredPortsQuery ($ device , $ relationships , $ request )
141137 ->paginate (fn ($ total ) => $ this ->settings ['perPage ' ] == 'all ' ? $ total : (int ) $ this ->settings ['perPage ' ]) // @phpstan-ignore-line missing closure type
142- ->appends ('perPage ' , $ this ->settings ['perPage ' ])
143- ->appends ('searchPort ' , $ request ->input ('searchPort ' ));
138+ ->appends ('perPage ' , $ this ->settings ['perPage ' ]);
144139
145140 $ data = [
146141 'ports ' => $ ports ,
@@ -296,8 +291,8 @@ private function portSecurityData(Device $device): array
296291 private function getTabs (Device $ device ): array
297292 {
298293 $ tabs = [
299- ['name ' => __ ('Basic ' ), 'url ' => 'basic ' ],
300- ['name ' => __ ('Detail ' ), 'url ' => 'detail ' ],
294+ ['name ' => __ ('Basic ' ), 'url ' => 'basic ' , ' class ' => ' sync-filter-url ' ],
295+ ['name ' => __ ('Detail ' ), 'url ' => 'detail ' , ' class ' => ' sync-filter-url ' ],
301296 ];
302297
303298 if ($ device ->macs ()->exists ()) {
@@ -340,24 +335,28 @@ private function getGraphLinks(): array
340335 [
341336 'name ' => __ ('port.graphs.bits ' ),
342337 'url ' => 'graphs?type=bits ' ,
338+ 'class ' => 'sync-filter-url ' ,
343339 'sub_name ' => __ ('Mini ' ),
344340 'sub_url ' => 'mini_graphs?type=bits ' ,
345341 ],
346342 [
347343 'name ' => __ ('port.graphs.upkts ' ),
348344 'url ' => 'graphs?type=upkts ' ,
345+ 'class ' => 'sync-filter-url ' ,
349346 'sub_name ' => __ ('Mini ' ),
350347 'sub_url ' => 'mini_graphs?type=upkts ' ,
351348 ],
352349 [
353350 'name ' => __ ('port.graphs.nupkts ' ),
354351 'url ' => 'graphs?type=nupkts ' ,
352+ 'class ' => 'sync-filter-url ' ,
355353 'sub_name ' => __ ('Mini ' ),
356354 'sub_url ' => 'mini_graphs?type=nupkts ' ,
357355 ],
358356 [
359357 'name ' => __ ('port.graphs.errors ' ),
360358 'url ' => 'graphs?type=errors ' ,
359+ 'class ' => 'sync-filter-url ' ,
361360 'sub_name ' => __ ('Mini ' ),
362361 'sub_url ' => 'mini_graphs?type=errors ' ,
363362 ],
@@ -377,8 +376,14 @@ private function getGraphLinks(): array
377376
378377 private function loadSettings (Request $ request ): void
379378 {
380- $ input = $ request ->only (['perPage ' , 'sort ' , 'order ' , 'disabled ' , 'ignored ' , 'admin ' , 'status ' ]);
381- $ saved = UserPref::getPref ($ request ->user (), 'ports_ui_settings ' ) ?? [];
379+ $ input = $ request ->only (['perPage ' , 'sort ' , 'order ' ]);
380+ $ saved = UserPref::getPref ($ request ->user (), 'ports_ui_settings ' );
381+
382+ if ($ saved === null ) {
383+ $ saved = [];
384+ } elseif (array_key_exists ('admin ' , $ saved )) {
385+ $ saved = $ this ->migrateFilterSettings ($ saved );
386+ }
382387
383388 $ this ->settings = $ input + $ saved + $ this ->defaults ;
384389
@@ -402,21 +407,10 @@ private function getFilteredPortsQuery(Device $device, array $relationships = []
402407 default => 'ifIndex ' ,
403408 };
404409
405- // Get search parameter
406- $ searchPort = $ request ?->input('searchPort ' );
407-
408410 return Port::where ('device_id ' , $ device ->device_id )
409411 ->isNotDeleted ()
410412 ->hasAccess (Auth::user ())->with ($ relationships )
411- ->when (! $ this ->settings ['disabled ' ], fn (Builder $ q , $ disabled ) => $ q ->where ('disabled ' , 0 ))
412- ->when (! $ this ->settings ['ignored ' ], fn (Builder $ q , $ disabled ) => $ q ->where ('ignore ' , 0 ))
413- ->when ($ this ->settings ['admin ' ] != 'any ' , fn (Builder $ q , $ admin ) => $ q ->where ('ifAdminStatus ' , $ this ->settings ['admin ' ]))
414- ->when ($ this ->settings ['status ' ] != 'any ' , fn (Builder $ q , $ admin ) => $ q ->where ('ifOperStatus ' , $ this ->settings ['status ' ]))
415- ->when ($ searchPort , fn (Builder $ q ) => $ q ->where (function (Builder $ q ) use ($ searchPort ): void {
416- $ q ->where ('ifName ' , 'LIKE ' , '% ' . $ searchPort . '% ' )
417- ->orWhere ('ifDescr ' , 'LIKE ' , '% ' . $ searchPort . '% ' )
418- ->orWhere ('ifAlias ' , 'LIKE ' , '% ' . $ searchPort . '% ' );
419- }))
413+ ->when ($ request ->array ('filter ' ), fn (Builder $ q , $ filters ) => $ q ->applyFilters ($ filters ))
420414 ->when ($ this ->settings ['sort ' ] == 'port ' , fn (Builder $ q , $ sort ) => $ q
421415 ->orderByRaw ('SOUNDEX(ifName) ' . $ this ->settings ['order ' ])
422416 ->orderByRaw ('CHAR_LENGTH(ifName) ' . $ this ->settings ['order ' ])
@@ -440,37 +434,89 @@ private function parseTab(Request $request): string
440434 return $ request ->route ('vars ' , LibrenmsConfig::get ('ports_page_default ' )); // fourth segment is called vars to handle legacy urls
441435 }
442436
443- private function pageLinks ( Request $ request ): array
437+ private function migrateFilterSettings ( array $ saved ): array
444438 {
445- $ disabled = $ this ->settings ['disabled ' ];
446- $ ignored = $ this ->settings ['ignored ' ];
447- $ admin = $ this ->settings ['admin ' ] == 'any ' ;
448- $ status = $ this ->settings ['status ' ] == 'up ' ;
439+ $ filter = [];
449440
441+ if (! $ saved ['disabled ' ]) { // 0: disabled hidden 1: not filtered
442+ $ filter ['disabled ' ] = ['eq ' => 0 ];
443+ }
444+
445+ if (! $ saved ['ignored ' ]) { // 0: ignored hidden 1: not filtered
446+ $ filter ['ignore ' ] = ['eq ' => 0 ];
447+ }
448+
449+ if ($ saved ['status ' ] == 'up ' ) { // up: only status up, any: not filtered
450+ $ filter ['state ' ] = ['eq ' => 'up ' ];
451+ } elseif ($ saved ['admin ' ] == 'up ' ) { // up: only != shutdown, any: not filtered
452+ $ filter ['state ' ] = ['neq ' => 'shutdown ' ];
453+ }
454+
455+ Arr::forget ($ saved , ['admin ' , 'status ' , 'disabled ' , 'ignored ' ]);
456+ UserPref::setPref (request ()->user (), 'ports_ui_settings ' , $ saved );
457+ UserPref::setPref (request ()->user (), 'filters.device.ports ' , $ filter );
458+
459+ return $ saved ;
460+ }
461+
462+ private function filterFields (int $ device_id ): array
463+ {
450464 return [
451465 [
452- 'icon ' => $ status ? 'fa-regular fa-square-check ' : 'fa-regular fa-square ' ,
453- 'url ' => $ request ->fullUrlWithQuery (['status ' => $ status ? $ this ->defaults ['status ' ] : 'up ' ]),
454- 'title ' => __ ('port.filters.status_up ' ),
455- 'external ' => false ,
466+ 'key ' => 'search ' ,
467+ 'label ' => 'Description ' ,
468+ 'type ' => 'text ' ,
469+ ],
470+ [
471+ 'key ' => 'state ' ,
472+ 'label ' => 'Oper Status ' ,
473+ 'type ' => 'select ' ,
474+ 'options ' => ['up ' , 'down ' , 'shutdown ' ],
475+ ],
476+ [
477+ 'key ' => 'ifSpeed ' ,
478+ 'label ' => 'Speed ' ,
479+ 'type ' => 'select ' ,
480+ 'endpoint ' => route ('ajax.select.port-field ' ),
481+ 'params ' => [
482+ 'field ' => 'ifSpeed ' ,
483+ 'device ' => $ device_id ,
484+ ],
485+ ],
486+ [
487+ 'key ' => 'ifType ' ,
488+ 'label ' => 'Media ' ,
489+ 'type ' => 'select ' ,
490+ 'endpoint ' => route ('ajax.select.port-field ' ),
491+ 'params ' => [
492+ 'field ' => 'ifType ' ,
493+ 'device ' => $ device_id ,
494+ ],
495+ ],
496+ [
497+ 'key ' => 'port_type ' ,
498+ 'label ' => 'Port Type ' ,
499+ 'type ' => 'select ' ,
500+ 'endpoint ' => route ('ajax.select.port-field ' ),
501+ 'params ' => [
502+ 'field ' => 'port_descr_type ' ,
503+ 'device ' => $ device_id ,
504+ ],
456505 ],
457506 [
458- 'icon ' => $ admin ? 'fa-regular fa-square-check ' : 'fa-regular fa-square ' ,
459- 'url ' => $ request ->fullUrlWithQuery (['admin ' => $ admin ? $ this ->defaults ['admin ' ] : 'any ' ]),
460- 'title ' => __ ('port.filters.admin_down ' ),
461- 'external ' => false ,
507+ 'key ' => 'ignore ' ,
508+ 'label ' => 'Ignored ' ,
509+ 'type ' => 'boolean ' ,
462510 ],
463511 [
464- 'icon ' => $ disabled ? 'fa-regular fa-square-check ' : 'fa-regular fa-square ' ,
465- 'url ' => $ request ->fullUrlWithQuery (['disabled ' => ! $ disabled ]),
466- 'title ' => __ ('port.filters.disabled ' ),
467- 'external ' => false ,
512+ 'key ' => 'disabled ' ,
513+ 'label ' => 'Disabled ' ,
514+ 'type ' => 'boolean ' ,
468515 ],
469516 [
470- 'icon ' => $ ignored ? 'fa-regular fa-square-check ' : 'fa-regular fa-square ' ,
471- 'url ' => $ request ->fullUrlWithQuery (['ignored ' => ! $ ignored ]),
472- 'title ' => __ ('port.filters.ignored ' ),
473- 'external ' => false ,
517+ 'key ' => 'deleted ' ,
518+ 'label ' => 'Deleted ' ,
519+ 'type ' => 'boolean ' ,
474520 ],
475521 ];
476522 }
0 commit comments