diff --git a/library/Notifications/Widget/TimeGrid/DynamicGrid.php b/library/Notifications/Widget/TimeGrid/DynamicGrid.php index 7825e1a7e..91839ae31 100644 --- a/library/Notifications/Widget/TimeGrid/DynamicGrid.php +++ b/library/Notifications/Widget/TimeGrid/DynamicGrid.php @@ -129,7 +129,7 @@ protected function assemble() ]); $overlay = $this->createGridOverlay(); - if ($overlay->isEmpty()) { + if ($overlay->isEmpty() || count($overlay) < count($this->sideBar())) { $this->style->addFor($this, [ '--primaryRows' => count($this->sideBar()) ]); diff --git a/library/Notifications/Widget/Timeline.php b/library/Notifications/Widget/Timeline.php index f3cfb46aa..f185d3092 100644 --- a/library/Notifications/Widget/Timeline.php +++ b/library/Notifications/Widget/Timeline.php @@ -14,6 +14,7 @@ use Icinga\Module\Notifications\Widget\TimeGrid\Timescale; use Icinga\Module\Notifications\Widget\TimeGrid\Util; use Icinga\Module\Notifications\Widget\Timeline\Entry; +use Icinga\Module\Notifications\Widget\Timeline\FutureEntry; use Icinga\Module\Notifications\Widget\Timeline\MinimalGrid; use Icinga\Module\Notifications\Widget\Timeline\Rotation; use IntlDateFormatter; @@ -173,7 +174,9 @@ public function getEntries(): Traversable $occupiedCells = []; foreach ($rotations as $rotation) { + $entryFound = false; foreach ($rotation->fetchTimeperiodEntries($this->start, $this->getGrid()->getGridEnd()) as $entry) { + $entryFound = true; if (! $this->minimalLayout) { $entry->setPosition($maxPriority - $rotation->getPriority()); @@ -182,6 +185,13 @@ public function getEntries(): Traversable $occupiedCells += $getDesiredCells($entry); } + + if (! $entryFound && ! $this->minimalLayout) { + yield (new FutureEntry()) + ->setStart($this->getGrid()->getGridStart()) + ->setEnd($this->getGrid()->getGridEnd()) + ->setPosition($maxPriority - $rotation->getPriority()); + } } $entryToCellsMap = new SplObjectStorage(); diff --git a/library/Notifications/Widget/Timeline/FutureEntry.php b/library/Notifications/Widget/Timeline/FutureEntry.php new file mode 100644 index 000000000..74f26c31f --- /dev/null +++ b/library/Notifications/Widget/Timeline/FutureEntry.php @@ -0,0 +1,47 @@ + 'future-entry']; + + protected $continuationType = Entry::TO_NEXT_GRID; + + public function __construct() + { + parent::__construct(0); + } + + public function getColor(int $transparency): string + { + return ''; // No user, no color, CSS will handle it + } + + protected function assembleContainer(BaseHtmlElement $container): void + { + $container->addHtml(new HtmlElement( + 'div', + new Attributes([ + 'title' => $this->translate('Rotation starts in the future') + ]), + new Icon('angle-right'), + new HtmlElement('span', new Attributes(['class' => 'outline'])), + new HtmlElement('span', new Attributes(['class' => 'outline'])), + new HtmlElement('span', new Attributes(['class' => 'outline'])) + )); + } +} diff --git a/public/css/timeline.less b/public/css/timeline.less index 8f3de51d6..ff156a820 100644 --- a/public/css/timeline.less +++ b/public/css/timeline.less @@ -44,19 +44,66 @@ } } - .overlay .entry { - margin-top: 1em; - margin-bottom: 1em; - z-index: 2; // overlap the .clock .time-hand + .overlay { + .entry { + margin-top: 1em; + margin-bottom: 1em; + z-index: 2; // overlap the .clock .time-hand + + .title { + height: 100%; + flex-wrap: nowrap; + align-items: baseline; + padding: .15em .5em; + + .name { + .text-ellipsis(); + } + } + } - .title { - height: 100%; - flex-wrap: nowrap; - align-items: baseline; - padding: .15em .5em; + .future-entry { + display: flex; + justify-content: end; + z-index: 2; // overlap the .clock .time-hand + pointer-events: all; - .name { - .text-ellipsis(); + > div { + margin-top: 1em; + margin-bottom: 1em; + display: flex; + align-items: center; + justify-content: end; + position: relative; + width: 3em; + + .outline { + content: ''; + display: block; + position: absolute; + border: 1px solid @gray-light; + border-right-width: 0; + top: -1px; + bottom: -1px; + width: 100%; + .rounded-corners(0.25em 0 0 0.25em); + } + + .icon { + color: @gray; + } + + .outline:nth-of-type(1) { + left: -1px; // Dock at the grid border + } + + .outline:nth-of-type(2) { + left: 3px; // 4px gap + } + + .outline:nth-of-type(3) { + left: 7px; // Same gap + } } } }