From f5e4331d7154a1fd1b28c692232922a0ae69af48 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 27 Mar 2014 09:38:57 +0100 Subject: [PATCH] Add timeline view script and styles refs #4190 --- config/modules/monitoring/menu.ini | 4 + library/Icinga/Util/Color.php | 39 ++++-- .../controllers/TimelineController.php | 42 +++++-- .../views/scripts/timeline/index.phtml | 83 +++++++++++- .../library/Monitoring/Timeline/TimeLine.php | 118 +++--------------- public/css/icinga/monitoring-colors.less | 95 ++++++++++++++ 6 files changed, 261 insertions(+), 120 deletions(-) diff --git a/config/modules/monitoring/menu.ini b/config/modules/monitoring/menu.ini index 0c7e37dea..5ea74f1ca 100644 --- a/config/modules/monitoring/menu.ini +++ b/config/modules/monitoring/menu.ini @@ -87,6 +87,10 @@ url = "monitoring/list/notifications" title = "All Events" url = "monitoring/list/eventhistory?raw_timestamp>=-2+days" +[History.Timeline] +title = "Timeline" +url = "monitoring/timeline" + [System.Process Info] title = "Process Info" url = "monitoring/process/info" diff --git a/library/Icinga/Util/Color.php b/library/Icinga/Util/Color.php index 4f8a0d71c..09c6639b6 100644 --- a/library/Icinga/Util/Color.php +++ b/library/Icinga/Util/Color.php @@ -30,7 +30,6 @@ namespace Icinga\Util; * Provide functions to change and convert colors. */ class Color { - /** * Convert a given color string to an rgb-array containing * each color as a decimal value. @@ -71,7 +70,6 @@ class Color { . (strlen($b) > 1 ? $b : '0' . $b); } - /** * Change the saturation for a given color. * @@ -85,10 +83,20 @@ class Color { */ public static function changeSaturation($color, $change) { - $rgb = self::rgbAsArray($color); - $rgb = self::changeRgbSaturation($rgb, $change); - $col = self::arrayToRgb($rgb); - return $col; + return self::arrayToRgb(self::changeRgbSaturation(self::rgbAsArray($color), $change)); + } + + /** + * Change the brightness for a given color + * + * @param $color string The color to change + * @param $change float The change in percent + * + * @return string + */ + public static function changeBrightness($color, $change) + { + return self::arrayToRgb(self::changeRgbBrightness(self::rgbAsArray($color), $change)); } /** @@ -115,4 +123,21 @@ class Color { $rgb[2] = (int)($p + ($b - $p) * $change); return $rgb; } -} \ No newline at end of file + + /** + * @param $rgb array The rgb-array to change + * @param $change float The factor + * + * @return array The updated rgb-array + */ + private static function changeRgbBrightness(array $rgb, $change) + { + $red = $rgb[0] + (255 * $change); + $green = $rgb[1] + (255 * $change); + $blue = $rgb[2] + (255 * $change); + $rgb[0] = $red < 255 ? (int) $red : 255; + $rgb[1] = $green < 255 ? (int) $green : 255; + $rgb[2] = $blue < 255 ? (int) $blue : 255; + return $rgb; + } +} diff --git a/modules/monitoring/application/controllers/TimelineController.php b/modules/monitoring/application/controllers/TimelineController.php index 408d53f39..6c825794e 100644 --- a/modules/monitoring/application/controllers/TimelineController.php +++ b/modules/monitoring/application/controllers/TimelineController.php @@ -19,6 +19,7 @@ class Monitoring_TimelineController extends ActionController $this->setupIntervalBox(); list($displayRange, $forecastRange) = $this->buildTimeRanges(); + $detailUrl = '/monitoring/list/eventhistory?raw_timestamp<=%s&raw_timestamp>=%s&type=%s'; $timeline = new TimeLine( EventHistoryView::fromRequest( $this->getRequest(), @@ -28,14 +29,39 @@ class Monitoring_TimelineController extends ActionController ) ), array( - 'notify' => array('label' => t('Notifications'), 'color' => 'red'), - 'hard_state' => array('label' => t('Hard state changes'), 'color' => 'green'), - 'comment' => array('label' => t('Comments'), 'color' => 'blue'), - 'ack' => array('label' => t('Acknowledgements'), 'color' => 'black'), - 'dt_start' => array('label' => t('Started downtimes'), 'color' => 'grey'), - 'dt_end' => array('label' => t('Ended downtimes'), 'color' => 'white') + 'notify' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Notifications'), + 'color' => '#3a71ea' + ), + 'hard_state' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Hard state changes'), + 'color' => '#ff7000' + ), + 'comment' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Comments'), + 'color' => '#79bdba' + ), + 'ack' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Acknowledgements'), + 'color' => '#a2721d' + ), + 'dt_start' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Started downtimes'), + 'color' => '#8e8e8e' + ), + 'dt_end' => array( + 'detailUrl' => $detailUrl, + 'label' => t('Ended downtimes'), + 'color' => '#d5d6ad' + ) ) ); + $timeline->setMaximumCircleWidth('6em'); $timeline->setDisplayRange($displayRange); $timeline->setForecastRange($forecastRange); $timeline->setSession($this->getWindowSession('timeline')); @@ -99,13 +125,13 @@ class Monitoring_TimelineController extends ActionController case '1d': return $this->getDateFormat(); case '1w': - return '\W\e\ek #W \of Y'; + return '\W\e\ek #W\\of Y'; case '1m': return 'F Y'; case '1y': return 'Y'; default: - return $this->getDateFormat() . ' ' . $this->getTimeFormat(); + return $this->getDateFormat() . '\' . $this->getTimeFormat(); } } diff --git a/modules/monitoring/application/views/scripts/timeline/index.phtml b/modules/monitoring/application/views/scripts/timeline/index.phtml index 3249b5638..9c561031f 100644 --- a/modules/monitoring/application/views/scripts/timeline/index.phtml +++ b/modules/monitoring/application/views/scripts/timeline/index.phtml @@ -1,8 +1,85 @@ -compact): ?> +getGroupInfo(); +$firstRow = true; +?>
- intervalBox; ?> + +
+
+

translate('Legend'); ?>

+ + + + +
+
+ + + + + + $labelAndColor): ?> + + + + + + +
+ + end->format($intervalFormat); ?> + + +
+ +calculateCircleWidth($timeInfo[1][$groupName], 2); +$extrapolatedCircleWidth = $timeline->getExtrapolatedCircleWidth($timeInfo[1][$groupName], 2); +?> + +getColor(), 0.25), + ((float) substr($extrapolatedCircleWidth, 0, -2) / 2) . 'em', + $extrapolatedCircleWidth +); +?> +
+ +
-timeline->buildTimeline(); ?> +getColor(), + $circleWidth +); +?> + +
+ +   + +
+
+
diff --git a/modules/monitoring/library/Monitoring/Timeline/TimeLine.php b/modules/monitoring/library/Monitoring/Timeline/TimeLine.php index 2122e0ada..0a809340b 100644 --- a/modules/monitoring/library/Monitoring/Timeline/TimeLine.php +++ b/modules/monitoring/library/Monitoring/Timeline/TimeLine.php @@ -162,6 +162,22 @@ class TimeLine implements IteratorAggregate } } + /** + * Return all known group types (identifiers) with their respective labels and colors as array + * + * @return array + */ + public function getGroupInfo() + { + $groupInfo = array(); + foreach ($this->identifiers as $name => $attributes) { + $groupInfo[$name]['label'] = $attributes['label']; + $groupInfo[$name]['color'] = $attributes['color']; + } + + return $groupInfo; + } + /** * Return the circle's diameter for the given event group * @@ -410,106 +426,4 @@ class TimeLine implements IteratorAggregate return $array; } - - /** - * Build the legend - */ - private function buildLegend() - { - // TODO: Put this in some sort of dedicated stylesheet - $circleStyle = 'width:75px;height:75px;border-radius:50%;box-shadow:4px 4px 8px grey;border:2px solid;margin:auto;'; - $labelStyle = 'font-size:12px;margin-top:10px;text-align:center;'; - $titleStyle = 'margin-left:25px;'; - - $elements = array(); - foreach ($this->getGroups() as $groupName => $groupInfo) { - $groupColor = $groupInfo['color'] !== null ? $groupInfo['color'] : $this->getRandomCssColor(); - $elements[] = '' . - '
' . - '

' . $groupName . '

'; - } - - $legend = '' . - '

' . t('Shown event groups') . '

' . - '
' . - implode( - '', - array_map( - function ($e) { return '
' . $e . '
'; }, - $elements - ) - ) . - '
'; - - return $legend; - } - - /** - * Build the timeline - */ - public function buildTimeline() - { - $timelineGroups = array(); - foreach ($this->displayData as $group) { - $timestamp = $group->getDateTime()->getTimestamp(); - - if (!array_key_exists($timestamp, $timelineGroups)) { - $timelineGroups[$timestamp] = array(); - } - - $timelineGroups[$timestamp][] = $group; - } - - $elements = array(); - foreach ($this->range as $timestamp => $timeframe) { - $elementGroups = array(); - $biggestWidth = 0; - - if (array_key_exists($timestamp, $timelineGroups)) { - foreach ($timelineGroups[$timestamp] as $group) { - $circleWidth = $this->calculateCircleWidth( - empty($elements) ? $this->extrapolateEventCount($group, 4) : $group->getValue() - ); - $groupColor = $group->getColor() !== null ? $group->getColor() : $this->getRandomCssColor(); - $elementGroups[] = sprintf( - '', - $group->getDetailUrl(), - $this->diameterUnit, - $group->getValue(), - $circleWidth, - $groupColor - ); - - if ($circleWidth > $biggestWidth) { - $biggestWidth = $circleWidth; - } - } - } - - $timeframeUrl = '';/*$this->getRequest()->getBaseUrl() . '/monitoring/list/eventhistory?timestamp<=' . - $timeframe->start->getTimestamp() . '×tamp>=' . $timeframe->end->getTimestamp();*/ - $elements[] = sprintf( - '
%1$s
', - implode('', $elementGroups), - $this->diameterUnit, - $biggestWidth - ); - $elements[] = '
'; - $elements[] = '
' . - $timeframe->end->format($this->getIntervalFormat()) . '' . - '
'; - } - - $elements[] = ''; - return implode('', $elements); - } } diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index b423c4780..ce8b4f739 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -630,6 +630,101 @@ table.pivot { /* End of monitoring pivot table styles */ +/* Monitoring timeline styles */ + +div.timeline-legend { + float: left; + padding: 0.5em; + border: 1px solid #ccc; + border-radius: 0.5em; + background-color: #eee; + + &:after { + clear: left; + } + + h2 { + margin: 0; + margin-left: 0.5em; + line-height: 1.1em; + } + + & > span { + display: inline-block; + padding: 0.5em; + margin: 0.5em; + border-radius: 0.5em; + + span { + color: white; + font-size: 0.8em; + font-weight: bold; + white-space: nowrap; + } + } +} + +table.timeline { + th { + padding-right: 1.5em; + + a { + color: black; + font-size: 0.8em; + text-decoration: none; + white-space: nowrap; + + &:hover { + color: #666; + } + } + } + + td { + padding: 0.5em; + + div.circle-box { + width: 6em; + height: 6em; + position: relative; + + div.outer-circle { + width: 100%; + height: 100%; + position: absolute; + + &.extrapolated { + // width: inline-style; + // height: inline-style; + top: 49%; // Compensate border + left: 49%; // Compensate border + // margin-top: inline-style; + // margin-left: inline-style; + border: 1px dashed #666; + border-radius: 100%; + // background-color: inline-style; + } + + a.inner-circle { + // width: inline-style; + // height: inline-style; + display: block; + position: absolute; + top: 49%; // Compensate border + left: 49%; // Compensate border + // margin-top: inline-style; + // margin-left: inline-style; + border: 1px solid black; + border-radius: 100%; + // background-color: inline-style; + } + } + } + } +} + +/* End of monitoring timeline styles */ + .controls { font-size: 0.9em; }