mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-23 13:54:26 +02:00
commit
7bb7fe469f
@ -41,6 +41,11 @@ title = "Services"
|
|||||||
url = "monitoring/list/services"
|
url = "monitoring/list/services"
|
||||||
priority = 50
|
priority = 50
|
||||||
|
|
||||||
|
[Overview.Servicematrix]
|
||||||
|
title = "Servicematrix"
|
||||||
|
url = "monitoring/list/servicematrix"
|
||||||
|
priority = 51
|
||||||
|
|
||||||
[Overview.Servicegroups]
|
[Overview.Servicegroups]
|
||||||
title = "Servicegroups"
|
title = "Servicegroups"
|
||||||
url = "monitoring/list/servicegroups"
|
url = "monitoring/list/servicegroups"
|
||||||
|
48
application/views/scripts/pivottablePagination.phtml
Normal file
48
application/views/scripts/pivottablePagination.phtml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
if ($xAxisPaginator->count() <= 1 && $yAxisPaginator->count() <= 1) {
|
||||||
|
return; // Display this pagination only if there are multiple pages
|
||||||
|
}
|
||||||
|
|
||||||
|
$fromTo = $this->translate('%s: %d to %d of %d');
|
||||||
|
$xAxisPages = $xAxisPaginator->getPages('all');
|
||||||
|
$yAxisPages = $yAxisPaginator->getPages('all');
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="pivot-pagination">
|
||||||
|
<span><?= $this->translate('Navigation'); ?></span>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($yAxisPages->pagesInRange as $yAxisPage): ?>
|
||||||
|
<tr>
|
||||||
|
<?php foreach ($xAxisPages->pagesInRange as $xAxisPage): ?>
|
||||||
|
<td<?= $xAxisPage === $xAxisPages->current && $yAxisPage === $yAxisPages->current ? ' class="active"' : ''; ?>>
|
||||||
|
<?php if ($xAxisPage !== $xAxisPages->current || $yAxisPage !== $yAxisPages->current): ?>
|
||||||
|
<a href="<?= Url::fromRequest()->overwriteParams(
|
||||||
|
array('page' => $xAxisPage . ',' . $yAxisPage)
|
||||||
|
)->getAbsoluteUrl(); ?>" title="<?= sprintf(
|
||||||
|
$fromTo,
|
||||||
|
$this->translate('Hosts'),
|
||||||
|
($yAxisPage - 1) * $yAxisPages->itemCountPerPage + 1,
|
||||||
|
$yAxisPage === $yAxisPages->last ? $yAxisPages->totalItemCount : $yAxisPage * $yAxisPages->itemCountPerPage,
|
||||||
|
$yAxisPages->totalItemCount
|
||||||
|
) . '; ' . sprintf(
|
||||||
|
$fromTo,
|
||||||
|
$this->translate('Services'),
|
||||||
|
($xAxisPage - 1) * $xAxisPages->itemCountPerPage + 1,
|
||||||
|
$xAxisPage === $xAxisPages->last ? $xAxisPages->totalItemCount : $xAxisPage * $xAxisPages->itemCountPerPage,
|
||||||
|
$xAxisPages->totalItemCount
|
||||||
|
); ?>"></a>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
@ -41,6 +41,11 @@ title = "Services"
|
|||||||
url = "monitoring/list/services"
|
url = "monitoring/list/services"
|
||||||
priority = 50
|
priority = 50
|
||||||
|
|
||||||
|
[Overview.Servicematrix]
|
||||||
|
title = "Servicematrix"
|
||||||
|
url = "monitoring/list/servicematrix"
|
||||||
|
priority = 51
|
||||||
|
|
||||||
[Overview.Servicegroups]
|
[Overview.Servicegroups]
|
||||||
title = "Servicegroups"
|
title = "Servicegroups"
|
||||||
url = "monitoring/list/servicegroups"
|
url = "monitoring/list/servicegroups"
|
||||||
|
@ -59,6 +59,13 @@ abstract class BaseQuery implements Filterable
|
|||||||
*/
|
*/
|
||||||
private $limitOffset;
|
private $limitOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether its a distinct query or not
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $distinct = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The backend independent filter to use for this query
|
* The backend independent filter to use for this query
|
||||||
*
|
*
|
||||||
@ -294,6 +301,30 @@ abstract class BaseQuery implements Filterable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return only distinct results
|
||||||
|
*
|
||||||
|
* @param bool $distinct Whether the query should be distinct or not
|
||||||
|
*
|
||||||
|
* @return BaseQuery
|
||||||
|
*/
|
||||||
|
public function distinct($distinct = true)
|
||||||
|
{
|
||||||
|
$this->distinct = $distinct;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether this query returns only distinct results
|
||||||
|
*
|
||||||
|
* @return bool True in case its a distinct query otherwise false
|
||||||
|
*/
|
||||||
|
public function isDistinct()
|
||||||
|
{
|
||||||
|
return $this->distinct;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this query will be ordered explicitly
|
* Determine whether this query will be ordered explicitly
|
||||||
*
|
*
|
||||||
@ -392,7 +423,7 @@ abstract class BaseQuery implements Filterable
|
|||||||
*/
|
*/
|
||||||
public function paginate($limit = null, $page = null)
|
public function paginate($limit = null, $page = null)
|
||||||
{
|
{
|
||||||
if ($page === null && $limit === null) {
|
if ($page === null || $limit === null) {
|
||||||
$request = \Zend_Controller_Front::getInstance()->getRequest();
|
$request = \Zend_Controller_Front::getInstance()->getRequest();
|
||||||
|
|
||||||
if ($page === null) {
|
if ($page === null) {
|
||||||
|
@ -80,6 +80,21 @@ class Query extends BaseQuery
|
|||||||
$this->baseQuery = $this->db->select();
|
$this->baseQuery = $this->db->select();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
if ($this->baseQuery !== null) {
|
||||||
|
$this->baseQuery = clone $this->baseQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->selectQuery !== null) {
|
||||||
|
$this->selectQuery = clone $this->selectQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->countQuery !== null) {
|
||||||
|
$this->countQuery = clone $this->countQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the raw base query
|
* Return the raw base query
|
||||||
*
|
*
|
||||||
@ -141,6 +156,7 @@ class Query extends BaseQuery
|
|||||||
{
|
{
|
||||||
$this->selectQuery = clone($this->baseQuery);
|
$this->selectQuery = clone($this->baseQuery);
|
||||||
$this->selectQuery->columns($this->getColumns());
|
$this->selectQuery->columns($this->getColumns());
|
||||||
|
$this->selectQuery->distinct($this->isDistinct());
|
||||||
if ($this->hasOrder()) {
|
if ($this->hasOrder()) {
|
||||||
foreach ($this->getOrderColumns() as $col) {
|
foreach ($this->getOrderColumns() as $col) {
|
||||||
$this->selectQuery->order(
|
$this->selectQuery->order(
|
||||||
@ -193,8 +209,8 @@ class Query extends BaseQuery
|
|||||||
*/
|
*/
|
||||||
private function createCountQuery()
|
private function createCountQuery()
|
||||||
{
|
{
|
||||||
if ($this->useSubqueryCount) {
|
if ($this->isDistinct() || $this->useSubqueryCount) {
|
||||||
$this->countQuery = $this->createCountAsSubquery();
|
$this->countQuery = $this->createCountAsSubQuery();
|
||||||
} else {
|
} else {
|
||||||
$this->countQuery = $this->createCustomCountQuery();
|
$this->countQuery = $this->createCustomCountQuery();
|
||||||
}
|
}
|
||||||
|
@ -112,15 +112,14 @@ class TreeToSqlParser
|
|||||||
private function parseConjunctionNode(Node $node)
|
private function parseConjunctionNode(Node $node)
|
||||||
{
|
{
|
||||||
$queryString = '';
|
$queryString = '';
|
||||||
$leftQuery = $this->nodeToSqlQuery($node->left);
|
$leftQuery = $node->left !== null ? $this->nodeToSqlQuery($node->left) : '';
|
||||||
$rightQuery = $this->nodeToSqlQuery($node->right);
|
$rightQuery = $node->right !== null ? $this->nodeToSqlQuery($node->right) : '';
|
||||||
|
|
||||||
if ($leftQuery != '') {
|
if ($leftQuery != '') {
|
||||||
$queryString .= $leftQuery . ' ';
|
$queryString .= $leftQuery . ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rightQuery != '') {
|
if ($rightQuery != '') {
|
||||||
|
|
||||||
$queryString .= (($queryString !== '') ? $node->type . ' ' : ' ') . $rightQuery;
|
$queryString .= (($queryString !== '') ? $node->type . ' ' : ' ') . $rightQuery;
|
||||||
}
|
}
|
||||||
return $queryString;
|
return $queryString;
|
||||||
@ -193,8 +192,7 @@ class TreeToSqlParser
|
|||||||
if ($tree->root == null) {
|
if ($tree->root == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$tree->root = $tree->normalizeTree($tree->root);
|
$sql = $this->nodeToSqlQuery($tree->normalizeTree($tree->root));
|
||||||
$sql = $this->nodeToSqlQuery($tree->root);
|
|
||||||
|
|
||||||
if ($this->filtersAggregate()) {
|
if ($this->filtersAggregate()) {
|
||||||
$baseQuery->having($sql);
|
$baseQuery->having($sql);
|
||||||
|
@ -1,135 +1,188 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
namespace Icinga\Data;
|
namespace Icinga\Data;
|
||||||
|
|
||||||
|
use \Zend_Paginator;
|
||||||
|
use Icinga\Data\BaseQuery;
|
||||||
|
use Icinga\Application\Icinga;
|
||||||
|
use Icinga\Web\Paginator\Adapter\QueryAdapter;
|
||||||
|
|
||||||
class PivotTable
|
class PivotTable
|
||||||
{
|
{
|
||||||
protected $query;
|
/**
|
||||||
|
* The query to fetch as pivot table
|
||||||
|
*
|
||||||
|
* @var BaseQuery
|
||||||
|
*/
|
||||||
|
protected $baseQuery;
|
||||||
|
|
||||||
protected $verticalColumn;
|
/**
|
||||||
|
* The query to fetch the x axis labels
|
||||||
|
*
|
||||||
|
* @var BaseQuery
|
||||||
|
*/
|
||||||
|
protected $xAxisQuery;
|
||||||
|
|
||||||
protected $horizontalColumn;
|
/**
|
||||||
|
* The query to fetch the y axis labels
|
||||||
|
*
|
||||||
|
* @var BaseQuery
|
||||||
|
*/
|
||||||
|
protected $yAxisQuery;
|
||||||
|
|
||||||
protected $limit;
|
/**
|
||||||
|
* The column that contains the labels for the x axis
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $xAxisColumn;
|
||||||
|
|
||||||
protected $offset;
|
/**
|
||||||
|
* The column that contains the labels for the y axis
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $yAxisColumn;
|
||||||
|
|
||||||
protected $verticalLimit;
|
/**
|
||||||
|
* Create a new pivot table
|
||||||
protected $horizontalLimit;
|
*
|
||||||
|
* @param BaseQuery $query The query to fetch as pivot table
|
||||||
public function __construct(QueryInterface $query, $verticalColumn, $horizontalColumn)
|
* @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
|
||||||
|
*/
|
||||||
|
public function __construct(BaseQuery $query, $xAxisColumn, $yAxisColumn)
|
||||||
{
|
{
|
||||||
$this->query = $query;
|
$this->baseQuery = $query;
|
||||||
$this->verticalColumn = $verticalColumn;
|
$this->xAxisColumn = $xAxisColumn;
|
||||||
$this->horizontalColumn = $horizontalColumn;
|
$this->yAxisColumn = $yAxisColumn;
|
||||||
}
|
$this->prepareQueries();
|
||||||
|
|
||||||
public function limit($limit = null, $offset = null)
|
|
||||||
{
|
|
||||||
$this->limit = $limit;
|
|
||||||
$this->offset = $offset;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLimit()
|
|
||||||
{
|
|
||||||
if ($this->limit === null) {
|
|
||||||
return 20;
|
|
||||||
}
|
|
||||||
return $this->limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOffset()
|
|
||||||
{
|
|
||||||
if ($this->limit === null) {
|
|
||||||
return 20;
|
|
||||||
}
|
|
||||||
return $this->offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function verticalLimit($limit = null, $offset = null)
|
|
||||||
{
|
|
||||||
// TODO: Trigger limit by calling $this->limit()?
|
|
||||||
if ($limit === null) {
|
|
||||||
$limit = $this->getLimit();
|
|
||||||
}
|
|
||||||
if ($offset === null) {
|
|
||||||
$offset = $this->getOffset();
|
|
||||||
}
|
|
||||||
$this->verticalLimit = $limit;
|
|
||||||
$this->verticalOffset = $offset;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function paginateVertical($limit = null, $offset = null)
|
|
||||||
{
|
|
||||||
$this->verticalLimit($limit, $offset);
|
|
||||||
return Paginator($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getVerticalLimit()
|
|
||||||
{
|
|
||||||
if ($this->verticalLimit === null) {
|
|
||||||
return 20;
|
|
||||||
}
|
|
||||||
return $this->verticalLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getVerticalOffset()
|
|
||||||
{
|
|
||||||
if ($this->verticalLimit === null) {
|
|
||||||
return 20;
|
|
||||||
}
|
|
||||||
return $this->verticalOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all columns
|
* Prepare the queries used for the pre processing
|
||||||
*/
|
*/
|
||||||
public function fetchAll()
|
protected function prepareQueries()
|
||||||
{
|
{
|
||||||
$xcol = $this->horizontalColumn;
|
$this->xAxisQuery = clone $this->baseQuery;
|
||||||
$ycol = $this->verticalColumn;
|
$this->xAxisQuery->distinct();
|
||||||
$queryX = clone($this->query);
|
$this->xAxisQuery->setColumns(array($this->xAxisColumn));
|
||||||
$queryX->columns($xcol);
|
$this->yAxisQuery = clone $this->baseQuery;
|
||||||
if ($this->limit !== null) {
|
$this->yAxisQuery->distinct();
|
||||||
$queryX->limit($this->getLimit(), $this->getOffset());
|
$this->yAxisQuery->setColumns(array($this->yAxisColumn));
|
||||||
}
|
}
|
||||||
$queryX->limit(40);
|
|
||||||
$listX = $queryX->fetchColumn();
|
|
||||||
$queryY = clone($this->query);
|
|
||||||
|
|
||||||
$queryY->columns($ycol);
|
/**
|
||||||
if ($this->verticalLimit !== null) {
|
* Return the value for the given request parameter
|
||||||
$queryY->limit($this->getVerticalLimit(), $this->getVerticalOffset());
|
*
|
||||||
}
|
* @param string $axis The axis for which to return the parameter ('x' or 'y')
|
||||||
$queryY->limit(50);
|
* @param string $param The parameter name to return
|
||||||
$listY = $queryY->fetchColumn();
|
* @param int $default The default value to return
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function getPaginationParameter($axis, $param, $default = null)
|
||||||
|
{
|
||||||
|
$request = Icinga::app()->getFrontController()->getRequest();
|
||||||
|
|
||||||
// TODO: resetOrder
|
$value = $request->getParam($param, '');
|
||||||
$this->query
|
if (strpos($value, ',') > 0) {
|
||||||
->where($ycol, $listY)
|
$parts = explode(',', $value, 2);
|
||||||
->where($xcol, $listX)
|
return intval($parts[$axis === 'x' ? 0 : 1]);
|
||||||
->order($ycol)
|
|
||||||
->order($xcol);
|
|
||||||
$pivot = array();
|
|
||||||
$emptyrow = (object) array();
|
|
||||||
foreach ($this->query->listColumns() as $col) {
|
|
||||||
$emptyrow->$col = null;
|
|
||||||
}
|
}
|
||||||
foreach ($listY as $y) {
|
|
||||||
foreach ($listX as $x) {
|
return $default !== null ? $default : 0;
|
||||||
$row = clone($emptyrow);
|
}
|
||||||
$row->$xcol = $x;
|
|
||||||
$row->$ycol = $y;
|
/**
|
||||||
$pivot[$y][$x] = $row;
|
* Return a pagination adapter for the x axis query
|
||||||
|
*
|
||||||
|
* $limit and $page are taken from the current request if not given.
|
||||||
|
*
|
||||||
|
* @param int $limit The maximum amount of entries to fetch
|
||||||
|
* @param int $page The page to set as current one
|
||||||
|
*
|
||||||
|
* @return Zend_Paginator
|
||||||
|
*/
|
||||||
|
public function paginateXAxis($limit = null, $page = null)
|
||||||
|
{
|
||||||
|
if ($limit === null || $page === null) {
|
||||||
|
if ($limit === null) {
|
||||||
|
$limit = $this->getPaginationParameter('x', 'limit', 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page === null) {
|
||||||
|
$page = $this->getPaginationParameter('x', 'page', 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->query->fetchAll() as $row) {
|
$this->xAxisQuery->limit($limit, $page > 0 ? ($page - 1) * $limit : 0);
|
||||||
$pivot[$row->$ycol][$row->$xcol] = $row;
|
|
||||||
|
$paginator = new Zend_Paginator(new QueryAdapter($this->xAxisQuery));
|
||||||
|
$paginator->setItemCountPerPage($limit);
|
||||||
|
$paginator->setCurrentPageNumber($page);
|
||||||
|
return $paginator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a pagination adapter for the y axis query
|
||||||
|
*
|
||||||
|
* $limit and $page are taken from the current request if not given.
|
||||||
|
*
|
||||||
|
* @param int $limit The maximum amount of entries to fetch
|
||||||
|
* @param int $page The page to set as current one
|
||||||
|
*
|
||||||
|
* @return Zend_Paginator
|
||||||
|
*/
|
||||||
|
public function paginateYAxis($limit = null, $page = null)
|
||||||
|
{
|
||||||
|
if ($limit === null || $page === null) {
|
||||||
|
if ($limit === null) {
|
||||||
|
$limit = $this->getPaginationParameter('y', 'limit', 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page === null) {
|
||||||
|
$page = $this->getPaginationParameter('y', 'page', 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->yAxisQuery->limit($limit, $page > 0 ? ($page - 1) * $limit : 0);
|
||||||
|
|
||||||
|
$paginator = new Zend_Paginator(new QueryAdapter($this->yAxisQuery));
|
||||||
|
$paginator->setItemCountPerPage($limit);
|
||||||
|
$paginator->setCurrentPageNumber($page);
|
||||||
|
return $paginator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the pivot table as array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
$xAxis = $this->xAxisQuery->fetchColumn();
|
||||||
|
$yAxis = $this->yAxisQuery->fetchColumn();
|
||||||
|
|
||||||
|
$pivot = array();
|
||||||
|
if (!empty($xAxis) && !empty($yAxis)) {
|
||||||
|
$this->baseQuery->where($this->xAxisColumn, $xAxis)->where($this->yAxisColumn, $yAxis);
|
||||||
|
|
||||||
|
foreach ($this->baseQuery->fetchAll() as $row) {
|
||||||
|
if (!array_key_exists($row->{$this->yAxisColumn}, $pivot)) {
|
||||||
|
$defaults = array();
|
||||||
|
foreach ($xAxis as $label) {
|
||||||
|
$defaults[$label] = null;
|
||||||
|
}
|
||||||
|
$pivot[$row->{$this->yAxisColumn}] = $defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pivot[$row->{$this->yAxisColumn}][$row->{$this->xAxisColumn}] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $pivot;
|
return $pivot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,12 +232,12 @@ class Tree
|
|||||||
$node->left = $this->removeInvalidFilter($node->left, $filter);
|
$node->left = $this->removeInvalidFilter($node->left, $filter);
|
||||||
$node->right = $this->removeInvalidFilter($node->right, $filter);
|
$node->right = $this->removeInvalidFilter($node->right, $filter);
|
||||||
|
|
||||||
if ($node->left && $node->right) {
|
if ($node->left || $node->right) {
|
||||||
|
if (!$node->left) {
|
||||||
|
$node->left = $node->right;
|
||||||
|
$node->right = null;
|
||||||
|
}
|
||||||
return $node;
|
return $node;
|
||||||
} elseif ($node->left) {
|
|
||||||
return $node->left;
|
|
||||||
} elseif ($node->right) {
|
|
||||||
return $node->right;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -182,6 +182,6 @@ EOT;
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$this->buildBaseUrl();
|
$this->buildBaseUrl();
|
||||||
return $this->nodeToBadge($this->tree->root);
|
return $this->nodeToBadge(Tree::normalizeTree($this->tree->root));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,6 +458,34 @@ class Monitoring_ListController extends Controller
|
|||||||
$this->view->history = $query->paginate();
|
$this->view->history = $query->paginate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function servicematrixAction()
|
||||||
|
{
|
||||||
|
$this->view->title = 'Servicematrix';
|
||||||
|
$this->addTitleTab('servicematrix');
|
||||||
|
$dataview = ServiceStatusView::fromRequest(
|
||||||
|
$this->getRequest(),
|
||||||
|
array(
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'service_state',
|
||||||
|
'service_output',
|
||||||
|
'service_handled'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setupFilterControl($dataview, 'servicematrix');
|
||||||
|
$this->setupSortControl(
|
||||||
|
array(
|
||||||
|
'host_name' => 'Hostname',
|
||||||
|
'service_description' => 'Service description'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->view->pivot = $dataview->pivot('service_description', 'host_name');
|
||||||
|
$this->view->horizontalPaginator = $this->view->pivot->paginateXAxis();
|
||||||
|
$this->view->verticalPaginator = $this->view->pivot->paginateYAxis();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply current users monitoring/filter restrictions to the given query
|
* Apply current users monitoring/filter restrictions to the given query
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
<?php if (!$this->compact): ?>
|
||||||
|
<div class="controls">
|
||||||
|
<?= $this->tabs; ?>
|
||||||
|
<div style="margin: 1em;" class="dontprint">
|
||||||
|
<!--<?= $this->filterBox; ?>-->Sort by <?= $this->sortControl->render($this); ?>
|
||||||
|
</div>
|
||||||
|
<?= $this->partial(
|
||||||
|
'pivottablePagination.phtml',
|
||||||
|
'default',
|
||||||
|
array(
|
||||||
|
'xAxisPaginator' => $this->horizontalPaginator,
|
||||||
|
'yAxisPaginator' => $this->verticalPaginator
|
||||||
|
)
|
||||||
|
); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
<div class="content" data-base-target="_next">
|
||||||
|
<table class="pivot servicestates">
|
||||||
|
<?php $hasHeader = false; ?>
|
||||||
|
<?php foreach ($this->pivot->toArray() as $host_name => $serviceStates): ?>
|
||||||
|
<?php if (!$hasHeader): ?>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th colspan="<?= count($serviceStates); ?>">
|
||||||
|
<div>
|
||||||
|
<?php foreach (array_keys($serviceStates) as $service_description): ?>
|
||||||
|
<span>
|
||||||
|
<abbr title="<?= $service_description; ?>">
|
||||||
|
<?= strlen($service_description) > 18 ? substr($service_description, 0, 18) . '...' : $service_description; ?>
|
||||||
|
</abbr>
|
||||||
|
</span>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $hasHeader = true; ?>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php if (count(array_filter(array_values($serviceStates)))): ?>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="<?= $this->href('monitoring/show/host', array('host' => $host_name)); ?>">
|
||||||
|
<?= $host_name; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<?php foreach (array_values($serviceStates) as $service): ?>
|
||||||
|
<?php if ($service !== null): ?>
|
||||||
|
<td>
|
||||||
|
<a href="<?= $this->href(
|
||||||
|
'monitoring/show/service',
|
||||||
|
array(
|
||||||
|
'host' => $service->host_name,
|
||||||
|
'service' => $service->service_description
|
||||||
|
)
|
||||||
|
); ?>" title="<?= $this->escape($service->service_output); ?>" class="state_<?= $this->monitoringState($service, 'service'); ?> <?= $service->service_handled ? 'handled' : ''; ?>"></a>
|
||||||
|
<?php else: ?>
|
||||||
|
<td>
|
||||||
|
·
|
||||||
|
<?php endif ?>
|
||||||
|
</td>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tr>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
@ -30,6 +30,7 @@
|
|||||||
namespace Icinga\Module\Monitoring\DataView;
|
namespace Icinga\Module\Monitoring\DataView;
|
||||||
|
|
||||||
use Icinga\Data\BaseQuery;
|
use Icinga\Data\BaseQuery;
|
||||||
|
use Icinga\Data\PivotTable;
|
||||||
use Icinga\Filter\Filterable;
|
use Icinga\Filter\Filterable;
|
||||||
use Icinga\Filter\Query\Tree;
|
use Icinga\Filter\Query\Tree;
|
||||||
use Icinga\Module\Monitoring\Backend;
|
use Icinga\Module\Monitoring\Backend;
|
||||||
@ -167,6 +168,19 @@ abstract class DataView implements Filterable
|
|||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a pivot table for the given columns based on the current query
|
||||||
|
*
|
||||||
|
* @param string $xAxisColumn The column to use for the x axis
|
||||||
|
* @param string $yAxisColumn The column to use for the y axis
|
||||||
|
*
|
||||||
|
* @return PivotTable
|
||||||
|
*/
|
||||||
|
public function pivot($xAxisColumn, $yAxisColumn)
|
||||||
|
{
|
||||||
|
return new PivotTable($this->query, $xAxisColumn, $yAxisColumn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the rows, according to the specified sort column and order
|
* Sort the rows, according to the specified sort column and order
|
||||||
*
|
*
|
||||||
|
@ -501,6 +501,143 @@ div.box.contactgroup div.box.entry p {
|
|||||||
/* End of monitoring box element styles */
|
/* End of monitoring box element styles */
|
||||||
|
|
||||||
|
|
||||||
|
/* Monitoring pivot table styles */
|
||||||
|
|
||||||
|
div.pivot-pagination {
|
||||||
|
margin: 1em;
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-spacing: 0.2em;
|
||||||
|
border-collapse: separate;
|
||||||
|
border: 1px solid LightGrey;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1em;
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
|
||||||
|
&:hover, &.active {
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.pivot {
|
||||||
|
thead {
|
||||||
|
th {
|
||||||
|
height: 6em;
|
||||||
|
padding: 2px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
div {
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
right: -1.5em;
|
||||||
|
position: absolute;
|
||||||
|
padding-left: 1.2em;
|
||||||
|
|
||||||
|
span {
|
||||||
|
width: 1.5em;
|
||||||
|
margin-right: 4px;
|
||||||
|
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 {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
th {
|
||||||
|
padding: 0 14px 0 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
min-width: 1.5em;
|
||||||
|
min-height: 1.5em;
|
||||||
|
padding: 2px;
|
||||||
|
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 */
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user