diff --git a/LibreNMS/Util/Colors.php b/LibreNMS/Util/Color.php similarity index 52% rename from LibreNMS/Util/Colors.php rename to LibreNMS/Util/Color.php index e633749c08..8b801bc60e 100644 --- a/LibreNMS/Util/Colors.php +++ b/LibreNMS/Util/Color.php @@ -1,8 +1,8 @@ 'afcc7c', ]; } + + /** + * Get highlight color based on device status + */ + public static function forDeviceStatus(Device $device): string + { + if ($device->disabled) { + return '#808080'; + } + + if ($device->ignore) { + return '#000000'; + } + + return $device->status ? '#008000' : '#ff0000'; + } + + /** + * Get highlight color based on Port status + */ + public static function forPortStatus(Port $port): string + { + // Ignored ports + if ($port->ignore) { + return '#000000'; + } + + // Shutdown ports + if ($port->ifAdminStatus === 'down') { + return '#808080'; + } + + // Down Ports + if ($port->ifOperStatus !== 'up') { + return '#ff0000'; + } + + // Errored ports + if ($port->ifInErrors_delta > 0 || $port->ifOutErrors_delta > 0) { + return '#ffa500'; + } + + // Up ports + return '#008000'; + } + + /** + * Get highlight color based on BgpPeer status + */ + public static function forBgpPeerStatus(BgpPeer $peer): string + { + // Session inactive + if ($peer->bgpPeerAdminStatus !== 'start') { + return '#000000'; + } + + // Session active but errored + if ($peer->bgpPeerState !== 'established') { + return '#ffa500'; + } + + // Session Up + return '#008000'; + } } diff --git a/LibreNMS/Util/Html.php b/LibreNMS/Util/Html.php index 812d0663dc..1d8a3a817a 100644 --- a/LibreNMS/Util/Html.php +++ b/LibreNMS/Util/Html.php @@ -140,9 +140,9 @@ class Html { $percent = min($percent, 100); if ($colors === null) { - $colors = Colors::percentage($percent, $warn ?: null); + $colors = Color::percentage($percent, $warn ?: null); } - $default = Colors::percentage(0); + $default = Color::percentage(0); $left_text_color = $colors['left_text'] ?? 'ffffff'; $right_text_color = $colors['right_text'] ?? 'ffffff'; $left_color = $colors['left'] ?? $default['left']; diff --git a/app/Http/Controllers/Ajax/BgpSearchController.php b/app/Http/Controllers/Ajax/BgpSearchController.php new file mode 100644 index 0000000000..edf32e3d27 --- /dev/null +++ b/app/Http/Controllers/Ajax/BgpSearchController.php @@ -0,0 +1,72 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2021 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Ajax; + +use App\Models\BgpPeer; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; +use LibreNMS\Util\Color; +use LibreNMS\Util\Url; + +class BgpSearchController extends SearchController +{ + public function buildQuery(string $search, Request $request): Builder + { + return BgpPeer::hasAccess($request->user()) + ->with('device') + ->where(function (Builder $query) use ($search) { + $like_search = "%$search%"; + + return $query->orWhere('astext', 'LIKE', $like_search) + ->orWhere('bgpPeerDescr', 'LIKE', $like_search) + ->orWhere('bgpPeerIdentifier', 'LIKE', $like_search) + ->orWhere('bgpPeerRemoteAs', 'LIKE', $like_search); + }) + ->orderBy('astext'); + } + + /** + * @param \App\Models\BgpPeer $peer + * @return array + */ + public function formatItem($peer): array + { + $bgp_image = $peer->bgpPeerRemoteAs == $peer->device->bgpLocalAs + ? 'fa fa-square fa-lg icon-theme' + : 'fa fa-external-link-square fa-lg icon-theme'; + + return [ + 'url' => Url::deviceUrl($peer->device, ['tab' => 'routing', 'proto' => 'bgp']), + 'name' => $peer->bgpPeerIdentifier, + 'description' => $peer->astext, + 'localas' => $peer->device->bgpLocalAs, + 'bgp_image' => $bgp_image, + 'remoteas' => $peer->bgpPeerRemoteAs, + 'colours' => Color::forBgpPeerStatus($peer), + 'hostname' => $peer->device->displayName(), + ]; + } +} diff --git a/app/Http/Controllers/Ajax/DeviceSearchController.php b/app/Http/Controllers/Ajax/DeviceSearchController.php new file mode 100644 index 0000000000..667bb001c3 --- /dev/null +++ b/app/Http/Controllers/Ajax/DeviceSearchController.php @@ -0,0 +1,104 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2021 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Ajax; + +use App\Models\Device; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; +use LibreNMS\Config; +use LibreNMS\Util\Color; + +class DeviceSearchController extends SearchController +{ + public function buildQuery(string $search, Request $request): Builder + { + $baseQuery = Device::hasAccess($request->user()) + ->leftJoin('locations', 'locations.id', '=', 'devices.location_id') + ->select(['devices.*', 'locations.location']) + ->distinct() + ->orderBy('devices.hostname'); + + return $baseQuery + ->where(function (Builder $query) use ($search, $baseQuery) { + // search filter + $like_search = "%$search%"; + $query->orWhere('hostname', 'LIKE', $like_search) + ->orWhere('sysName', 'LIKE', $like_search) + ->orWhere('display', 'LIKE', $like_search) + ->orWhere('location', 'LIKE', $like_search) + ->orWhere('purpose', 'LIKE', $like_search) + ->orWhere('serial', 'LIKE', $like_search) + ->orWhere('notes', 'LIKE', $like_search); + + if (\LibreNMS\Util\IPv4::isValid($search, false)) { + $baseQuery->leftJoin('ports', 'ports.device_id', '=', 'devices.device_id') + ->leftJoin('ipv4_addresses', 'ipv4_addresses.port_id', 'ports.port_id'); + + $query->orWhere('ipv4_address', '=', $search) + ->orWhere('overwrite_ip', '=', $search) + ->orWhere('ip', '=', inet_pton($search)); + } elseif (\LibreNMS\Util\IPv6::isValid($search, false)) { + $baseQuery->leftJoin('ports', 'ports.device_id', '=', 'devices.device_id') + ->leftJoin('ipv6_addresses', 'ipv6_addresses.port_id', 'ports.port_id'); + + $query->orWhere('ipv6_address', '=', $search) + ->orWhere('overwrite_ip', '=', $search) + ->orWhere('ip', '=', inet_pton($search)); + } elseif (ctype_xdigit($mac_search = str_replace([':', '-', '.'], '', $search))) { + $baseQuery->leftJoin('ports', 'ports.device_id', '=', 'devices.device_id'); + + $query->orWhere('ifPhysAddress', 'LIKE', "%$mac_search%"); + } + + return $query; + }); + } + + /** + * @param Device $device + * @return array + */ + public function formatItem($device): array + { + $name = $device->displayName(); + if (! request()->get('map') && $name !== $device->sysName) { + $name .= " ($device->sysName)"; + } + + return [ + 'name' => $name, + 'device_id' => $device->device_id, + 'url' => \LibreNMS\Util\Url::deviceUrl($device), + 'colours' => Color::forDeviceStatus($device), + 'device_ports' => $device->ports()->count(), + 'device_image' => $device->icon, + 'device_hardware' => $device->hardware, + 'device_os' => Config::getOsSetting($device->os, 'text'), + 'version' => $device->version, + 'location' => $device->location, + ]; + } +} diff --git a/app/Http/Controllers/Ajax/PortSearchController.php b/app/Http/Controllers/Ajax/PortSearchController.php new file mode 100644 index 0000000000..a453846811 --- /dev/null +++ b/app/Http/Controllers/Ajax/PortSearchController.php @@ -0,0 +1,76 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2021 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Ajax; + +use App\Models\Port; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\Request; +use LibreNMS\Util\Color; +use LibreNMS\Util\Url; + +class PortSearchController extends SearchController +{ + public function buildQuery(string $search, Request $request): Builder + { + return Port::hasAccess($request->user()) + ->with('device') + ->where('deleted', 0) + ->where(function (Builder $query) use ($request) { + $search = $request->get('search'); + $like_search = "%$search%"; + + return $query->orWhere('ifAlias', 'LIKE', $like_search) + ->orWhere('ifDescr', 'LIKE', $like_search) + ->orWhere('ifName', 'LIKE', $like_search) + ->orWhere('port_descr_descr', 'LIKE', $like_search) + ->orWhere('portName', 'LIKE', $like_search); + }) + ->orderBy('ifDescr'); + } + + /** + * @param \App\Models\Port $port + * @return array + */ + public function formatItem($port): array + { + $description = $port->getDescription(); + $label = $port->getLabel(); + + if ($description !== $port->ifDescr && $label !== $port->ifDescr) { + $description .= " ($port->ifDescr)"; + } + + return [ + 'url' => Url::portUrl($port), + 'name' => $label, + 'description' => $description, + 'colours' => Color::forPortStatus($port), + 'hostname' => $port->device->displayName(), + 'port_id' => $port->port_id, + ]; + } +} diff --git a/app/Http/Controllers/Ajax/SearchController.php b/app/Http/Controllers/Ajax/SearchController.php new file mode 100644 index 0000000000..107b7be2fa --- /dev/null +++ b/app/Http/Controllers/Ajax/SearchController.php @@ -0,0 +1,55 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2021 Tony Murray + * @author Tony Murray + */ + +namespace App\Http\Controllers\Ajax; + +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use LibreNMS\Config; + +abstract class SearchController +{ + public function __invoke(Request $request): JsonResponse + { + $search = $request->get('search'); + if (empty($search)) { + return new JsonResponse; + } + + $query = $this->buildQuery($search, $request) + ->limit((int) Config::get('webui.global_search_result_limit')); + + return response()->json($query->get()->map([$this, 'formatItem'])); + } + + abstract public function buildQuery(string $search, Request $request): Builder; + + /** + * @param \Illuminate\Database\Eloquent\Model $item + * @return array + */ + abstract public function formatItem($item): array; +} diff --git a/database/migrations/2021_11_29_160744_change_ports_text_fields_to_varchar.php b/database/migrations/2021_11_29_160744_change_ports_text_fields_to_varchar.php new file mode 100644 index 0000000000..fb82065bef --- /dev/null +++ b/database/migrations/2021_11_29_160744_change_ports_text_fields_to_varchar.php @@ -0,0 +1,36 @@ +string('ifAlias')->change(); + $table->string('ifType', 64)->change(); + $table->string('ifPhysAddress', 64)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('ports', function (Blueprint $table) { + $table->text('ifAlias')->change(); + $table->text('ifType')->change(); + $table->text('ifPhysAddress')->change(); + }); + } +} diff --git a/database/migrations/2021_11_29_165046_improve_devices_search_index.php b/database/migrations/2021_11_29_165046_improve_devices_search_index.php new file mode 100644 index 0000000000..ba37b742d5 --- /dev/null +++ b/database/migrations/2021_11_29_165046_improve_devices_search_index.php @@ -0,0 +1,34 @@ +index(['hostname', 'sysName', 'display']); + $table->dropIndex('devices_hostname_index'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('devices', function (Blueprint $table) { + $table->index('hostname'); + $table->dropIndex('devices_hostname_sysname_display_index'); + }); + } +} diff --git a/database/migrations/2021_11_29_165436_improve_ports_search_index.php b/database/migrations/2021_11_29_165436_improve_ports_search_index.php new file mode 100644 index 0000000000..050178dba6 --- /dev/null +++ b/database/migrations/2021_11_29_165436_improve_ports_search_index.php @@ -0,0 +1,36 @@ +index(['ifAlias', 'port_descr_descr', 'portName']); + $table->index(['ifDescr', 'ifName']); + $table->dropIndex('ports_ifdescr_index'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('ports', function (Blueprint $table) { + $table->index('ifDescr'); + $table->dropIndex('ports_ifalias_port_descr_descr_portname_index'); + $table->dropIndex('ports_ifdescr_ifname_index'); + }); + } +} diff --git a/html/ajax_search.php b/html/ajax_search.php deleted file mode 100644 index f13109c18a..0000000000 --- a/html/ajax_search.php +++ /dev/null @@ -1,362 +0,0 @@ - 0) { - $found = 0; - - if (! Auth::user()->hasGlobalRead()) { - $device_ids = Permissions::devicesForUser()->toArray() ?: [0]; - $perms_sql = '`D`.`device_id` IN ' . dbGenPlaceholders(count($device_ids)) . ' AND '; - } else { - $device_ids = []; - $perms_sql = ''; - } - - if ($_REQUEST['type'] == 'group') { - foreach (dbFetchRows('SELECT id,name FROM device_groups WHERE name LIKE ?', ["%$search%"]) as $group) { - if ($_REQUEST['map']) { - $results[] = [ - 'name' => 'g:' . $group['name'], - 'group_id' => $group['id'], - ]; - } else { - $results[] = ['name' => $group['name']]; - } - } - - exit(json_encode($results)); - } elseif ($_REQUEST['type'] == 'alert-rules') { - foreach (dbFetchRows('SELECT name FROM alert_rules WHERE name LIKE ?', ["%$search%"]) as $rules) { - $results[] = ['name' => $rules['name']]; - } - - exit(json_encode($results)); - } elseif ($_REQUEST['type'] == 'device') { - // Device search - - $query = 'SELECT *, `D`.`device_id` AS `device_id` FROM `devices` as `D` - LEFT JOIN `locations` AS `L` ON `L`.`id` = `D`.`location_id`'; - - // user depending limitation - if (! Auth::user()->hasGlobalRead()) { - $query_args_list = $device_ids; - $query_filter = $perms_sql; - } else { - $query_args_list = []; - $query_filter = ''; - } - - // search filter - $query_filter .= '(`D`.`hostname` LIKE ? - OR `L`.`location` LIKE ? - OR `D`.`sysName` LIKE ? - OR `D`.`purpose` LIKE ? - OR `D`.`serial` LIKE ? - OR `D`.`notes` LIKE ?'; - $query_args_list = array_merge($query_args_list, ["%$search%", "%$search%", "%$search%", - "%$search%", "%$search%", "%$search%", ]); - - if (\LibreNMS\Util\IPv4::isValid($search, false)) { - $query .= ' LEFT JOIN `ports` AS `P` ON `P`.`device_id` = `D`.`device_id` - LEFT JOIN `ipv4_addresses` AS `V4` ON `V4`.`port_id` = `P`.`port_id`'; - $query_filter .= ' OR `V4`.`ipv4_address` LIKE ? - OR `D`.`overwrite_ip` LIKE ? - OR `D`.`ip` = ? '; - $query_args_list = array_merge($query_args_list, ["%$search%", "%$search%", inet_pton($search)]); - } elseif (\LibreNMS\Util\IPv6::isValid($search, false)) { - $query .= ' LEFT JOIN `ports` AS `P` ON `P`.`device_id` = `D`.`device_id` - LEFT JOIN `ipv6_addresses` AS `V6` ON `V6`.`port_id` = `P`.`port_id`'; - $query_filter .= ' OR `V6`.`ipv6_address` LIKE ? - OR `D`.`overwrite_ip` LIKE ? - OR `D`.`ip` = ? '; - $query_args_list = array_merge($query_args_list, ["%$search%", "%$search%", inet_pton($search)]); - } elseif (ctype_xdigit($mac_search = str_replace([':', '-', '.'], '', $search))) { - $query .= ' LEFT JOIN `ports` as `M` on `M`.`device_id` = `D`.`device_id`'; - $query_filter .= ' OR `M`.`ifPhysAddress` LIKE ? '; - $query_args_list[] = "%$mac_search%"; - } - - $query_filter .= ')'; - - // result limitation - $query_args_list[] = $limit; - $results = dbFetchRows($query . - ' WHERE ' . $query_filter . - ' GROUP BY `D`.`hostname` - ORDER BY `D`.`hostname` LIMIT ?', $query_args_list); - - if (count($results)) { - $found = 1; - $devices = count($results); - - foreach ($results as $result) { - $name = $result['hostname']; - if ($_REQUEST['map'] != 1 && $result['sysName'] != $name && ! empty($result['sysName'])) { - $name .= ' (' . $result['sysName'] . ') '; - } - if ($result['disabled'] == 1) { - $highlight_colour = '#808080'; - } elseif ($result['ignored'] == 1 && $result['disabled'] == 0) { - $highlight_colour = '#000000'; - } elseif ($result['status'] == 0 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#ff0000'; - } elseif ($result['status'] == 1 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#008000'; - } - - $num_ports = dbFetchCell('SELECT COUNT(*) FROM `ports` AS `I`, `devices` AS `D` WHERE ' . $perms_sql . ' `I`.`device_id` = `D`.`device_id` AND `I`.`ignore` = 0 AND `I`.`deleted` = 0 AND `D`.`device_id` = ?', array_merge($device_ids, [$result['device_id']])); - - $device[] = [ - 'name' => $name, - 'device_id' => $result['device_id'], - 'url' => \LibreNMS\Util\Url::deviceUrl((int) $result['device_id']), - 'colours' => $highlight_colour, - 'device_ports' => $num_ports, - 'device_image' => getIcon($result), - 'device_hardware' => $result['hardware'], - 'device_os' => \LibreNMS\Config::getOsSetting($result['os'], 'text'), - 'version' => $result['version'], - 'location' => $result['location'], - ]; - }//end foreach - }//end if - - $json = json_encode($device); - exit($json); - } elseif ($_REQUEST['type'] == 'ports') { - // Search ports - if (Auth::user()->hasGlobalRead()) { - $results = dbFetchRows( - 'SELECT `ports`.*,`devices`.* FROM `ports` LEFT JOIN `devices` ON `ports`.`device_id` = `devices`.`device_id` WHERE `ifAlias` LIKE ? OR `ifDescr` LIKE ? OR `ifName` LIKE ? ORDER BY ifDescr LIMIT ?', - ["%$search%", "%$search%", "%$search%", $limit] - ); - } else { - $results = dbFetchRows( - "SELECT DISTINCT(`I`.`port_id`), `I`.*, `D`.`hostname` FROM `ports` AS `I`, `devices` AS `D` WHERE $perms_sql `D`.`device_id` = `I`.`device_id` AND (`ifAlias` LIKE ? OR `ifDescr` LIKE ? OR `ifName` LIKE ?) ORDER BY ifDescr LIMIT ?", - array_merge($device_ids, ["%$search%", "%$search%", "%$search%", $limit]) - ); - } - - if (count($results)) { - $found = 1; - - foreach ($results as $result) { - $name = $result['ifDescr'] == $result['ifAlias'] ? $result['ifName'] : $result['ifDescr']; - $description = \LibreNMS\Util\Clean::html($result['ifAlias'], []); - - if ($result['deleted'] == 0 && ($result['ignore'] == 0 || $result['ignore'] == 0) && ($result['ifInErrors_delta'] > 0 || $result['ifOutErrors_delta'] > 0)) { - // Errored ports - $port_colour = '#ffa500'; - } elseif ($result['deleted'] == 0 && ($result['ignore'] == 1 || $result['ignore'] == 1)) { - // Ignored ports - $port_colour = '#000000'; - } elseif ($result['deleted'] == 0 && $result['ifAdminStatus'] == 'down' && $result['ignore'] == 0 && $result['ignore'] == 0) { - // Shutdown ports - $port_colour = '#808080'; - } elseif ($result['deleted'] == 0 && $result['ifOperStatus'] == 'down' && $result['ifAdminStatus'] == 'up' && $result['ignore'] == 0 && $result['ignore'] == 0) { - // Down ports - $port_colour = '#ff0000'; - } elseif ($result['deleted'] == 0 && $result['ifOperStatus'] == 'up' && $result['ignore'] == 0 && $result['ignore'] == 0) { - // Up ports - $port_colour = '#008000'; - }//end if - - $ports[] = [ - 'count' => count($results), - 'url' => generate_port_url($result), - 'name' => $name, - 'description' => $description, - 'colours' => $port_colour, - 'hostname' => format_hostname($result), - 'port_id' => $result['port_id'], - ]; - }//end foreach - }//end if - - $json = json_encode($ports); - exit($json); - } elseif ($_REQUEST['type'] == 'bgp') { - // Search bgp peers - $results = dbFetchRows( - "SELECT `bgpPeers`.*,`D`.* FROM `bgpPeers`, `devices` AS `D` WHERE $perms_sql `bgpPeers`.`device_id`=`D`.`device_id` AND (`astext` LIKE ? OR `bgpPeerIdentifier` LIKE ? OR `bgpPeerRemoteAs` LIKE ?) ORDER BY `astext` LIMIT ?", - array_merge($device_ids, ["%$search%", "%$search%", "%$search%", $limit]) - ); - - if (count($results)) { - $found = 1; - - foreach ($results as $result) { - $name = $result['bgpPeerIdentifier']; - $description = $result['astext']; - $remoteas = $result['bgpPeerRemoteAs']; - $localas = $result['bgpLocalAs']; - - if ($result['bgpPeerAdminStatus'] == 'start' && $result['bgpPeerState'] != 'established') { - // Session active but errored - $port_colour = '#ffa500'; - } elseif ($result['bgpPeerAdminStatus'] != 'start') { - // Session inactive - $port_colour = '#000000'; - } elseif ($result['bgpPeerAdminStatus'] == 'start' && $result['bgpPeerState'] == 'established') { - // Session Up - $port_colour = '#008000'; - } - - if ($result['bgpPeerRemoteAs'] == $result['bgpLocalAs']) { - $bgp_image = 'fa fa-square fa-lg icon-theme'; - } else { - $bgp_image = 'fa fa-external-link-square fa-lg icon-theme'; - } - - $bgp[] = [ - 'count' => count($results), - 'url' => \LibreNMS\Util\Url::generate(['page' => 'device', 'device' => $result['device_id'], 'tab' => 'routing', 'proto' => 'bgp'], []), - 'name' => $name, - 'description' => $description, - 'localas' => $localas, - 'bgp_image' => $bgp_image, - 'remoteas' => $remoteas, - 'colours' => $port_colour, - 'hostname' => format_hostname($result), - ]; - }//end foreach - }//end if - - $json = json_encode($bgp); - exit($json); - } elseif ($_REQUEST['type'] == 'applications') { - // Device search - $results = dbFetchRows( - "SELECT * FROM `applications` INNER JOIN `devices` AS `D` ON `D`.`device_id` = `applications`.`device_id` WHERE $perms_sql (`app_type` LIKE ? OR `hostname` LIKE ?) ORDER BY hostname LIMIT ?", - array_merge($device_ids, ["%$search%", "%$search%", $limit]) - ); - - if (count($results)) { - $found = 1; - $devices = count($results); - - foreach ($results as $result) { - $name = $result['app_type']; - if ($result['disabled'] == 1) { - $highlight_colour = '#808080'; - } elseif ($result['ignored'] == 1 && $result['disabled'] == 0) { - $highlight_colour = '#000000'; - } elseif ($result['status'] == 0 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#ff0000'; - } elseif ($result['status'] == 1 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#008000'; - } - - $device[] = [ - 'name' => $name, - 'hostname' => format_hostname($result), - 'app_id' => $result['app_id'], - 'device_id' => $result['device_id'], - 'colours' => $highlight_colour, - 'device_image' => getIcon($result), - 'device_hardware' => $result['hardware'], - 'device_os' => \LibreNMS\Config::getOsSetting($result['os'], 'text'), - 'version' => $result['version'], - 'location' => $result['location'], - ]; - }//end foreach - }//end if - - $json = json_encode($device); - exit($json); - } elseif ($_REQUEST['type'] == 'munin') { - // Device search - $results = dbFetchRows( - "SELECT * FROM `munin_plugins` INNER JOIN `devices` AS `D` ON `D`.`device_id` = `munin_plugins`.`device_id` WHERE $perms_sql (`mplug_type` LIKE ? OR `mplug_title` LIKE ? OR `hostname` LIKE ?) ORDER BY hostname LIMIT ?", - array_merge($device_ids, ["%$search%", "%$search%", "%$search%", $limit]) - ); - - if (count($results)) { - $found = 1; - $devices = count($results); - - foreach ($results as $result) { - $name = $result['mplug_title']; - if ($result['disabled'] == 1) { - $highlight_colour = '#808080'; - } elseif ($result['ignored'] == 1 && $result['disabled'] == 0) { - $highlight_colour = '#000000'; - } elseif ($result['status'] == 0 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#ff0000'; - } elseif ($result['status'] == 1 && $result['ignore'] == 0 && $result['disabled'] == 0) { - $highlight_colour = '#008000'; - } - - $device[] = [ - 'name' => $name, - 'hostname' => format_hostname($result), - 'device_id' => $result['device_id'], - 'colours' => $highlight_colour, - 'device_image' => getIcon($result), - 'device_hardware' => $result['hardware'], - 'device_os' => \LibreNMS\Config::getOsSetting($result['os'], 'text'), - 'version' => $result['version'], - 'location' => $result['location'], - 'plugin' => $result['mplug_type'], - ]; - }//end foreach - }//end if - - $json = json_encode($device); - exit($json); - } elseif ($_REQUEST['type'] == 'iftype') { - // Device search - $results = dbFetchRows( - "SELECT `ports`.ifType FROM `ports` WHERE $perms_sql `ifType` LIKE ? GROUP BY ifType ORDER BY ifType LIMIT ?", - array_merge($device_ids, ["%$search%", $limit]) - ); - - if (count($results)) { - $found = 1; - $devices = count($results); - - foreach ($results as $result) { - $device[] = [ - 'filter' => $result['ifType'], - ]; - }//end foreach - }//end if - - $json = json_encode($device); - exit($json); - } elseif ($_REQUEST['type'] == 'bill') { - // Device search - if (Auth::user()->hasGlobalRead()) { - $results = dbFetchRows( - 'SELECT `bills`.bill_id, `bills`.bill_name FROM `bills` WHERE `bill_name` LIKE ? OR `bill_notes` LIKE ? LIMIT ?', - ["%$search%", "%$search%", $limit] - ); - } else { - $results = dbFetchRows( - 'SELECT `bills`.bill_id, `bills`.bill_name FROM `bills` INNER JOIN `bill_perms` ON `bills`.bill_id = `bill_perms`.bill_id WHERE `bill_perms`.user_id = ? AND (`bill_name` LIKE ? OR `bill_notes` LIKE ?) LIMIT ?', - [Auth::id(), "%$search%", "%$search%", $limit] - ); - } - $json = json_encode($results); - exit($json); - }//end if - }//end if -}//end if diff --git a/html/js/typeahead.bundle.min.js b/html/js/typeahead.bundle.min.js index 06385c51bd..f3c2719acd 100644 --- a/html/js/typeahead.bundle.min.js +++ b/html/js/typeahead.bundle.min.js @@ -1,9 +1,9 @@ /*! - * typeahead.js 1.3.0 + * typeahead.js 1.3.1 * https://github.com/corejavascript/typeahead.js - * Copyright 2013-2019 Twitter, Inc. and other contributors; Licensed MIT + * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT */ -!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.Bloodhound=b(c)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):a.Bloodhound=b(a.jQuery)}(this,function(a){var b=function(){"use strict";return{isMsie:function(){return!!/(msie|trident)/i.test(navigator.userAgent)&&navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:function(a){return"function"==typeof a},isObject:a.isPlainObject,isUndefined:function(a){return void 0===a},isElement:function(a){return!(!a||1!==a.nodeType)},isJQuery:function(b){return b instanceof a},toStr:function(a){return b.isUndefined(a)||null===a?"":a+""},bind:a.proxy,each:function(b,c){function d(a,b){return c(b,a)}a.each(b,d)},map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){if(!(d=c.call(null,e,a,b)))return!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){if(d=c.call(null,e,a,b))return!1}),!!d):d},mixin:a.extend,identity:function(a){return a},clone:function(b){return a.extend(!0,{},b)},getIdGenerator:function(){var a=0;return function(){return a++}},templatify:function(b){function c(){return String(b)}return ("function"==typeof b)?b:c},defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,j<=0?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},stringify:function(a){return b.isString(a)?a:JSON.stringify(a)},guid:function(){function a(a){var b=(Math.random().toString(16)+"000000000").substr(2,8);return a?"-"+b.substr(0,4)+"-"+b.substr(4,4):b}return"tt-"+a()+a(!0)+a(!0)+a()},noop:function(){}}}(),c="1.3.0",d=function(){"use strict";function a(a){return a=b.toStr(a),a?a.split(/\s+/):[]}function c(a){return a=b.toStr(a),a?a.split(/\W+/):[]}function d(a){a=b.toStr(a);var c=[],d="";return b.each(a.split(""),function(a){a.match(/\s+/)?d="":(c.push(d+a),d+=a)}),c}function e(a){return function(c){return c=Array.isArray(c)?c:[].slice.call(arguments,0),function(d){var e=[];return b.each(c,function(c){e=e.concat(a(b.toStr(d[c])))}),e}}}return{nonword:c,whitespace:a,ngram:d,obj:{nonword:e(c),whitespace:e(a),ngram:e(d)}}}(),e=function(){"use strict";function c(c){this.maxSize=b.isNumber(c)?c:100,this.reset(),this.maxSize<=0&&(this.set=this.get=a.noop)}function d(){this.head=this.tail=null}function e(a,b){this.key=a,this.val=b,this.prev=this.next=null}return b.mixin(c.prototype,{set:function(a,b){var c,d=this.list.tail;this.size>=this.maxSize&&(this.list.remove(d),delete this.hash[d.key],this.size--),(c=this.hash[a])?(c.val=b,this.list.moveToFront(c)):(c=new e(a,b),this.list.add(c),this.hash[a]=c,this.size++)},get:function(a){var b=this.hash[a];if(b)return this.list.moveToFront(b),b.val},reset:function(){this.size=0,this.hash={},this.list=new d}}),b.mixin(d.prototype,{add:function(a){this.head&&(a.next=this.head,this.head.prev=a),this.head=a,this.tail=this.tail||a},remove:function(a){a.prev?a.prev.next=a.next:this.head=a.next,a.next?a.next.prev=a.prev:this.tail=a.prev},moveToFront:function(a){this.remove(a),this.add(a)}}),c}(),f=function(){"use strict";function c(a,c){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+b.escapeRegExChars(this.prefix)),this.ls=c||h,!this.ls&&this._noop()}function d(){return(new Date).getTime()}function e(a){return JSON.stringify(b.isUndefined(a)?null:a)}function f(b){return a.parseJSON(b)}function g(a){var b,c,d=[],e=h.length;for(b=0;bc)}}),c}(),g=function(){"use strict";function c(a){a=a||{},this.maxPendingRequests=a.maxPendingRequests||6,this.cancelled=!1,this.lastReq=null,this._send=a.transport,this._get=a.limiter?a.limiter(this._get):this._get,this._cache=!1===a.cache?new e(0):g}var d=0,f={},g=new e(10);return c.setMaxPendingRequests=function(a){this.maxPendingRequests=a},c.resetCache=function(){g.reset()},b.mixin(c.prototype,{_fingerprint:function(b){return b=b||{},b.url+b.type+a.param(b.data||{})},_get:function(a,b){function c(a){b(null,a),j._cache.set(h,a)}function e(){b(!0)}function g(){d--,delete f[h],j.onDeckRequestArgs&&(j._get.apply(j,j.onDeckRequestArgs),j.onDeckRequestArgs=null)}var h,i,j=this;h=this._fingerprint(a),this.cancelled||h!==this.lastReq||((i=f[h])?i.done(c).fail(e):db[d]?d++:(e.push(a[c]),c++,d++);return e}var h="c",i="i";return b.mixin(c.prototype,{bootstrap:function(a){this.datums=a.datums,this.trie=a.trie},add:function(a){var c=this;a=Array.isArray(a)?a:[a],b.each(a,function(a){var f,g;c.datums[f=c.identify(a)]=a,g=d(c.datumTokenizer(a)),b.each(g,function(a){var b,d,g;for(b=c.trie,d=a.split("");g=d.shift();)b=b[h][g]||(b[h][g]=e()),b[i].push(f)})})},get:function(a){var c=this;return b.map(a,function(a){return c.datums[a]})},search:function(a){var c,e,j=this;return c=d(this.queryTokenizer(a)),b.each(c,function(a){var b,c,d,f;if(e&&0===e.length&&!j.matchAnyQueryToken)return!1;for(b=j.trie,c=a.split("");b&&(d=c.shift());)b=b[h][d];if(b&&0===c.length)f=b[i].slice(0),e=e?g(e,f):f;else if(!j.matchAnyQueryToken)return e=[],!1}),e?b.map(f(e),function(a){return j.datums[a]}):[]},all:function(){var a=[];for(var b in this.datums)a.push(this.datums[b]);return a},reset:function(){this.datums={},this.trie=e()},serialize:function(){return{datums:this.datums,trie:this.trie}}}),c}(),i=function(){"use strict";function a(a){this.url=a.url,this.ttl=a.ttl,this.cache=a.cache,this.prepare=a.prepare,this.transform=a.transform,this.transport=a.transport,this.thumbprint=a.thumbprint,this.storage=new f(a.cacheKey)}var c;return c={data:"data",protocol:"protocol",thumbprint:"thumbprint"},b.mixin(a.prototype,{_settings:function(){return{url:this.url,type:"GET",dataType:"json"}},store:function(a){this.cache&&(this.storage.set(c.data,a,this.ttl),this.storage.set(c.protocol,location.protocol,this.ttl),this.storage.set(c.thumbprint,this.thumbprint,this.ttl))},fromCache:function(){var a,b={};return this.cache?(b.data=this.storage.get(c.data),b.protocol=this.storage.get(c.protocol),b.thumbprint=this.storage.get(c.thumbprint),a=b.thumbprint!==this.thumbprint||b.protocol!==location.protocol,b.data&&!a?b.data:null):null},fromNetwork:function(a){function b(){a(!0)}function c(b){a(null,e.transform(b))}var d,e=this;a&&(d=this.prepare(this._settings()),this.transport(d).fail(b).done(c))},clear:function(){return this.storage.clear(),this}}),a}(),j=function(){"use strict";function a(a){this.url=a.url,this.prepare=a.prepare,this.transform=a.transform,this.indexResponse=a.indexResponse,this.transport=new g({cache:a.cache,limiter:a.limiter,transport:a.transport,maxPendingRequests:a.maxPendingRequests})}return b.mixin(a.prototype,{_settings:function(){return{url:this.url,type:"GET",dataType:"json"}},get:function(a,b){function c(a,c){b(a?[]:e.transform(c))}var d,e=this;if(b)return a=a||"",d=this.prepare(a,this._settings()),this.transport.get(d,c)},cancelLastRequest:function(){this.transport.cancel()}}),a}(),k=function(){"use strict";function d(d){var e;return d?(e={url:null,ttl:864e5,cache:!0,cacheKey:null,thumbprint:"",prepare:b.identity,transform:b.identity,transport:null},d=b.isString(d)?{url:d}:d,d=b.mixin(e,d),!d.url&&a.error("prefetch requires url to be set"),d.transform=d.filter||d.transform,d.cacheKey=d.cacheKey||d.url,d.thumbprint=c+d.thumbprint,d.transport=d.transport?h(d.transport):a.ajax,d):null}function e(c){var d;if(c)return d={url:null,cache:!0,prepare:null,replace:null,wildcard:null,limiter:null,rateLimitBy:"debounce",rateLimitWait:300,transform:b.identity,transport:null},c=b.isString(c)?{url:c}:c,c=b.mixin(d,c),!c.url&&a.error("remote requires url to be set"),c.transform=c.filter||c.transform,c.prepare=f(c),c.limiter=g(c),c.transport=c.transport?h(c.transport):a.ajax,delete c.replace,delete c.wildcard,delete c.rateLimitBy,delete c.rateLimitWait,c}function f(a){function b(a,b){return b.url=f(b.url,a),b}function c(a,b){return b.url=b.url.replace(g,encodeURIComponent(a)),b}function d(a,b){return b}var e,f,g;return e=a.prepare,f=a.replace,g=a.wildcard,e||(e=f?b:a.wildcard?c:d)}function g(a){var c,d,e;return c=a.limiter,d=a.rateLimitBy,e=a.rateLimitWait,c||(c=/^throttle$/i.test(d)?function(a){return function(c){return b.throttle(c,a)}}(e):function(a){return function(c){return b.debounce(c,a)}}(e)),c}function h(c){return function(d){function e(a){b.defer(function(){g.resolve(a)})}function f(a){b.defer(function(){g.reject(a)})}var g=a.Deferred();return c(d,e,f),g}}return function(c){var f,g;return f={initialize:!0,identify:b.stringify,datumTokenizer:null,queryTokenizer:null,matchAnyQueryToken:!1,sufficient:5,indexRemote:!1,sorter:null,local:[],prefetch:null,remote:null},c=b.mixin(f,c||{}),!c.datumTokenizer&&a.error("datumTokenizer is required"),!c.queryTokenizer&&a.error("queryTokenizer is required"),g=c.sorter,c.sorter=g?function(a){return a.sort(g)}:b.identity,c.local=("function"==typeof c.local)?c.local():c.local,c.prefetch=d(c.prefetch),c.remote=e(c.remote),c}}();return function(){"use strict";function c(a){a=k(a),this.sorter=a.sorter,this.identify=a.identify,this.sufficient=a.sufficient,this.indexRemote=a.indexRemote,this.local=a.local,this.remote=a.remote?new j(a.remote):null,this.prefetch=a.prefetch?new i(a.prefetch):null,this.index=new h({identify:this.identify,datumTokenizer:a.datumTokenizer,queryTokenizer:a.queryTokenizer}),!1!==a.initialize&&this.initialize()}var e;return e=window&&window.Bloodhound,c.noConflict=function(){return window&&(window.Bloodhound=e),c},c.tokenizers=d,b.mixin(c.prototype,{__ttAdapter:function(){function a(a,b,d){return c.search(a,b,d)}function b(a,b){return c.search(a,b)}var c=this;return this.remote?a:b},_loadPrefetch:function(){function b(a,b){if(a)return c.reject();e.add(b),e.prefetch.store(e.index.serialize()),c.resolve()}var c,d,e=this;return c=a.Deferred(),this.prefetch?(d=this.prefetch.fromCache())?(this.index.bootstrap(d),c.resolve()):this.prefetch.fromNetwork(b):c.resolve(),c.promise()},_initialize:function(){function a(){b.add(b.local)}var b=this;return this.clear(),(this.initPromise=this._loadPrefetch()).done(a),this.initPromise},initialize:function(a){return!this.initPromise||a?this._initialize():this.initPromise},add:function(a){return this.index.add(a),this},get:function(a){return a=Array.isArray(a)?a:[].slice.call(arguments),this.index.get(a)},search:function(a,c,d){function e(a){var c=[];b.each(a,function(a){!b.some(f,function(b){return g.identify(a)===g.identify(b)})&&c.push(a)}),g.indexRemote&&g.add(c),d(c)}var f,g=this;return c=c||b.noop,d=d||b.noop,f=this.sorter(this.index.search(a)),c(this.remote?f.slice():f),this.remote&&f.length',menu:'
'}}function d(a){var c={};return b.each(a,function(a,b){c[b]="."+a}),c}function e(){var a={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},menu:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return b.isMsie()&&b.mixin(a.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),a}var f={wrapper:"twitter-typeahead",input:"tt-input",hint:"tt-hint",menu:"tt-menu",dataset:"tt-dataset",suggestion:"tt-suggestion",selectable:"tt-selectable",empty:"tt-empty",open:"tt-open",cursor:"tt-cursor",highlight:"tt-highlight"};return a}(),d=function(){"use strict";function c(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d,e;return d="typeahead:",e={render:"rendered",cursorchange:"cursorchanged",select:"selected",autocomplete:"autocompleted"},b.mixin(c.prototype,{_trigger:function(b,c){var e=a.Event(d+b);return this.$el.trigger.call(this.$el,e,c||[]),e},before:function(a){var b,c;return b=[].slice.call(arguments,1),c=this._trigger("before"+a,b),c.isDefaultPrevented()},trigger:function(a){var b;this._trigger(a,[].slice.call(arguments,1)),(b=e[a])&&this._trigger(b,[].slice.call(arguments,1))}}),c}(),e=function(){"use strict";function a(a,b,c,d){var e;if(!c)return this;for(b=b.split(h),c=d?g(c,d):c,this._callbacks=this._callbacks||{};e=b.shift();)this._callbacks[e]=this._callbacks[e]||{sync:[],async:[]},this._callbacks[e][a].push(c);return this}function b(b,c,d){return a.call(this,"async",b,c,d)}function c(b,c,d){return a.call(this,"sync",b,c,d)}function d(a){var b;if(!this._callbacks)return this;for(a=a.split(h);b=a.shift();)delete this._callbacks[b];return this}function e(a){var b,c,d,e,g;if(!this._callbacks)return this;for(a=a.split(h),d=[].slice.call(arguments,1);(b=a.shift())&&(c=this._callbacks[b]);)e=f(c.sync,this,[b].concat(d)),g=f(c.async,this,[b].concat(d)),e()&&i(g);return this}function f(a,b,c){function d(){for(var d,e=0,f=a.length;!d&&e