Skip to content

Commit 49d332a

Browse files
(WIP): Display the skipped notifications if any in the detail view
1 parent c47296b commit 49d332a

8 files changed

Lines changed: 197 additions & 13 deletions

File tree

library/Notifications/Model/Contactgroup.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @property Query|RuleEscalationRecipient $rule_escalation_recipient
3030
* @property Query|IncidentHistory $incident_history
3131
* @property Query|NotificationHistory $notification_history
32+
* @property Query|SkippedNotificationHistory $skipped_notification_history
3233
*/
3334
class Contactgroup extends Model
3435
{
@@ -90,5 +91,7 @@ public function createRelations(Relations $relations): void
9091
->setJoinType('LEFT');
9192
$relations->hasMany('notification_history', NotificationHistory::class)
9293
->setJoinType('LEFT');
94+
$relations->hasMany('skipped_notification_history', SkippedNotificationHistory::class)
95+
->setJoinType('LEFT');
9396
}
9497
}

library/Notifications/Model/NotificationHistory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* @property Query|Contactgroup $contactgroup
4242
* @property Query|Channel $channel
4343
* @property Query|Schedule $schedule
44+
* @property Query|SkippedNotificationHistory $skipped
4445
*/
4546
class NotificationHistory extends Model
4647
{
@@ -110,6 +111,8 @@ public function createRelations(Relations $relations): void
110111
$relations->belongsTo('contactgroup', Contactgroup::class)->setJoinType('LEFT');
111112
$relations->belongsTo('channel', Channel::class)->setJoinType('LEFT');
112113
$relations->belongsTo('schedule', Schedule::class)->setJoinType('LEFT');
114+
$relations->hasMany('skipped', SkippedNotificationHistory::class)
115+
->setJoinType('LEFT');
113116
}
114117

115118
public static function on(Connection $db): Query

library/Notifications/Model/Rule.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* @property Query|Incident $incident
2828
* @property Query|IncidentHistory $incident_history
2929
* @property Query|NotificationHistory $notification_history
30+
* @property Query|SkippedNotificationHistory $skipped_notification_history
3031
*/
3132
class Rule extends Model
3233
{
@@ -92,5 +93,7 @@ public function createRelations(Relations $relations): void
9293
$relations->hasMany('incident_history', IncidentHistory::class)->setJoinType('LEFT');
9394
$relations->hasMany('notification_history', NotificationHistory::class)
9495
->setJoinType('LEFT');
96+
$relations->hasMany('skipped_notification_history', SkippedNotificationHistory::class)
97+
->setJoinType('LEFT');
9598
}
9699
}

library/Notifications/Model/RuleEscalation.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* @property Query|RuleEscalationRecipient $rule_escalation_recipient
3232
* @property Query|IncidentHistory $incident_history
3333
* @property Query|NotificationHistory $notification_history
34+
* @property Query|SkippedNotificationHistory $skipped_notification_history
3435
*/
3536
class RuleEscalation extends Model
3637
{
@@ -113,5 +114,7 @@ public function createRelations(Relations $relations): void
113114
->setJoinType('LEFT');
114115
$relations->hasMany('notification_history', NotificationHistory::class)
115116
->setJoinType('LEFT');
117+
$relations->hasMany('skipped_notification_history', SkippedNotificationHistory::class)
118+
->setJoinType('LEFT');
116119
}
117120
}

library/Notifications/Model/Schedule.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* @property Query|IncidentHistory $incident_history
2626
* @property Query|RuleEscalation $rule_escalation
2727
* @property Query|NotificationHistory $notification_history
28+
* @property Query|SkippedNotificationHistory $skipped_notification_history
2829
*/
2930
class Schedule extends Model
3031
{
@@ -85,5 +86,7 @@ public function createRelations(Relations $relations): void
8586
->setJoinType('LEFT');
8687
$relations->hasMany('notification_history', NotificationHistory::class)
8788
->setJoinType('LEFT');
89+
$relations->hasMany('skipped_notification_history', SkippedNotificationHistory::class)
90+
->setJoinType('LEFT');
8891
}
8992
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
// SPDX-FileCopyrightText: 2026 Icinga GmbH <https://icinga.com>
4+
// SPDX-License-Identifier: GPL-3.0-or-later
5+
6+
namespace Icinga\Module\Notifications\Model;
7+
8+
use DateTime;
9+
use Icinga\Module\Notifications\Common\Model;
10+
use ipl\Orm\Behavior\MillisecondTimestamp;
11+
use ipl\Orm\Behaviors;
12+
use ipl\Orm\Query;
13+
use ipl\Orm\Relations;
14+
15+
/**
16+
* NotificationHistory
17+
*
18+
* @property int $id
19+
* @property int $notification_history_id
20+
* @property int $event_id
21+
* @property int $rule_id
22+
* @property int $rule_escalation_id
23+
* @property ?int $contactgroup_id
24+
* @property int $channel_id
25+
* @property ?int $schedule_id
26+
* @property DateTime $triggered_at
27+
*
28+
* @property Query|Incident $incident
29+
* @property Query|Rule $rule
30+
* @property Query|RuleEscalation $rule_escalation
31+
* @property Query|Contactgroup $contactgroup
32+
* @property Query|Channel $channel
33+
* @property Query|Schedule $schedule
34+
*/
35+
class SkippedNotificationHistory extends Model
36+
{
37+
public function getTableName(): string
38+
{
39+
return 'skipped_notification_history';
40+
}
41+
42+
public function getKeyName(): string
43+
{
44+
return 'id';
45+
}
46+
47+
public function getColumns(): array
48+
{
49+
return [
50+
'notification_history_id',
51+
'rule_id',
52+
'rule_escalation_id',
53+
'contactgroup_id',
54+
'schedule_id'
55+
];
56+
}
57+
58+
public function createRelations(Relations $relations): void
59+
{
60+
$relations->belongsTo('rule', Rule::class);
61+
$relations->belongsTo('rule_escalation', RuleEscalation::class);
62+
$relations->belongsTo('notification_history', NotificationHistory::class);
63+
64+
$relations->belongsTo('contactgroup', Contactgroup::class)->setJoinType('LEFT');
65+
$relations->belongsTo('channel', Channel::class)->setJoinType('LEFT');
66+
$relations->belongsTo('schedule', Schedule::class)->setJoinType('LEFT');
67+
}
68+
}

library/Notifications/Widget/Detail/NotificationHistoryDetail.php

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Icinga\Module\Notifications\Common\Auth;
99
use Icinga\Module\Notifications\Common\EscalationConditionDescriber;
10+
use Icinga\Module\Notifications\Common\NotificationTransmissionReason;
1011
use Icinga\Module\Notifications\Model\NotificationHistory;
1112
use Icinga\Module\Notifications\View\IncidentRenderer;
1213
use Icinga\Module\Notifications\Widget\ItemList\ObjectList;
@@ -122,17 +123,24 @@ protected function createIncident(): ?array
122123

123124
protected function createReason(): array
124125
{
125-
return [
126-
new HtmlElement('h2', content: Text::create($this->translate('Trigger Chain'))),
126+
$triggerChain = new HtmlElement(
127+
'div',
128+
Attributes::create(['class' => 'trigger-chain']),
127129
new HtmlElement(
128-
'div',
129-
Attributes::create(['class' => 'trigger-chain']),
130-
new HtmlElement(
131-
'span',
132-
Attributes::create(['class' => 'item']),
133-
Text::create($this->notificationHistory->reason->getLabel())
134-
),
135-
//TODO: in case MUTE, UNMUTE, notifiaction is snet with rule<escalation triggered>, fix chain down below
130+
'span',
131+
Attributes::create(['class' => 'item']),
132+
Text::create($this->notificationHistory->reason->getLabel())
133+
)
134+
);
135+
136+
if (
137+
! in_array(
138+
$this->notificationHistory->reason,
139+
[NotificationTransmissionReason::MUTED, NotificationTransmissionReason::UNMUTED],
140+
true
141+
)
142+
) {
143+
$triggerChain->addHtml(
136144
new HtmlElement(
137145
'span',
138146
Attributes::create(['class' => 'item']),
@@ -151,7 +159,43 @@ protected function createReason(): array
151159
Attributes::create(['class' => 'item']),
152160
$this->notificationHistory->state->getIcon()
153161
)
154-
)
162+
);
163+
}
164+
165+
$query = $this->notificationHistory->skipped
166+
->with([
167+
'contactgroup',
168+
'schedule',
169+
'rule',
170+
'rule_escalation'
171+
]);
172+
$skip = [];
173+
foreach ($query as $skipped) {
174+
$skip[] = new HtmlElement('li', Attributes::create(['class' => 'popup-item']), Text::create(
175+
sprintf(
176+
'Rule: %s, Escalation: %s, Schedule: %s, Contactgroup: %s',
177+
$skipped->rule->name,
178+
$skipped->rule_escalation->position,
179+
$skipped->schedule->name,
180+
$skipped->contactgroup->name
181+
)
182+
));
183+
}
184+
185+
if (! empty($skip)) {
186+
$triggerChain->addHtml(
187+
new HtmlElement(
188+
'ul',
189+
Attributes::create(['class' => 'skipped']),
190+
Text::create(sprintf($this->translate('(%s Skipped)'), count($skip))),
191+
new HtmlElement('div', Attributes::create(['class' => ['popup']]), ...$skip)
192+
)
193+
);
194+
}
195+
196+
return [
197+
new HtmlElement('h2', content: Text::create($this->translate('Trigger Chain'))),
198+
$triggerChain
155199
];
156200
}
157201

public/css/detail/notification-history-detail.less

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
cursor: pointer;
2525
}
2626

27-
28-
&:not(:last-child):after {
27+
&:has(~ .item):after {
2928
content: "";
3029
display: block;
3130
position: absolute;
@@ -42,6 +41,50 @@
4241
.item:not(:first-child) {
4342
padding-left: 2em;
4443
}
44+
45+
.skipped {
46+
color: @default-text-color-light;
47+
position: relative;
48+
margin-left: 0.5em;
49+
padding: 0;
50+
51+
.popup {
52+
list-style: none;
53+
position: absolute;
54+
padding: 0 0.5em;
55+
right: 0;
56+
top: 3em;
57+
z-index: 1;
58+
width: max-content;
59+
display: none;
60+
61+
&:before {
62+
content: '';
63+
position: absolute;
64+
display: inline-block;
65+
width: 1.5em;
66+
height: 1.5em;
67+
right: 1.5em;
68+
top: ~"calc(-0.75em - 1px)";
69+
border-left: 1px solid @gray-light;
70+
border-top: 1px solid @gray-light;
71+
transform: rotate(45deg);
72+
}
73+
74+
.popup-item {
75+
padding: .5em 0;
76+
77+
&:not(:last-child) {
78+
border-bottom: 1px solid @gray-light;
79+
}
80+
}
81+
}
82+
83+
&:hover .popup {
84+
display: flex;
85+
flex-direction: column;
86+
}
87+
}
4588
}
4689

4790
// style
@@ -54,5 +97,19 @@
5497
.item {
5598
.notification-icon-ball-state();
5699
}
100+
101+
.skipped .popup {
102+
border: 1px solid @gray-light;
103+
background-color: @body-bg-color;
104+
border-radius: .25em;
105+
106+
&:before {
107+
background-color: @body-bg-color;
108+
}
109+
110+
.popup-item:not(:last-child) {
111+
border-bottom: 1px solid @gray-light;
112+
}
113+
}
57114
}
58115
}

0 commit comments

Comments
 (0)