From a37efd2876cd24773a296c22622ad42a2a2543f3 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Tue, 18 Jun 2024 23:58:10 -0500 Subject: [PATCH] Device Ports settings (#16132) * Device Ports settings * Save port settings per user * style * Delete user pref if it matches the defaults * Because we are saving settings now, we must explicitly set to make the links work --- .../Device/Tabs/PortsController.php | 81 ++++++++++++------- misc/config_definitions.json | 56 ------------- 2 files changed, 51 insertions(+), 86 deletions(-) diff --git a/app/Http/Controllers/Device/Tabs/PortsController.php b/app/Http/Controllers/Device/Tabs/PortsController.php index 30a2aa04bd..5e4fe5f542 100644 --- a/app/Http/Controllers/Device/Tabs/PortsController.php +++ b/app/Http/Controllers/Device/Tabs/PortsController.php @@ -29,6 +29,7 @@ use App\Models\Device; use App\Models\Link; use App\Models\Port; use App\Models\Pseudowire; +use App\Models\UserPref; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; @@ -41,9 +42,16 @@ use LibreNMS\Interfaces\UI\DeviceTab; class PortsController implements DeviceTab { private bool $detail = false; - private int|string $perPage = 32; - private string $sortOrder = 'asc'; - private string $sortColumn = 'default'; + private array $settings = []; + private array $defaults = [ + 'perPage' => 32, + 'sort' => 'ifIndex', + 'order' => 'asc', + 'disabled' => false, + 'ignored' => false, + 'admin' => 'up', + 'status' => 'any', + ]; public function visible(Device $device): bool { @@ -73,7 +81,7 @@ class PortsController implements DeviceTab 'sort' => 'in:media,mac,port,traffic,speed', 'order' => 'in:asc,desc', 'disabled' => 'in:0,1', - 'ignore' => 'in:0,1', + 'ignored' => 'in:0,1', 'admin' => 'in:up,down,testing,any', 'status' => 'in:up,down,testing,unknown,dormant,notPresent,lowerLayerDown,any', 'type' => 'in:bits,upkts,nupkts,errors,etherlike', @@ -81,6 +89,7 @@ class PortsController implements DeviceTab 'to' => ['regex:/^(int|[+-]\d+[hdmy])$/'], ]); + $this->loadSettings($request); $tab = $this->parseTab($request); $this->detail = $tab == 'detail'; $data = match ($tab) { @@ -98,9 +107,9 @@ class PortsController implements DeviceTab __('Graphs') => $this->getGraphLinks(), ], 'page_links' => $this->pageLinks($request), - 'perPage' => $this->perPage, - 'sort' => $this->sortColumn, - 'next_order' => $this->sortOrder == 'asc' ? 'desc' : 'asc', + 'perPage' => $this->settings['perPage'], + 'sort' => $this->settings['sort'], + 'next_order' => $this->settings['order'] == 'asc' ? 'desc' : 'asc', ], $data); } @@ -115,9 +124,9 @@ class PortsController implements DeviceTab } /** @var Collection|LengthAwarePaginator $ports */ - $ports = $this->getFilteredPortsQuery($device, $request, $relationships) - ->paginate(fn ($total) => $this->perPage == 'all' ? $total : (int) $this->perPage) // @phpstan-ignore-line missing closure type - ->appends('perPage', $this->perPage); + $ports = $this->getFilteredPortsQuery($device, $relationships) + ->paginate(fn ($total) => $this->settings['perPage'] == 'all' ? $total : (int) $this->settings['perPage']) // @phpstan-ignore-line missing closure type + ->appends('perPage', $this->settings['perPage']); $data = [ 'ports' => $ports, @@ -238,7 +247,7 @@ class PortsController implements DeviceTab { return [ 'graph_type' => 'port_' . $request->get('type'), - 'ports' => $this->getFilteredPortsQuery($device, $request)->get(), + 'ports' => $this->getFilteredPortsQuery($device)->get(), ]; } @@ -330,13 +339,25 @@ class PortsController implements DeviceTab return $graph_links; } - private function getFilteredPortsQuery(Device $device, Request $request, array $relationships = []): Builder + private function loadSettings(Request $request): void { - $this->perPage = $request->input('perPage', 32); - $this->sortOrder = $request->input('order', 'asc'); - $this->sortColumn = $request->input('sort', 'default'); + $input = $request->only(['perPage', 'sort', 'order', 'disabled', 'ignored', 'admin', 'status']); + $saved = UserPref::getPref($request->user(), 'ports_ui_settings') ?? []; - $orderBy = match ($this->sortColumn) { + $this->settings = $input + $saved + $this->defaults; + + if ($this->settings != $saved) { + if ($this->settings == $this->defaults) { + UserPref::forgetPref($request->user(), 'ports_ui_settings'); + } else { + UserPref::setPref($request->user(), 'ports_ui_settings', $this->settings); + } + } + } + + private function getFilteredPortsQuery(Device $device, array $relationships = []): Builder + { + $orderBy = match ($this->settings['sort']) { 'traffic' => \DB::raw('ports.ifInOctets_rate + ports.ifOutOctets_rate'), 'speed' => 'ifSpeed', 'media' => 'ifType', @@ -348,11 +369,11 @@ class PortsController implements DeviceTab return Port::where('device_id', $device->device_id) ->isNotDeleted() ->hasAccess(Auth::user())->with($relationships) - ->when(! $request->input('disabled'), fn (Builder $q, $disabled) => $q->where('disabled', 0)) - ->when(! $request->input('ignore'), fn (Builder $q, $disabled) => $q->where('ignore', 0)) - ->when($request->input('admin') != 'any', fn (Builder $q, $admin) => $q->where('ifAdminStatus', $request->input('admin', 'up'))) - ->when($request->input('status', 'any') != 'any', fn (Builder $q, $admin) => $q->where('ifOperStatus', $request->input('status'))) - ->orderBy($orderBy, $this->sortOrder); + ->when(! $this->settings['disabled'], fn (Builder $q, $disabled) => $q->where('disabled', 0)) + ->when(! $this->settings['ignored'], fn (Builder $q, $disabled) => $q->where('ignore', 0)) + ->when($this->settings['admin'] != 'any', fn (Builder $q, $admin) => $q->where('ifAdminStatus', $this->settings['admin'])) + ->when($this->settings['status'] != 'any', fn (Builder $q, $admin) => $q->where('ifOperStatus', $this->settings['status'])) + ->orderBy($orderBy, $this->settings['order']); } /** @@ -372,33 +393,33 @@ class PortsController implements DeviceTab private function pageLinks(Request $request): array { - $disabled = $request->input('disabled'); - $ignore = $request->input('ignore'); - $admin = $request->input('admin') == 'any'; - $status = $request->input('status') == 'up'; + $disabled = $this->settings['disabled']; + $ignored = $this->settings['ignored']; + $admin = $this->settings['admin'] == 'any'; + $status = $this->settings['status'] == 'up'; return [ [ 'icon' => $status ? 'fa-regular fa-square-check' : 'fa-regular fa-square', - 'url' => $status ? $request->fullUrlWithoutQuery('status') : $request->fullUrlWithQuery(['status' => 'up']), + 'url' => $request->fullUrlWithQuery(['status' => $status ? $this->defaults['status'] : 'up']), 'title' => __('port.filters.status_up'), 'external' => false, ], [ 'icon' => $admin ? 'fa-regular fa-square-check' : 'fa-regular fa-square', - 'url' => $admin ? $request->fullUrlWithoutQuery('admin') : $request->fullUrlWithQuery(['admin' => 'any']), + 'url' => $request->fullUrlWithQuery(['admin' => $admin ? $this->defaults['admin'] : 'any']), 'title' => __('port.filters.admin_down'), 'external' => false, ], [ 'icon' => $disabled ? 'fa-regular fa-square-check' : 'fa-regular fa-square', - 'url' => $disabled ? $request->fullUrlWithoutQuery('disabled') : $request->fullUrlWithQuery(['disabled' => 1]), + 'url' => $request->fullUrlWithQuery(['disabled' => ! $disabled]), 'title' => __('port.filters.disabled'), 'external' => false, ], [ - 'icon' => $ignore ? 'fa-regular fa-square-check' : 'fa-regular fa-square', - 'url' => $ignore ? $request->fullUrlWithoutQuery('ignore') : $request->fullUrlWithQuery(['ignore' => 1]), + 'icon' => $ignored ? 'fa-regular fa-square-check' : 'fa-regular fa-square', + 'url' => $request->fullUrlWithQuery(['ignored' => ! $ignored]), 'title' => __('port.filters.ignored'), 'external' => false, ], diff --git a/misc/config_definitions.json b/misc/config_definitions.json index 348d12dc24..022c6dd234 100644 --- a/misc/config_definitions.json +++ b/misc/config_definitions.json @@ -5214,62 +5214,6 @@ "default": true, "type": "boolean" }, - "ports_ui.default_sort": { - "order": 10, - "group": "webui", - "section": "ports", - "default": "ifIndex", - "type": "select", - "options": [ - "ifIndex", - "mac", - "media", - "port", - "speed", - "traffic" - ] - }, - "ports_ui.show_disabled": { - "order": 50, - "group": "webui", - "section": "ports", - "default": false, - "type": "boolean" - }, - "ports_ui.show_ignored": { - "order": 60, - "group": "webui", - "section": "ports", - "default": false, - "type": "boolean" - }, - "ports_ui.filter_admin_status": { - "order": 70, - "group": "webui", - "section": "ports", - "default": "up", - "type": "select", - "options": [ - "up", - "down", - "any" - ] - }, - "ports_ui.filter_oper_status": { - "order": 80, - "group": "webui", - "section": "ports", - "default": "up", - "type": "select", - "options": [ - "up", - "down", - "notPresent", - "lowerLayerDown", - "unknown", - "any" - ] - }, "port_descr_parser": { "default": "includes/port-descr-parser.inc.php", "type": "text"