diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index af681a13..ef1feae9 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -2,18 +2,21 @@ namespace Icinga\Module\Eagle\Controllers; -use Exception; use Icinga\Exception\NotFoundError; use Icinga\Module\Eagle\Common\CommandActions; use Icinga\Module\Eagle\Common\HostLinks; use Icinga\Module\Eagle\Common\Links; use Icinga\Module\Eagle\Model\History; use Icinga\Module\Eagle\Model\Host; +use Icinga\Module\Eagle\Model\Service; use Icinga\Module\Eagle\Web\Controller; use Icinga\Module\Eagle\Widget\Detail\ObjectDetail; use Icinga\Module\Eagle\Widget\Detail\QuickActions; +use Icinga\Module\Eagle\Widget\DowntimeList; use Icinga\Module\Eagle\Widget\HostList; +use Icinga\Module\Eagle\Widget\ItemList\CommentList; use Icinga\Module\Eagle\Widget\ItemList\HistoryList; +use Icinga\Module\Eagle\Widget\ServiceList; class HostController extends Controller { @@ -59,6 +62,44 @@ class HostController extends Controller $this->addContent(new ObjectDetail($this->host)); } + public function commentsAction() + { + $this->setTitle($this->translate('Comments')); + + $this->addControl((new HostList([$this->host]))->setViewMode('compact')); + + $comments = $this->host->comment; + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($comments); + + yield $this->export($comments); + + $this->addControl($paginationControl); + $this->addControl($limitControl); + + $this->addContent(new CommentList($comments)); + } + + public function downtimesAction() + { + $this->setTitle($this->translate('Downtimes')); + + $this->addControl((new HostList([$this->host]))->setViewMode('compact')); + + $downtimes = $this->host->downtime; + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($downtimes); + + yield $this->export($downtimes); + + $this->addControl($paginationControl); + $this->addControl($limitControl); + + $this->addContent(new DowntimeList($downtimes)); + } + public function historyAction() { $this->addControl((new HostList([$this->host]))->setViewMode('compact')); @@ -92,6 +133,38 @@ class HostController extends Controller $this->addContent(new HistoryList($history)); } + public function servicesAction() + { + $this->addControl((new HostList([$this->host]))->setViewMode('compact')); + + $db = $this->getDb(); + + $services = Service::on($db)->with([ + 'state', + 'host', + 'host.state' + ]); + + $services + ->getSelectBase() + ->where(['service_host.id = ?' => $this->host->id]); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($services); + $viewModeSwitcher = $this->createViewModeSwitcher(); + + yield $this->export($services); + + $serviceList = (new ServiceList($services)) + ->setViewMode($viewModeSwitcher->getViewMode()); + + $this->addControl($paginationControl); + $this->addControl($viewModeSwitcher); + $this->addControl($limitControl); + + $this->addContent($serviceList); + } + protected function createTabs() { return $this @@ -100,6 +173,10 @@ class HostController extends Controller 'label' => $this->translate('Host'), 'url' => Links::host($this->host) ]) + ->add('services', [ + 'label' => $this->translate('Services'), + 'url' => HostLinks::services($this->host) + ]) ->add('history', [ 'label' => $this->translate('History'), 'url' => HostLinks::history($this->host) diff --git a/application/controllers/HostgroupController.php b/application/controllers/HostgroupController.php new file mode 100644 index 00000000..b7991349 --- /dev/null +++ b/application/controllers/HostgroupController.php @@ -0,0 +1,67 @@ +setTitle($this->translate('Host Group')); + + $name = $this->params->shiftRequired('name'); + + $query = Hostgroupsummary::on($this->getDb()); + + FilterProcessor::apply( + new FilterExpression('hostgroup.name', '=', $name), + $query + ); + + $hostgroup = $query->first(); + if ($hostgroup === null) { + throw new NotFoundError($this->translate('Host group not found')); + } + + $this->hostgroup = $hostgroup; + } + public function indexAction() + { + $this->addControl((new HostgroupList([$this->hostgroup]))); + + $db = $this->getDb(); + + $hosts = Host::on($db)->with('state'); + + FilterProcessor::apply( + new FilterExpression('hostgroup.id', '=', $this->hostgroup->id), + $hosts + ); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($hosts); + $viewModeSwitcher = $this->createViewModeSwitcher(); + + $hostList = (new HostList($hosts)) + ->setViewMode($viewModeSwitcher->getViewMode()); + + yield $this->export($hosts); + + $this->addControl($paginationControl); + $this->addControl($viewModeSwitcher); + $this->addControl($limitControl); + + $this->addContent($hostList); + } +} diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index ebde328c..237ed72b 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -12,6 +12,9 @@ use Icinga\Module\Eagle\Model\Service; use Icinga\Module\Eagle\Web\Controller; use Icinga\Module\Eagle\Widget\Detail\ObjectDetail; use Icinga\Module\Eagle\Widget\Detail\QuickActions; +use Icinga\Module\Eagle\Widget\DowntimeList; +use Icinga\Module\Eagle\Widget\HostList; +use Icinga\Module\Eagle\Widget\ItemList\CommentList; use Icinga\Module\Eagle\Widget\ItemList\HistoryList; use Icinga\Module\Eagle\Widget\ServiceList; use ipl\Sql\Sql; @@ -66,6 +69,44 @@ class ServiceController extends Controller $this->addContent(new ObjectDetail($this->service)); } + public function commentsAction() + { + $this->setTitle($this->translate('Comments')); + + $this->addControl((new ServiceList([$this->service]))->setViewMode('compact')); + + $comments = $this->service->comment; + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($comments); + + yield $this->export($comments); + + $this->addControl($paginationControl); + $this->addControl($limitControl); + + $this->addContent(new CommentList($comments)); + } + + public function downtimesAction() + { + $this->setTitle($this->translate('Downtimes')); + + $this->addControl((new ServiceList([$this->service]))->setViewMode('compact')); + + $downtimes = $this->service->downtime; + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($downtimes); + + yield $this->export($downtimes); + + $this->addControl($paginationControl); + $this->addControl($limitControl); + + $this->addContent(new DowntimeList($downtimes)); + } + public function historyAction() { $this->addControl((new ServiceList([$this->service]))->setViewMode('compact')); diff --git a/application/controllers/ServicegroupController.php b/application/controllers/ServicegroupController.php new file mode 100644 index 00000000..98314476 --- /dev/null +++ b/application/controllers/ServicegroupController.php @@ -0,0 +1,71 @@ +setTitle($this->translate('Service Group')); + + $name = $this->params->shiftRequired('name'); + + $query = Servicegroupsummary::on($this->getDb()); + + FilterProcessor::apply( + new FilterExpression('servicegroup.name', '=', $name), + $query + ); + + $servicegroup = $query->first(); + if ($servicegroup === null) { + throw new NotFoundError($this->translate('Service group not found')); + } + + $this->servicegroup = $servicegroup; + } + public function indexAction() + { + $this->addControl((new ServicegroupList([$this->servicegroup]))); + + $db = $this->getDb(); + + $services = Service::on($db)->with([ + 'state', + 'host', + 'host.state' + ]); + + FilterProcessor::apply( + new FilterExpression('servicegroup.id', '=', $this->servicegroup->id), + $services + ); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($services); + $viewModeSwitcher = $this->createViewModeSwitcher(); + + $serviceList = (new ServiceList($services)) + ->setViewMode($viewModeSwitcher->getViewMode()); + + yield $this->export($services); + + $this->addControl($paginationControl); + $this->addControl($viewModeSwitcher); + $this->addControl($limitControl); + + $this->addContent($serviceList); + } +} diff --git a/application/controllers/UserController.php b/application/controllers/UserController.php new file mode 100644 index 00000000..e4d18ef5 --- /dev/null +++ b/application/controllers/UserController.php @@ -0,0 +1,58 @@ +setTitle($this->translate('User')); + + $name = $this->params->shiftRequired('name'); + + $query = User::on($this->getDb()); + $query->getSelectBase() + ->where(['name = ?' => $name]); + + $user = $query->first(); + if ($user === null) { + throw new NotFoundError($this->translate('User not found')); + } + + $this->user = $user; + } + + public function indexAction() + { + $this->addControl(new UserList([$this->user])); + + $this->addContent(Html::tag('h2', 'Details')); + $this->addContent(Html::tag('ul', ['class' => 'key-value-list'], [ + Html::tag('li', [ + Html::tag('span', ['class' => 'label'], 'E-Mail'), + Html::tag( + 'span', + ['class' => 'value'], + $this->user->email ?: Html::tag('span', ['class' => 'text-muted'], 'Unset') + ) + ]), + Html::tag('li', [ + Html::tag('span', ['class' => 'label'], 'Pager'), + Html::tag( + 'span', + ['class' => 'value'], + $this->user->pager ?: Html::tag('span', ['class' => 'text-muted'], 'Unset') + ) + ]) + ])); + } +} diff --git a/library/Eagle/Common/HostLinks.php b/library/Eagle/Common/HostLinks.php index 55b9d2d4..99f01cb7 100644 --- a/library/Eagle/Common/HostLinks.php +++ b/library/Eagle/Common/HostLinks.php @@ -56,4 +56,9 @@ abstract class HostLinks { return Url::fromPath('eagle/host/send-custom-notification', ['name' => $host->name]); } + + public static function services(Host $host) + { + return Url::fromPath('eagle/host/services', ['name' => $host->name]); + } } diff --git a/library/Eagle/Common/Links.php b/library/Eagle/Common/Links.php index 8728aa16..6e3453a7 100644 --- a/library/Eagle/Common/Links.php +++ b/library/Eagle/Common/Links.php @@ -28,7 +28,7 @@ abstract class Links return Url::fromPath('eagle/host', ['name' => $host->name]); } - public static function hostgroup(Hostgroup $hostgroup) + public static function hostgroup($hostgroup) { return Url::fromPath('eagle/hostgroup', ['name' => $hostgroup->name]); } @@ -38,7 +38,7 @@ abstract class Links return Url::fromPath('eagle/service', ['name' => $service->name, 'host.name' => $host->name]); } - public static function servicegroup(Servicegroup $servicegroup) + public static function servicegroup($servicegroup) { return Url::fromPath('eagle/servicegroup', ['name' => $servicegroup->name]); } diff --git a/library/Eagle/Model/Hostgroupsummary.php b/library/Eagle/Model/Hostgroupsummary.php index 21b77e2e..a253006e 100644 --- a/library/Eagle/Model/Hostgroupsummary.php +++ b/library/Eagle/Model/Hostgroupsummary.php @@ -14,7 +14,7 @@ class Hostgroupsummary extends UnionModel public function getKeyName() { - return 'hostgroup_id'; + return ['id' => 'hostgroup_id']; } public function getColumns() diff --git a/library/Eagle/Model/ServicegroupSummary.php b/library/Eagle/Model/ServicegroupSummary.php index 2f6af318..dcbe321e 100644 --- a/library/Eagle/Model/ServicegroupSummary.php +++ b/library/Eagle/Model/ServicegroupSummary.php @@ -14,7 +14,7 @@ class ServicegroupSummary extends UnionModel public function getKeyName() { - return 'servicegroup_id'; + return ['id' => 'servicegroup_id']; } public function getColumns() diff --git a/library/Eagle/Widget/Detail/ObjectDetail.php b/library/Eagle/Widget/Detail/ObjectDetail.php index c8261152..60640002 100644 --- a/library/Eagle/Widget/Detail/ObjectDetail.php +++ b/library/Eagle/Widget/Detail/ObjectDetail.php @@ -73,7 +73,7 @@ class ObjectDetail extends BaseHtmlElement return [ Html::tag('h2', 'Downtimes'), - new DowntimeList($this->object->downtime), + new DowntimeList($downtimes), new ShowMore($downtimes, $link) ]; } diff --git a/library/Eagle/Widget/ItemList/HostgroupListItem.php b/library/Eagle/Widget/ItemList/HostgroupListItem.php index 191d0ebd..009290e9 100644 --- a/library/Eagle/Widget/ItemList/HostgroupListItem.php +++ b/library/Eagle/Widget/ItemList/HostgroupListItem.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Eagle\Widget\ItemList; use Icinga\Chart\Donut; use Icinga\Module\Eagle\Common\BaseTableRowItem; +use Icinga\Module\Eagle\Common\Links; use Icinga\Module\Eagle\Widget\HostStateBadges; use Icinga\Module\Eagle\Widget\ServiceStateBadges; use Icinga\Module\Eagle\Widget\VerticalKeyValue; @@ -11,6 +12,7 @@ use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\HtmlDocument; use ipl\Html\HtmlString; +use ipl\Web\Widget\Link; class HostgroupListItem extends BaseTableRowItem { @@ -56,7 +58,7 @@ class HostgroupListItem extends BaseTableRowItem protected function assembleTitle(BaseHtmlElement $title) { $title->add([ - $this->item->display_name, + new Link($this->item->display_name, Links::hostgroup($this->item)), Html::tag('br'), $this->item->name ]); diff --git a/library/Eagle/Widget/ItemList/ServicegroupListItem.php b/library/Eagle/Widget/ItemList/ServicegroupListItem.php index 4afeaddd..71e7fb89 100644 --- a/library/Eagle/Widget/ItemList/ServicegroupListItem.php +++ b/library/Eagle/Widget/ItemList/ServicegroupListItem.php @@ -4,12 +4,14 @@ namespace Icinga\Module\Eagle\Widget\ItemList; use Icinga\Chart\Donut; use Icinga\Module\Eagle\Common\BaseTableRowItem; +use Icinga\Module\Eagle\Common\Links; use Icinga\Module\Eagle\Widget\ServiceStateBadges; use Icinga\Module\Eagle\Widget\VerticalKeyValue; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\HtmlDocument; use ipl\Html\HtmlString; +use ipl\Web\Widget\Link; class ServicegroupListItem extends BaseTableRowItem { @@ -39,7 +41,7 @@ class ServicegroupListItem extends BaseTableRowItem protected function assembleTitle(BaseHtmlElement $title) { $title->add([ - $this->item->display_name, + new Link($this->item->display_name, Links::servicegroup($this->item)), Html::tag('br'), $this->item->name ]); diff --git a/library/Eagle/Widget/ItemList/UserListItem.php b/library/Eagle/Widget/ItemList/UserListItem.php index c3774abf..c10b04ec 100644 --- a/library/Eagle/Widget/ItemList/UserListItem.php +++ b/library/Eagle/Widget/ItemList/UserListItem.php @@ -2,8 +2,10 @@ namespace Icinga\Module\Eagle\Widget\ItemList; +use Icinga\Module\Eagle\Common\Links; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Link; class UserListItem extends BaseHtmlElement { @@ -25,9 +27,9 @@ class UserListItem extends BaseHtmlElement Html::tag('div', ['class' => 'user-ball'], $this->item->display_name[0]) ]), Html::tag('div', ['class' => 'title col'], [ - $this->item->name, + new Link($this->item->display_name, Links::user($this->item)), Html::tag('br'), - $this->item->display_name + $this->item->name ]), Html::tag('div', ['class' => 'col'], $this->item->email), Html::tag('div', ['class' => 'col'], $this->item->pager) diff --git a/library/Eagle/Widget/ItemList/UsergroupListItem.php b/library/Eagle/Widget/ItemList/UsergroupListItem.php index d85d7576..d674f82a 100644 --- a/library/Eagle/Widget/ItemList/UsergroupListItem.php +++ b/library/Eagle/Widget/ItemList/UsergroupListItem.php @@ -2,8 +2,10 @@ namespace Icinga\Module\Eagle\Widget\ItemList; +use Icinga\Module\Eagle\Common\Links; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Link; class UsergroupListItem extends BaseHtmlElement { @@ -25,9 +27,9 @@ class UsergroupListItem extends BaseHtmlElement Html::tag('div', ['class' => 'usergroup-ball'], $this->item->display_name[0]) ]), Html::tag('div', ['class' => 'title col'], [ - $this->item->name, + new Link($this->item->display_name, Links::usergroup($this->item)), Html::tag('br'), - $this->item->display_name + $this->item->name ]) ]); } diff --git a/public/css/module.less b/public/css/module.less index b5c1c372..39bfd265 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -228,6 +228,10 @@ text-align: center; } +.text-muted { + color: @gray; +} + .comment-detail button { .button(); background-color: white; diff --git a/public/css/widgets.less b/public/css/widgets.less index 1a1c6ccf..10ab5036 100644 --- a/public/css/widgets.less +++ b/public/css/widgets.less @@ -177,6 +177,7 @@ padding: 0; } } + .state-change { .state-ball { box-shadow: 0 0 0 1px white; @@ -191,3 +192,23 @@ background-color: white; } } + +.key-value-list { + list-style-type: none; + margin: 0; + padding: 0; + + li { + display: flex; + } + + li > span { + padding: .25em; + + &.label { + display: block; + padding-left: 0; + width: 12em; + } + } +}