LibreNMSでポート一覧から無効にしているポートを除外して表示したい

LibreNMにはポートの一覧で、未使用ポートを除外するフィルターがない。
とくにYAMAHA RTXなどをは大量の pp[XX], pp[anonymousXX], Tunnel[XX] が使っていなくても一覧に表示されるため、見たいものがリストのなかに埋もれるほか、レスポンスも悪くなり、使い勝手が悪い。

Observiumだと Quick Filters で表示しないものを
Hide UP, Hide DOWN, Hide SHUTDOWN, Hide IGNORED, Hide DELETED, Hide ALL
から組み合わせて指定できるので、これ相当のものを実装した。

```
diff --git a/html/pages/device/ports.inc.php b/html/pages/device/ports.inc.php
index 4110d66..7a66326 100644
--- a/html/pages/device/ports.inc.php
+++ b/html/pages/device/ports.inc.php
@@ -12,6 +12,23 @@ if (!$vars['view']) {
     $vars['view'] = trim($config['ports_page_default'], '/');
 }
 
+$quickfilter_conditions = array(
+    'down'      => FALSE,
+    'shutdown'  => FALSE,
+    'ignored'   => FALSE,
+    'disabled'  => FALSE,
+    'deleted'   => FALSE,
+);
+if (isset($vars['filters'])) {
+    foreach (explode(',', $vars['filters']) as $filter) {
+        $quickfilter_conditions[$filter] = TRUE;
+    }
+} else {
+    foreach (array('deleted', 'disabled', 'shutdown') as $filter) {
+        $quickfilter_conditions[$filter] = TRUE;
+    }
+}
+
 $link_array = array(
     'page'   => 'device',
     'device' => $device['device_id'],
@@ -88,8 +105,38 @@ foreach ($graph_types as $type => $descr) {
     $type_sep = ' | ';
 }//end foreach
 
+if (in_array($vars['view'], array('basic', 'details', 'graphs', 'minigraphs'))) {
+    echo '<div class="dropdown pull-right">
+<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
+Quick Filters
+<span class="caret"></span></button>
+<ul class="dropdown-menu">';
+
+    foreach ($quickfilter_conditions as $name => $enabled) {
+	echo '<li>';
+	echo $enabled ? "<span class='pagemenu-selected'>" : "<span>";
+	$filter = $quickfilter_conditions;
+	$filter[$name] = !$filter[$name];
+	echo generate_link("Hide ".strtoupper($name), $link_array, array($option, 'filters' => implode(',', array_keys(array_filter($filter)))));
+	echo "</span>";
+	echo "</li>\n";
+    }
+    echo "</ul></div>\n";
+}
+
 print_optionbar_end();
 
+function port_filter($port)
+{
+    global $quickfilter_conditions;
+    $is_filtered =
+        ($quickfilter_conditions['down'] && $port['ifOperStatus'] != 'up' && $port['ifAdminStatus'] == 'up') ||
+        ($quickfilter_conditions['shutdown'] && $port['ifAdminStatus'] == 'down') ||
+        ($quickfilter_conditions['ignored']  && $port['ignore']) ||
+        ($quickfilter_conditions['deleted']  && $port['deleted']);
+    return !$is_filtered;
+}
+
 if ($vars['view'] == 'minigraphs') {
     $timeperiods = array(
         '-1day',
@@ -104,6 +151,7 @@ if ($vars['view'] == 'minigraphs') {
     // FIXME - FIX THIS. UGLY.
     foreach (dbFetchRows('select * from ports WHERE device_id = ? ORDER BY ifIndex', array($device['device_id'])) as $port) {
         $port = cleanPort($port, $device);
+        if (!port_filter($port)) { continue; }
         echo "<div style='display: block; padding: 3px; margin: 3px; min-width: 183px; max-width:183px; min-height:90px; max-height:90px; text-align: center; float: left; background-color: #e9e9e9;'>
             <div style='font-weight: bold;'>".makeshortif($port['ifDescr']).'</div>
             <a href="'.generate_port_url($port)."\" onmouseover=\"return overlib('\
@@ -146,6 +194,8 @@ if ($vars['view'] == 'minigraphs') {
     // As we've dragged the whole database, lets pre-populate our caches :)
     // FIXME - we should probably split the fetching of link/stack/etc into functions and cache them here too to cut down on single row queries.
 
+$ports = array_filter($ports, port_filter);
+
 foreach ($ports as $key => $port) {
     $port_cache[$port['port_id']] = $port;
     $port_index_cache[$port['device_id']][$port['ifIndex']] = $port;
```