mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Cleanup and optimize the availability widget (#14329)
* Cleanup and optimize the availability widget Default sort is display name Sort applies to services too (services always last) May need to refresh the page to get new css * style * We don't need request (lint fix) * Wrong service field name
This commit is contained in:
@@ -25,11 +25,14 @@
|
||||
|
||||
namespace App\Http\Controllers\Widgets;
|
||||
|
||||
use App\Models\AlertSchedule;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceGroup;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Util\Url;
|
||||
|
||||
class AvailabilityMapController extends WidgetController
|
||||
{
|
||||
@@ -44,7 +47,7 @@ class AvailabilityMapController extends WidgetController
|
||||
'color_only_select' => 0,
|
||||
'show_disabled_and_ignored' => 0,
|
||||
'mode_select' => 0,
|
||||
'order_by' => Config::get('webui.availability_map_sort_status') ? 'status' : 'hostname',
|
||||
'order_by' => Config::get('webui.availability_map_sort_status') ? 'status' : 'display-name',
|
||||
'device_group' => null,
|
||||
];
|
||||
}
|
||||
@@ -53,20 +56,8 @@ class AvailabilityMapController extends WidgetController
|
||||
{
|
||||
$data = $this->getSettings();
|
||||
|
||||
$devices = [];
|
||||
$device_totals = [];
|
||||
$services = [];
|
||||
$services_totals = [];
|
||||
|
||||
$mode = $data['mode_select'];
|
||||
if ($mode == 0 || $mode == 2) {
|
||||
[$devices, $device_totals] = $this->getDevices($request);
|
||||
}
|
||||
if ($mode > 0) {
|
||||
[$services, $services_totals] = $this->getServices($request);
|
||||
}
|
||||
|
||||
$data['device'] = Device::first();
|
||||
[$devices, $device_totals] = $this->getDevices();
|
||||
[$services, $services_totals] = $this->getServices();
|
||||
|
||||
$data['devices'] = $devices;
|
||||
$data['device_totals'] = $device_totals;
|
||||
@@ -81,142 +72,206 @@ class AvailabilityMapController extends WidgetController
|
||||
return view('widgets.settings.availability-map', $this->getSettings(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
private function getDevices(Request $request)
|
||||
private function getDevices(): array
|
||||
{
|
||||
$settings = $this->getSettings();
|
||||
|
||||
if ($settings['mode_select'] == 1) { // services only
|
||||
return [[], []];
|
||||
}
|
||||
|
||||
// filter for by device group or show all
|
||||
if ($settings['device_group']) {
|
||||
$device_query = DeviceGroup::find($settings['device_group'])->devices()->hasAccess($request->user());
|
||||
$device_query = DeviceGroup::find($settings['device_group'])->devices()->hasAccess(Auth::user());
|
||||
} else {
|
||||
$device_query = Device::hasAccess($request->user());
|
||||
$device_query = Device::hasAccess(Auth::user());
|
||||
}
|
||||
|
||||
if (! $settings['show_disabled_and_ignored']) {
|
||||
$device_query->isNotDisabled();
|
||||
}
|
||||
$devices = $device_query->select(['devices.device_id', 'hostname', 'sysName', 'display', 'status', 'uptime', 'last_polled', 'disabled', 'disable_notify', 'location_id'])->get();
|
||||
$devices = $device_query->select(['devices.device_id', 'hostname', 'sysName', 'display', 'status', 'uptime', 'last_polled', 'disabled', 'ignore'])->get();
|
||||
|
||||
// process status
|
||||
$uptime_warn = Config::get('uptime_warning', 86400);
|
||||
$uptime_warn = (int) Config::get('uptime_warning', 86400);
|
||||
$check_maintenance = AlertSchedule::isActive()->exists(); // check if any maintenance schedule is active
|
||||
$totals = ['warn' => 0, 'up' => 0, 'down' => 0, 'maintenance' => 0, 'ignored' => 0, 'disabled' => 0];
|
||||
$data = [];
|
||||
|
||||
// add another field for the selected device label
|
||||
$label_type = $settings['color_only_select'];
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$row = ['device' => $device];
|
||||
if ($device->disabled) {
|
||||
$totals['disabled']++;
|
||||
$row['stateName'] = 'disabled';
|
||||
$row['labelClass'] = 'blackbg';
|
||||
} elseif ($device->disable_notify) {
|
||||
$totals['ignored']++;
|
||||
$row['stateName'] = 'alert-dis';
|
||||
$row['labelClass'] = 'label-default';
|
||||
} elseif ($device->status == 1) {
|
||||
if (($device->uptime < $uptime_warn) && ($device->uptime != 0)) {
|
||||
$totals['warn']++;
|
||||
$row['stateName'] = 'warn';
|
||||
$row['labelClass'] = 'label-warning';
|
||||
} else {
|
||||
$totals['up']++;
|
||||
$row['stateName'] = 'up';
|
||||
$row['labelClass'] = 'label-success';
|
||||
}
|
||||
} else {
|
||||
$totals['down']++;
|
||||
$row['stateName'] = 'down';
|
||||
$row['labelClass'] = 'label-danger';
|
||||
}
|
||||
// parse state and count
|
||||
[$state_name, $class] = $this->parseDeviceState($device, $uptime_warn);
|
||||
$totals[$state_name]++;
|
||||
|
||||
if ($device->isUnderMaintenance()) {
|
||||
$row['labelClass'] = 'label-default';
|
||||
if ($check_maintenance && $device->isUnderMaintenance()) {
|
||||
$class = 'label-default';
|
||||
$totals['maintenance']++;
|
||||
}
|
||||
|
||||
if ($label_type == 1) {
|
||||
$row['label'] = null;
|
||||
} elseif ($label_type == 4) {
|
||||
$row['label'] = strtolower($device->shortDisplayName());
|
||||
} elseif ($label_type == 2) {
|
||||
$row['label'] = strtolower($device->hostname);
|
||||
} elseif ($label_type == 3) {
|
||||
$row['label'] = strtolower($device->sysName);
|
||||
} else {
|
||||
$row['label'] = $device->status;
|
||||
if ($settings['type'] == 1) {
|
||||
$class = "availability-map-oldview-box-$state_name";
|
||||
}
|
||||
|
||||
$data[] = $row;
|
||||
$data[] = [
|
||||
'status' => $device->status,
|
||||
'link' => Url::deviceUrl($device),
|
||||
'tooltip' => $this->getDeviceTooltip($device, $state_name),
|
||||
'label' => $this->getDeviceLabel($device, $state_name), // add another field for the selected label
|
||||
'labelClass' => $class,
|
||||
];
|
||||
}
|
||||
|
||||
// now apply sorting, depending on the selected device label
|
||||
$order_by = $settings['order_by'];
|
||||
|
||||
if ($order_by == 'status') {
|
||||
usort($data, function ($l, $r) {
|
||||
$retval = $l['device']->status <=> $r['device']->status;
|
||||
if ($retval == 0) {
|
||||
$retval = $l['label'] <=> $r['label'];
|
||||
}
|
||||
|
||||
return $retval;
|
||||
});
|
||||
} elseif ($order_by == 'label') {
|
||||
usort($data, function ($l, $r) {
|
||||
return $l['label'] <=> $r['label'];
|
||||
});
|
||||
}
|
||||
$this->sort($data);
|
||||
|
||||
return [$data, $totals];
|
||||
}
|
||||
|
||||
private function getServices($request)
|
||||
private function getServices(): array
|
||||
{
|
||||
$settings = $this->getSettings();
|
||||
|
||||
// filter for by device group or show all
|
||||
if ($settings['device_group']) {
|
||||
$services_query = DeviceGroup::find($settings['device_group'])->services()->hasAccess($request->user());
|
||||
} else {
|
||||
$services_query = Service::hasAccess($request->user());
|
||||
if ($settings['mode_select'] == 0) { // devices only
|
||||
return [[], []];
|
||||
}
|
||||
|
||||
if ($settings['order_by'] == 'status') {
|
||||
$services_query->orderBy('service_status', 'DESC')->orderBy('service_type');
|
||||
} elseif ($settings['order_by'] == 'hostname') {
|
||||
$services_query->leftJoin('devices', 'services.device_id', 'devices.device_id')->orderBy('hostname')->orderBy('service_type');
|
||||
// filter for by device group or show all
|
||||
if ($settings['device_group']) {
|
||||
$services_query = DeviceGroup::find($settings['device_group'])->services()->hasAccess(Auth::user());
|
||||
} else {
|
||||
$services_query = Service::hasAccess(Auth::user());
|
||||
}
|
||||
$services = $services_query->with(['device' => function ($query) {
|
||||
$query->select(['devices.device_id', 'hostname', 'sysName']);
|
||||
}])->select(['service_id', 'services.device_id', 'service_type', 'service_desc', 'service_status'])->get();
|
||||
|
||||
$services = $services_query->with([
|
||||
'device' => function ($query) {
|
||||
$query->select(['devices.device_id', 'hostname', 'sysName', 'display']);
|
||||
},
|
||||
])->select(['service_id', 'services.device_id', 'service_type', 'service_name', 'service_desc', 'service_status'])->get();
|
||||
|
||||
// process status
|
||||
$totals = ['warn' => 0, 'up' => 0, 'down' => 0];
|
||||
$data = [];
|
||||
foreach ($services as $service) {
|
||||
$row = ['service' => $service];
|
||||
if ($service->service_status == 0) {
|
||||
$row['labelClass'] = 'label-success';
|
||||
$row['stateName'] = 'up';
|
||||
$totals['up']++;
|
||||
} elseif ($service->service_status == 1) {
|
||||
$row['labelClass'] = 'label-warning';
|
||||
$row['stateName'] = 'warn';
|
||||
$totals['warn']++;
|
||||
} else {
|
||||
$row['labelClass'] = 'label-danger';
|
||||
$row['stateName'] = 'down';
|
||||
$totals['down']++;
|
||||
[$state_name, $class] = $this->parseServiceState($service);
|
||||
$totals[$state_name]++;
|
||||
|
||||
if ($settings['type'] == 1) {
|
||||
$class = "availability-map-oldview-box-$state_name";
|
||||
}
|
||||
$data[] = $row;
|
||||
|
||||
$data[] = [
|
||||
'status' => $service->service_status,
|
||||
'link' => Url::deviceUrl($service->device),
|
||||
'tooltip' => $this->getServiceTooltip($service),
|
||||
'label' => $this->getServiceLabel($service, $state_name),
|
||||
'labelClass' => $class,
|
||||
];
|
||||
}
|
||||
|
||||
$this->sort($data);
|
||||
|
||||
return [$data, $totals];
|
||||
}
|
||||
|
||||
private function sort(array &$data): void
|
||||
{
|
||||
switch ($this->getSettings()['order_by']) {
|
||||
case 'status':
|
||||
usort($data, function ($l, $r) {
|
||||
return ($l['status'] <=> $r['status']) ?: strcasecmp($l['label'], $r['label']);
|
||||
});
|
||||
break;
|
||||
case 'label':
|
||||
usort($data, function ($l, $r) {
|
||||
return strcasecmp($l['label'], $r['label']);
|
||||
});
|
||||
break;
|
||||
default: // device display name (tooltip starts with the display name)
|
||||
usort($data, function ($l, $r) {
|
||||
return strcasecmp($l['tooltip'], $r['tooltip']) ?: strcasecmp($l['label'], $r['label']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private function getDeviceLabel(Device $device, string $state_name): string
|
||||
{
|
||||
switch ($this->getSettings()['color_only_select']) {
|
||||
case 1:
|
||||
return '';
|
||||
case 4:
|
||||
return $device->shortDisplayName();
|
||||
case 2:
|
||||
return strtolower($device->hostname);
|
||||
case 3:
|
||||
return strtolower($device->sysName);
|
||||
default:
|
||||
return __($state_name);
|
||||
}
|
||||
}
|
||||
|
||||
private function getServiceLabel(Service $service, string $state_name): string
|
||||
{
|
||||
if ($this->getSettings()['color_only_select'] == 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $service->service_type . ' - ' . __($state_name);
|
||||
}
|
||||
|
||||
private function getDeviceTooltip(Device $device, string $state_name): string
|
||||
{
|
||||
$tooltip = $device->displayName();
|
||||
$time = $device->formatDownUptime(true);
|
||||
|
||||
if ($time) {
|
||||
$tooltip .= ' - ' . ($state_name == 'down' ? 'downtime ' : '') . $time;
|
||||
}
|
||||
|
||||
return $tooltip;
|
||||
}
|
||||
|
||||
private function getServiceTooltip(Service $service): string
|
||||
{
|
||||
$tooltip = $service->device->displayName() . ' [' . $service->service_type . ']';
|
||||
|
||||
$description = $service->service_name ?: $service->service_desc;
|
||||
if ($description) {
|
||||
$tooltip .= ' ' . $description;
|
||||
}
|
||||
|
||||
return $tooltip;
|
||||
}
|
||||
|
||||
private function parseDeviceState(Device $device, int $uptime_warn): array
|
||||
{
|
||||
if ($device->disabled) {
|
||||
return ['disabled', 'blackbg'];
|
||||
}
|
||||
|
||||
if ($device->ignore) {
|
||||
return ['ignored', 'label-default'];
|
||||
}
|
||||
|
||||
if ($device->status == 1) {
|
||||
if (($device->uptime < $uptime_warn) && ($device->uptime != 0)) {
|
||||
return ['warn', 'label-warning'];
|
||||
}
|
||||
|
||||
return ['up', 'label-success'];
|
||||
}
|
||||
|
||||
return ['down', 'label-danger'];
|
||||
}
|
||||
|
||||
private function parseServiceState(Service $service): array
|
||||
{
|
||||
if ($service->service_status == 0) {
|
||||
return ['up', 'label-success'];
|
||||
}
|
||||
|
||||
if ($service->service_status == 1) {
|
||||
return ['warn', 'label-warning'];
|
||||
}
|
||||
|
||||
return ['down', 'label-danger'];
|
||||
}
|
||||
}
|
||||
|
@@ -2060,7 +2060,8 @@ label {
|
||||
margin:2px;
|
||||
}
|
||||
|
||||
.widget-availability-fixed {
|
||||
.widget-availability:empty {
|
||||
display: inline;
|
||||
min-width: 2.4em;
|
||||
min-height: 1.3em;
|
||||
max-height: 1.6em;
|
||||
|
@@ -7630,16 +7630,6 @@ parameters:
|
||||
count: 1
|
||||
path: app/Http/Controllers/UserPreferencesController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Http\\\\Controllers\\\\Widgets\\\\AvailabilityMapController\\:\\:getServices\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: app/Http/Controllers/Widgets/AvailabilityMapController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Http\\\\Controllers\\\\Widgets\\\\AvailabilityMapController\\:\\:getServices\\(\\) has parameter \\$request with no type specified\\.$#"
|
||||
count: 1
|
||||
path: app/Http/Controllers/Widgets/AvailabilityMapController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Http\\\\Controllers\\\\Widgets\\\\DeviceSummaryController\\:\\:getData\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
@@ -42,7 +42,7 @@
|
||||
<link href="{{ asset('css/query-builder.default.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset(LibreNMS\Config::get('stylesheet', 'css/styles.css')) }}?ver=20210421" rel="stylesheet">
|
||||
<link href="{{ asset(LibreNMS\Config::get('stylesheet', 'css/styles.css')) }}?ver=20220910" rel="stylesheet">
|
||||
<link href="{{ asset('css/' . LibreNMS\Config::get('applied_site_style', 'light') . '.css?ver=632417643') }}" rel="stylesheet">
|
||||
@foreach(LibreNMS\Config::get('webui.custom_css', []) as $custom_css)
|
||||
<link href="{{ $custom_css }}" rel="stylesheet">
|
||||
|
@@ -26,35 +26,21 @@
|
||||
<br style="clear:both;">
|
||||
|
||||
@foreach($devices as $row)
|
||||
<a href="@deviceUrl($row['device'])" title="{{$row['device']->displayName() }}@if($row['stateName'] == 'up' or $row['stateName'] == 'warn')@if($row['device']->formatDownUptime(true)) - @endif{{ $row['device']->formatDownUptime(true) }}@elseif($row['stateName'] == 'down')@if($row['device']->formatDownUptime(true)) - downtime @endif{{$row['device']->formatDownUptime(true)}}@endif">
|
||||
<a href="{{ $row['link'] }}" title="{{$row['tooltip'] }}">
|
||||
@if($type == 0)
|
||||
@if($color_only_select == 1)
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability-fixed widget-availability label-font-border"> </span>
|
||||
@elseif($color_only_select == 2)
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['device']->hostname }}</span>
|
||||
@elseif($color_only_select == 3)
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['device']->sysName }}</span>
|
||||
@elseif($color_only_select == 4)
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['device']->shortDisplayName() }}</span>
|
||||
@else
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ __($row['stateName']) }}</span>
|
||||
@endif
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['label'] }}</span>
|
||||
@else
|
||||
<div class="availability-map-oldview-box-{{ $row['stateName'] }}" style="width:{{ $tile_size }}px;height:{{ $tile_size }}px;"></div>
|
||||
<div class="{{ $row['labelClass'] }}" style="width:{{ $tile_size }}px;height:{{ $tile_size }}px;"></div>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
@foreach($services as $row)
|
||||
<a href="@deviceUrl($row['service']->device, ['tab' => 'services'])" title="{{ $row['service']->device->displayName() }} - {{ $row['service']->service_type }} - {{ $row['service']->service_desc }}">
|
||||
<a href="{{ $row['link'] }}" title="{{$row['tooltip'] }}">
|
||||
@if($type == 0)
|
||||
@if($color_only_select)
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability-fixed widget-availability label-font-border"> </span>
|
||||
@else
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['service']->service_type }} - {{ $row['stateName'] }}</span>
|
||||
@endif
|
||||
<span class="label {{ $row['labelClass'] }} widget-availability label-font-border">{{ $row['label'] }}</span>
|
||||
@else
|
||||
<div class="availability-map-oldview-box-{{ $row['stateName'] }}" style="width:{{ $tile_size }}px;height:{{ $tile_size }}px;"></div>
|
||||
<div class="{{ $row['labelClass'] }}" style="width:{{ $tile_size }}px;height:{{ $tile_size }}px;"></div>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
|
@@ -21,7 +21,7 @@
|
||||
<option value="4" @if($color_only_select == 4) selected @endunless>{{ __('Display Name') }}</option>
|
||||
<option value="2" @if($color_only_select == 2) selected @endunless>{{ __('Hostname') }}</option>
|
||||
<option value="3" @if($color_only_select == 3) selected @endunless>{{ __('SNMP sysName') }}</option>
|
||||
<option value="0" @unless($color_only_select) selected @endunless>{{ __('Device Status') }}</option>
|
||||
<option value="0" @unless($color_only_select) selected @endunless>{{ __('Status') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<select class="form-control" name="order_by" id="order_by-{{ $id }}">
|
||||
<option value="label" @if($order_by == 'label') selected @endif>{{ __('Label') }}</option>
|
||||
<option value="status" @if($order_by == 'status') selected @endif>{{ __('Status') }}</option>
|
||||
<option value="display-name" @if($order_by == 'display-name') selected @endif>{{ __('Display Name') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +73,6 @@
|
||||
init_select2('#device_group-{{ $id }}', 'device-group', {});
|
||||
|
||||
function toggle_availability_type(el, id) {
|
||||
console.log(el.value);
|
||||
if (el.value === '0') {
|
||||
$('#tile_size-group-' + id).hide();
|
||||
$('#color_only_select-group-' + id).show();
|
||||
|
Reference in New Issue
Block a user