File tree 4 files changed +119
-11
lines changed
library/Notifications/Widget
4 files changed +119
-11
lines changed Original file line number Diff line number Diff line change 7
7
use DateInterval ;
8
8
use DateTime ;
9
9
use Generator ;
10
+ use Icinga \Module \Notifications \Widget \Timeline \FutureEntry ;
10
11
use ipl \Html \Attributes ;
11
12
use ipl \Html \BaseHtmlElement ;
12
13
use ipl \Html \HtmlElement ;
@@ -421,6 +422,20 @@ final protected function yieldFixedEntries(Traversable $entries): Generator
421
422
}
422
423
423
424
$ 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
+
424
439
if ($ rowStart > $ lastRow ) {
425
440
$ lastRow = $ rowStart ;
426
441
}
Original file line number Diff line number Diff line change 14
14
use Icinga \Module \Notifications \Widget \TimeGrid \Timescale ;
15
15
use Icinga \Module \Notifications \Widget \TimeGrid \Util ;
16
16
use Icinga \Module \Notifications \Widget \Timeline \Entry ;
17
+ use Icinga \Module \Notifications \Widget \Timeline \FutureEntry ;
17
18
use Icinga \Module \Notifications \Widget \Timeline \MinimalGrid ;
18
19
use Icinga \Module \Notifications \Widget \Timeline \Rotation ;
19
20
use IntlDateFormatter ;
@@ -173,7 +174,9 @@ public function getEntries(): Traversable
173
174
174
175
$ occupiedCells = [];
175
176
foreach ($ rotations as $ rotation ) {
177
+ $ entryFound = false ;
176
178
foreach ($ rotation ->fetchTimeperiodEntries ($ this ->start , $ this ->getGrid ()->getGridEnd ()) as $ entry ) {
179
+ $ entryFound = true ;
177
180
if (! $ this ->minimalLayout ) {
178
181
$ entry ->setPosition ($ maxPriority - $ rotation ->getPriority ());
179
182
@@ -182,6 +185,10 @@ public function getEntries(): Traversable
182
185
183
186
$ occupiedCells += $ getDesiredCells ($ entry );
184
187
}
188
+
189
+ if (! $ entryFound && ! $ this ->minimalLayout ) {
190
+ yield (new FutureEntry ())->setPosition ($ maxPriority - $ rotation ->getPriority ());
191
+ }
185
192
}
186
193
187
194
$ 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 48
48
}
49
49
}
50
50
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
+ }
55
68
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 ;
61
72
62
- .name {
63
- .text-ellipsis ();
73
+ .entry {
74
+ display : flex ;
75
+ align-items : center ;
76
+ justify-content : center ;
77
+
78
+ position : relative ;
79
+ padding-left : 6px ; // 2px before + 1px border + 2px after + 1px border
80
+
81
+ width : 3em ;
82
+ flex-shrink : 0 ;
83
+
84
+ & :before ,
85
+ & :after {
86
+ content : ' ' ;
87
+ display : block ;
88
+ position : absolute ;
89
+ border : 1px solid var (--entry-border-color );
90
+ border-right : transparent ;
91
+ height : ~ " calc(100% + 2px)" ; // border top and bottom
92
+ width : 100% ;
93
+ left : 2px ;
94
+ .rounded-corners (0.25em );
95
+ }
96
+
97
+ & :after {
98
+ left : 5px ; // 2px before + 1px border + 2px after
99
+ }
64
100
}
65
101
}
66
102
}
You can’t perform that action at this time.
0 commit comments