diff --git a/library/Icinga/Web/View/DateTimeRenderer.php b/library/Icinga/Web/View/DateTimeRenderer.php new file mode 100644 index 000000000..639befb7f --- /dev/null +++ b/library/Icinga/Web/View/DateTimeRenderer.php @@ -0,0 +1,205 @@ +future = $future; + $this->now = new DateTime(); + $this->dateTime = $this->normalize($dateTime); + $this->detectType(); + } + + /** + * Creates a new DateTimeRenderer + * + * @param DateTime|int $dateTime + * @param bool $future + * + * @return DateTimeRenderer + */ + public static function create($dateTime, $future = false) + { + return new static($dateTime, $future); + } + + /** + * Detects the DateTime context + */ + protected function detectType() + { + if ($this->now->format('Y-m-d') !== $this->dateTime->format('Y-m-d')) { + $this->type = self::TYPE_DATETIME; + return; + } + + if ( + $this->now->format('Y-m-d') === $this->dateTime->format('Y-m-d') && + (abs($this->now->getTimestamp() - $this->dateTime->getTimestamp()) >= self::HOUR) + ) { + $this->type = self::TYPE_TIME; + return; + } + + if ( + $this->now->format('Y-m-d') === $this->dateTime->format('Y-m-d') && + (abs($this->now->getTimestamp() - $this->dateTime->getTimestamp()) < self::HOUR) + ) { + $this->type = self::TYPE_TIMESPAN; + return; + } + } + + /** + * Normalizes the given DateTime + * + * @param DateTime|int $dateTime + * + * @return DateTime + */ + public static function normalize($dateTime) + { + if (! ($dt = $dateTime) instanceof DateTime) { + $dt = new DateTime(); + $dt->setTimestamp($dateTime); + } + return $dt; + } + + /** + * Checks whether DateTime is a date with time + * + * @return bool + */ + public function isDateTime() + { + return $this->type === self::TYPE_DATETIME; + } + + /** + * Checks whether DateTime is a time of the current day + * + * @return bool + */ + public function isTime() + { + return $this->type === self::TYPE_TIME; + } + + /** + * Checks whether DateTime is in a defined interval + * + * @return bool + */ + public function isTimespan() + { + return $this->type === self::TYPE_TIMESPAN; + } + + /** + * Returns the type of the DateTime + * + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * Renders the DateTime on the basis of the type and returns suited text + * + * @param string $dateTimeText + * @param string $timeText + * @param string $timespanText + * + * @return string + */ + public function render($dateTimeText, $timeText, $timespanText) + { + if ($this->isDateTime()) { + return sprintf($dateTimeText, $this); + } elseif ($this->isTime()) { + return sprintf($timeText, $this); + } elseif ($this->isTimespan()) { + return sprintf($timespanText, $this); + } + + return $dateTimeText; + } + + /** + * Returns a rendered html wrapped text + * + * @return string + */ + public function __toString() + { + switch ($this->type) { + case self::TYPE_DATETIME: + $format = $this->dateTime->format('d.m.Y - H:i:s'); + break; + case self::TYPE_TIME: + $format = $this->dateTime->format('H:i:s'); + break; + case self::TYPE_TIMESPAN: + $format = $this->dateTime->diff($this->now)->format(t('%im %ss', 'timespan')); + break; + default: + $format = $this->dateTime->format('d.m.Y - H:i:s'); + break; + } + + $css = ''; + if ($this->type === self::TYPE_TIMESPAN) { + $css = $this->future === true ? 'timeuntil' : 'timesince'; + } + + return sprintf( + '%s', + $css, + $this->dateTime->format('d.m.Y - H:i:s'), + $format + ); + } +} diff --git a/library/Icinga/Web/View/helpers/format.php b/library/Icinga/Web/View/helpers/format.php index 0d902acfd..a203f2fb3 100644 --- a/library/Icinga/Web/View/helpers/format.php +++ b/library/Icinga/Web/View/helpers/format.php @@ -44,3 +44,7 @@ $this->addHelperFunction('prefixedTimeUntil', function ($timestamp, $ucfirst = f Format::prefixedTimeUntil($timestamp, $ucfirst) ); }); + +$this->addHelperFunction('dateTimeRenderer', function ($dateTimeOrTimestamp, $future = false) { + return DateTimeRenderer::create($dateTimeOrTimestamp, $future); +}); diff --git a/modules/monitoring/application/views/scripts/list/notifications.phtml b/modules/monitoring/application/views/scripts/list/notifications.phtml index ee414f502..826254fd8 100644 --- a/modules/monitoring/application/views/scripts/list/notifications.phtml +++ b/modules/monitoring/application/views/scripts/list/notifications.phtml @@ -44,7 +44,14 @@ foreach ($notifications as $notification): } ?> - timeSince($notification->notification_start_time) ?> + + dateTimeRenderer($notification->notification_start_time)->render( + $this->translate('on %s', 'datetime'), + $this->translate('at %s', 'time'), + $this->translate('%s ago', 'timespan') + ); + ?> + service ?> on host ?> diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js index ef5e43f70..28ce353e1 100644 --- a/public/js/icinga/ui.js +++ b/public/js/icinga/ui.js @@ -543,25 +543,39 @@ refreshTimeSince: function () { $('.timesince').each(function (idx, el) { - var m = el.innerHTML.match(/^(.*?)(-?\d+)m\s(-?\d+)s/); + + // todo remove after replace timeSince + var mp = el.innerHTML.match(/^(.*?)(-?\d+)d\s(-?\d+)h/); + if (mp !== null) { + return true; + } + + var m = el.innerHTML.match(/^(.*?)(-?\d+)(.+\s)(-?\d+)(.+)/); if (m !== null) { var nm = parseInt(m[2]); - var ns = parseInt(m[3]); + var ns = parseInt(m[4]); if (ns < 59) { ns++; } else { ns = 0; nm++; } - $(el).html(m[1] + nm + 'm ' + ns + 's'); + $(el).html(m[1] + nm + m[3] + ns + m[5]); } }); $('.timeuntil').each(function (idx, el) { - var m = el.innerHTML.match(/^(.*?)(-?\d+)m\s(-?\d+)s/); + + // todo remove after replace timeUntil + var mp = el.innerHTML.match(/^(.*?)(-?\d+)d\s(-?\d+)h/); + if (mp !== null) { + return true; + } + + var m = el.innerHTML.match(/^(.*?)(-?\d+)(.+\s)(-?\d+)(.+)/); if (m !== null) { var nm = parseInt(m[2]); - var ns = parseInt(m[3]); + var ns = parseInt(m[4]); var signed = ''; var sec = 0; @@ -589,7 +603,7 @@ nm = Math.floor(sec/60); ns = sec - nm * 60; - $(el).html(m[1] + signed + nm + 'm ' + ns + 's'); + $(el).html(m[1] + signed + nm + m[3] + ns + m[5]); } }); }, diff --git a/test/php/library/Icinga/Web/View/DateTimeRendererTest.php b/test/php/library/Icinga/Web/View/DateTimeRendererTest.php new file mode 100644 index 000000000..e45d3fdfe --- /dev/null +++ b/test/php/library/Icinga/Web/View/DateTimeRendererTest.php @@ -0,0 +1,102 @@ +assertInstanceOf( + 'Icinga\Web\View\DateTimeRenderer', + $dt, + 'Dashboard::create() could not create DateTimeRenderer' + ); + } + + /** + * @depends testWhetherCreateCreatesDateTimeRenderer + */ + public function testWhetherIsDateTimeReturnsRightType() + { + $dateTime = new DateTime('+1 day'); + $dt = DateTimeRenderer::create($dateTime); + + $this->assertTrue( + $dt->isDateTime(), + 'Dashboard::isDateTime() returns wrong type' + ); + } + + /** + * @depends testWhetherCreateCreatesDateTimeRenderer + */ + public function testWhetherIsTimeReturnsRightType() + { + $dateTime = new DateTime('+1 hour'); + $dt = DateTimeRenderer::create($dateTime); + + $this->assertTrue( + $dt->isTime(), + 'Dashboard::isTime() returns wrong type' + ); + } + + /** + * @depends testWhetherCreateCreatesDateTimeRenderer + */ + public function testWhetherIsTimespanReturnsRightType() + { + $dateTime = new DateTime('+1 minute'); + $dt = DateTimeRenderer::create($dateTime); + + $this->assertTrue( + $dt->isTimespan(), + 'Dashboard::isTimespan() returns wrong type' + ); + } + + /** + * @depends testWhetherCreateCreatesDateTimeRenderer + */ + public function testWhetherNormalizeReturnsNormalizedDateTime() + { + $dateTime = time(); + $dt = DateTimeRenderer::normalize($dateTime); + + $this->assertInstanceOf( + 'DateTime', + $dt, + 'Dashboard::normalize() returns wrong instance' + ); + } + + /** + * @depends testWhetherCreateCreatesDateTimeRenderer + */ + public function testWhetherRenderReturnsRightText() + { + $dateTime = new DateTime('+1 minute'); + $dt = DateTimeRenderer::create($dateTime); + + $text = $dt->render( + '#1 The service is down since %s', + '#2 The service is down since %s o\'clock.', + '#3 The service is down for %s.' + ); + + $this->assertRegExp( + '/#3/', + $text, + 'Dashboard::render() returns wrong text' + ); + } +}