File tree Expand file tree Collapse file tree
library/Notifications/Widget Expand file tree Collapse file tree Original file line number Diff line number Diff line change 77use DateInterval ;
88use DateTime ;
99use Generator ;
10+ use Icinga \Module \Notifications \Widget \Timeline \FutureEntry ;
1011use ipl \Html \Attributes ;
1112use ipl \Html \BaseHtmlElement ;
1213use ipl \Html \HtmlElement ;
@@ -421,6 +422,20 @@ final protected function yieldFixedEntries(Traversable $entries): Generator
421422 }
422423
423424 $ rowStart = $ position + $ rowStartModifier ;
425+
426+ if ($ entry instanceof FutureEntry) {
427+ $ gridArea = $ this ->getGridArea (
428+ $ rowStart ,
429+ $ rowStart + 1 ,
430+ 1 ,
431+ $ gridBorderAt + 1
432+ );
433+
434+ yield $ gridArea => $ entry ;
435+
436+ continue ;
437+ }
438+
424439 if ($ rowStart > $ lastRow ) {
425440 $ lastRow = $ rowStart ;
426441 }
Original file line number Diff line number Diff line change 1414use Icinga \Module \Notifications \Widget \TimeGrid \Timescale ;
1515use Icinga \Module \Notifications \Widget \TimeGrid \Util ;
1616use Icinga \Module \Notifications \Widget \Timeline \Entry ;
17+ use Icinga \Module \Notifications \Widget \Timeline \FutureEntry ;
1718use Icinga \Module \Notifications \Widget \Timeline \MinimalGrid ;
1819use Icinga \Module \Notifications \Widget \Timeline \Rotation ;
1920use IntlDateFormatter ;
@@ -173,7 +174,9 @@ public function getEntries(): Traversable
173174
174175 $ occupiedCells = [];
175176 foreach ($ rotations as $ rotation ) {
177+ $ entryFound = false ;
176178 foreach ($ rotation ->fetchTimeperiodEntries ($ this ->start , $ this ->getGrid ()->getGridEnd ()) as $ entry ) {
179+ $ entryFound = true ;
177180 if (! $ this ->minimalLayout ) {
178181 $ entry ->setPosition ($ maxPriority - $ rotation ->getPriority ());
179182
@@ -182,6 +185,10 @@ public function getEntries(): Traversable
182185
183186 $ occupiedCells += $ getDesiredCells ($ entry );
184187 }
188+
189+ if (! $ entryFound && ! $ this ->minimalLayout ) {
190+ yield (new FutureEntry ())->setPosition ($ maxPriority - $ rotation ->getPriority ());
191+ }
185192 }
186193
187194 $ entryToCellsMap = new SplObjectStorage ();
Original file line number Diff line number Diff line change 1+ <?php
2+
3+ /* Icinga Notifications Web | (c) 2025 Icinga GmbH | GPLv2 */
4+
5+ namespace Icinga \Module \Notifications \Widget \Timeline ;
6+
7+ use Icinga \Module \Notifications \Widget \TimeGrid \Entry ;
8+ use ipl \Html \Attributes ;
9+ use ipl \Html \BaseHtmlElement ;
10+ use ipl \Html \HtmlElement ;
11+ use ipl \Web \Widget \Icon ;
12+
13+ /**
14+ * FutureEntry
15+ *
16+ * Visualize a future entry of the rotation
17+ *
18+ * @extends Entry<0>
19+ */
20+ class FutureEntry extends Entry
21+ {
22+ public function __construct ()
23+ {
24+ parent ::__construct (0 );
25+
26+ $ this ->setContinuationType (Entry::TO_NEXT_GRID );
27+ }
28+
29+ public function getColor (int $ transparency ): string
30+ {
31+ // --base-disabled (#d0d3da) -> hsl(222, 12%, 84%) + transparency
32+ return sprintf ('~"hsl(222 12%% 84%% / %d%%)" ' , $ transparency );
33+ }
34+
35+ protected function assembleContainer (BaseHtmlElement $ container ): void
36+ {
37+ $ futureBadge = new HtmlElement (
38+ 'div ' ,
39+ new Attributes ([
40+ 'title ' => $ this ->translate ('Rotation starts in the future ' ),
41+ $ container ->getAttributes ()->get ('class ' )
42+ ]),
43+ new Icon ('angle-right ' )
44+ );
45+
46+ $ container
47+ ->setAttribute ('class ' , 'future-entry ' ) // override the default class
48+ ->addHtml ($ futureBadge );
49+ }
50+ }
Original file line number Diff line number Diff line change 4848 }
4949 }
5050
51- .overlay .entry {
52- margin-top : 1em ;
53- margin-bottom : 1em ;
54- z-index : 2 ; // overlap the .clock .time-hand
51+ .overlay {
52+ .entry {
53+ margin-top : 1em ;
54+ margin-bottom : 1em ;
55+ z-index : 2 ; // overlap the .clock .time-hand
56+
57+ .title {
58+ height : 100% ;
59+ flex-wrap : nowrap ;
60+ align-items : baseline ;
61+ padding : .15em .5em ;
62+
63+ .name {
64+ .text-ellipsis ();
65+ }
66+ }
67+ }
5568
56- .title {
57- height : 100% ;
58- flex-wrap : nowrap ;
59- align-items : baseline ;
60- padding : .15em .5em ;
69+ .future-entry {
70+ display : flex ;
71+ justify-content : end ;
6172
62- .name {
63- .text-ellipsis ();
73+ .entry {
74+ display : flex ;
75+ align-items : center ;
76+ justify-content : end ;
77+ flex-shrink : 0 ;
78+ position : relative ;
79+ padding-right : .25em ;
80+ width : 3em ;
81+
82+ & :before ,
83+ & :after {
84+ content : ' ' ;
85+ display : block ;
86+ position : absolute ;
87+ border : 1px solid var (--entry-border-color );
88+ top : -1px ;
89+ bottom : -1px ;
90+ left : 2px ;
91+ width : 100% ;
92+ .rounded-corners (0.25em );
93+ }
94+
95+ & :after {
96+ left : 5px ; // 2px before + 1px border + 2px after
97+ }
6498 }
6599 }
66100 }
You can’t perform that action at this time.
0 commit comments