From 0a7a8d377e95ae1cecd58d3264ac0cbfa5a14f40 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 13:34:14 +0200 Subject: [PATCH 01/34] Remove unnecessary import in the PivotTable refs #9333 --- library/Icinga/Data/PivotTable.php | 1 - 1 file changed, 1 deletion(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index cf703ae9c..29fbca75c 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -4,7 +4,6 @@ namespace Icinga\Data; use Icinga\Data\Filter\Filter; -use Icinga\Data\SimpleQuery; use Icinga\Application\Icinga; use Icinga\Web\Paginator\Adapter\QueryAdapter; use Zend_Paginator; From d0f288736723735806ea39fa5a9ff8bc5677bd44 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 13:35:50 +0200 Subject: [PATCH 02/34] Fix PHPDoc indents in the PivotTable refs #9333 --- library/Icinga/Data/PivotTable.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index 29fbca75c..2966c94ad 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -62,7 +62,7 @@ class PivotTable /** * Create a new pivot table * - * @param SimpleQuery $query The query to fetch as pivot table + * @param SimpleQuery $query The query to fetch as pivot table * @param string $xAxisColumn The column that contains the labels for the x axis * @param string $yAxisColumn The column that contains the labels for the y axis */ @@ -106,7 +106,7 @@ class PivotTable * @param string $param The parameter name to return * @param int $default The default value to return * - * @return int + * @return int */ protected function getPaginationParameter($axis, $param, $default = null) { @@ -124,7 +124,7 @@ class PivotTable /** * Query horizontal (x) axis * - * @return SimpleQuery + * @return SimpleQuery */ protected function queryXAxis() { @@ -149,7 +149,7 @@ class PivotTable /** * Query vertical (y) axis * - * @return SimpleQuery + * @return SimpleQuery */ protected function queryYAxis() { @@ -236,7 +236,7 @@ class PivotTable /** * Return the pivot table as array * - * @return array + * @return array */ public function toArray() { From d1f9c5ff0d93593e220e14077c801392567b747a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 13:42:06 +0200 Subject: [PATCH 03/34] Don't call setUseSubqueryCount() in the PivotTable The query implementation handles this automatically. refs #9333 --- library/Icinga/Data/PivotTable.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index 2966c94ad..3a2941bfb 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -132,7 +132,6 @@ class PivotTable $this->xAxisQuery = clone $this->baseQuery; $this->xAxisQuery->group($this->xAxisColumn); $this->xAxisQuery->columns(array($this->xAxisColumn)); - $this->xAxisQuery->setUseSubqueryCount(); if ($this->xAxisFilter !== null) { $this->xAxisQuery->addFilter($this->xAxisFilter); @@ -157,7 +156,6 @@ class PivotTable $this->yAxisQuery = clone $this->baseQuery; $this->yAxisQuery->group($this->yAxisColumn); $this->yAxisQuery->columns(array($this->yAxisColumn)); - $this->yAxisQuery->setUseSubqueryCount(); if ($this->yAxisFilter !== null) { $this->yAxisQuery->addFilter($this->yAxisFilter); From f2f1e12b8ea615651939ce2e8f98834556a01e41 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 14:17:07 +0200 Subject: [PATCH 04/34] Let PivotTable implement Sortable refs #9333 --- library/Icinga/Data/PivotTable.php | 76 +++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index 3a2941bfb..b3b8c7a79 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -8,7 +8,7 @@ use Icinga\Application\Icinga; use Icinga\Web\Paginator\Adapter\QueryAdapter; use Zend_Paginator; -class PivotTable +class PivotTable implements Sortable { /** * The query to fetch as pivot table @@ -17,20 +17,6 @@ class PivotTable */ protected $baseQuery; - /** - * The query to fetch the x axis labels - * - * @var SimpleQuery - */ - protected $xAxisQuery; - - /** - * The query to fetch the y axis labels - * - * @var SimpleQuery - */ - protected $yAxisQuery; - /** * The column that contains the labels for the x axis * @@ -59,6 +45,27 @@ class PivotTable */ protected $yAxisFilter; + /** + * The query to fetch the x axis labels + * + * @var SimpleQuery + */ + protected $xAxisQuery; + + /** + * The query to fetch the y axis labels + * + * @var SimpleQuery + */ + protected $yAxisQuery; + + /** + * Column for sorting the result set + * + * @var array + */ + protected $order = array(); + /** * Create a new pivot table * @@ -73,6 +80,31 @@ class PivotTable $this->yAxisColumn = $yAxisColumn; } + /** + * {@inheritdoc} + */ + public function getOrder() + { + return $this->order; + } + + /** + * {@inheritdoc} + */ + public function hasOrder() + { + return ! empty($this->order); + } + + /** + * {@inheritdoc} + */ + public function order($field, $direction = null) + { + $this->order[$field] = $direction; + return $this; + } + /** * Set the filter to apply on the query for the x axis * @@ -137,9 +169,10 @@ class PivotTable $this->xAxisQuery->addFilter($this->xAxisFilter); } - if (! $this->xAxisQuery->hasOrder($this->xAxisColumn)) { - $this->xAxisQuery->order($this->xAxisColumn, 'asc'); - } + $this->xAxisQuery->order( + $this->xAxisColumn, + isset($this->order[$this->xAxisColumn]) ? $this->order[$this->xAxisColumn] : self::SORT_ASC + ); } return $this->xAxisQuery; @@ -161,9 +194,10 @@ class PivotTable $this->yAxisQuery->addFilter($this->yAxisFilter); } - if (! $this->yAxisQuery->hasOrder($this->yAxisColumn)) { - $this->yAxisQuery->order($this->yAxisColumn, 'asc'); - } + $this->yAxisQuery->order( + $this->yAxisColumn, + isset($this->order[$this->yAxisColumn]) ? $this->order[$this->yAxisColumn] : self::SORT_ASC + ); } return $this->yAxisQuery; From 1492218962ee85af4e921398bf5f205e1fb18989 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 14:18:48 +0200 Subject: [PATCH 05/34] Fix SortBox not usable w/o SortRules The SortBox assumes the first avaiable sort column as default column if the given Sortable does not implement the SortRules interface. When changing the direction of the default sort column, the sort box did not pass the column to Sortable::sort(). Thus the Sortable did not know by which column to sort. Now the SortBox passes the sort column even if the direction of the default column is changed. refs #9333 --- library/Icinga/Web/Widget/SortBox.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/Icinga/Web/Widget/SortBox.php b/library/Icinga/Web/Widget/SortBox.php index c9d38f2b7..862dad22c 100644 --- a/library/Icinga/Web/Widget/SortBox.php +++ b/library/Icinga/Web/Widget/SortBox.php @@ -118,12 +118,12 @@ class SortBox extends AbstractWidget if ($request === null) { $request = Icinga::app()->getRequest(); } - - if (($sort = $request->getParam('sort'))) { - $this->query->order($sort, $request->getParam('dir')); - } elseif (($dir = $request->getParam('dir'))) { - $this->query->order(null, $dir); + if (null === $sort = $request->getParam('sort')) { + list($sort, $dir) = $this->getSortDefaults(); + } else { + list($_, $dir) = $this->getSortDefaults($sort); } + $this->query->order($sort, $request->getParam('dir', $dir)); } return $this; @@ -148,8 +148,10 @@ class SortBox extends AbstractWidget if ($column !== null && isset($sortRules[$column]['order'])) { $direction = strtoupper($sortRules[$column]['order']) === Sortable::SORT_DESC ? 'desc' : 'asc'; } + } elseif ($column === null) { + reset($this->sortFields); + $column = key($this->sortFields); } - return array($column, $direction); } From d449ff661ed64f589fefdeb4cb1db679c0c5eb07 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 14:23:12 +0200 Subject: [PATCH 06/34] monitoring/service grid: Set up the sort control for the pivot table instead of the service status query refs #9333 --- .../monitoring/application/controllers/ListController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index d26cc0c52..364e5957b 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -591,16 +591,16 @@ class Monitoring_ListController extends Controller )); $this->filterQuery($query); $this->applyRestriction('monitoring/filter/objects', $query); - $this->setupSortControl(array( - 'host_name' => $this->translate('Hostname'), - 'service_description' => $this->translate('Service description') - ), $query); $pivot = $query->pivot( 'service_description', 'host_name', $problems ? Filter::where('service_problem', 1) : null, $problems ? Filter::where('service_problem', 1) : null ); + $this->setupSortControl(array( + 'host_name' => $this->translate('Hostname'), + 'service_description' => $this->translate('Service description') + ), $pivot); $this->view->pivot = $pivot; $this->view->horizontalPaginator = $pivot->paginateXAxis(); $this->view->verticalPaginator = $pivot->paginateYAxis(); From f5ffa8047c97023b2b53b8404957c9ff1306ba85 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 16:36:00 +0200 Subject: [PATCH 07/34] monitoring: Fix handling of collated columns w/ PostgreSQL fixes #9954 fxies #9955 --- .../Monitoring/Backend/Ido/Query/IdoQuery.php | 81 ++++++------------- 1 file changed, 25 insertions(+), 56 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php index 85d9169a9..da2815e98 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php @@ -461,17 +461,24 @@ abstract class IdoQuery extends DbQuery if ($filter->getExpression() === '*') { return; // Wildcard only filters are ignored so stop early here to avoid joining a table for nothing } - - $col = $filter->getColumn(); - $this->requireColumn($col); - - if ($this->isCustomvar($col)) { - $col = $this->getCustomvarColumnName($col); + $alias = $filter->getColumn(); + $this->requireColumn($alias); + if ($this->isCustomvar($alias)) { + $column = $this->getCustomvarColumnName($alias); } else { - $col = $this->aliasToColumnName($col); + $column = $this->aliasToColumnName($alias); } + if (isset($this->columnsWithoutCollation[$alias])) { + // $column = 'LOWER(' . $column . ')'; + $expression = $filter->getExpression(); + if (is_array($expression)) { + $filter->setExpression(array_map('strtolower', $expression)); + } else { + $filter->setExpression(strtolower($expression)); - $filter->setColumn($col); + } + } + $filter->setColumn($column); } else { foreach ($filter->filters() as $filter) { $this->requireFilterColumns($filter); @@ -485,48 +492,11 @@ abstract class IdoQuery extends DbQuery return parent::addFilter($filter); } - /** - * Recurse the given filter and ensure that any string conversion is case-insensitive - * - * @param Filter $filter - */ - protected function lowerColumnsWithoutCollation(Filter $filter) - { - if ($filter instanceof FilterExpression) { - if ( - in_array($filter->getColumn(), $this->columnsWithoutCollation) - && strpos($filter->getColumn(), 'LOWER') !== 0 - ) { - $filter->setColumn('LOWER(' . $filter->getColumn() . ')'); - $expression = $filter->getExpression(); - if (is_array($expression)) { - $filter->setExpression(array_map('strtolower', $expression)); - } else { - $filter->setExpression(strtolower($expression)); - } - } - } else { - foreach ($filter->filters() as $chainedFilter) { - $this->lowerColumnsWithoutCollation($chainedFilter); - } - } - } - - protected function applyFilterSql($select) - { - if (! empty($this->columnsWithoutCollation)) { - $this->lowerColumnsWithoutCollation($this->filter); - } - - parent::applyFilterSql($select); - } - public function where($condition, $value = null) { if ($value === '*') { return $this; // Wildcard only filters are ignored so stop early here to avoid joining a table for nothing } - $this->requireColumn($condition); $col = $this->getMappedField($condition); if ($col === null) { @@ -574,7 +544,6 @@ abstract class IdoQuery extends DbQuery if (! empty($this->columnsWithoutCollation)) { return in_array($column, $this->columnsWithoutCollation) || strpos($column, 'LOWER') !== 0; } - return preg_match('/ COLLATE .+$/', $column) === 1; } @@ -599,27 +568,27 @@ abstract class IdoQuery extends DbQuery } /** - * Apply postgresql specific query initialization + * Apply PostgreSQL specific query initialization */ private function initializeForPostgres() { $this->customVarsJoinTemplate = '%1$s = %2$s.object_id AND LOWER(%2$s.varname) = %3$s'; - foreach ($this->columnMap as $table => & $columns) { - foreach ($columns as $key => & $value) { - $value = preg_replace('/ COLLATE .+$/', '', $value, -1, $count); - if ($count > 0) { - $this->columnsWithoutCollation[] = $this->getMappedField($key); + foreach ($this->columnMap as $table => &$columns) { + foreach ($columns as $alias => &$column) { + if (false !== $pos = strpos($column, ' COLLATE')) { + $column = 'LOWER(' . substr($column, 0, $pos) . ')'; + $this->columnsWithoutCollation[$alias] = true; } - $value = preg_replace( + $column = preg_replace( '/inet_aton\(([[:word:].]+)\)/i', '(CASE WHEN $1 ~ \'(?:[0-9]{1,3}\\\\.){3}[0-9]{1,3}\' THEN $1::inet - \'0.0.0.0\' ELSE NULL END)', - $value + $column ); - $value = preg_replace( + $column = preg_replace( '/UNIX_TIMESTAMP(\((?>[^()]|(?-1))*\))/i', 'CASE WHEN ($1 < \'1970-01-03 00:00:00+00\'::timestamp with time zone) THEN 0 ELSE UNIX_TIMESTAMP($1) END', - $value + $column ); } } From 18f720d31fc4fdce96a58d8726e8aadafc8eced9 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 18 Aug 2015 16:37:14 +0200 Subject: [PATCH 08/34] monitoring: Eliminate unncessary GROUP BY clauses in the ServicestatusQuery refs #9956 --- .../Backend/Ido/Query/ServicestatusQuery.php | 112 ++++++++---------- 1 file changed, 52 insertions(+), 60 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php index ce988e944..7e716ee1b 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php @@ -366,68 +366,60 @@ class ServicestatusQuery extends IdoQuery if (! is_array($group)) { $group = array($group); } - - if ($this->hasJoinedVirtualTable('hostgroups') || $this->hasJoinedVirtualTable('servicegroups')) { - $group[] = 's.service_id'; - $group[] = 'so.object_id'; - - if ($this->hasJoinedVirtualTable('hosts')) { - $group[] = 'h.host_id'; - } - - if ($this->hasJoinedVirtualTable('hoststatus')) { - $group[] = 'hs.hoststatus_id'; - } - - if ($this->hasJoinedVirtualTable('servicestatus')) { - $group[] = 'ss.servicestatus_id'; - } - - if ($this->hasJoinedVirtualTable('hostgroups')) { - $selected = false; - foreach ($this->columns as $alias => $column) { - if ($column instanceof Zend_Db_Expr) { - continue; - } - - $table = $this->aliasToTableName( - $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) - ); - if ($table === 'hostgroups') { - $selected = true; - break; - } - } - - if ($selected) { - $group[] = 'hg.hostgroup_id'; - $group[] = 'hgo.object_id'; - } - } - - if ($this->hasJoinedVirtualTable('servicegroups')) { - $selected = false; - foreach ($this->columns as $alias => $column) { - if ($column instanceof Zend_Db_Expr) { - continue; - } - - $table = $this->aliasToTableName( - $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) - ); - if ($table === 'servicegroups') { - $selected = true; - break; - } - } - - if ($selected) { - $group[] = 'sg.servicegroup_id'; - $group[] = 'sgo.object_id'; - } + $groupedTables = array(); + if ($this->hasJoinedVirtualTable('servicegroups')) { + $serviceGroupColumns = array_keys($this->columnMap['servicegroups']); + $selectedServiceGroupColumns = array_intersect($serviceGroupColumns, array_keys($this->columns)); + if (! empty($selectedServiceGroupColumns)) { + $group[] = 'so.object_id'; + $group[] = 's.service_id'; + $group[] = 'sgo.object_id'; + $groupedTables['services'] = true; + $groupedTables['servicegroups'] = true; + } + } + if ($this->hasJoinedVirtualTable('hostgroups')) { + $hostGroupColumns = array_keys($this->columnMap['hostgroups']); + $selectedHostGroupColumns = array_intersect($hostGroupColumns, array_keys($this->columns)); + if (! empty($selectedHostGroupColumns)) { + if (! isset($groupedTables['services'])) { + $group[] = 'so.object_id'; + $group[] = 's.service_id'; + $groupedTables['services'] = true; + } + $group[] = 'hgo.object_id'; + $groupedTables['hostgroups'] = true; + } + } + if (! empty($groupedTables)) { + foreach ($this->columns as $alias => $column) { + if ($column instanceof Zend_Db_Expr || $column === '(NULL)') { + continue; + } + $tableName = $this->aliasToTableName( + $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) + ); + if (isset($groupedTables[$tableName])) { + continue; + } + switch ($tableName) { + case 'hosts': + $groupColumn = 'h.host_id'; + break; + case 'hoststatus': + $groupColumn = 'hs.hoststatus_id'; + break; + case 'servicestatus': + $groupColumn = 'ss.servicestatus_id'; + break; + default: + continue 2; + } + /** @var string $groupColumn */ + $group[] = $groupColumn; + $groupedTables[$tableName] = true; } } - return $group; } } From 6e12dd4d782d578ae3007767a83a2ee868454d6a Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Aug 2015 11:39:51 +0200 Subject: [PATCH 09/34] monitoring: Fix service status grouping when selecting group alias columns refs #9956 --- .../Backend/Ido/Query/ServicestatusQuery.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php index 7e716ee1b..a135d8b41 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/ServicestatusQuery.php @@ -374,6 +374,7 @@ class ServicestatusQuery extends IdoQuery $group[] = 'so.object_id'; $group[] = 's.service_id'; $group[] = 'sgo.object_id'; + $group[] = 'sg.servicegroup_id'; $groupedTables['services'] = true; $groupedTables['servicegroups'] = true; } @@ -388,6 +389,7 @@ class ServicestatusQuery extends IdoQuery $groupedTables['services'] = true; } $group[] = 'hgo.object_id'; + $group[] = 'hg.hostgroup_id'; $groupedTables['hostgroups'] = true; } } @@ -404,19 +406,17 @@ class ServicestatusQuery extends IdoQuery } switch ($tableName) { case 'hosts': - $groupColumn = 'h.host_id'; + $group[] = 'h.host_id'; break; case 'hoststatus': - $groupColumn = 'hs.hoststatus_id'; + $group[] = 'hs.hoststatus_id'; break; case 'servicestatus': - $groupColumn = 'ss.servicestatus_id'; + $group[] = 'ss.servicestatus_id'; break; default: continue 2; } - /** @var string $groupColumn */ - $group[] = $groupColumn; $groupedTables[$tableName] = true; } } From 4ab20b91427ccc19a102819bc515ee2536d83e55 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Aug 2015 11:40:37 +0200 Subject: [PATCH 10/34] monitoring: Eliminate unncessary GROUP BY clauses in the HoststatusQuery refs #9956 --- .../Backend/Ido/Query/HoststatusQuery.php | 111 +++++++++--------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/HoststatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/HoststatusQuery.php index 968d5607e..4169bc1b1 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/HoststatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/HoststatusQuery.php @@ -242,62 +242,65 @@ class HoststatusQuery extends IdoQuery */ public function getGroup() { - $group = array(); - if ($this->hasJoinedVirtualTable('hostgroups') || $this->hasJoinedVirtualTable('services')) { - $group = array('h.host_id', 'ho.object_id'); - if ($this->hasJoinedVirtualTable('hoststatus')) { - $group[] = 'hs.hoststatus_id'; - } - - if ($this->hasJoinedVirtualTable('serviceproblemsummary')) { - $group[] = 'sps.unhandled_services_count'; - } - - if ($this->hasJoinedVirtualTable('hostgroups')) { - $selected = false; - foreach ($this->columns as $alias => $column) { - if ($column instanceof Zend_Db_Expr) { - continue; - } - - $table = $this->aliasToTableName( - $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) - ); - if ($table === 'hostgroups') { - $selected = true; - break; - } - } - - if ($selected) { - $group[] = 'hg.hostgroup_id'; - $group[] = 'hgo.object_id'; - } - } - - if ($this->hasJoinedVirtualTable('servicegroups')) { - $selected = false; - foreach ($this->columns as $alias => $column) { - if ($column instanceof Zend_Db_Expr) { - continue; - } - - $table = $this->aliasToTableName( - $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) - ); - if ($table === 'servicegroups') { - $selected = true; - break; - } - } - - if ($selected) { - $group[] = 'sg.servicegroup_id'; - $group[] = 'sgo.object_id'; - } + $group = parent::getGroup() ?: array(); + if (! is_array($group)) { + $group = array($group); + } + $groupedTables = array(); + if ($this->hasJoinedVirtualTable('servicegroups')) { + $serviceGroupColumns = array_keys($this->columnMap['servicegroups']); + $selectedServiceGroupColumns = array_intersect($serviceGroupColumns, array_keys($this->columns)); + if (! empty($selectedServiceGroupColumns)) { + $group[] = 'ho.object_id'; + $group[] = 'h.host_id'; + $group[] = 'sgo.object_id'; + $group[] = 'sg.servicegroup_id'; + $groupedTables['hosts'] = true; + $groupedTables['servicegroups'] = true; + } + } + if ($this->hasJoinedVirtualTable('hostgroups')) { + $hostGroupColumns = array_keys($this->columnMap['hostgroups']); + $selectedHostGroupColumns = array_intersect($hostGroupColumns, array_keys($this->columns)); + if (! empty($selectedHostGroupColumns)) { + if (! isset($groupedTables['hosts'])) { + $group[] = 'ho.object_id'; + $group[] = 'h.host_id'; + $groupedTables['hosts'] = true; + } + $group[] = 'hgo.object_id'; + $group[] = 'hg.hostgroup_id'; + $groupedTables['hostgroups'] = true; + } + } + if (! empty($groupedTables)) { + foreach ($this->columns as $alias => $column) { + if ($column instanceof Zend_Db_Expr || $column === '(NULL)') { + continue; + } + $tableName = $this->aliasToTableName( + $this->hasAliasName($alias) ? $alias : $this->customAliasToAlias($alias) + ); + if (isset($groupedTables[$tableName])) { + continue; + } + switch ($tableName) { + case 'hoststatus': + $group[] = 'hs.hoststatus_id'; + break; + case 'serviceproblemsummary': + $group[] = 'sps.unhandled_services_count'; + break; + case 'services': + $group[] = 'so.object_id'; + $group[] = 's.service_id'; + break; + default: + continue 2; + } + $groupedTables[$tableName] = true; } } - return $group; } From 0c43e4a36b9ebbebee883e74aab4aaef42a4a384 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Aug 2015 12:41:58 +0200 Subject: [PATCH 11/34] monitoring: Sort by display_names in the service grid refs #9538 --- .../application/controllers/ListController.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index d26cc0c52..113efdcf4 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -581,29 +581,31 @@ class Monitoring_ListController extends Controller { $this->addTitleTab('servicegrid', $this->translate('Service Grid'), $this->translate('Show the Service Grid')); $this->setAutorefreshInterval(15); - $problems = (bool) $this->params->shift('problems', 0); $query = $this->backend->select()->from('servicestatus', array( + 'host_display_name', 'host_name', 'service_description', - 'service_state', + 'service_display_name', + 'service_handled', 'service_output', - 'service_handled' + 'service_state' )); $this->filterQuery($query); $this->applyRestriction('monitoring/filter/objects', $query); $this->setupSortControl(array( - 'host_name' => $this->translate('Hostname'), - 'service_description' => $this->translate('Service description') + 'host_display_name' => $this->translate('Hostname'), + 'service_display_name' => $this->translate('Service Name') ), $query); + $filter = (bool) $this->params->shift('problems', false) ? Filter::where('service_problem', 1) : null; $pivot = $query->pivot( 'service_description', 'host_name', - $problems ? Filter::where('service_problem', 1) : null, - $problems ? Filter::where('service_problem', 1) : null + $filter, + $filter ? clone $filter : null ); $this->view->pivot = $pivot; $this->view->horizontalPaginator = $pivot->paginateXAxis(); - $this->view->verticalPaginator = $pivot->paginateYAxis(); + $this->view->verticalPaginator = $pivot->paginateYAxis(); } /** From 1741a4f10b854f5dc81fdefc23bb98edea026287 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Aug 2015 12:48:28 +0200 Subject: [PATCH 12/34] monitoring: Use display names for the aria-label in the service grid refs #9538 --- .../application/views/scripts/list/servicegrid.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index 73fbfe3b5..c2f52db8b 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -91,8 +91,8 @@ foreach ($serviceDescriptions as $service_description): ?> 'title' => $this->escape($service->service_output), 'aria-label' => sprintf( $this->translate('Show detailed information for service %s on host %s'), - $service->service_description, - $service->host_name + $service->service_display_name, + $service->host_display_name ) ) ); ?> From 5d8f09120906f291c9abe9b2504af4ebd8a33870 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 20 Aug 2015 16:46:31 +0200 Subject: [PATCH 13/34] lib: Don't alias Zend classes in Module --- library/Icinga/Application/Modules/Module.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 9ec35b565..11994c694 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -4,23 +4,23 @@ namespace Icinga\Application\Modules; use Exception; +use Zend_Controller_Router_Route; use Zend_Controller_Router_Route_Abstract; -use Zend_Controller_Router_Route as Route; -use Zend_Controller_Router_Route_Regex as RegexRoute; +use Zend_Controller_Router_Route_Regex; use Icinga\Application\ApplicationBootstrap; use Icinga\Application\Config; use Icinga\Application\Icinga; use Icinga\Application\Logger; use Icinga\Data\ConfigObject; +use Icinga\Exception\IcingaException; +use Icinga\Exception\ProgrammingError; +use Icinga\Module\Setup\SetupWizard; +use Icinga\Util\File; use Icinga\Util\Translator; use Icinga\Web\Hook; use Icinga\Web\Menu; use Icinga\Web\Widget; use Icinga\Web\Widget\Dashboard\Pane; -use Icinga\Module\Setup\SetupWizard; -use Icinga\Util\File; -use Icinga\Exception\ProgrammingError; -use Icinga\Exception\IcingaException; /** * Module handling @@ -1044,7 +1044,7 @@ class Module } $router->addRoute( $this->name . '_jsprovider', - new Route( + new Zend_Controller_Router_Route( 'js/' . $this->name . '/:file', array( 'controller' => 'static', @@ -1055,7 +1055,7 @@ class Module ); $router->addRoute( $this->name . '_img', - new RegexRoute( + new Zend_Controller_Router_Route_Regex( 'img/' . $this->name . '/(.+)', array( 'controller' => 'static', From 800173b19f54ea5a173c428ad81776ec84d40949 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 20 Aug 2015 16:47:17 +0200 Subject: [PATCH 14/34] lib: Fix type hint for $router in Module --- library/Icinga/Application/Modules/Module.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 11994c694..ff88a00ba 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -1039,6 +1039,7 @@ class Module protected function registerRoutes() { $router = $this->app->getFrontController()->getRouter(); + /** @var \Zend_Controller_Router_Rewrite $router */ foreach ($this->routes as $name => $route) { $router->addRoute($name, $route); } From 9aa62c9898acfed014131c3f38477721ea24b3f3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 20 Aug 2015 16:58:24 +0200 Subject: [PATCH 15/34] lib: Fix type hint for $tabs in Module --- library/Icinga/Application/Modules/Module.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index ff88a00ba..270a552bb 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -770,6 +770,7 @@ class Module { $this->launchConfigScript(); $tabs = Widget::create('tabs'); + /** @var \Icinga\Web\Widget\Tabs $tabs */ $tabs->add('info', array( 'url' => 'config/module', 'urlParams' => array('name' => $this->getName()), From 5da139943c4b315d049c073ee1517338433a2b8c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 20 Aug 2015 16:59:02 +0200 Subject: [PATCH 16/34] lib: Fix type hint for $menuItems in Module --- library/Icinga/Application/Modules/Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 270a552bb..7c415e05c 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -188,7 +188,7 @@ class Module /** * A set of menu elements * - * @var array + * @var Menu[] */ protected $menuItems = array(); From d461270bf8b9e1e4a474452f626fdb01ed7de39d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:29:29 +0200 Subject: [PATCH 17/34] monitoring: Rename $host_name to $hostName in the servicegrid view script refs #9538 --- .../application/views/scripts/list/servicegrid.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index c2f52db8b..8f2bc7c78 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -23,7 +23,7 @@ if (count($pivotData) === 0) { $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')'; ?> - $serviceStates): ?> + $serviceStates): ?> @@ -66,10 +66,10 @@ foreach ($serviceDescriptions as $service_description): ?> From 9d40013b21e1b87f672f56f1528bbc9239dff15f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:30:18 +0200 Subject: [PATCH 18/34] monitoring: Rename $service_description to $serviceDescription in the servicegrid view script refs #9538 --- .../application/views/scripts/list/servicegrid.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index 8f2bc7c78..fac48b012 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -41,16 +41,16 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ' $serviceDescriptions = array_keys($serviceStates); $serviceFilter = '(service_description=' . implode('|service_description=', $serviceDescriptions) . ')'; -foreach ($serviceDescriptions as $service_description): ?> +foreach ($serviceDescriptions as $serviceDescription): ?> qlink( - '' . (strlen($service_description) > 18 ? substr($service_description, 0, 18) . '...' : $service_description) . '', + '' . (strlen($serviceDescription) > 18 ? substr($serviceDescription, 0, 18) . '...' : $serviceDescription) . '', 'monitoring/list/services?' . $hostFilter, array( - 'service_description' => $service_description + 'service_description' => $serviceDescription ), array( - 'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $service_description) + 'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $serviceDescription) ), false ); ?> From 1ab8fc0012555826a4bc014f6974e00db22825ca Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:32:33 +0200 Subject: [PATCH 19/34] monitoring: Use View::ellipsis() in the servicegrid view script refs #9538 --- .../monitoring/application/views/scripts/list/servicegrid.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index fac48b012..c94c14278 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -44,7 +44,7 @@ $serviceFilter = '(service_description=' . implode('|service_description=', $ser foreach ($serviceDescriptions as $serviceDescription): ?> qlink( - '' . (strlen($serviceDescription) > 18 ? substr($serviceDescription, 0, 18) . '...' : $serviceDescription) . '', + '' . $this->ellipsis($serviceDescription, 18) . '', 'monitoring/list/services?' . $hostFilter, array( 'service_description' => $serviceDescription From 71b89ea51a7d07c0c3fd6b3929c87919eb0c668b Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:35:03 +0200 Subject: [PATCH 20/34] monitoring: Rename $serviceStates to $services in the servicegrid view script refs #9538 --- .../application/views/scripts/list/servicegrid.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index c94c14278..af63210a8 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -23,7 +23,7 @@ if (count($pivotData) === 0) { $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')'; ?>
qlink( - $host_name, + $hostName, 'monitoring/list/services?' . $serviceFilter, - array('host' => $host_name), - array('title' => sprintf($this->translate('List all reported services on host %s'), $host_name)) + array('host' => $hostName), + array('title' => sprintf($this->translate('List all reported services on host %s'), $hostName)) ); ?>
- $serviceStates): ?> + $services): ?> @@ -35,10 +35,10 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ' 'yAxisPaginator' => $verticalPaginator ) ); ?> - - +
+
@@ -72,7 +72,7 @@ foreach ($serviceDescriptions as $serviceDescription): ?> array('title' => sprintf($this->translate('List all reported services on host %s'), $hostName)) ); ?>
From 5ae541db253b79f7b7ef17af4167b75595020d0b Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:35:30 +0200 Subject: [PATCH 21/34] monitoring: Drop unnecessary call to array_values in the servicegrid view script refs #9538 --- .../monitoring/application/views/scripts/list/servicegrid.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index af63210a8..6e66ae6ae 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -72,7 +72,7 @@ foreach ($serviceDescriptions as $serviceDescription): ?> array('title' => sprintf($this->translate('List all reported services on host %s'), $hostName)) ); ?> - + From b629115ba716e9dff0553b4a8397b9215decf1fa Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 11:37:46 +0200 Subject: [PATCH 22/34] monitoring: Use empty() for is empty check in the servicegrid view script refs #9538 --- .../monitoring/application/views/scripts/list/servicegrid.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index 6e66ae6ae..7136aaa43 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -15,7 +15,7 @@ if (! $this->compact): ?> $hasHeader = false; $pivotData = $this->pivot->toArray(); -if (count($pivotData) === 0) { +if (empty($pivotData)) { echo $this->translate('No services found matching the filter') . ''; return; } From 2760c5816269e9372cc515cc76946de6ac69899c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 16:40:30 +0200 Subject: [PATCH 23/34] css: Add mixins.less --- public/css/icinga/mixins.less | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 public/css/icinga/mixins.less diff --git a/public/css/icinga/mixins.less b/public/css/icinga/mixins.less new file mode 100644 index 000000000..d1f9929a0 --- /dev/null +++ b/public/css/icinga/mixins.less @@ -0,0 +1,9 @@ +/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ + +.transform(@transform) { + -webkit-transform: @transform; + -moz-transform: @transform; + -ms-transform: @transform; + -o-transform: @transform; + transform: @transform; +} From 4c91d4285350af35abe9ca1c0cb0d4606fde177f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 16:44:30 +0200 Subject: [PATCH 24/34] css: add rounded-corners mixin --- public/css/icinga/mixins.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/css/icinga/mixins.less b/public/css/icinga/mixins.less index d1f9929a0..e22b4cd51 100644 --- a/public/css/icinga/mixins.less +++ b/public/css/icinga/mixins.less @@ -7,3 +7,13 @@ -o-transform: @transform; transform: @transform; } + +.rounded-corners(@border-radius: 0.4em) { + -webkit-border-radius: @border-radius; + -moz-border-radius: @border-radius; + border-radius: @border-radius; + + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} From ceaba908723058024cf739593978ce94f7e97ab3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 21 Aug 2015 16:45:05 +0200 Subject: [PATCH 25/34] css: Load mixins.less --- library/Icinga/Web/StyleSheet.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index af807c6e4..f22e66d33 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -12,6 +12,7 @@ class StyleSheet protected static $lessFiles = array( '../application/fonts/fontello-ifont/css/ifont-embedded.css', 'css/vendor/tipsy.css', + 'css/icinga/mixins.less', 'css/icinga/defaults.less', 'css/icinga/animation.less', 'css/icinga/layout-colors.less', From cfad85cce124ad11deff568cf7f61a44807e3ebb Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Mon, 24 Aug 2015 09:23:46 +0200 Subject: [PATCH 26/34] monitoring: Collect display names as table headers for the service grid refs #9538 --- .../controllers/ListController.php | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 113efdcf4..c4c02ce3a 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -603,7 +603,27 @@ class Monitoring_ListController extends Controller $filter, $filter ? clone $filter : null ); - $this->view->pivot = $pivot; + $pivotData = $pivot->toArray(); + // TODO(el): list($pivotData, $pivotHeader) = $pivot->toArray(); + $pivotHeader = array( + 'cols' => array(), + 'rows' => array() + ); + foreach ($pivotData as $hostName => $services) { + foreach ($services as $serviceDescription => $service) { + if ($service === null) { + continue; + } + if (! isset($pivotHeader['rows'][$hostName])) { + $pivotHeader['rows'][$hostName] = $service->host_display_name; + } + if (! isset($pivotHeader['cols'][$serviceDescription])) { + $pivotHeader['cols'][$serviceDescription] = $service->service_display_name; + } + } + } + $this->view->pivotData = $pivotData; + $this->view->pivotHeader = $pivotHeader; $this->view->horizontalPaginator = $pivot->paginateXAxis(); $this->view->verticalPaginator = $pivot->paginateYAxis(); } From cc7eab674662cf728f9c66ba685b0bc30b06b76c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:44:27 +0200 Subject: [PATCH 27/34] monitoring: Remove CSS for the service grid Will be rewritten. refs #9538 --- modules/monitoring/public/css/module.less | 106 ---------------------- 1 file changed, 106 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 3aabe1f51..46c7bc4f6 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -846,112 +846,6 @@ table.joystick-pagination { } } -table.pivot { - a { - text-decoration: none; - color: black; - - &:hover { - color: @colorTextDefault; - } - } - - & > thead { - th { - height: 6em; - - div { - margin-right: -1.5em; - padding-left: 1.3em; - - span { - width: 1.5em; - margin-right: 0.25em; - margin-top: 4em; - line-height: 2em; - white-space: nowrap; - display: block; - float: left; - - transform: rotate(-45deg); - transform-origin: bottom left; - -o-transform: rotate(-45deg); - -o-transform-origin: bottom left; - -ms-transform: rotate(-45deg); - -ms-transform-origin: bottom left; - -moz-transform: rotate(-45deg); - -moz-transform-origin: bottom left; - -webkit-transform: rotate(-45deg); - -webkit-transform-origin: bottom left; - //filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); - - abbr { - border: 0; // Remove highlighting in firefox - font-size: 0.8em; - } - } - } - } - } - - & > tbody { - th { - padding: 0 14px 0 0; - white-space: nowrap; - - a { - font-size: 0.8em; - } - } - - td { - padding: 2px; - min-width: 1.5em; - line-height: 1.5em; - text-align: center; - - a { - width: 1.5em; - height: 1.5em; - display: block; - border-radius: 0.5em; - - &.state_ok { - background-color: @colorOk; - } - - &.state_pending { - background-color: @colorPending; - } - - &.state_warning { - background-color: @colorWarning; - - &.handled { - background-color: @colorWarningHandled; - } - } - - &.state_critical { - background-color: @colorCritical; - - &.handled { - background-color: @colorCriticalHandled; - } - } - - &.state_unknown { - background-color: @colorUnknown; - - &.handled { - background-color: @colorUnknownHandled; - } - } - } - } - } -} - /* End of monitoring pivot table styles */ /* Monitoring timeline styles */ From 403f7016ca633688ec8e190f79799efc16db7f5f Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:46:23 +0200 Subject: [PATCH 28/34] lib: Allow to set axis header columns in the pivot table PivotTable::toArray() now returns the pivot data and the pivot header. refs #9538 --- library/Icinga/Data/PivotTable.php | 107 ++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 19 deletions(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index cf703ae9c..a197bf803 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -60,6 +60,20 @@ class PivotTable */ protected $yAxisFilter; + /** + * X-axis header + * + * @var string|null + */ + protected $xAxisHeader; + + /** + * Y-axis header + * + * @var string|null + */ + protected $yAxisHeader; + /** * Create a new pivot table * @@ -100,6 +114,56 @@ class PivotTable return $this; } + /** + * Get the x-axis header + * + * Defaults to {@link $xAxisColumn} in case no x-axis header has been set using {@link setXAxisHeader()} + * + * @return string + */ + public function getXAxisHeader() + { + return $this->xAxisHeader !== null ? $this->xAxisHeader : $this->xAxisColumn; + } + + /** + * Set the x-axis header + * + * @param string $xAxisHeader + * + * @return $this + */ + public function setXAxisHeader($xAxisHeader) + { + $this->xAxisHeader = (string) $xAxisHeader; + return $this; + } + + /** + * Get the y-axis header + * + * Defaults to {@link $yAxisColumn} in case no x-axis header has been set using {@link setYAxisHeader()} + * + * @return string + */ + public function getYAxisHeader() + { + return $this->yAxisHeader !== null ? $this->yAxisHeader : $this->yAxisColumn; + } + + /** + * Set the y-axis header + * + * @param string $yAxisHeader + * + * @return $this + */ + public function setYAxisHeader($yAxisHeader) + { + $this->yAxisHeader = (string) $yAxisHeader; + return $this; + } + /** * Return the value for the given request parameter * @@ -132,7 +196,7 @@ class PivotTable if ($this->xAxisQuery === null) { $this->xAxisQuery = clone $this->baseQuery; $this->xAxisQuery->group($this->xAxisColumn); - $this->xAxisQuery->columns(array($this->xAxisColumn)); + $this->xAxisQuery->columns(array($this->xAxisColumn, $this->getXAxisHeader())); $this->xAxisQuery->setUseSubqueryCount(); if ($this->xAxisFilter !== null) { @@ -157,7 +221,7 @@ class PivotTable if ($this->yAxisQuery === null) { $this->yAxisQuery = clone $this->baseQuery; $this->yAxisQuery->group($this->yAxisColumn); - $this->yAxisQuery->columns(array($this->yAxisColumn)); + $this->yAxisQuery->columns(array($this->yAxisColumn, $this->getYAxisHeader())); $this->yAxisQuery->setUseSubqueryCount(); if ($this->yAxisFilter !== null) { @@ -168,7 +232,6 @@ class PivotTable $this->yAxisQuery->order($this->yAxisColumn, 'asc'); } } - return $this->yAxisQuery; } @@ -245,33 +308,39 @@ class PivotTable ($this->xAxisFilter === null && $this->yAxisFilter === null) || ($this->xAxisFilter !== null && $this->yAxisFilter !== null) ) { - $xAxis = $this->queryXAxis()->fetchColumn(); - $yAxis = $this->queryYAxis()->fetchColumn(); + $xAxis = $this->queryXAxis()->fetchPairs(); + $yAxis = $this->queryYAxis()->fetchPairs(); } else { if ($this->xAxisFilter !== null) { - $xAxis = $this->queryXAxis()->fetchColumn(); - $yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchColumn(); + $xAxis = $this->queryXAxis()->fetchPairs(); + $yAxis = $this->queryYAxis()->where($this->xAxisColumn, $xAxis)->fetchPairs(); } else { // $this->yAxisFilter !== null - $yAxis = $this->queryYAxis()->fetchColumn(); - $xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchColumn(); + $yAxis = $this->queryYAxis()->fetchPairs(); + $xAxis = $this->queryXAxis()->where($this->yAxisColumn, $yAxis)->fetchPairs(); } } + $pivotData = array(); + $pivotHeader = array( + 'cols' => $xAxis, + 'rows' => $yAxis + ); + if (! empty($xAxis) && ! empty($yAxis)) { + $xAxisKeys = array_keys($xAxis); + $yAxisKeys = array_keys($yAxis); + $this->baseQuery + ->where($this->xAxisColumn, $xAxisKeys) + ->where($this->yAxisColumn, $yAxisKeys); - $pivot = array(); - if (!empty($xAxis) && !empty($yAxis)) { - $this->baseQuery->where($this->xAxisColumn, $xAxis)->where($this->yAxisColumn, $yAxis); - - foreach ($yAxis as $yLabel) { - foreach ($xAxis as $xLabel) { - $pivot[$yLabel][$xLabel] = null; + foreach ($yAxisKeys as $yAxisKey) { + foreach ($xAxisKeys as $xAxisKey) { + $pivotData[$yAxisKey][$xAxisKey] = null; } } foreach ($this->baseQuery as $row) { - $pivot[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row; + $pivotData[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row; } } - - return $pivot; + return array($pivotData, $pivotHeader); } } From d8c7c216f1c3035f32af97a659cd6f485bb7b69d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:47:16 +0200 Subject: [PATCH 29/34] monitoring: Add colors.less Colors.less includes atomic definitions for background-colors related to different states at the moment. These definitions should be used when coloring backgrounds according to host and service states. refs #9538 --- modules/monitoring/public/css/colors.less | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 modules/monitoring/public/css/colors.less diff --git a/modules/monitoring/public/css/colors.less b/modules/monitoring/public/css/colors.less new file mode 100644 index 000000000..c7e5ef5c6 --- /dev/null +++ b/modules/monitoring/public/css/colors.less @@ -0,0 +1,43 @@ +/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ + +.bg-state-ok, +.bg-state-up { + background-color: @colorOk; +} + +.bg-state-warning { + background-color: @colorWarning; + + &.handled { + background-color: @colorWarningHandled; + } +} + +.bg-state-critical, +.bg-state-down { + background-color: @colorCritical; + + &.handled { + background-color: @colorCriticalHandled; + } +} + +.bg-state-unreachable { + background-color: @colorUnreachable; + + &.handled { + background-color: @colorUnreachableHandled; + } +} + +.bg-state-unknown { + background-color: @colorUnknown; + + &.handled { + background-color: @colorUnknownHandled; + } +} + +.bg-state-pending { + background-color: @colorPending; +} From 83a0e53a46e50e7da8c92f2c514026434f0673c6 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:48:32 +0200 Subject: [PATCH 30/34] monitoring: Add service-grid.less Rewritten CSS for the service grid. refs #9538 --- .../monitoring/public/css/service-grid.less | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 modules/monitoring/public/css/service-grid.less diff --git a/modules/monitoring/public/css/service-grid.less b/modules/monitoring/public/css/service-grid.less new file mode 100644 index 000000000..d89e3d5b4 --- /dev/null +++ b/modules/monitoring/public/css/service-grid.less @@ -0,0 +1,38 @@ +/*! Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */ + +table.service-grid-table { + white-space: nowrap; + + th { + a { + color: @colorMainLink; + font-weight: normal; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + } + + td { + text-align: center; + width: 1.5em; + + a { + .rounded-corners(0.4em); + display: block; + height: 1.5em; + width: 1.5em; + } + } + + th.rotate-45 { + height: 6em; + + div { + .transform(translate(0.4em, 2.1em) rotate(315deg)); + width: 1.5em; + } + } +} From 1f7c8c712fcfdd97e49d606eb43c7326a1164c8e Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:53:46 +0200 Subject: [PATCH 31/34] monitoring: Load colors.less and service-grid.less refs #9538 --- modules/monitoring/configuration.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index 8844c3247..2da1dc078 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -223,3 +223,9 @@ $dashboard->add( $this->translate('Host Problems'), 'monitoring/list/hosts?host_problem=1&sort=host_severity' ); + +/* + * CSS + */ +$this->provideCssFile('colors.less'); +$this->provideCssFile('service-grid.less'); From bf7d1ba87864ca14c3f49c5a67413f7cd84b020c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:54:15 +0200 Subject: [PATCH 32/34] monitoring: Set display names as axis headers for the service grid refs #9538 --- .../controllers/ListController.php | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index c4c02ce3a..a1c9af099 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -597,35 +597,20 @@ class Monitoring_ListController extends Controller 'service_display_name' => $this->translate('Service Name') ), $query); $filter = (bool) $this->params->shift('problems', false) ? Filter::where('service_problem', 1) : null; - $pivot = $query->pivot( - 'service_description', - 'host_name', - $filter, - $filter ? clone $filter : null - ); - $pivotData = $pivot->toArray(); - // TODO(el): list($pivotData, $pivotHeader) = $pivot->toArray(); - $pivotHeader = array( - 'cols' => array(), - 'rows' => array() - ); - foreach ($pivotData as $hostName => $services) { - foreach ($services as $serviceDescription => $service) { - if ($service === null) { - continue; - } - if (! isset($pivotHeader['rows'][$hostName])) { - $pivotHeader['rows'][$hostName] = $service->host_display_name; - } - if (! isset($pivotHeader['cols'][$serviceDescription])) { - $pivotHeader['cols'][$serviceDescription] = $service->service_display_name; - } - } - } - $this->view->pivotData = $pivotData; - $this->view->pivotHeader = $pivotHeader; + $pivot = $query + ->pivot( + 'service_description', + 'host_name', + $filter, + $filter ? clone $filter : null + ) + ->setXAxisHeader('service_display_name') + ->setYAxisHeader('host_display_name'); $this->view->horizontalPaginator = $pivot->paginateXAxis(); $this->view->verticalPaginator = $pivot->paginateYAxis(); + list($pivotData, $pivotHeader) = $pivot->toArray(); + $this->view->pivotData = $pivotData; + $this->view->pivotHeader = $pivotHeader; } /** From c5fe641c439ed8f9dde18588a1b594cd25719930 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 14:55:02 +0200 Subject: [PATCH 33/34] monitoring: Rewrite service-grid view script refs #9538 --- .../views/scripts/list/servicegrid.phtml | 149 ++++++++---------- 1 file changed, 68 insertions(+), 81 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index 7136aaa43..22d730515 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -12,97 +12,84 @@ if (! $this->compact): ?>
pivot->toArray(); if (empty($pivotData)) { echo $this->translate('No services found matching the filter') . '
'; return; } - $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . ')'; ?> - - $services): ?> - - - - -
partial( - 'joystickPagination.phtml', - 'default', - array( - 'xAxisPaginator' => $horizontalPaginator, - 'yAxisPaginator' => $verticalPaginator - ) - ); ?> -
- - - qlink( - '' . $this->ellipsis($serviceDescription, 18) . '', + + + + + $serviceDisplayName): ?> + - + ) ?> + + - - - - - - - - - - - - - + $hostDisplayName): ?> + + + + + + + -
partial( + 'joystickPagination.phtml', + 'default', + array( + 'xAxisPaginator' => $horizontalPaginator, + 'yAxisPaginator' => $verticalPaginator + ) + ); ?>
qlink( + $this->ellipsis($serviceDisplayName, 18), 'monitoring/list/services?' . $hostFilter, - array( - 'service_description' => $serviceDescription - ), - array( - 'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $serviceDescription) - ), + array('service_description' => $serviceDescription), + array('title' => sprintf( + $this->translate('List all services with the name "%s" on all reported hosts'), + $serviceDisplayName + )), false - ); ?> - - -
-
- qlink( - $hostName, - 'monitoring/list/services?' . $serviceFilter, - array('host' => $hostName), - array('title' => sprintf($this->translate('List all reported services on host %s'), $hostName)) - ); ?> - - - escape($service->service_output); ?> - - qlink( - '', - 'monitoring/show/service', - array( - 'host' => $service->host_name, - 'service' => $service->service_description - ), - array( - 'aria-describedby' => $service->host_name . '_' . $service->service_description . '_desc', - 'class' => 'state_' . Service::getStateText($service->service_state). ($service->service_handled ? ' handled' : ''), - 'title' => $this->escape($service->service_output), - 'aria-label' => sprintf( - $this->translate('Show detailed information for service %s on host %s'), - $service->service_display_name, - $service->host_display_name - ) - ) - ); ?> -
qlink( + $hostDisplayName, + 'monitoring/list/services?' . $serviceFilter, + array('host_name' => $hostName), + array('title' => sprintf($this->translate('List all reported services on host %s'), $hostDisplayName)) + ); + ?> + + + + protectId($service->host_name . '_' . $service->service_description . '_desc') ?> + + escape($service->service_output) ?> + + qlink( + '', + 'monitoring/show/service', + array( + 'host' => $hostName, + 'service' => $serviceDescription + ), + array( + 'aria-describedby' => $ariaDescribedById, + 'class' => 'bg-state-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''), + 'title' => $this->escape($service->service_output), + 'aria-label' => sprintf( + $this->translate('Show detailed information for service %s on host %s'), + $service->service_display_name, + $service->host_display_name + ) + ) + ); ?> +
+
From e27d2e998be6fb0be004f3bc62590508eaa5041d Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 25 Aug 2015 16:13:34 +0200 Subject: [PATCH 34/34] monitoring: Fix grouping and ordering of the service when using display names refs #9538 refs #9333 --- library/Icinga/Data/PivotTable.php | 50 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index 93e9d4081..8463b483e 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -18,14 +18,14 @@ class PivotTable implements Sortable protected $baseQuery; /** - * The column that contains the labels for the x axis + * X-axis pivot column * * @var string */ protected $xAxisColumn; /** - * The column that contains the labels for the y axis + * Y-axis pivot column * * @var string */ @@ -39,42 +39,42 @@ class PivotTable implements Sortable protected $order = array(); /** - * The filter being applied on the query for the x axis + * The filter being applied on the query for the x-axis * * @var Filter */ protected $xAxisFilter; /** - * The filter being applied on the query for the y axis + * The filter being applied on the query for the y-axis * * @var Filter */ protected $yAxisFilter; /** - * The query to fetch the x axis labels + * The query to fetch the leading x-axis rows and their headers * * @var SimpleQuery */ protected $xAxisQuery; /** - * The query to fetch the y axis labels + * The query to fetch the leading y-axis rows and their headers * * @var SimpleQuery */ protected $yAxisQuery; /** - * X-axis header + * X-axis header column * * @var string|null */ protected $xAxisHeader; /** - * Y-axis header + * Y-axis header column * * @var string|null */ @@ -84,8 +84,8 @@ class PivotTable implements Sortable * Create a new pivot table * * @param SimpleQuery $query The query to fetch as pivot table - * @param string $xAxisColumn The column that contains the labels for the x axis - * @param string $yAxisColumn The column that contains the labels for the y axis + * @param string $xAxisColumn X-axis pivot column + * @param string $yAxisColumn Y-axis pivot column */ public function __construct(SimpleQuery $query, $xAxisColumn, $yAxisColumn) { @@ -120,7 +120,7 @@ class PivotTable implements Sortable } /** - * Set the filter to apply on the query for the x axis + * Set the filter to apply on the query for the x-axis * * @param Filter $filter * @@ -133,7 +133,7 @@ class PivotTable implements Sortable } /** - * Set the filter to apply on the query for the y axis + * Set the filter to apply on the query for the y-axis * * @param Filter $filter * @@ -226,16 +226,18 @@ class PivotTable implements Sortable { if ($this->xAxisQuery === null) { $this->xAxisQuery = clone $this->baseQuery; - $this->xAxisQuery->group($this->xAxisColumn); - $this->xAxisQuery->columns(array($this->xAxisColumn, $this->getXAxisHeader())); + $xAxisHeader = $this->getXAxisHeader(); + $columns = array($this->xAxisColumn, $xAxisHeader); + $this->xAxisQuery->group(array_unique($columns)); // xAxisColumn and header may be the same column + $this->xAxisQuery->columns($columns); if ($this->xAxisFilter !== null) { $this->xAxisQuery->addFilter($this->xAxisFilter); } $this->xAxisQuery->order( - $this->xAxisColumn, - isset($this->order[$this->xAxisColumn]) ? $this->order[$this->xAxisColumn] : self::SORT_ASC + $xAxisHeader, + isset($this->order[$xAxisHeader]) ? $this->order[$xAxisHeader] : self::SORT_ASC ); } @@ -251,23 +253,25 @@ class PivotTable implements Sortable { if ($this->yAxisQuery === null) { $this->yAxisQuery = clone $this->baseQuery; - $this->yAxisQuery->group($this->yAxisColumn); - $this->yAxisQuery->columns(array($this->yAxisColumn, $this->getYAxisHeader())); + $yAxisHeader = $this->getYAxisHeader(); + $columns = array($this->yAxisColumn, $yAxisHeader); + $this->yAxisQuery->group(array_unique($columns)); // yAxisColumn and header may be the same column + $this->yAxisQuery->columns($columns); if ($this->yAxisFilter !== null) { $this->yAxisQuery->addFilter($this->yAxisFilter); } $this->yAxisQuery->order( - $this->yAxisColumn, - isset($this->order[$this->yAxisColumn]) ? $this->order[$this->yAxisColumn] : self::SORT_ASC + $yAxisHeader, + isset($this->order[$yAxisHeader]) ? $this->order[$yAxisHeader] : self::SORT_ASC ); } return $this->yAxisQuery; } /** - * Return a pagination adapter for the x axis query + * Return a pagination adapter for the x-axis query * * $limit and $page are taken from the current request if not given. * @@ -298,7 +302,7 @@ class PivotTable implements Sortable } /** - * Return a pagination adapter for the y axis query + * Return a pagination adapter for the y-axis query * * $limit and $page are taken from the current request if not given. * @@ -329,7 +333,7 @@ class PivotTable implements Sortable } /** - * Return the pivot table as array + * Return the pivot table as an array of pivot data and pivot header * * @return array */