Skip to content

Commit

Permalink
Support mute, unmute and notification suppression (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
nilmerg authored Jul 5, 2024
2 parents 3b469ea + 223ec05 commit 9f4658b
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 20 deletions.
4 changes: 4 additions & 0 deletions library/Notifications/Common/Icons.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ private function __construct()

public const CUSTOM = 'message';

public const MUTE = 'volume-xmark';

public const UNMUTE = 'volume-high';

public const SEVERITY_OK = 'heart';

public const SEVERITY_CRIT = 'circle-exclamation';
Expand Down
23 changes: 17 additions & 6 deletions library/Notifications/Model/Behavior/IdTagAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use ipl\Sql\Adapter\Pgsql;
use ipl\Stdlib\Filter;

use function ipl\Stdlib\iterable_key_first;

class IdTagAggregator extends PropertyBehavior implements RewriteColumnBehavior, QueryAwareBehavior
{
/** @var Query */
Expand All @@ -37,10 +39,14 @@ public function rewriteColumn($column, ?string $relation = null)
$path = ($relation ?? $this->query->getModel()->getTableAlias()) . '.object_id_tag';

$this->query->utilize($path);
$pathAlias = $this->query->getResolver()->getAlias(
$this->query->getResolver()->resolveRelation($path)->getTarget()
);

$pathRelation = $this->query->getResolver()->resolveRelation($path);
if ($relation !== null) {
// TODO: This is really another case where ipl-orm could automatically adjust the join type...
$pathRelation->setJoinType($this->query->getResolver()->resolveRelation($relation)->getJoinType());
}

$pathAlias = $this->query->getResolver()->getAlias($pathRelation->getTarget());
$myAlias = $this->query->getResolver()->getAlias(
$relation
? $this->query->getResolver()->resolveRelation($relation)->getTarget()
Expand All @@ -49,8 +55,8 @@ public function rewriteColumn($column, ?string $relation = null)

return new AliasedExpression("{$myAlias}_id_tags", sprintf(
$this->query->getDb()->getAdapter() instanceof Pgsql
? 'json_object_agg(%s, %s)'
: 'json_objectagg(%s, %s)',
? 'json_object_agg(COALESCE(%s, \'\'), %s)'
: 'json_objectagg(COALESCE(%s, \'\'), %s)',
$this->query->getResolver()->qualifyColumn('tag', $pathAlias),
$this->query->getResolver()->qualifyColumn('value', $pathAlias)
));
Expand All @@ -68,7 +74,12 @@ public function fromDb($value, $key, $context)
return [];
}

return json_decode($value, true) ?? [];
$tags = json_decode($value, true) ?? [];
if (iterable_key_first($tags) === '') {
return [];
}

return $tags;
}

public function toDb($value, $key, $context)
Expand Down
21 changes: 20 additions & 1 deletion library/Notifications/Model/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Common\Icons;
use ipl\Orm\Behavior\Binary;
use ipl\Orm\Behavior\BoolCast;
use ipl\Orm\Behavior\MillisecondTimestamp;
use ipl\Orm\Behaviors;
use ipl\Orm\Model;
Expand All @@ -27,6 +28,8 @@
* @property ?string $severity
* @property ?string $message
* @property ?string $username
* @property ?bool $mute
* @property ?string $mute_reason
*
* @property Query | Objects $object
* @property Query | IncidentHistory $incident_history
Expand All @@ -53,6 +56,8 @@ public function getColumns()
'severity',
'message',
'username',
'mute',
'mute_reason'
];
}

Expand All @@ -64,7 +69,9 @@ public function getColumnDefinitions()
'type' => t('Type'),
'severity' => t('Severity'),
'message' => t('Message'),
'username' => t('Username')
'username' => t('Username'),
'mute' => t('Mute'),
'mute_reason' => t('Mute Reason')
];
}

Expand Down Expand Up @@ -95,6 +102,7 @@ public function createBehaviors(Behaviors $behaviors)
{
$behaviors->add(new MillisecondTimestamp(['time']));
$behaviors->add(new Binary(['object_id']));
$behaviors->add(new BoolCast(['mute']));
}

public function createRelations(Relations $relations)
Expand Down Expand Up @@ -188,6 +196,10 @@ public function getTypeText(): string
return t('left a flapping period', 'notifications.type');
case 'incident-age':
return t('exceeded a time constraint', 'notifications.type');
case 'mute':
return t('was muted', 'notifications.type');
case 'unmute':
return t('was unmuted', 'notifications.type');
default: // custom
return '';
}
Expand Down Expand Up @@ -259,6 +271,13 @@ public function getIcon(): ?Icon
break;
case 'custom':
$icon = new Icon(Icons::CUSTOM);
break;
case 'mute':
$icon = new Icon(Icons::MUTE);
break;
case 'unmute':
$icon = new Icon(Icons::UNMUTE);
break;
}

return $icon;
Expand Down
2 changes: 2 additions & 0 deletions library/Notifications/Model/IncidentHistory.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ public static function translateNotificationState(string $state): string
return t('failed', 'notifications.transmission.state');
case 'pending':
return t('pending', 'notifications.transmission.state');
case 'suppressed':
return t('suppressed', 'notifications.transmission.state');
default:
return t('unknown', 'notifications.transmission.state');
}
Expand Down
4 changes: 3 additions & 1 deletion library/Notifications/Model/Objects.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* @property string $host
* @property ?string $service
* @property ?string $url
* @property ?string $mute_reason
*
* @property Query | Event $event
* @property Query | Incident $incident
Expand All @@ -48,7 +49,8 @@ public function getColumns()
return [
'source_id',
'name',
'url'
'url',
'mute_reason'
];
}

Expand Down
34 changes: 29 additions & 5 deletions library/Notifications/Widget/Detail/EventDetail.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,48 @@ protected function createInfo(): array
$info[] = new HorizontalKeyValue(t('Severity'), $severity);
}

if ($this->event->mute !== null) {
$info[] = new HorizontalKeyValue(
t('Muted'),
$this->event->mute ? t('Yes') : t('No')
);
}

return $info;
}

/** @return ValidHtml[] */
protected function createMessage(): array
{
return [
Html::tag('h2', t('Message')),
Html::tag(
$messages = [];

if ($this->event->mute_reason !== null) {
$messages[] = Html::tag('h2', t('Mute Reason'));
$messages[] = Html::tag(
'div',
[
'id' => 'mute-reason-' . $this->event->id,
'class' => 'collapsible',
'data-visible-height' => 100
],
$this->event->mute_reason
);
}

if ($this->event->message !== null) {
$messages[] = Html::tag('h2', t('Message'));
$messages[] = Html::tag(
'div',
[
'id' => 'message-' . $this->event->id,
'class' => 'collapsible',
'data-visible-height' => 100
],
$this->event->message
)
];
);
}

return $messages;
}

/** @return ValidHtml[] */
Expand Down
23 changes: 19 additions & 4 deletions library/Notifications/Widget/ItemList/EventListItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\Model\Objects;
use Icinga\Module\Notifications\Model\Source;
use Icinga\Module\Notifications\Widget\IconBall;
use Icinga\Module\Notifications\Widget\SourceIcon;
use InvalidArgumentException;
use ipl\Html\BaseHtmlElement;
use ipl\Html\Html;
use ipl\Html\HtmlElement;
use ipl\Stdlib\Str;
use ipl\Web\Common\BaseListItem;
use ipl\Web\Widget\Icon;
use ipl\Web\Widget\Link;
use ipl\Web\Widget\TimeAgo;

Expand Down Expand Up @@ -82,7 +79,25 @@ protected function assembleTitle(BaseHtmlElement $title): void

protected function assembleCaption(BaseHtmlElement $caption): void
{
$caption->add($this->item->message);
switch ($this->item->type) {
case 'mute':
case 'unmute':
case 'flapping-start':
case 'flapping-end':
case 'downtime-start':
case 'downtime-end':
case 'downtime-removed':
case 'acknowledgement-set':
case 'acknowledgement-cleared':
if ($this->item->mute_reason !== null) {
$caption->add($this->item->mute_reason);
break;
}

// Sometimes these events have no mute reason, but a message
default:
$caption->add($this->item->message);
}
}

protected function assembleHeader(BaseHtmlElement $header): void
Expand Down
16 changes: 16 additions & 0 deletions library/Notifications/Widget/ItemList/IncidentHistoryListItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ protected function getIncidentEventIcon(): string
switch ($this->item->type) {
case 'opened':
return Icons::OPENED;
case 'muted':
return Icons::MUTE;
case 'unmuted':
return Icons::UNMUTE;
case 'incident_severity_changed':
return $this->getSeverityIcon();
case 'recipient_role_changed':
Expand Down Expand Up @@ -180,6 +184,10 @@ protected function buildMessage(): string
);
}

if ($this->item->notification_state === 'suppressed') {
$this->getAttributes()->add('class', 'notification-suppressed');
}

break;
case 'incident_severity_changed':
$message = sprintf(
Expand Down Expand Up @@ -251,6 +259,14 @@ protected function buildMessage(): string
$this->item->rule_escalation->name
);

break;
case 'muted':
$message = t('Notifications for this incident have been muted');

break;
case 'unmuted':
$message = t('Notifications for this incident have been unmuted');

break;
default:
$message = '';
Expand Down
4 changes: 4 additions & 0 deletions library/Notifications/Widget/ItemList/IncidentListItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ protected function assembleHeader(BaseHtmlElement $header): void
$header->add($this->createTitle());
$meta = new HtmlElement('span', Attributes::create(['class' => 'meta']));

if ($this->item->severity !== 'ok' && $this->item->object->mute_reason !== null) {
$meta->addHtml(new Icon(Icons::MUTE, ['title' => $this->item->object->mute_reason]));
}

/** @var Source $source */
$source = $this->item->object->source;
$meta->addHtml((new SourceIcon(SourceIcon::SIZE_BIG))->addHtml($source->getIcon()));
Expand Down
5 changes: 2 additions & 3 deletions public/css/common.less
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@

.event-list .list-item,
.incident-list .list-item {
.meta .source-icon {
margin-left: auto;
.meta > :not(:last-child) {
margin-right: 0.5em;
}
}
}
4 changes: 4 additions & 0 deletions public/css/detail/incident-detail.less
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@
}
}
}

.list-item.notification-suppressed {
opacity: .75;
}
}

0 comments on commit 9f4658b

Please sign in to comment.