From 5eaa4292c6db2c1ee1282c938c899dc5b88db65f Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 20 Apr 2020 11:49:17 +0200 Subject: [statistics] New filter UI --- modules-available/statistics/config.json | 1 - .../statistics/hooks/translation.inc.php | 30 ++ .../statistics/inc/statisticsfilter.inc.php | 270 +++++++++-------- modules-available/statistics/lang/de/filters.json | 24 ++ .../statistics/lang/de/template-tags.json | 11 +- modules-available/statistics/lang/en/filters.json | 24 ++ .../statistics/lang/en/template-tags.json | 11 +- modules-available/statistics/page.inc.php | 24 +- modules-available/statistics/pages/list.inc.php | 11 +- modules-available/statistics/pages/summary.inc.php | 13 +- modules-available/statistics/style.css | 31 +- .../statistics/templates/cpumodels.html | 4 +- .../statistics/templates/filterbox.html | 330 +++++++-------------- modules-available/statistics/templates/id44.html | 2 +- .../statistics/templates/kvmstate.html | 2 +- modules-available/statistics/templates/memory.html | 2 +- 16 files changed, 401 insertions(+), 389 deletions(-) create mode 100644 modules-available/statistics/hooks/translation.inc.php create mode 100644 modules-available/statistics/lang/de/filters.json create mode 100644 modules-available/statistics/lang/en/filters.json (limited to 'modules-available/statistics') diff --git a/modules-available/statistics/config.json b/modules-available/statistics/config.json index 412dc3cb..11d3fba3 100644 --- a/modules-available/statistics/config.json +++ b/modules-available/statistics/config.json @@ -2,7 +2,6 @@ "category": "main.status", "dependencies": [ "js_chart", - "js_selectize", "bootstrap_datepicker" ], "permission": "0" diff --git a/modules-available/statistics/hooks/translation.inc.php b/modules-available/statistics/hooks/translation.inc.php new file mode 100644 index 00000000..4d09553a --- /dev/null +++ b/modules-available/statistics/hooks/translation.inc.php @@ -0,0 +1,30 @@ +activate(1, false)) + return array(); + $want = StatisticsFilter::$columns; + foreach ($want as &$entry) { + $entry = true; + } + return $want; +}; diff --git a/modules-available/statistics/inc/statisticsfilter.inc.php b/modules-available/statistics/inc/statisticsfilter.inc.php index 1bc512f5..6999654d 100644 --- a/modules-available/statistics/inc/statisticsfilter.inc.php +++ b/modules-available/statistics/inc/statisticsfilter.inc.php @@ -6,9 +6,9 @@ class StatisticsFilter { /** - * Delimiter for js_selectize filters + * Legacy delimiter for js_selectize filters - used to redirect old URLs */ - const DELIMITER = '~,~'; + const LEGACY_DELIMITER = '~,~'; const SIZE_ID44 = array(0, 8, 16, 24, 30, 40, 50, 60, 80, 100, 120, 150, 180, 250, 300, 400, 500, 1000, 2000, 4000); const SIZE_RAM = array(1, 2, 3, 4, 6, 8, 10, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 320, 480, 512, 768, 1024); @@ -90,61 +90,34 @@ class StatisticsFilter } /* parse a query into an array of filters */ - public static function parseQuery($query) + public static function parseQuery() { - $operators = ['<=', '>=', '!=', '!~', '=', '~', '<', '>']; + // Get current settings from GET + $currentValues = self::loadFilterFromGet(); $filters = []; - if (empty($query)) - return $filters; - foreach (explode(self::DELIMITER, $query) as $q) { - $q = trim($q); - if (empty($q)) + foreach ($currentValues as $filterType => $data) { + if (!$data['filter']) continue; - // Special case: User pasted UUID, turn into filter - if (preg_match('/^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/', $q)) { - $filters[] = new StatisticsFilter('machineuuid', '=', $q); - continue; - } - // Special case: User pasted IP, turn into filter - if (preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $q)) { - $filters[] = new StatisticsFilter('clientip', '=', $q); - continue; - } - /* find position of first operator */ - $pos = 10000; - $operator = false; - foreach ($operators as $op) { - $newpos = strpos($q, $op); - if ($newpos > -1 && ($newpos < $pos)) { - $pos = $newpos; - $operator = $op; - } - } - if ($pos == 10000) { - error_log("couldn't find operator in segment " . $q); - /* TODO */ - continue; - } - $lhs = trim(substr($q, 0, $pos)); - $rhs = trim(substr($q, $pos + strlen($operator))); - - if ($lhs === 'gbram') { - $filters[] = new RamGbStatisticsFilter($operator, $rhs); - } elseif ($lhs === 'runtime') { - $filters[] = new RuntimeStatisticsFilter($operator, $rhs); - } elseif ($lhs === 'state') { - $filters[] = new StateStatisticsFilter($operator, $rhs); - } elseif ($lhs === 'hddgb') { - $filters[] = new Id44StatisticsFilter($operator, $rhs); - } elseif ($lhs === 'location') { - $filters[] = new LocationStatisticsFilter($operator, $rhs); - } elseif ($lhs === 'subnet') { - $filters[] = new SubnetStatisticsFilter($operator, $rhs); + $operator = $data['op']; + $argument = $data['argument']; + + if ($filterType === 'gbram') { + $filters[] = new RamGbStatisticsFilter($operator, $argument); + } elseif ($filterType === 'runtime') { + $filters[] = new RuntimeStatisticsFilter($operator, $argument); + } elseif ($filterType === 'state') { + $filters[] = new StateStatisticsFilter($operator, $argument); + } elseif ($filterType === 'hddgb') { + $filters[] = new Id44StatisticsFilter($operator, $argument); + } elseif ($filterType === 'location') { + $filters[] = new LocationStatisticsFilter($operator, $argument); + } elseif ($filterType === 'subnet') { + $filters[] = new SubnetStatisticsFilter($operator, $argument); } else { - if (array_key_exists($lhs, self::$columns) && self::$columns[$lhs]['column']) { - $filters[] = new StatisticsFilter($lhs, $operator, $rhs); + if (array_key_exists($filterType, self::$columns)) { + $filters[] = new StatisticsFilter($filterType, $operator, $argument); } else { - Message::addError('invalid-filter-key', $lhs); + Message::addError('invalid-filter-key', $filterType); } } } @@ -152,18 +125,107 @@ class StatisticsFilter return $filters; } + private static function loadFilterFromGet() + { + $ops = Request::get('op', [], 'array'); + $currentValues = ArrayUtil::mergeByKey([ + 'filter' => Request::get('filter', [], 'array'), + 'op' => $ops, + 'argument' => Request::get('arg', [], 'array'), + ]); + if (Request::get('show') === false && empty($ops)) { + $currentValues['lastseen'] = [ + 'filter' => true, + 'op' => '>', + 'argument' => gmdate('Y-m-d', strtotime('-30 day')), + ]; + } + return $currentValues; + } + /** * @param \StatisticsFilterSet $filterSet */ - public static function renderFilterBox($show, $filterSet, $query) + public static function renderFilterBox($show, $filterSet) { + // Build location list, with permissions + $locs = []; + if (Module::isAvailable('locations')) { + $allowed = $filterSet->getAllowedLocations(); + foreach (Location::getLocations(-1, 0, true) as $loc) { + $locs[] = [ + 'key' => $loc['locationid'], + 'value' => $loc['locationpad'] . ' ' . $loc['locationname'], + 'disabled' => $allowed !== false && !in_array($loc['locationid'], $allowed) + ? 'disabled' : '', + ]; + } + } + // Get current settings from GET + $currentValues = self::loadFilterFromGet(); + // Build column array for rendering + $columns = []; + foreach (self::$columns as $key => $col) { + if ($key === 'location') { + $col['values'] = $locs; + } + $col['key'] = $key; + $col['name'] = Dictionary::translateFile('filters', $key, true); + if ($col['type'] === 'int') { + $col['input'] = 'number'; + } elseif ($col['type'] === 'string') { + $col['input'] = 'text'; + } elseif ($col['type'] === 'date') { + $col['input'] = 'text'; + $col['inputclass'] = 'is-date'; + } elseif ($col['type'] === 'enum') { + $col['enum'] = true; + if (isset($col['values'][0])) { + if (!is_array($col['values'][0])) { + // Arrayize + $col['values'] = array_map(function($e) { return [ + 'key' => $e, + 'value' => $e, + ]; }, $col['values']); + } + } else { + $col['values'] = array_map(function($v, $k) { return [ + 'key' => $k, + 'value' => $v, + ]; }, $col['values'], array_keys($col['values'])); + } + if (isset($currentValues[$key]['argument'])) { + // Current value from GET + foreach ($col['values'] as &$value) { + if ($value['key'] == $currentValues[$key]['argument']) { + $value['selected'] = 'selected'; + } + } + } + } + // current value from GET + if (isset($currentValues[$key])) { + $col['currentvalue'] = $currentValues[$key]['argument'] ?? ''; + if ($currentValues[$key]['filter']) { + $col['checked'] = 'checked'; + } elseif (!isset($col['show']) || !$col['show']) { + $col['collapse'] = 'collapse'; + } + } elseif (!isset($col['show']) || !$col['show']) { + $col['collapse'] = 'collapse'; + } + // Current value, arrayize + foreach ($col['op'] as &$value) { + $value = ['op' => $value]; + if (($currentValues[$key]['op'] ?? '=') === $value['op']) { + $value['selected'] = 'selected'; + } + } + $columns[] = $col; + } $data = array( 'show' => $show, - 'query' => $query, - 'delimiter' => StatisticsFilter::DELIMITER, - 'sortDirection' => $filterSet->getSortDirection(), - 'sortColumn' => $filterSet->getSortColumn(), - 'columns' => json_encode(StatisticsFilter::$columns), + 'columns' => $columns, ); if ($show === 'list') { @@ -175,42 +237,16 @@ class StatisticsFilter } - $locsFlat = array(); - if (Module::isAvailable('locations')) { - $allowed = $filterSet->getAllowedLocations(); - foreach (Location::getLocations() as $loc) { - $locsFlat['L' . $loc['locationid']] = array( - 'pad' => $loc['locationpad'], - 'name' => $loc['locationname'], - 'disabled' => $allowed !== false && !in_array($loc['locationid'], $allowed), - ); - } - } - Permission::addGlobalTags($data['perms'], null, ['view.summary', 'view.list']); - $data['locations'] = json_encode($locsFlat); Render::addTemplate('filterbox', $data); } - private static $query = false; - - public static function getQuery() - { - if (self::$query === false) { - self::$query = Request::any('filters', false, 'string'); - if (self::$query === false) { - self::$query = 'lastseen > ' . gmdate('Y-m-d', strtotime('-30 day')); - } - } - return self::$query; - } - /* * Simple filters that map directly to DB columns */ - const OP_ORDINAL = ['!=', '<=', '>=', '=', '<', '>']; - const OP_STRCMP = ['!~', '~', '=', '!=']; + const OP_ORDINAL = ['=', '!=', '<', '>', '<=', '>=']; + const OP_STRCMP = [ '=', '!=', '!~', '~']; const OP_NOMINAL = ['!=', '=']; public static $columns; @@ -221,127 +257,123 @@ class StatisticsFilter { self::$columns = [ + 'clientip' => [ + 'op' => self::OP_NOMINAL, + 'type' => 'string', + 'placeholder' => '1.2.3.4', + 'show' => true, + ], + 'hostname' => [ + 'op' => self::OP_STRCMP, + 'type' => 'string', + 'placeholder' => 'pc.fqdn.example.com', + ], 'machineuuid' => [ 'op' => self::OP_NOMINAL, 'type' => 'string', - 'column' => true, + 'placeholder' => '88888888-4444-4444-121212121212', + 'show' => true, ], 'macaddr' => [ 'op' => self::OP_NOMINAL, 'type' => 'string', - 'column' => true, + 'placeholder' => '11-22-33-44-55-66', ], 'firstseen' => [ 'op' => self::OP_ORDINAL, 'type' => 'date', - 'column' => true, + 'placeholder' => '2020-10-15', ], 'lastseen' => [ 'op' => self::OP_ORDINAL, 'type' => 'date', - 'column' => true, + 'placeholder' => '2020-10-15', ], 'logintime' => [ 'op' => self::OP_ORDINAL, 'type' => 'date', - 'column' => true, + 'placeholder' => '2020-10-15', ], 'lastboot' => [ 'op' => self::OP_ORDINAL, 'type' => 'date', - 'column' => true + 'placeholder' => '2020-10-15', ], 'runtime' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true ], 'realcores' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true, ], 'systemmodel' => [ 'op' => self::OP_STRCMP, 'type' => 'string', - 'column' => true, + 'placeholder' => 'PC-365 (IBM)', ], 'cpumodel' => [ 'op' => self::OP_STRCMP, 'type' => 'string', - 'column' => true, + 'placeholder' => 'Pentium Pro 200', ], 'hddgb' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => false, + 'placeholder' => 'GiB', 'map_sort' => 'id44mb' ], 'gbram' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', 'map_sort' => 'mbram', - 'column' => false, + 'placeholder' => 'GiB', ], 'kvmstate' => [ 'op' => self::OP_NOMINAL, 'type' => 'enum', - 'column' => true, 'values' => ['ENABLED', 'DISABLED', 'UNSUPPORTED'] ], 'badsectors' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true - ], - 'clientip' => [ - 'op' => self::OP_NOMINAL, - 'type' => 'string', - 'column' => true - ], - 'hostname' => [ - 'op' => self::OP_STRCMP, - 'type' => 'string', - 'column' => true ], 'subnet' => [ 'op' => self::OP_NOMINAL, 'type' => 'string', - 'column' => false ], 'currentuser' => [ 'op' => self::OP_NOMINAL, 'type' => 'string', - 'column' => true + 'placeholder' => 'login', ], 'state' => [ 'op' => self::OP_NOMINAL, 'type' => 'enum', - 'column' => true, 'values' => ['occupied', 'on', 'off', 'idle', 'standby'] ], 'live_swapfree' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true + 'placeholder' => 'MiB', ], 'live_memfree' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true + 'placeholder' => 'MiB', ], 'live_tmpfree' => [ 'op' => self::OP_ORDINAL, 'type' => 'int', - 'column' => true + 'placeholder' => 'MiB', ], ]; if (Module::isAvailable('locations')) { self::$columns['location'] = [ 'op' => self::OP_STRCMP, 'type' => 'enum', - 'column' => false, - 'values' => array_keys(Location::getLocationsAssoc()), + 'show' => true, + // values filled on render NOCOMMIT ]; } } @@ -534,4 +566,4 @@ class IsClientStatisticsFilter extends StatisticsFilter } -StatisticsFilter::initConstants(); \ No newline at end of file +StatisticsFilter::initConstants(); diff --git a/modules-available/statistics/lang/de/filters.json b/modules-available/statistics/lang/de/filters.json new file mode 100644 index 00000000..3fe97532 --- /dev/null +++ b/modules-available/statistics/lang/de/filters.json @@ -0,0 +1,24 @@ +{ + "badsectors": "Defekte Sektoren", + "clientip": "IP-Adresse", + "cpumodel": "CPU-Modell", + "currentuser": "Aktueller\/Letzter Benutzer", + "firstseen": "Erster Boot", + "gbram": "RAM (GB)", + "hddgb": "ID44 (GB)", + "hostname": "Hostname", + "kvmstate": "Virtualisierung", + "lastboot": "Letzter Boot", + "lastseen": "Letzte Aktivit\u00e4t", + "live_memfree": "RAM frei (MB)", + "live_swapfree": "swap frei (MB)", + "live_tmpfree": "ID44 frei (MB)", + "location": "Raum\/Ort", + "logintime": "Letzter Login", + "macaddr": "MAC-Adresse", + "machineuuid": "System-UUID", + "realcores": "CPU-Kerne (real)", + "runtime": "Laufzeit (Stunden)", + "state": "Zustand", + "systemmodel": "System-Modell" +} \ No newline at end of file diff --git a/modules-available/statistics/lang/de/template-tags.json b/modules-available/statistics/lang/de/template-tags.json index f48518ab..1916abfa 100644 --- a/modules-available/statistics/lang/de/template-tags.json +++ b/modules-available/statistics/lang/de/template-tags.json @@ -1,8 +1,7 @@ { "lang_64bitSupport": "64\u2009Bit Gast-Support", - "lang_add": "Hinzuf\u00fcgen", - "lang_add_filter": "Filter hinzuf\u00fcgen", "lang_address": "Adresse", + "lang_apply": "Anwenden", "lang_biosDate": "Ver\u00f6ffentlichungsdatum", "lang_biosFixes": "BIOS-Fehlerkorrekturen", "lang_biosUpdate": "BIOS Update", @@ -13,7 +12,6 @@ "lang_cores": "Kerne", "lang_cpuCores": "CPU-Kerne", "lang_cpuModel": "CPU", - "lang_currentUser": "Aktueller\/Letzter Benutzer", "lang_details": "Details", "lang_devices": "Ger\u00e4te", "lang_duration": "Dauer", @@ -34,7 +32,6 @@ "lang_kvmSupport": "64\u2009Bit G\u00e4ste", "lang_labelFilter": "Aktive Filter (UND-Logik)", "lang_lastBoot": "Letzter Boot", - "lang_lastLogin": "Letzer Login", "lang_lastSeen": "Zuletzt gesehen", "lang_listDropdown": "Als Text", "lang_location": "Ort", @@ -50,10 +47,8 @@ "lang_machineSummary": "Zusammenfassung", "lang_maximumAbbrev": "Max.", "lang_mediaIntegrityErrors": "\"Media Integrity Errors\"", - "lang_memFree": "RAM frei (MB)", "lang_memoryStats": "Arbeitsspeicher", "lang_mobomodel": "Mainboard", - "lang_model": "Modell", "lang_modelCount": "Anzahl", "lang_modelName": "Modellname", "lang_modelNo": "Modell", @@ -93,7 +88,6 @@ "lang_roomplan": "Raumplan", "lang_runMode": "Betriebsmodus", "lang_runmodeMachines": "Mit besonderem Betriebsmodus", - "lang_runtimeHours": "Laufzeit (Stunden)", "lang_screens": "Bildschirme", "lang_serialNo": "Serien-Nr", "lang_showList": "Liste", @@ -101,16 +95,13 @@ "lang_shutdown": "Herunterfahren", "lang_shutdownConfirm": "Ausgew\u00e4hlte Rechner wirklich herunterfahren?", "lang_sockets": "Sockel", - "lang_subnet": "Subnetz", "lang_sureDeletePermanent": "M\u00f6chten Sie diese(n) Rechner wirklich unwiderruflich aus der Datenbank entfernen?\r\n\r\nWichtig: L\u00f6schen verhindert nicht, dass ein Rechner nach erneutem Starten von bwLehrpool wieder in die Datenbank aufgenommen wird.", "lang_sureReplaceNoUndo": "Wollen Sie die Daten der ausgew\u00e4hlten Rechner \u00fcbertragen? Diese Aktion kann nicht r\u00fcckg\u00e4ngig gemacht werden.", "lang_swap": "Swap", - "lang_swapFree": "swap frei (MB)", "lang_tempPart": "Temp. Partition", "lang_tempPartStats": "Tempor\u00e4re Partition", "lang_thoseAreProjectors": "Diese Modellnamen werden als Beamer behandelt, auch wenn die EDID-Informationen des Ger\u00e4tes anderes berichten.", "lang_timebarDesc": "Visuelle Darstellung der letzten Tage. Rote Abschnitte zeigen, wann der Rechner belegt war, gr\u00fcne, wann er nicht verwendet wurde, aber eingeschaltet war. Die leicht abgedunkelten Abschnitte markieren N\u00e4chte (22 bis 8 Uhr).", - "lang_tmpFree": "ID44 frei (MB)", "lang_tmpGb": "Temp-HDD", "lang_total": "Gesamt", "lang_usageDetails": "Nutzungsdetails", diff --git a/modules-available/statistics/lang/en/filters.json b/modules-available/statistics/lang/en/filters.json new file mode 100644 index 00000000..bd262d32 --- /dev/null +++ b/modules-available/statistics/lang/en/filters.json @@ -0,0 +1,24 @@ +{ + "badsectors": "Bad sectors", + "clientip": "IP address", + "cpumodel": "CPU model", + "currentuser": "Current\/last user", + "firstseen": "First boot", + "gbram": "RAM (GB)", + "hddgb": "ID44 (GB)", + "hostname": "Host name", + "kvmstate": "Virtualization", + "lastboot": "Last boot", + "lastseen": "Last activity", + "live_memfree": "RAM free (MB)", + "live_swapfree": "swap free (MB)", + "live_tmpfree": "ID44 free (MB)", + "location": "Room\/Location", + "logintime": "Last login", + "macaddr": "MAC address", + "machineuuid": "System UUID", + "realcores": "CPU cores (real)", + "runtime": "Uptime (hours)", + "state": "State", + "systemmodel": "System model" +} \ No newline at end of file diff --git a/modules-available/statistics/lang/en/template-tags.json b/modules-available/statistics/lang/en/template-tags.json index a3260727..fca82b83 100644 --- a/modules-available/statistics/lang/en/template-tags.json +++ b/modules-available/statistics/lang/en/template-tags.json @@ -1,8 +1,7 @@ { "lang_64bitSupport": "64\u2009Bit guest support", - "lang_add": "Add", - "lang_add_filter": "Add Filter", "lang_address": "Address", + "lang_apply": "Apply", "lang_biosDate": "Release date", "lang_biosFixes": "BIOS fixes", "lang_biosUpdate": "BIOS update", @@ -13,7 +12,6 @@ "lang_cores": "Cores", "lang_cpuCores": "CPU cores", "lang_cpuModel": "CPU", - "lang_currentUser": "Current\/last user", "lang_details": "Details", "lang_devices": "Devices", "lang_duration": "Duration", @@ -34,7 +32,6 @@ "lang_kvmSupport": "64\u2009Bit guests", "lang_labelFilter": "Active filters (AND logic)", "lang_lastBoot": "Last boot", - "lang_lastLogin": "Last login", "lang_lastSeen": "Last seen", "lang_listDropdown": "As text", "lang_location": "Location", @@ -50,10 +47,8 @@ "lang_machineSummary": "Summary", "lang_maximumAbbrev": "max.", "lang_mediaIntegrityErrors": "Media Integrity Errors", - "lang_memFree": "RAM free (MB)", "lang_memoryStats": "Memory", "lang_mobomodel": "Mainboard", - "lang_model": "Model", "lang_modelCount": "Count", "lang_modelName": "Model name", "lang_modelNo": "Model", @@ -93,7 +88,6 @@ "lang_roomplan": "Location", "lang_runMode": "Mode of operation", "lang_runmodeMachines": "With special mode of operation", - "lang_runtimeHours": "Runtime (hours)", "lang_screens": "Screens", "lang_serialNo": "Serial no", "lang_showList": "List", @@ -101,16 +95,13 @@ "lang_shutdown": "Shutdown", "lang_shutdownConfirm": "Shutdown selected machines?", "lang_sockets": "Sockets", - "lang_subnet": "Subnet", "lang_sureDeletePermanent": "Are your sure you want to delete the selected machine(s) from the database? This cannot be undone.\r\n\r\nNote: Deleting machines from the database does not prevent booting up bwLehrpool again, which would recreate their respective database entries.", "lang_sureReplaceNoUndo": "Are you sure you want to replace the selected machine pairs? This action cannot be undone.", "lang_swap": "swap", - "lang_swapFree": "swap free (MB)", "lang_tempPart": "Temp. partition", "lang_tempPartStats": "Temporary partition", "lang_thoseAreProjectors": "These model names will always be treated as beamers, even if the device's EDID data says otherwise.", "lang_timebarDesc": "Visual representation of the last few days. Red parts mark periods where the client was occupied, green parts where the client was idle. Dimmed parts mark nights (10pm to 8am).", - "lang_tmpFree": "ID44 free (MB)", "lang_tmpGb": "Temp HDD", "lang_total": "Total", "lang_usageDetails": "Detailed usage", diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php index 533a9bf9..deba6681 100644 --- a/modules-available/statistics/page.inc.php +++ b/modules-available/statistics/page.inc.php @@ -19,6 +19,7 @@ class Page_Statistics extends Page } if (Request::isGet()) { + $this->transformLegacyQuery(); $this->show = Request::any('show', false, 'string'); if ($this->show === false) { if (Request::get('uuid') !== false) { @@ -85,6 +86,27 @@ class Page_Statistics extends Page Util::redirect('?do=statistics'); } + private function transformLegacyQuery() + { + if (!Request::isGet()) + return; + $query = Request::get('filters', false, 'string'); + if ($query === false) + return; + foreach (explode(StatisticsFilter::LEGACY_DELIMITER, $query) as $q) { + if (!preg_match('/^\s*(\w+)\s*([<>=!~]{1,2})\s*(.*?)\s*$/', $q, $out)) + continue; + $key = $out[1]; + $_GET['filter'][$key] = '1'; + $_GET['op'][$key] = $out[2]; + $_GET['arg'][$key] = $out[3]; + } + unset($_GET['filters']); + if (!empty($_GET['filter'])) { + Util::redirect('?' . http_build_query($_GET)); + } + } + private function wol() { if (!Module::isAvailable('rebootcontrol')) @@ -201,7 +223,7 @@ class Page_Statistics extends Page $sortColumn = Request::any('sortColumn'); $sortDirection = Request::any('sortDirection'); - $filters = StatisticsFilter::parseQuery(StatisticsFilter::getQuery()); + $filters = StatisticsFilter::parseQuery(); $filterSet = new StatisticsFilterSet($filters); $filterSet->setSort($sortColumn, $sortDirection); diff --git a/modules-available/statistics/pages/list.inc.php b/modules-available/statistics/pages/list.inc.php index 4df60044..a709ab3d 100644 --- a/modules-available/statistics/pages/list.inc.php +++ b/modules-available/statistics/pages/list.inc.php @@ -13,7 +13,7 @@ class SubPage $sortColumn = Request::any('sortColumn'); $sortDirection = Request::any('sortDirection'); - $filters = StatisticsFilter::parseQuery(StatisticsFilter::getQuery()); + $filters = StatisticsFilter::parseQuery(); $filterSet = new StatisticsFilterSet($filters); $filterSet->setSort($sortColumn, $sortDirection); @@ -21,9 +21,7 @@ class SubPage Message::addError('main.no-permission'); Util::redirect('?do=main'); } - Render::openTag('div', array('class' => 'row')); - StatisticsFilter::renderFilterBox('list', $filterSet, StatisticsFilter::getQuery()); - Render::closeTag('div'); + StatisticsFilter::renderFilterBox('list', $filterSet); self::showMachineList($filterSet); } @@ -119,11 +117,6 @@ class SubPage $data = array( 'rowCount' => count($rows), 'rows' => $rows, - 'query' => StatisticsFilter::getQuery(), - 'delimiter' => StatisticsFilter::DELIMITER, - 'sortDirection' => $filterSet->getSortDirection(), - 'sortColumn' => $filterSet->getSortColumn(), - 'columns' => json_encode(StatisticsFilter::$columns), 'showList' => 1, 'show' => 'list', 'redirect' => $_SERVER['QUERY_STRING'], diff --git a/modules-available/statistics/pages/summary.inc.php b/modules-available/statistics/pages/summary.inc.php index bf150f3e..c2e3ac80 100644 --- a/modules-available/statistics/pages/summary.inc.php +++ b/modules-available/statistics/pages/summary.inc.php @@ -15,7 +15,7 @@ class SubPage $sortColumn = Request::any('sortColumn'); $sortDirection = Request::any('sortDirection'); - $filters = StatisticsFilter::parseQuery(StatisticsFilter::getQuery()); + $filters = StatisticsFilter::parseQuery(); $filterSet = new StatisticsFilterSet($filters); $filterSet->setSort($sortColumn, $sortDirection); @@ -31,8 +31,8 @@ class SubPage } $filterSet->filterNonClients(); + StatisticsFilter::renderFilterBox('summary', $filterSet); Render::openTag('div', array('class' => 'row')); - StatisticsFilter::renderFilterBox('summary', $filterSet, StatisticsFilter::getQuery()); self::showSummary($filterSet); self::showMemory($filterSet); self::showId44($filterSet); @@ -87,7 +87,6 @@ class SubPage } } $data['json'] = json_encode(array('labels' => $labels, 'datasets' => array($points1, $points2))); - $data['query'] = StatisticsFilter::getQuery(); if (Module::get('runmode') !== false) { $res = Database::queryFirst('SELECT Count(*) AS cnt FROM runmode'); $data['runmode'] = $res['cnt']; @@ -123,7 +122,7 @@ class SubPage ++$id; } self::capChart($json, $lines, 0.92); - Render::addTemplate('cpumodels', array('rows' => $lines, 'query' => StatisticsFilter::getQuery(), 'json' => json_encode($json))); + Render::addTemplate('cpumodels', array('rows' => $lines, 'json' => json_encode($json))); } /** @@ -167,7 +166,6 @@ class SubPage } self::capChart($json, $data['rows'], 0.92); $data['json'] = json_encode($json); - $data['query'] = StatisticsFilter::getQuery(); Render::addTemplate('memory', $data); } @@ -189,7 +187,7 @@ class SubPage 'value' => $row['count'], ); } - Render::addTemplate('kvmstate', array('rows' => $lines, 'query' => StatisticsFilter::getQuery(),'json' => json_encode($json))); + Render::addTemplate('kvmstate', array('rows' => $lines, 'json' => json_encode($json))); } /** @@ -239,7 +237,6 @@ class SubPage } self::capChart($json, $data['rows'], 0.95); $data['json'] = json_encode($json); - $data['query'] = StatisticsFilter::getQuery(); Render::addTemplate('id44', $data); } @@ -313,4 +310,4 @@ class SubPage } } -} \ No newline at end of file +} diff --git a/modules-available/statistics/style.css b/modules-available/statistics/style.css index 000cefaf..7e1539ec 100644 --- a/modules-available/statistics/style.css +++ b/modules-available/statistics/style.css @@ -63,4 +63,33 @@ .open > .dropdown-menu { min-width: inherit; -} \ No newline at end of file +} + +.filter-list .filter-row { + margin-bottom: 2px; +} + +.filter-list input, .filter-list select { + padding: 3px 7px; +} + +@media(min-width: 992px) { + .filter-list { + column-count:2; + column-gap:20px; + column-rule: 1px solid #eee; + } +} + +.slx-focus { + animation-name: slxFocus; + animation-duration: .3s; + animation-iteration-count: 2; + animation-timing-function: ease; +} + +@keyframes slxFocus { + 0% { background: unset } + 50% { background: #f2dede } + 100% { background: unset } +} diff --git a/modules-available/statistics/templates/cpumodels.html b/modules-available/statistics/templates/cpumodels.html index d89a5b2f..2e36a287 100644 --- a/modules-available/statistics/templates/cpumodels.html +++ b/modules-available/statistics/templates/cpumodels.html @@ -19,11 +19,11 @@
- {{systemmodel}} + {{systemmodel}}
- {{cores}} + {{cores}} {{count}} diff --git a/modules-available/statistics/templates/filterbox.html b/modules-available/statistics/templates/filterbox.html index f71c918d..34f4d3a6 100644 --- a/modules-available/statistics/templates/filterbox.html +++ b/modules-available/statistics/templates/filterbox.html @@ -1,201 +1,104 @@ -