Additional custom map features (#15806)

* Added options on edges for a label and to show graphs as bps as well as percentages

I think that vis.js needs to be updated to allow both bps and percentages at the same time.

* Add database migration

* Try to avoid putting multiple mid points in the same position

* Added a URL parameter for screenshot mode, where node labels are blanked out
Also fixed up the node labels in the editor

* Added legend to the editor as well as database options for reversing arrows and adjusting the edge separation

All features have been implemented in the editor, but need to be implemented in the viewer

* Fix missing defaults on the edit map list page
Added arrow reverse code to the viewer
Added legend code to the viewer
Added code to the editor to correclty handle moving the legend

* Formatting fixes and DB schema update

* Remove view from database schema
This commit is contained in:
eskyuu
2024-02-08 01:42:35 +08:00
committed by GitHub
parent d6ce29c052
commit cb09ae0d54
13 changed files with 680 additions and 57 deletions

View File

@@ -30,6 +30,7 @@ use App\Http\Requests\CustomMapSettingsRequest;
use App\Models\CustomMap;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
use LibreNMS\Config;
@@ -47,6 +48,16 @@ class CustomMapController extends Controller
'maps' => CustomMap::orderBy('name')->get(['custom_map_id', 'name']),
'name' => 'New Map',
'node_align' => 10,
'edge_separation' => 10,
'reverse_arrows' => 0,
'legend' => [
'x' => -1,
'y' => -1,
'steps' => 7,
'hide_invalid' => 0,
'hide_overspeed' => 0,
'font_size' => 14,
],
'background' => null,
'map_conf' => [
'height' => '800px',
@@ -75,8 +86,14 @@ class CustomMapController extends Controller
->header('Content-Type', 'text/plain');
}
public function show(CustomMap $map): View
public function show(Request $request, CustomMap $map): View
{
$request->validate([
'screenshot' => 'nullable|in:yes',
]);
$screenshot = $request->input('screenshot') === 'yes' ? 1 : 0;
$map_conf = $map->options;
$map_conf['width'] = $map->width;
$map_conf['height'] = $map->height;
@@ -84,6 +101,8 @@ class CustomMapController extends Controller
'edit' => false,
'map_id' => $map->custom_map_id,
'name' => $map->name,
'reverse_arrows' => $map->reverse_arrows,
'legend' => $this->legendConfig($map),
'background' => (bool) $map->background_suffix,
'bgversion' => $map->background_version,
'page_refresh' => Config::get('page_refresh', 300),
@@ -93,6 +112,7 @@ class CustomMapController extends Controller
'newnode_conf' => $map->newnodeconfig,
'vmargin' => 20,
'hmargin' => 20,
'screenshot' => $screenshot,
];
return view('map.custom-view', $data);
@@ -104,6 +124,9 @@ class CustomMapController extends Controller
'map_id' => $map->custom_map_id,
'name' => $map->name,
'node_align' => $map->node_align,
'edge_separation' => $map->edge_separation,
'reverse_arrows' => $map->reverse_arrows,
'legend' => $this->legendConfig($map),
'newedge_conf' => $map->newedgeconfig,
'newnode_conf' => $map->newnodeconfig,
'map_conf' => $map->options,
@@ -142,6 +165,8 @@ class CustomMapController extends Controller
'name' => $map->name,
'width' => $map->width,
'height' => $map->height,
'reverse_arrows' => $map->reverse_arrows,
'edge_separation' => $map->edge_separation,
]);
}
@@ -164,4 +189,21 @@ class CustomMapController extends Controller
return $images;
}
/**
* Return the legend config
*/
private function legendConfig(CustomMap $map): array
{
$legend = [
'x' => $map->legend_x,
'y' => $map->legend_y,
'steps' => $map->legend_steps,
'hide_invalid' => $map->legend_hide_invalid,
'hide_overspeed' => $map->legend_hide_overspeed,
'font_size' => $map->legend_font_size,
];
return $legend;
}
}

View File

@@ -55,6 +55,8 @@ class CustomMapDataController extends Controller
'reverse' => $edge->reverse,
'style' => $edge->style,
'showpct' => $edge->showpct,
'showbps' => $edge->showbps,
'label' => $edge->label,
'text_face' => $edge->text_face,
'text_size' => $edge->text_size,
'text_colour' => $edge->text_colour,
@@ -122,6 +124,8 @@ class CustomMapDataController extends Controller
$edges[$edgeid]['colour_to'] = $this->speedColour($edges[$edgeid]['port_topct']);
$edges[$edgeid]['colour_from'] = $this->speedColour($edges[$edgeid]['port_frompct']);
}
$edges[$edgeid]['port_tobps'] = $this->rateString($rateto);
$edges[$edgeid]['port_frombps'] = $this->rateString($ratefrom);
$edges[$edgeid]['width_to'] = $this->speedWidth($speedto);
$edges[$edgeid]['width_from'] = $this->speedWidth($speedfrom);
}
@@ -185,11 +189,20 @@ class CustomMapDataController extends Controller
'newedgeconf' => 'array',
'nodes' => 'array',
'edges' => 'array',
'legend_x' => 'integer',
'legend_y' => 'integer',
]);
$map->load(['nodes', 'edges']);
DB::transaction(function () use ($map, $data) {
if ($map->legend_x != $data['legend_x'] || $map->legend_y != $data['legend_y']) {
$map->legend_x = $data['legend_x'];
$map->legend_y = $data['legend_y'];
$map->save();
}
$dbnodes = $map->nodes->keyBy('custom_map_node_id')->all();
$dbedges = $map->edges->keyBy('custom_map_edge_id')->all();
@@ -249,6 +262,8 @@ class CustomMapDataController extends Controller
$dbedge->port_id = $edge['port_id'] ? $edge['port_id'] : null;
$dbedge->reverse = filter_var($edge['reverse'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$dbedge->showpct = filter_var($edge['showpct'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$dbedge->showbps = filter_var($edge['showbps'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
$dbedge->label = $edge['label'] ? $edge['label'] : '';
$dbedge->style = $edge['style'];
$dbedge->text_face = $edge['text_face'];
$dbedge->text_size = $edge['text_size'];
@@ -274,6 +289,23 @@ class CustomMapDataController extends Controller
return response()->json(['id' => $map->custom_map_id]);
}
private function rateString(int $rate): string
{
if ($rate < 1000) {
return $rate . ' bps';
} elseif ($rate < 1000000) {
return intval($rate / 1000) . ' kbps';
} elseif ($rate < 1000000000) {
return intval($rate / 1000000) . ' Mbps';
} elseif ($rate < 1000000000000) {
return intval($rate / 1000000000) . ' Gbps';
} elseif ($rate < 1000000000000000) {
return intval($rate / 1000000000000) . ' Tbps';
} else {
return intval($rate / 1000000000000000) . ' Pbps';
}
}
private function snmpSpeed(string $speeds): int
{
// Only succeed if the string startes with a number optionally followed by a unit

View File

@@ -25,6 +25,8 @@ class CustomMapSettingsRequest extends FormRequest
return [
'name' => 'required|string',
'node_align' => 'integer',
'reverse_arrows' => 'boolean',
'edge_separation' => 'integer',
'width_type' => 'in:px,%',
'width' => [
function (string $attribute, mixed $value, Closure $fail) {
@@ -49,6 +51,12 @@ class CustomMapSettingsRequest extends FormRequest
}
},
],
'legend_x' => 'integer',
'legend_y' => 'integer',
'legend_steps' => 'integer',
'legend_font_size' => 'integer',
'legend_hide_invalid' => 'boolean',
'legend_hide_overspeed' => 'boolean',
];
}
}

View File

@@ -44,6 +44,14 @@ class CustomMap extends BaseModel
'width',
'height',
'node_align',
'reverse_arrows',
'edge_separation',
'legend_x',
'legend_y',
'legend_steps',
'legend_font_size',
'legend_hide_invalid',
'legend_hide_overspeed',
'background_suffix',
'background_version',
];