Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion application/controllers/IncidentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

use Icinga\Module\Notifications\Common\Auth;
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Common\Links;
use Icinga\Module\Notifications\Hook\ObjectsRendererHook;
use Icinga\Module\Notifications\Model\Contact;
use Icinga\Module\Notifications\View\IncidentRenderer;
use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\Widget\ItemList\ObjectList;
use ipl\Orm\Query;
use ipl\Sql\Expression;
use ipl\Stdlib\Filter;
use ipl\Web\Compat\CompatController;
use ipl\Web\Compat\SearchControls;
Expand All @@ -20,6 +24,7 @@
use ipl\Web\Layout\MinimalItemLayout;
use ipl\Web\Widget\ItemList;
use ipl\Web\Widget\ListItem;
use ipl\Web\Widget\Tabs;

class IncidentsController extends CompatController
{
Expand All @@ -31,7 +36,7 @@ class IncidentsController extends CompatController

public function indexAction(): void
{
$this->addTitleTab(t('Incidents'));
$this->getTabs()->activate('incidents');

$incidents = Incident::on(Database::get())
->with(['object', 'object.source'])
Expand Down Expand Up @@ -128,4 +133,29 @@ public function getFilter(): Filter\Rule

return $this->filter;
}

public function getTabs(): Tabs
{
$tabs = parent::getTabs();

$tabs->add('incidents', [
'label' => t('Incidents'),
'url' => $this->getRequest()->getUrl(),
'baseTarget' => '_main'
]);

$contact = Contact::on(Database::get())
->columns([new Expression('1')])
->filter(Filter::equal('username', $this->Auth()->getUser()->getUsername()))
->first();
if ($contact !== null) {
$tabs->add('my-incidents', [
'label' => t('My Incidents'),
'url' => Links::myIncidents(),
'baseTarget' => '_main'
]);
}

return $tabs;
}
}
147 changes: 147 additions & 0 deletions application/controllers/MyIncidentsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

/* Icinga Notifications Web | (c) 2025 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Notifications\Controllers;

use Icinga\Module\Notifications\Common\Auth;
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Common\Links;
use Icinga\Module\Notifications\Hook\ObjectsRendererHook;
use Icinga\Module\Notifications\Model\Contact;
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\View\IncidentRenderer;
use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Notifications\Widget\ItemList\ObjectList;
use ipl\Sql\Expression;
use ipl\Stdlib\Filter;
use ipl\Web\Compat\CompatController;
use ipl\Web\Compat\SearchControls;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Filter\QueryString;
use ipl\Web\Layout\MinimalItemLayout;
use ipl\Web\Widget\ItemList;
use ipl\Web\Widget\ListItem;
use ipl\Web\Widget\Tabs;

class MyIncidentsController extends CompatController
{
use Auth;
use SearchControls;

/** @var Filter\Rule Filter from query string parameters */
private $filter;

public function indexAction(): void
{
$this->getTabs()->activate('my-incidents');

$incidents = Incident::on(Database::get())
->with(['object', 'object.source'])
->withColumns('object.id_tags')
->filter(Filter::equal('contact.username', $this->Auth()->getUser()->getUsername()));

$limitControl = $this->createLimitControl();
$sortControl = $this->createSortControl(
$incidents,
[
'incident.severity desc, incident.started_at' => t('Severity'),
'incident.started_at desc' => t('Opened On'),
'incident.recovered_at' => t('Recovered At'),
]
);

$paginationControl = $this->createPaginationControl($incidents);
$searchBar = $this->createSearchBar($incidents, [
$limitControl->getLimitParam(),
$sortControl->getSortParam(),
]);

if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) {
if ($searchBar->hasBeenSubmitted()) {
$filter = QueryString::parse((string) $this->params);
} else {
$this->addControl($searchBar);
$this->sendMultipartUpdate();
return;
}
} else {
$filter = $searchBar->getFilter();
}

$this->applyRestrictions($incidents);
$incidents->filter($filter);

$this->addControl($paginationControl);
$this->addControl($sortControl);
$this->addControl($limitControl);
$this->addControl($searchBar);

$incidentList = (new ObjectList($incidents, new IncidentRenderer()))
->setItemLayoutClass(MinimalItemLayout::class)
->on(ItemList::ON_ITEM_ADD, function (ListItem $item, Incident $data) {
ObjectsRendererHook::register($data->object);
})
->on(ItemList::ON_ASSEMBLED, function () {
ObjectsRendererHook::load();
});

$this->addContent($incidentList);

if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {
$this->sendMultipartUpdate();
}

$this->setAutorefreshInterval(10);
}

public function completeAction(): void
{
$suggestions = new ObjectSuggestions();
$suggestions->setModel(Incident::class);
$suggestions->forRequest($this->getServerRequest());
$this->getDocument()->add($suggestions);
}

public function searchEditorAction(): void
{
$editor = $this->createSearchEditor(Incident::on(Database::get()), [
LimitControl::DEFAULT_LIMIT_PARAM,
SortControl::DEFAULT_SORT_PARAM,
]);

$this->getDocument()->add($editor);
$this->setTitle(t('Adjust Filter'));
}

protected function getPageSize($default)
{
return parent::getPageSize($default ?? 50);
}

public function getTabs(): Tabs
{
$tabs = parent::getTabs();

$tabs->add('incidents', [
'label' => t('Incidents'),
'url' => Links::incidents(),
'baseTarget' => '_main'
]);

$contact = Contact::on(Database::get())
->columns([new Expression('1')])
->filter(Filter::equal('username', $this->Auth()->getUser()->getUsername()))
->first();
if ($contact !== null) {
$tabs->add('my-incidents', [
'label' => t('My Incidents'),
'url' => $this->getRequest()->getUrl(),
'baseTarget' => '_main'
]);
}

return $tabs;
}
}
14 changes: 9 additions & 5 deletions configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Icinga\Application\Modules\Module;
use Icinga\Authentication\Auth;
use Icinga\Module\Notifications\Common\Links;
use ipl\Stdlib\Filter;

/** @var Module $this */

Expand All @@ -21,11 +23,11 @@
$configLandingPage = null;
if ($authenticated) {
if ($auth->hasPermission('notifications/config/schedules')) {
$configLandingPage = 'notifications/schedules';
$configLandingPage = Links::schedules()->getAbsoluteUrl();
} elseif ($auth->hasPermission('notifications/config/event-rules')) {
$configLandingPage = 'notifications/event-rules';
$configLandingPage = Links::eventRules()->getAbsoluteUrl();
} elseif ($auth->hasPermission('notifications/config/contacts')) {
$configLandingPage = 'notifications/contacts';
$configLandingPage = Links::contacts()->getAbsoluteUrl();
}
}

Expand All @@ -34,7 +36,9 @@
[
'icon' => 'th-list',
'description' => $this->translate('Open Incidents'),
'url' => 'notifications/incidents?incident.severity!=ok',
'url' => Links::incidents()
->setFilter(Filter::unequal('incident.severity', 'ok'))
->getAbsoluteUrl(),
'priority' => 10
]
);
Expand All @@ -44,7 +48,7 @@
[
'icon' => 'history',
'description' => $this->translate('Events'),
'url' => 'notifications/events',
'url' => Links::events()->getAbsoluteUrl(),
'priority' => 20
]
);
Expand Down
9 changes: 7 additions & 2 deletions library/Notifications/Common/Links.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,21 @@ public static function events(): Url
return Url::fromPath('notifications/events');
}

public static function incidents(): Url
public static function myIncidents(): Url
{
return Url::fromPath('notifications/incidents');
return Url::fromPath('notifications/my-incidents');
}

public static function incident(int $id): Url
{
return Url::fromPath('notifications/incident', ['id' => $id]);
}

public static function incidents(): Url
{
return Url::fromPath('notifications/incidents');
}

public static function contacts(): Url
{
return Url::fromPath('notifications/contacts');
Expand Down
Loading