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 4444 }
4545 }
4646
47- .overlay .entry {
48- margin-top : 1em ;
49- margin-bottom : 1em ;
50- z-index : 2 ; // overlap the .clock .time-hand
47+ .overlay {
48+ .entry {
49+ margin-top : 1em ;
50+ margin-bottom : 1em ;
51+ z-index : 2 ; // overlap the .clock .time-hand
52+
53+ .title {
54+ height : 100% ;
55+ flex-wrap : nowrap ;
56+ align-items : baseline ;
57+ padding : .15em .5em ;
58+
59+ .name {
60+ .text-ellipsis ();
61+ }
62+ }
63+ }
5164
52- .title {
53- height : 100% ;
54- flex-wrap : nowrap ;
55- align-items : baseline ;
56- padding : .15em .5em ;
65+ .future-entry {
66+ display : flex ;
67+ justify-content : end ;
5768
58- .name {
59- .text-ellipsis ();
69+ .entry {
70+ display : flex ;
71+ align-items : center ;
72+ justify-content : end ;
73+ flex-shrink : 0 ;
74+ position : relative ;
75+ padding-right : .25em ;
76+ width : 3em ;
77+
78+ & :before ,
79+ & :after {
80+ content : ' ' ;
81+ display : block ;
82+ position : absolute ;
83+ border : 1px solid var (--entry-border-color );
84+ top : -1px ;
85+ bottom : -1px ;
86+ left : 2px ;
87+ width : 100% ;
88+ .rounded-corners (0.25em );
89+ }
90+
91+ & :after {
92+ left : 5px ; // 2px before + 1px border + 2px after
93+ }
6094 }
6195 }
6296 }
You can’t perform that action at this time.
0 commit comments