Skip to content

Commit

Permalink
graph views and tidy controller
Browse files Browse the repository at this point in the history
basic port link view
  • Loading branch information
murrant committed Jun 14, 2024
1 parent 2cd58d3 commit 5449224
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 47 deletions.
115 changes: 75 additions & 40 deletions app/Http/Controllers/Device/Tabs/PortsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@
use App\Models\Port;
use App\Models\Pseudowire;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use LibreNMS\Config;
use LibreNMS\Interfaces\UI\DeviceTab;

class PortsController implements DeviceTab
{
private bool $detail = false;
private int $perPage = 15;
private string $sortOrder = 'asd';

public function visible(Device $device): bool
{
Expand All @@ -61,11 +65,25 @@ public function name(): string

public function data(Device $device, Request $request): array
{
Validator::validate($request->all(), [
'perPage' => 'int',
'sort' => 'in:media,mac,port,traffic,speed',
'order' => 'in:asc,desc',
'disabled' => 'in:0,1',
'ignore' => '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',
'from' => ['regex:/^(int|[+-]\d+[hdmy])$/'],
'to' => ['regex:/^(int|[+-]\d+[hdmy])$/'],
]);

$tab = $request->segment(4);
$this->detail = empty($tab) || $tab == 'detail';
$data = match ($tab) {
'links' => $this->linksData($device),
'xdsl' => $this->xdslData($device),
'graphs', 'mini_graphs' => $this->graphData($device, $request),
default => $this->portData($device, $request),
};

Expand All @@ -79,12 +97,8 @@ public function data(Device $device, Request $request): array
'details' => empty($tab) || $tab == 'detail',
'submenu' => [
$this->getTabs($device),
__('Graphs') => [
['name' => __('port.graphs.bits'), 'url' => 'bits'],
['name' => __('port.graphs.upkts'), 'url' => 'upkts'],
['name' => __('port.graphs.nupkts'), 'url' => 'nupkts'],
['name' => __('port.graphs.errors'), 'url' => 'errors'],
],
__('Graphs') => $this->getGraphLinks(),
__('Mini Graphs') => $this->getGraphLinks('mini_graphs'),
],
'page_links' => [
[
Expand All @@ -108,35 +122,18 @@ public function data(Device $device, Request $request): array
[
'icon' => $ignore ? 'fa-regular fa-square-check' : 'fa-regular fa-square',
'url' => $ignore ? $request->fullUrlWithoutQuery('ignore') : $request->fullUrlWithQuery(['ignore' => 1]),
'title' => __('port.filters.disabled'),
'title' => __('port.filters.ignored'),
'external' => false,
],
],
'perPage' => $this->perPage,
'sort' => $this->sortOrder,
'next_order' => $this->sortOrder == 'asc' ? 'desc' : 'asc',
], $data);
}

private function portData(Device $device, Request $request): array
{
Validator::validate($request->all(), [
'perPage' => 'int',
'sort' => 'in:media,mac,port,traffic,speed',
'order' => 'in:asc,desc',
'disabled' => 'in:0,1',
'ignore' => 'in:0,1',
'admin' => 'in:up,down,testing,any',
'status' => 'in:up,down,testing,unknown,dormant,notPresent,lowerLayerDown,any',
]);
$perPage = $request->input('perPage', 15);
$sort = $request->input('sort', 'port');
$orderBy = match ($sort) {
'traffic' => \DB::raw('ports.ifInOctets_rate + ports.ifOutOctets_rate'),
'speed' => 'ifSpeed',
'media' => 'ifType',
'mac' => 'ifPhysAddress',
default => 'ifIndex',
};
$order = $request->input('order', 'asc');

$relationships = ['groups', 'ipv4', 'ipv6', 'vlans', 'adsl', 'vdsl'];
if ($this->detail) {
$relationships[] = 'links';
Expand All @@ -145,29 +142,18 @@ private function portData(Device $device, Request $request): array
$relationships[] = 'ipv6Networks.ipv6';
}

$ports = $device->ports()
->isNotDeleted()
->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, $order)
->hasAccess(Auth::user())->with($relationships)
->paginate($perPage);
$ports = $this->getFilteredPortsQuery($device, $request, $relationships)->paginate($this->perPage);

$data = [
'ports' => $ports,
'perPage' => $perPage,
'sort' => $sort,
'next_order' => $order == 'asc' ? 'desc' : 'asc',
'neighbors' => $ports->keyBy('port_id')->map(fn ($port) => $this->findPortNeighbors($port)),
'graphs' => [
'bits' => [['type' => 'port_bits', 'title' => trans('Traffic'), 'vars' => [['from' => '-1d'], ['from' => '-7d'], ['from' => '-30d'], ['from' => '-1y']]]],
'upkts' => [['type' => 'port_upkts', 'title' => trans('Packets (Unicast)'), 'vars' => [['from' => '-1d'], ['from' => '-7d'], ['from' => '-30d'], ['from' => '-1y']]]],
'errors' => [['type' => 'port_errors', 'title' => trans('Errors'), 'vars' => [['from' => '-1d'], ['from' => '-7d'], ['from' => '-30d'], ['from' => '-1y']]]],
],
];

$data['neighbors'] = $ports->keyBy('port_id')->map(fn ($port) => $this->findPortNeighbors($port));
if ($this->detail) {
$data['neighbor_ports'] = Port::with('device')
->hasAccess(Auth::user())
Expand Down Expand Up @@ -273,6 +259,14 @@ private function addPortNeighbor(array &$neighbors, string $type, int $port_id):
$neighbors[$port_id][$type] = 1;
}

private function graphData(Device $device, Request $request): array
{
return [
'graph_type' => 'port_' . $request->get('type'),
'ports' => $this->getFilteredPortsQuery($device, $request)->get(),
];
}

private function xdslData(Device $device): array
{
$device->portsAdsl->load('port');
Expand Down Expand Up @@ -316,4 +310,45 @@ private function getTabs(Device $device): array

return $tabs;
}

/**
* @return array[]
*/
private function getGraphLinks(string $urlSlug = 'graphs'): array
{
$graph_links = [
['name' => __('port.graphs.bits'), 'url' => $urlSlug . '?type=bits'],
['name' => __('port.graphs.upkts'), 'url' => $urlSlug . '?type=upkts'],
['name' => __('port.graphs.nupkts'), 'url' => $urlSlug . '?type=nupkts'],
['name' => __('port.graphs.errors'), 'url' => $urlSlug . '?type=errors'],
];

if (Config::get('enable_ports_etherlike')) {
$graph_links[] = ['name' => __('port.graphs.etherlike'), 'url' => $urlSlug . '?type=etherlike'];
}

return $graph_links;
}

private function getFilteredPortsQuery(Device $device, Request $request, array $relationships = []): HasMany
{
$this->perPage = $request->input('perPage', 15);
$this->sortOrder = $request->input('order', 'asc');
$orderBy = match ($request->input('sort', 'port')) {
'traffic' => \DB::raw('ports.ifInOctets_rate + ports.ifOutOctets_rate'),
'speed' => 'ifSpeed',
'media' => 'ifType',
'mac' => 'ifPhysAddress',
default => 'ifIndex',
};

return $device->ports()
->isNotDeleted()
->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)
->hasAccess(Auth::user())->with($relationships);
}
}
8 changes: 6 additions & 2 deletions app/View/Components/PortLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ class PortLink extends Component
* @var string
*/
public $status;
public bool $basic;

/**
* Create a new component instance.
*
* @return void
*/
public function __construct(Port $port, ?array $graphs = null)
public function __construct(Port $port, ?array $graphs = null, bool $basic = false)
{
$this->basic = $basic;
$this->port = $port;
$this->link = Url::portUrl($port);
$this->label = Rewrite::normalizeIfName($port->getLabel());
Expand All @@ -64,7 +66,9 @@ public function __construct(Port $port, ?array $graphs = null)
*/
public function render()
{
return view('components.port-link');
return $this->basic
? view('components.port-link_basic')
: view('components.port-link');
}

private function status(): string
Expand Down
1 change: 1 addition & 0 deletions lang/en/port.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'upkts' => 'Unicast Packets',
'nupkts' => 'Non-Unicast Packets',
'errors' => 'Errors',
'etherlike' => 'Etherlike',
],
'mtu_label' => 'MTU :mtu',
'tabs' => [
Expand Down
6 changes: 1 addition & 5 deletions resources/views/components/port-link.blade.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
<x-popup>
<a class="@if($status=='disabled') tw-text-gray-400 visited:tw-text-gray-400 @elseif($status=='down') tw-text-red-600 visited:tw-text-red-600 @else tw-text-blue-900 visited:tw-text-blue-900 dark:tw-text-dark-white-100 dark:visited:tw-text-dark-white-100 @endif"
href="{{ $link }}"
{{ $attributes }}>
{{ $slot->isNotEmpty() ? $slot : $label }}
</a>
@include('components.port-link_basic')
<x-slot name="title">
<div class="tw-text-xl tw-font-bold">{{ $port->device->displayName() }} - {{ $label }}</div>
<div>{{ $description }}</div>
Expand Down
5 changes: 5 additions & 0 deletions resources/views/components/port-link_basic.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<a class="@if($status=='disabled') tw-text-gray-400 visited:tw-text-gray-400 @elseif($status=='down') tw-text-red-600 visited:tw-text-red-600 @else tw-text-blue-900 visited:tw-text-blue-900 dark:tw-text-dark-white-100 dark:visited:tw-text-dark-white-100 @endif"
href="{{ $link }}"
{{ $attributes }}>
{{ $slot->isNotEmpty() ? $slot : $label }}
</a>
19 changes: 19 additions & 0 deletions resources/views/device/tabs/ports/graphs.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@foreach($data['ports'] as $port)
<x-panel>
<x-slot name="title">
<div>
{{-- div to allow color to override boostrap title link color --}}
<x-port-link basic :port="$port">
<span class="tw-text-3xl tw-font-bold">
<i class="fa fa-tag" aria-hidden='true'></i>
{{ $port->getLabel() }}
@if($port->getLabel() !== $port->getDescription())
<span class="tw-text-xl tw-font-normal">{{ $port->getDescription() }}</span>
@endif
</span>
</x-port-link>
</div>
</x-slot>
<x-graph-row loading="lazy" columns="responsive" :port="$port" :type="$data['graph_type']" :graphs="[['from' => '-1d'], ['from' => '-1w'], ['from' => '-1m'], ['from' => '-1y']]" legend="no"></x-graph-row>
</x-panel>
@endforeach
8 changes: 8 additions & 0 deletions resources/views/device/tabs/ports/mini_graphs.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@foreach($data['ports'] as $port)
<div class="minigraph-div">
<x-port-link :port="$port">
<div class="tw-font-bold">{{ $port->getShortLabel() }}</div>
<x-graph :port="$port" :type="$data['graph_type']" :from="$request->input('from', '-1d')" width="180" height="55" legend="no"></x-graph>
</x-port-link>
</div>
@endforeach

0 comments on commit 5449224

Please sign in to comment.