summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:43:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:43:29 +0000
commita9b77c01caef9ae7a2c84e2333d28ceb028cf4d3 (patch)
tree4a77cd3e323c37b0e5b3d7578b9718cdf1a89262 /application
parentInitial commit. (diff)
downloadicingaweb2-module-eventdb-1a36f15b29b09992b11f58c551921fdbe500402a.tar.xz
icingaweb2-module-eventdb-1a36f15b29b09992b11f58c551921fdbe500402a.zip
Adding upstream version 1.3.0.upstream/1.3.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'application')
-rw-r--r--application/controllers/CommentsController.php17
-rw-r--r--application/controllers/ConfigController.php45
-rw-r--r--application/controllers/EventController.php216
-rw-r--r--application/controllers/EventsController.php186
-rw-r--r--application/controllers/IndexController.php14
-rw-r--r--application/forms/Config/BackendConfigForm.php112
-rw-r--r--application/forms/Config/GlobalConfigForm.php32
-rw-r--r--application/forms/Config/MonitoringConfigForm.php72
-rw-r--r--application/forms/Event/EventCommentForm.php144
-rw-r--r--application/forms/Events/AckFilterForm.php80
-rw-r--r--application/forms/Events/SeverityFilterForm.php224
-rw-r--r--application/locale/de_DE/LC_MESSAGES/eventdb.mobin0 -> 6301 bytes
-rw-r--r--application/locale/de_DE/LC_MESSAGES/eventdb.po413
-rw-r--r--application/views/helpers/Column.php51
-rw-r--r--application/views/helpers/ColumnHeader.php17
-rw-r--r--application/views/helpers/Event.php12
-rw-r--r--application/views/helpers/EventMessage.php70
-rw-r--r--application/views/scripts/config/index.phtml21
-rw-r--r--application/views/scripts/config/monitoring.phtml7
-rw-r--r--application/views/scripts/event/index-plain.phtml62
-rw-r--r--application/views/scripts/event/index.phtml174
-rw-r--r--application/views/scripts/events/details-plain.phtml18
-rw-r--r--application/views/scripts/events/details.phtml50
-rw-r--r--application/views/scripts/events/index-plain.phtml19
-rw-r--r--application/views/scripts/events/index.phtml93
-rw-r--r--application/views/scripts/format/text.phtml13
26 files changed, 2162 insertions, 0 deletions
diff --git a/application/controllers/CommentsController.php b/application/controllers/CommentsController.php
new file mode 100644
index 0000000..a371c7b
--- /dev/null
+++ b/application/controllers/CommentsController.php
@@ -0,0 +1,17 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Controllers;
+
+use Icinga\Module\Eventdb\EventdbController;
+
+class CommentsController extends EventdbController
+{
+ /**
+ * @deprecated Moved to eventdb/events/details
+ */
+ public function newAction()
+ {
+ $this->redirectNow($this->getRequest()->getUrl()->setPath('eventdb/events/details'));
+ }
+}
diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php
new file mode 100644
index 0000000..d812918
--- /dev/null
+++ b/application/controllers/ConfigController.php
@@ -0,0 +1,45 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Controllers;
+
+use Icinga\Module\Eventdb\Forms\Config\BackendConfigForm;
+use Icinga\Module\Eventdb\Forms\Config\GlobalConfigForm;
+use Icinga\Module\Eventdb\Forms\Config\MonitoringConfigForm;
+use Icinga\Web\Controller;
+
+class ConfigController extends Controller
+{
+ public function init()
+ {
+ $this->assertPermission('config/modules');
+ parent::init();
+ }
+
+ public function indexAction()
+ {
+ $backendConfig = new BackendConfigForm();
+ $backendConfig
+ ->setIniConfig($this->Config())
+ ->handleRequest();
+ $this->view->backendConfig = $backendConfig;
+
+ $globalConfig = new GlobalConfigForm();
+ $globalConfig
+ ->setIniConfig($this->Config())
+ ->handleRequest();
+ $this->view->globalConfig = $globalConfig;
+
+ $this->view->tabs = $this->Module()->getConfigTabs()->activate('config');
+ }
+
+ public function monitoringAction()
+ {
+ $monitoringConfig = new MonitoringConfigForm();
+ $monitoringConfig
+ ->setIniConfig($this->Config())
+ ->handleRequest();
+ $this->view->form = $monitoringConfig;
+ $this->view->tabs = $this->Module()->getConfigTabs()->activate('monitoring');
+ }
+}
diff --git a/application/controllers/EventController.php b/application/controllers/EventController.php
new file mode 100644
index 0000000..f6a323c
--- /dev/null
+++ b/application/controllers/EventController.php
@@ -0,0 +1,216 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Controllers;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Exception\NotFoundError;
+use Icinga\Module\Eventdb\Event;
+use Icinga\Module\Eventdb\EventdbController;
+use Icinga\Module\Eventdb\Forms\Event\EventCommentForm;
+use Icinga\Module\Eventdb\Hook\DetailviewExtensionHook;
+use Icinga\Module\Eventdb\Web\EventdbOutputFormat;
+use Icinga\Web\Hook;
+use Icinga\Web\Url;
+
+class EventController extends EventdbController
+{
+ public function indexAction()
+ {
+ $eventId = $this->params->getRequired('id');
+
+ $url = Url::fromRequest();
+
+ $this->getTabs()->add('event', array(
+ 'active' => ! $this->isFormatRequest(),
+ 'title' => $this->translate('Event'),
+ 'url' => $url->without(array('format'))
+ ))->extend(new EventdbOutputFormat(array(), array(EventdbOutputFormat::TYPE_TEXT)));
+
+ $columnConfig = $this->Config('columns');
+ if (! $columnConfig->isEmpty()) {
+ $additionalColumns = $columnConfig->keys();
+ } else {
+ $additionalColumns = array();
+ }
+
+ $event = $this->getDb()
+ ->select()
+ ->from('event');
+
+ $columns = array_merge($event->getColumns(), $additionalColumns);
+
+ $event->from('event', $columns);
+ $event->where('id', $eventId);
+
+ $event->applyFilter(Filter::matchAny(array_map(
+ '\Icinga\Data\Filter\Filter::fromQueryString',
+ $this->getRestrictions('eventdb/events/filter', 'eventdb/events')
+ )));
+
+ $eventData = $event->fetchRow();
+ if (! $eventData) {
+ throw new NotFoundError('Could not find event with id %d', $eventId);
+ }
+
+ $eventObj = Event::fromData($eventData);
+
+ $groupedEvents = null;
+ if ($this->getDb()->hasCorrelatorExtensions()) {
+ $group_leader = (int) $eventObj->group_leader;
+ if ($group_leader > 0) {
+ // redirect to group leader
+ $this->redirectNow(Url::fromPath('eventdb/event', array('id' => $group_leader)));
+ }
+
+ if ($group_leader === -1) {
+ // load grouped events, if any
+ $groupedEvents = $this->getDb()
+ ->select()
+ ->from('event')
+ ->where('group_leader', $eventObj->id)
+ ->order('ack', 'ASC')
+ ->order('created', 'DESC');
+ }
+ }
+
+ $comments = null;
+ $commentForm = null;
+ if ($this->hasPermission('eventdb/comments')) {
+ $comments = $this->getDb()
+ ->select()
+ ->from('comment', array(
+ 'id',
+ 'type',
+ 'message',
+ 'created',
+ 'modified',
+ 'user'
+ ))
+ ->where('event_id', $eventId)
+ ->order('created', 'DESC');
+
+ if ($this->hasPermission('eventdb/interact')) {
+ $commentForm = new EventCommentForm();
+ $commentForm
+ ->setDb($this->getDb())
+ ->setFilter(Filter::expression('id', '=', $eventId));
+ }
+ }
+
+ $format = $this->params->get('format');
+ if ($format === 'sql') {
+ $this->sendSqlSummary(array($event, $comments, $groupedEvents));
+ } elseif ($this->isApiRequest()) {
+ $data = new \stdClass;
+ $data->event = $eventData;
+ if ($comments !== null) {
+ $data->comments = $comments;
+ }
+ if ($groupedEvents !== null) {
+ $data->groupedEvents = $groupedEvents;
+ }
+ $this->sendJson($data);
+ } elseif ($this->isTextRequest()) {
+ $this->view->event = $eventObj;
+ $this->view->columnConfig = $columnConfig;
+ $this->view->additionalColumns = $additionalColumns;
+ $this->view->groupedEvents = $groupedEvents;
+ $this->view->comments = $comments;
+
+ $this->sendText(null, 'event/index-plain');
+ } else {
+ if ($commentForm !== null) {
+ $commentForm->handleRequest();
+ }
+
+ $this->view->event = $eventObj;
+ $this->view->columnConfig = $columnConfig;
+ $this->view->additionalColumns = $additionalColumns;
+ $this->view->groupedEvents = $groupedEvents;
+ $this->view->comments = $comments;
+ $this->view->commentForm = $commentForm;
+
+ $this->view->extensionsHtml = array();
+ foreach (Hook::all('Eventdb\DetailviewExtension') as $hook) {
+ /** @var DetailviewExtensionHook $hook */
+ $module = $this->view->escape($hook->getModule()->getName());
+ $this->view->extensionsHtml[] =
+ '<div class="icinga-module module-' . $module . '" data-icinga-module="' . $module . '">'
+ . $hook->setView($this->view)->getHtmlForEvent($eventObj)
+ . '</div>';
+ }
+ }
+ }
+
+ /**
+ * @deprecated redirects to index view now
+ */
+ public function commentsAction()
+ {
+ $this->redirectNow(
+ Url::fromPath(
+ 'eventdb/event',
+ array('id' => $this->params->getRequired('id'))
+ )
+ );
+ }
+
+ /**
+ * Action allowing you to be forwarded to host in Icinga monitoring
+ *
+ * **But** case insensitive!
+ */
+ public function hostAction()
+ {
+ $host = $this->params->getRequired('host');
+
+ $backend = $this->monitoringBackend();
+
+ $query = $backend->select()
+ ->from('hoststatus', array('host_name'))
+ ->where('host', $host);
+
+ $realHostname = $query->fetchOne();
+
+ if ($realHostname !== null && $realHostname !== false) {
+ $this->redirectNow(Url::fromPath('monitoring/host/services', array('host' => $realHostname)));
+ } else {
+ throw new NotFoundError('Could not find a hostname matching: %s', $host);
+ }
+ }
+
+ /**
+ * Action allowing you to be forwarded to host in Icinga monitoring
+ *
+ * **But** case insensitive!
+ */
+ public function serviceAction()
+ {
+ $host = $this->params->getRequired('host');
+ $service = $this->params->getRequired('service');
+
+ $backend = $this->monitoringBackend();
+
+ $query = $backend->select()
+ ->from('servicestatus', array('host_name', 'service'))
+ ->where('host', $host)
+ ->where('service', $service);
+
+ $realService = $query->fetchRow();
+
+ if ($realService !== null && $realService !== false) {
+ $this->redirectNow(
+ Url::fromPath(
+ 'monitoring/service/show',
+ array(
+ 'host' => $realService->host_name,
+ 'service' => $realService->service
+ )
+ )
+ );
+ } else {
+ throw new NotFoundError('Could not find a service "%s" for host "%s"', $service, $host);
+ }
+ }
+}
diff --git a/application/controllers/EventsController.php b/application/controllers/EventsController.php
new file mode 100644
index 0000000..09e5a8d
--- /dev/null
+++ b/application/controllers/EventsController.php
@@ -0,0 +1,186 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Controllers;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Module\Eventdb\EventdbController;
+use Icinga\Module\Eventdb\Forms\Event\EventCommentForm;
+use Icinga\Module\Eventdb\Forms\Events\AckFilterForm;
+use Icinga\Module\Eventdb\Forms\Events\SeverityFilterForm;
+use Icinga\Module\Eventdb\Hook\DetailviewExtensionHook;
+use Icinga\Module\Eventdb\Web\EventdbOutputFormat;
+use Icinga\Util\StringHelper;
+use Icinga\Web\Hook;
+use Icinga\Web\Url;
+
+class EventsController extends EventdbController
+{
+ public function init()
+ {
+ parent::init();
+ $this->view->title = 'EventDB: ' . $this->translate('Events');
+ }
+
+ public function indexAction()
+ {
+ $this->assertPermission('eventdb/events');
+
+ $this->getTabs()->add('events', array(
+ 'active' => ! $this->isFormatRequest(),
+ 'title' => $this->translate('Events'),
+ 'url' => Url::fromRequest()->without(array('format'))
+ ))->extend(new EventdbOutputFormat(array(), array(EventdbOutputFormat::TYPE_TEXT)));
+
+ $columnConfig = $this->Config('columns');
+ if ($this->params->has('columns')) {
+ $additionalColumns = StringHelper::trimSplit($this->params->get('columns'));
+ } elseif (! $columnConfig->isEmpty()) {
+ $additionalColumns = $columnConfig->keys();
+ } else {
+ $additionalColumns = array();
+ }
+
+ $events = $this->getDb()->select()
+ ->from('event');
+
+ $columns = array_merge($events->getColumns(), $additionalColumns);
+ $events->columns($columns);
+
+ $events->applyFilter(Filter::matchAny(array_map(
+ '\Icinga\Data\Filter\Filter::fromQueryString',
+ $this->getRestrictions('eventdb/events/filter', 'eventdb/events')
+ )));
+
+ $this->getDb()->filterGroups($events);
+
+ $this->setupPaginationControl($events);
+
+ $this->setupFilterControl(
+ $events,
+ array(
+ 'host_name' => $this->translate('Host'),
+ 'host_address' => $this->translate('Host Address'),
+ 'type' => $this->translate('Type'),
+ 'program' => $this->translate('Program'),
+ 'facility' => $this->translate('Facility'),
+ 'priority' => $this->translate('Priority'),
+ 'message' => $this->translate('Message'),
+ 'ack' => $this->translate('Acknowledged'),
+ 'created' => $this->translate('Created')
+ ),
+ array('host_name'),
+ array('columns', 'format')
+ );
+
+ $this->setupLimitControl();
+
+ $this->setupSortControl(
+ array(
+ 'host_name' => $this->translate('Host'),
+ 'host_address' => $this->translate('Host Address'),
+ 'type' => $this->translate('Type'),
+ 'program' => $this->translate('Program'),
+ 'facility' => $this->translate('Facility'),
+ 'priority' => $this->translate('Priority'),
+ 'message' => $this->translate('Message'),
+ 'ack' => $this->translate('Acknowledged'),
+ 'created' => $this->translate('Created')
+ ),
+ $events,
+ array('created' => 'desc')
+ );
+
+ if ($this->view->compact) {
+ $events->peekAhead();
+ }
+
+ if ($this->params->get('format') === 'sql') {
+ $this->sendSqlSummary($events);
+ } elseif ($this->isApiRequest()) {
+ $data = new \stdClass;
+ $data->events = $events->fetchAll();
+ $this->sendJson($data);
+ exit;
+ } elseif ($this->isTextRequest()) {
+ $this->view->columnConfig = $this->Config('columns');
+ $this->view->additionalColumns = $additionalColumns;
+ $this->view->events = $events;
+
+ $this->sendText(null, 'events/index-plain');
+ } else {
+ $this->setAutorefreshInterval(15);
+
+ $severityFilterForm = new SeverityFilterForm();
+ $severityFilterForm->handleRequest();
+
+ $ackFilterForm = new AckFilterForm();
+ $ackFilterForm->handleRequest();
+
+ $this->view->ackFilterForm = $ackFilterForm;
+ $this->view->columnConfig = $this->Config('columns');
+ $this->view->additionalColumns = $additionalColumns;
+ $this->view->events = $events;
+ $this->view->severityFilterForm = $severityFilterForm;
+ }
+ }
+
+ public function detailsAction()
+ {
+ $this->assertPermission('eventdb/events');
+
+ $url = Url::fromRequest()->without(array('format'));
+
+ $this->getTabs()->add('events', array(
+ 'active' => ! $this->isFormatRequest(),
+ 'title' => $this->translate('Events'),
+ 'url' => $url
+ ))->extend(new EventdbOutputFormat(array(), array(EventdbOutputFormat::TYPE_TEXT)));
+
+ $events = $this->getDb()
+ ->select()
+ ->from('event');
+
+ $this->getDb()->filterGroups($events);
+
+ $filter = Filter::fromQueryString($url->getQueryString());
+ $events->applyFilter($filter);
+
+ $events->applyFilter(Filter::matchAny(array_map(
+ '\Icinga\Data\Filter\Filter::fromQueryString',
+ $this->getRestrictions('eventdb/events/filter', 'eventdb/events')
+ )));
+
+ if ($this->isApiRequest()) {
+ $this->sendJson($events->fetchAll());
+ } elseif ($this->isTextRequest()) {
+ $this->view->events = $events->fetchAll();
+ $this->view->columnConfig = $this->Config('columns');
+
+ $this->sendText(null, 'events/details-plain');
+ } else {
+ $commentForm = null;
+ if ($this->hasPermission('eventdb/interact')) {
+ $commentForm = new EventCommentForm();
+ $commentForm
+ ->setDb($this->getDb())
+ ->setFilter($filter)
+ ->handleRequest();
+ $this->view->commentForm = $commentForm;
+ }
+
+ $this->view->events = $events->fetchAll();
+ $this->view->columnConfig = $this->Config('columns');
+
+ $this->view->extensionsHtml = array();
+ foreach (Hook::all('Eventdb\DetailviewExtension') as $hook) {
+ /** @var DetailviewExtensionHook $hook */
+ $module = $this->view->escape($hook->getModule()->getName());
+ $this->view->extensionsHtml[] =
+ '<div class="icinga-module module-' . $module . '" data-icinga-module="' . $module . '">'
+ . $hook->setView($this->view)->getHtmlForEvents($this->view->events)
+ . '</div>';
+ }
+ }
+ }
+}
diff --git a/application/controllers/IndexController.php b/application/controllers/IndexController.php
new file mode 100644
index 0000000..5322936
--- /dev/null
+++ b/application/controllers/IndexController.php
@@ -0,0 +1,14 @@
+<?php
+/* Icinga Web 2 | (c) 2018 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Controllers;
+
+use Icinga\Web\Controller;
+
+class IndexController extends Controller
+{
+ public function indexAction()
+ {
+ $this->redirectNow('eventdb/events');
+ }
+}
diff --git a/application/forms/Config/BackendConfigForm.php b/application/forms/Config/BackendConfigForm.php
new file mode 100644
index 0000000..a9c85c1
--- /dev/null
+++ b/application/forms/Config/BackendConfigForm.php
@@ -0,0 +1,112 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Config;
+
+use Exception;
+use Icinga\Data\ResourceFactory;
+use Icinga\Forms\ConfigForm;
+
+/**
+ * Form for managing the connection to the EventDB backend
+ */
+class BackendConfigForm extends ConfigForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setSubmitLabel($this->translate('Save'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $resources = array();
+ foreach (ResourceFactory::getResourceConfigs() as $name => $config) {
+ if ($config->type === 'db') {
+ $resources[] = $name;
+ }
+ }
+
+ $this->addElement(
+ 'select',
+ 'backend_resource',
+ array(
+ 'description' => $this->translate('The resource to use'),
+ 'label' => $this->translate('Resource'),
+ 'multiOptions' => array_combine($resources, $resources),
+ 'required' => true
+ )
+ );
+
+ if (isset($formData['skip_validation']) && $formData['skip_validation']) {
+ $this->addSkipValidationCheckbox();
+ }
+ }
+
+ /**
+ * Return whether the given values are valid
+ *
+ * @param array $formData The data to validate
+ *
+ * @return bool
+ */
+ public function isValid($formData)
+ {
+ if (! parent::isValid($formData)) {
+ return false;
+ }
+
+ if (($el = $this->getElement('skip_validation')) === null || ! $el->isChecked()) {
+ $resourceConfig = ResourceFactory::getResourceConfig($this->getValue('backend_resource'));
+
+ if (! $this->isValidEventDbSchema($resourceConfig)) {
+ if ($el === null) {
+ $this->addSkipValidationCheckbox();
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function isValidEventDbSchema($resourceConfig)
+ {
+ try {
+ $db = ResourceFactory::createResource($resourceConfig);
+ $db->select()->from('event', array('id'))->fetchOne();
+ } catch (Exception $_) {
+ $this->error($this->translate(
+ 'Cannot find the EventDB schema. Please verify that the given database '
+ . 'contains the schema and that the configured user has access to it.'
+ ));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add a checkbox to the form by which the user can skip the schema validation
+ */
+ protected function addSkipValidationCheckbox()
+ {
+ $this->addElement(
+ 'checkbox',
+ 'skip_validation',
+ array(
+ 'description' => $this->translate(
+ 'Check this to not to validate the EventDB schema of the chosen resource'
+ ),
+ 'ignore' => true,
+ 'label' => $this->translate('Skip Validation'),
+ 'order' => 0
+ )
+ );
+ }
+}
diff --git a/application/forms/Config/GlobalConfigForm.php b/application/forms/Config/GlobalConfigForm.php
new file mode 100644
index 0000000..5b4bf2a
--- /dev/null
+++ b/application/forms/Config/GlobalConfigForm.php
@@ -0,0 +1,32 @@
+<?php
+/* Icinga Web 2 - EventDB | (c) 2018 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Config;
+
+use Icinga\Forms\ConfigForm;
+
+class GlobalConfigForm extends ConfigForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setSubmitLabel($this->translate('Save'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'text',
+ 'global_default_filter',
+ array(
+ 'description' => $this->translate('Filter to be used by the menu link for EventDB by default'),
+ 'label' => $this->translate('Default Filter')
+ )
+ );
+ }
+}
diff --git a/application/forms/Config/MonitoringConfigForm.php b/application/forms/Config/MonitoringConfigForm.php
new file mode 100644
index 0000000..e1c7638
--- /dev/null
+++ b/application/forms/Config/MonitoringConfigForm.php
@@ -0,0 +1,72 @@
+<?php
+/* Icinga Web 2 - EventDB | (c) 2017 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Config;
+
+use Icinga\Forms\ConfigForm;
+
+/**
+ * Form for managing settings for the integration into monitoring module
+ */
+class MonitoringConfigForm extends ConfigForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setSubmitLabel($this->translate('Save'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'text',
+ 'monitoring_custom_var',
+ array(
+ 'description' => $this->translate('Name of the custom variable to enable EventDB integration for (usually "edb")'),
+ 'label' => $this->translate('Custom Variable')
+ )
+ );
+
+ $this->addElement(
+ 'checkbox',
+ 'monitoring_always_on_host',
+ array(
+ 'description' => $this->translate('Always enable the integration on hosts, even when the custom variable is not set'),
+ 'label' => $this->translate('Always enable for hosts')
+ )
+ );
+
+ $this->addElement(
+ 'checkbox',
+ 'monitoring_always_on_service',
+ array(
+ 'description' => $this->translate('Always enable the integration on services, even when the custom variable is not set'),
+ 'label' => $this->translate('Always enable for services')
+ )
+ );
+
+ $this->addElement(
+ 'checkbox',
+ 'monitoring_detailview_disable',
+ array(
+ 'description' => $this->translate('Disable the detail view inside the monitoring module'),
+ 'label' => $this->translate('Disable the detail view')
+ )
+ );
+
+ $this->addElement(
+ 'text',
+ 'monitoring_detailview_filter',
+ array(
+ 'description' => $this->translate('Filter events in the detail view area inside the monitoring module'),
+ 'label' => $this->translate('Filter the detail view'),
+ 'value' => 'ack=0', // Also see DetailviewExtension
+ )
+ );
+ }
+}
diff --git a/application/forms/Event/EventCommentForm.php b/application/forms/Event/EventCommentForm.php
new file mode 100644
index 0000000..130910c
--- /dev/null
+++ b/application/forms/Event/EventCommentForm.php
@@ -0,0 +1,144 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Event;
+
+use Exception;
+use Icinga\Data\Filter\Filter;
+use Icinga\Module\Eventdb\Eventdb;
+use Icinga\Web\Form;
+
+/**
+ * Form for managing the connection to the EventDB backend
+ */
+class EventCommentForm extends Form
+{
+ /**
+ * @var Eventdb
+ */
+ protected $db;
+
+ protected $filter;
+
+ protected static $types = array(
+ 'comment',
+ 'ack',
+ 'revoke'
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public static $defaultElementDecorators = array(
+ array('ViewHelper', array('separator' => '')),
+ array('Errors', array('separator' => '')),
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setSubmitLabel($this->translate('Submit'));
+ }
+
+ public function setDb(Eventdb $db)
+ {
+ $this->db = $db;
+ return $this;
+ }
+
+ public function setFilter(Filter $filter)
+ {
+ $this->filter = $filter;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'select',
+ 'type',
+ array(
+ 'label' => $this->translate('Type'),
+ 'multiOptions' => array(
+ 0 => $this->translate('Comment'),
+ 1 => $this->translate('Acknowledge'),
+ 2 => $this->translate('Revoke')
+ ),
+ 'required' => true,
+ 'value' => 1,
+ )
+ );
+ $this->addElement(
+ 'text',
+ 'comment',
+ array(
+ 'label' => $this->translate('Comment'),
+ 'required' => true
+ )
+ );
+ }
+
+ public function onSuccess()
+ {
+ $type = $this->getValue('type');
+ $comment = $this->getValue('comment');
+ $username = $this->Auth()->getUser()->getUsername();
+
+ $events = $this->db->select()->from('event', array('id'))->applyFilter($this->filter);
+
+ $dbAdapter = $this->db->getDataSource()->getDbAdapter();
+
+ $dbAdapter->beginTransaction();
+ try {
+ foreach ($events as $event) {
+ $this->db->insert('comment', array(
+ 'event_id' => $event->id,
+ 'type' => $type,
+ 'message' => $comment,
+ 'created' => date(Eventdb::DATETIME_FORMAT),
+ 'modified' => date(Eventdb::DATETIME_FORMAT),
+ 'user' => $username
+ ));
+
+ if ($type !== '0') {
+ $ackFilter = Filter::expression('id', '=', $event->id);
+ if ($this->db->hasCorrelatorExtensions()) {
+ $ackFilter = Filter::matchAny($ackFilter, Filter::where('group_leader', $event->id));
+ }
+ $this->db->update('event', array(
+ 'ack' => $type === '1' ? 1 : 0
+ ), $ackFilter);
+ }
+ }
+ $dbAdapter->commit();
+ return true;
+ } catch (Exception $e) {
+ $dbAdapter->rollback();
+ $this->error($e->getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function loadDefaultDecorators()
+ {
+ parent::loadDefaultDecorators();
+
+ $this->removeDecorator('FormHints');
+ }
+
+ public function addSubmitButton()
+ {
+ parent::addSubmitButton();
+
+ $btn = $this->getElement('btn_submit');
+ $btn->removeDecorator('HtmlTag');
+ }
+}
diff --git a/application/forms/Events/AckFilterForm.php b/application/forms/Events/AckFilterForm.php
new file mode 100644
index 0000000..829c6ce
--- /dev/null
+++ b/application/forms/Events/AckFilterForm.php
@@ -0,0 +1,80 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Events;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Web\Form;
+
+class AckFilterForm extends Form
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline ack-filter-form');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubmitButton()
+ {
+ if ((bool) $this->getRequest()->getUrl()->getParams()->get('ack', true)) {
+ $icon = 'ok';
+ $title = $this->translate('Hide acknowledged events');
+ } else {
+ $icon = 'cancel';
+ $title = $this->translate('Show also acknowledged events');
+ }
+
+ $this->addElements(array(
+ array(
+ 'button',
+ 'btn_submit',
+ array(
+ 'class' => 'link-button spinner',
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ ),
+ 'escape' => false,
+ 'ignore' => true,
+ 'label' => $this->getView()->icon($icon) . $this->translate('Ack'),
+ 'type' => 'submit',
+ 'title' => $title,
+ 'value' => $this->translate('Ack')
+ )
+ )
+ ));
+
+ return $this;
+ }
+
+ public function onSuccess()
+ {
+ $redirect = clone $this->getRequest()->getUrl();
+ $params = $redirect->getParams();
+ $modifyFilter = $params->shift('modifyFilter');
+ $columns = $params->shift('columns');
+ if (! (bool) $this->getRequest()->getUrl()->getParams()->get('ack', true)) {
+ $params->remove('ack');
+ } else {
+ $redirect->setQueryString(
+ Filter::fromQueryString($redirect->getQueryString())
+ ->andFilter(Filter::expression('ack', '=', 0))
+ ->toQueryString()
+ );
+ }
+ $params = $redirect->getParams();
+ if ($modifyFilter) {
+ $params->add('modifyFilter');
+ }
+ if ($columns) {
+ $params->add('columns', $columns);
+ }
+ $this->setRedirectUrl($redirect);
+ return true;
+ }
+}
diff --git a/application/forms/Events/SeverityFilterForm.php b/application/forms/Events/SeverityFilterForm.php
new file mode 100644
index 0000000..bd1ec5e
--- /dev/null
+++ b/application/forms/Events/SeverityFilterForm.php
@@ -0,0 +1,224 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Eventdb\Forms\Events;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Data\Filter\FilterAnd;
+use Icinga\Data\Filter\FilterChain;
+use Icinga\Data\Filter\FilterExpression;
+use Icinga\Data\Filter\FilterMatch;
+use Icinga\Module\Eventdb\Event;
+use Icinga\Web\Form;
+
+class SeverityFilterForm extends Form
+{
+ protected $includedPriorities;
+ protected $excludedPriorities;
+
+ /**
+ * @var FilterChain
+ */
+ protected $filter;
+
+ /**
+ * @var array
+ */
+ protected $filterEditorParams = array('modifyFilter', 'addFilter');
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline severity-filter-form');
+ }
+
+ protected function findPriorities(Filter $filter, $sign, &$target)
+ {
+ if ($filter->isEmpty()) {
+ return;
+ }
+
+ if ($filter->isChain()) {
+ /** @var FilterChain $filter */
+ foreach ($filter->filters() as $part) {
+ /** @var Filter $part */
+ if (! $part->isEmpty() && $part->isExpression()) {
+ /** @var FilterMatch $part */
+ if (strtolower($part->getColumn()) === 'priority' && $part->getSign() === $sign) {
+ $expression = $part->getExpression();
+ if (is_array($expression)) {
+ foreach ($expression as $priority) {
+ $target[(int) $priority] = $part;
+ }
+ } else {
+ $target[(int) $expression] = $part;
+ }
+ }
+ } else {
+ /** @var FilterChain $part */
+ foreach ($part->filters() as $or) {
+ /** @var FilterExpression $or */
+ if (strtolower($or->getColumn()) === 'priority' && $or->getSign() === $sign) {
+ $expression = $or->getExpression();
+ if (is_array($expression)) {
+ foreach ($expression as $priority) {
+ $target[(int) $priority] = $or;
+ }
+ } else {
+ $target[(int) $expression] = $or;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ /** @var FilterMatch $filter */
+ if (strtolower($filter->getColumn()) === 'priority' && $filter->getSign() === $sign) {
+ $expression = $filter->getExpression();
+ if (is_array($expression)) {
+ foreach ($expression as $priority) {
+ $target[(int) $priority] = $filter;
+ }
+ } else {
+ $target[(int) $expression] = $filter;
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $includedPriorities = array();
+ $excludedPriorities = array();
+ $params = $this->getRequest()->getUrl()->getParams()
+ ->without($this->filterEditorParams)
+ ->without('columns')
+ ->without('page');
+
+ $filter = Filter::fromQueryString((string) $params);
+
+ $this->findPriorities($filter, '=', $includedPriorities);
+ $this->findPriorities($filter, '!=', $excludedPriorities);
+
+ foreach (Event::$priorities as $id => $priority) {
+ $class = $priority;
+ if (
+ (empty($includedPriorities) or isset($includedPriorities[$id]))
+ && ! isset($excludedPriorities[$id])
+ ) {
+ $class .= ' active';
+ $title = $this->translate('Filter out %s');
+ } else {
+ $title = $this->translate('Filter in %s');
+ }
+
+ $label = ucfirst(substr($priority, 0, 1));
+ if ($id === 3) {
+ $label .= substr($priority, 1, 1);
+ }
+ $this->addElement(
+ 'submit',
+ $priority,
+ array(
+ 'class' => $class,
+ 'label' => $label,
+ 'title' => sprintf($title, ucfirst($priority)),
+ )
+ );
+ }
+
+ $this->includedPriorities = $includedPriorities;
+ $this->excludedPriorities = $excludedPriorities;
+
+ $this->filter = $filter;
+ }
+
+ public function onSuccess()
+ {
+ $postData = $this->getRequest()->getPost();
+ unset($postData['formUID']);
+ unset($postData['CSRFToken']);
+ reset($postData);
+ $priority = Event::getPriorityId(key($postData));
+ $redirect = clone $this->getRequest()->getUrl();
+
+ // convert inclusion to exclusion
+ if (! empty($this->includedPriorities)) {
+ if (empty($this->excludedPriorities)) {
+ $this->excludedPriorities = array();
+ }
+ // set exclusion with for all not included values
+ foreach (array_keys(Event::$priorities) as $id) {
+ if (! isset($this->includedPriorities[$id])
+ && ! isset($this->excludedPriorities[$id])
+ ) {
+ $this->excludedPriorities[$id] = true;
+ }
+ }
+ // purge from inclusions from filter
+ if ($this->filter instanceof FilterChain) {
+ foreach ($this->includedPriorities as $filter) {
+ if ($filter instanceof Filter) {
+ /** @var Filter $filter */
+ $this->filter = $this->filter->removeId($filter->getId());
+ }
+ }
+ }
+ }
+
+ if ($this->filter instanceof FilterChain) {
+ // purge existing exclusions from a complex filter
+ foreach ($this->excludedPriorities as $filter) {
+ if ($filter instanceof Filter) {
+ /** @var Filter $filter */
+ $this->filter = $this->filter->removeId($filter->getId());
+ }
+ }
+ } elseif (! empty($this->excludedPriorities)) {
+ // empty the filter - because it only was a simple exclusion
+ $this->filter = new FilterAnd;
+ }
+
+ // toggle exclusion
+ if (isset($this->excludedPriorities[$priority])) {
+ // in exclusion: just remove
+ unset($this->excludedPriorities[$priority]);
+ } else {
+ // not set: add to exclusion
+ $this->excludedPriorities[$priority] = true;
+ }
+
+ $priorityFilter = Filter::matchAll();
+ foreach (array_keys($this->excludedPriorities) as $id) {
+ $priorityFilter->andFilter(Filter::expression('priority', '!=', $id));
+ }
+
+ if ($this->filter->isEmpty()) {
+ // set the Filter
+ $this->filter = $priorityFilter;
+ } else {
+ // append our filter to the rest of the existing Filter
+ $this->filter = $this->filter->andFilter($priorityFilter);
+ }
+
+ $redirect->setQueryString($this->filter->toQueryString());
+
+ $requestParams = $this->getRequest()->getUrl()->getParams();
+ $redirectParams = $redirect->getParams();
+ foreach ($this->filterEditorParams as $filterEditorParam) {
+ if ($requestParams->has($filterEditorParam)) {
+ $redirectParams->add($filterEditorParam);
+ }
+ }
+ if ($requestParams->has('columns')) {
+ $redirectParams->add('columns', $this->getRequest()->getUrl()->getParam('columns'));
+ }
+ $this->setRedirectUrl($redirect);
+ return true;
+ }
+}
diff --git a/application/locale/de_DE/LC_MESSAGES/eventdb.mo b/application/locale/de_DE/LC_MESSAGES/eventdb.mo
new file mode 100644
index 0000000..0bcec3c
--- /dev/null
+++ b/application/locale/de_DE/LC_MESSAGES/eventdb.mo
Binary files differ
diff --git a/application/locale/de_DE/LC_MESSAGES/eventdb.po b/application/locale/de_DE/LC_MESSAGES/eventdb.po
new file mode 100644
index 0000000..29b432a
--- /dev/null
+++ b/application/locale/de_DE/LC_MESSAGES/eventdb.po
@@ -0,0 +1,413 @@
+# Icinga Web 2 - Head for multiple monitoring backends.
+# Copyright (C) 2018 Icinga Development Team
+# This file is distributed under the same license as Eventdb Module.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Eventdb Module (1.1.0)\n"
+"Report-Msgid-Bugs-To: dev@icinga.com\n"
+"POT-Creation-Date: 2018-01-25 14:31+0000\n"
+"PO-Revision-Date: 2018-01-25 15:32+0100\n"
+"Last-Translator: Markus Frosch <markus.frosch@icinga.com>\n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Basepath: .\n"
+"Language-Team: \n"
+"X-Generator: Poedit 2.0.5\n"
+"X-Poedit-SearchPath-0: .\n"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:15
+#, php-format
+msgctxt "Multi-selection count"
+msgid "%s row(s) selected"
+msgstr "%s Zeilen ausgewählt"
+
+#: ../../../../modules/eventdb/application/forms/Events/AckFilterForm.php:44
+#: ../../../../modules/eventdb/application/forms/Events/AckFilterForm.php:47
+msgid "Ack"
+msgstr "Bestätigt"
+
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:69
+msgid "Acknowledge"
+msgstr "Bestätigen"
+
+#: ../../../../modules/eventdb/application/views/helpers/Column.php:23
+#: ../../../../modules/eventdb/application/views/scripts/events/index-plain.phtml:10
+#: ../../../../modules/eventdb/application/views/scripts/events/details-plain.phtml:9
+#: ../../../../modules/eventdb/application/views/scripts/events/details.phtml:24
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:72
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:18
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:51
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:27
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:161
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:69
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:87
+msgid "Acknowledged"
+msgstr "Bestätigt"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:9
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:9
+msgid "Acknowledgement"
+msgstr "Bestätigung"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:60
+msgid "Actions"
+msgstr "Aktionen"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/details.phtml:41
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:118
+msgid "Add comment / acknowledge"
+msgstr "Kommentar / Bestätigung hinzufügen"
+
+#: ../../../../modules/eventdb/library/Eventdb/ProvidedHook/Monitoring/EventdbActionHook.php:151
+msgid "All events for host"
+msgstr "Alle Ereignisse für Host"
+
+#: ../../../../modules/eventdb/configuration.php:40
+msgid "Allow to acknowledge and comment events"
+msgstr "Erlauben Ereignisse zu Bestätigen und zu Kommentieren"
+
+#: ../../../../modules/eventdb/configuration.php:35
+msgid "Allow to view comments"
+msgstr "Erlauben Kommentare zu sehen"
+
+#: ../../../../modules/eventdb/configuration.php:30
+msgid "Allow to view events"
+msgstr "Erlauben Ereignisse zu sehen"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:40
+msgid "Always enable for hosts"
+msgstr "Immer für Hosts aktivieren"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:49
+msgid "Always enable for services"
+msgstr "Immer für Services aktivieren"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:39
+msgid ""
+"Always enable the integration on hosts, even when the custom variable is not "
+"set"
+msgstr ""
+"Immer bei Interaktionen mit Hosts anzeigen, auch wenn die angepasste "
+"Variable nicht gesetzt ist"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:48
+msgid ""
+"Always enable the integration on services, even when the custom variable is "
+"not set"
+msgstr ""
+"Immer bei Interaktionen mit Services anzeigen, auch wenn die angepasste "
+"Variable nicht gesetzt ist"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/details.phtml:44
+msgid "At least one event is set to auto-clear."
+msgstr "Mindestens ein Ereignis ist für automatische Bestätigung gesetzt."
+
+#: ../../../../modules/eventdb/application/views/scripts/events/details.phtml:25
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:73
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:28
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:162
+msgid "Auto-Clear"
+msgstr "Automatische Bestätigung"
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:86
+msgid ""
+"Cannot find the EventDB schema. Please verify that the given database "
+"contains the schema and that the configured user has access to it."
+msgstr ""
+"Kann das EventDB-Schema nicht finden. Bitte stellen Sie sicher, dass die "
+"angegebene Datenbankverbindung das Schema enthält und dass der konfigurierte "
+"Benutzer Zugriff darauf hat."
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:104
+msgid "Check this to not to validate the EventDB schema of the chosen resource"
+msgstr ""
+"Häkchen setzen um das EventDB Schema der gewählten Ressource nicht zu "
+"überprüfen."
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:8
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:8
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:68
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:80
+msgid "Comment"
+msgstr "Kommentar"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:28
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:128
+msgid "Comments"
+msgstr "Kommentare"
+
+#: ../../../../modules/eventdb/configuration.php:19
+msgid "Config"
+msgstr "Konfiguration"
+
+#: ../../../../modules/eventdb/configuration.php:18
+#, fuzzy
+msgid "Configure EventDB"
+msgstr "EventDB Datenbankverbindung einrichten"
+
+#: ../../../../modules/eventdb/configuration.php:23
+#: ../../../../modules/eventdb/application/views/scripts/config/monitoring.phtml:5
+msgid "Configure integration into the monitoring module"
+msgstr "Interaktionen im Monitoring Modul"
+
+#: ../../../../modules/eventdb/application/views/scripts/config/index.phtml:19
+msgid "Configure module"
+msgstr "Modul konfigurieren"
+
+#: ../../../../modules/eventdb/application/views/scripts/config/index.phtml:7
+msgid "Create a New Resource"
+msgstr "Neue Ressource erstellen"
+
+#: ../../../../modules/eventdb/application/views/scripts/config/index.phtml:14
+msgid "Create a new resource"
+msgstr "Neue Ressource erstellen"
+
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:70
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:88
+msgid "Created"
+msgstr "Erstellt"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:31
+msgid "Custom Variable"
+msgstr "Angepasste Variable"
+
+#: ../../../../modules/eventdb/application/views/scripts/config/index.phtml:5
+#, fuzzy
+msgid "Database backend"
+msgstr "EventDB Datenbankverbindung einrichten"
+
+#: ../../../../modules/eventdb/application/forms/Config/GlobalConfigForm.php:28
+msgid "Default Filter"
+msgstr "Standard Filter"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:36
+msgid "Details"
+msgstr "Details"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:58
+msgid "Disable the detail view"
+msgstr "Detailansicht deaktivieren"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:57
+msgid "Disable the detail view inside the monitoring module"
+msgstr "Die Detailansicht innerhalb des Monitoring Moduls deaktivieren"
+
+#: ../../../../modules/eventdb/application/controllers/EventController.php:26
+msgid "Event"
+msgstr "Ereignis"
+
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:22
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:31
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:136
+msgid "Events"
+msgstr "Ereignisse"
+
+# Spezifische Syslog Bezeichnung
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:66
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:84
+msgid "Facility"
+msgstr "Facility"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:66
+msgid "Filter events in the detail view area inside the monitoring module"
+msgstr "Ereignisse der Detailansicht im Monitoring Modul filtern"
+
+#: ../../../../modules/eventdb/application/forms/Events/SeverityFilterForm.php:117
+#, php-format
+msgid "Filter in %s"
+msgstr "Filtern nach %s"
+
+#: ../../../../modules/eventdb/application/forms/Events/SeverityFilterForm.php:115
+#, php-format
+msgid "Filter out %s"
+msgstr "Filtern ohne %s"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:67
+msgid "Filter the detail view"
+msgstr "Detailansicht filtern"
+
+#: ../../../../modules/eventdb/application/forms/Config/GlobalConfigForm.php:27
+msgid "Filter to be used by the menu link for EventDB by default"
+msgstr "Filter für die URL des Menü Eintrages der EventDB"
+
+#: ../../../../modules/eventdb/library/Eventdb/ProvidedHook/Monitoring/EventdbActionHook.php:134
+msgid "Filtered events"
+msgstr "Gefilterte Ereignisse"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:42
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:147
+msgid "Grouped Events"
+msgstr "Gruppierte Ereignisse"
+
+#: ../../../../modules/eventdb/application/forms/Events/AckFilterForm.php:26
+msgid "Hide acknowledged events"
+msgstr "Bestätigte Ereignisse verstecken"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:65
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:62
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:80
+msgid "Host"
+msgstr "Host"
+
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:63
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:81
+msgid "Host Address"
+msgstr "Host Adresse"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:105
+msgid "Host service status"
+msgstr "Host Service Status"
+
+#: ../../../../modules/eventdb/library/Eventdb/ProvidedHook/Monitoring/DetailviewExtension.php:66
+msgid "Loading"
+msgstr "Lade"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:35
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:50
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:68
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:86
+msgid "Message"
+msgstr "Meldung"
+
+#: ../../../../modules/eventdb/configuration.php:24
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:102
+msgid "Monitoring"
+msgstr "Monitoring"
+
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:30
+msgid ""
+"Name of the custom variable to enable EventDB integration for (usually \"edb"
+"\")"
+msgstr ""
+"Name der angepassten Variable um die EventDB Integration zu aktivieren "
+"(normalerweise \"edb\")"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:130
+msgid "No comments recorded for this event yet."
+msgstr "Keine Kommentare für dieses Ereignis."
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index-plain.phtml:3
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:33
+msgid "No events recorded yet."
+msgstr "Keine Ereignisse gespeichert."
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:63
+msgid "Other events for"
+msgstr "Andere Ereignisse für"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/details.phtml:45
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:122
+msgid "Please only acknowledge manually, if you know what that means."
+msgstr "Bitte nur manuell Bestätigen wenn Sie wissen was das bedeutet."
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:6
+msgctxt "Multi-selection help"
+msgid ""
+"Press and hold the Ctrl key while clicking on rows to select multiple rows "
+"or press and hold the Shift key to select a range of rows"
+msgstr ""
+"Drücken und halten Sie STRG während Sie auf Spalten klicken, um mehrere "
+"auszuwählen. Mit der Umschalttaste können Sie Bereiche von Spalten auswählen"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index-plain.phtml:9
+#: ../../../../modules/eventdb/application/views/scripts/events/details-plain.phtml:8
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:17
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:50
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:67
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:85
+msgid "Priority"
+msgstr "Priorität"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:75
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:65
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:83
+msgid "Program"
+msgstr "Programm"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:86
+msgid "Program and Host"
+msgstr "Programm und Host"
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:40
+msgid "Resource"
+msgstr "Ressource"
+
+#: ../../../../modules/eventdb/configuration.php:45
+msgid "Restrict views to the events that match the filter"
+msgstr "Ereignisse mit einem Filter einschränken"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:10
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:10
+msgid "Revocation"
+msgstr "Widerruf"
+
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:70
+msgid "Revoke"
+msgstr "Wiederrufen"
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:20
+#: ../../../../modules/eventdb/application/forms/Config/MonitoringConfigForm.php:18
+#: ../../../../modules/eventdb/application/forms/Config/GlobalConfigForm.php:15
+msgid "Save"
+msgstr "Speichern"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index.phtml:84
+msgid "Show More"
+msgstr "Mehr zeigen"
+
+#: ../../../../modules/eventdb/application/forms/Events/AckFilterForm.php:29
+msgid "Show also acknowledged events"
+msgstr "Auch bestätigte Ereignisse anzeigen"
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:107
+msgid "Skip Validation"
+msgstr "Überprüfung überspringen"
+
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:42
+msgid "Submit"
+msgstr "Absenden"
+
+#: ../../../../modules/eventdb/library/Eventdb/Web/EventdbOutputFormat.php:49
+msgid "Text"
+msgstr "Text"
+
+#: ../../../../modules/eventdb/application/forms/Config/BackendConfigForm.php:39
+msgid "The resource to use"
+msgstr "Die zu benutzenden Ressource"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index.phtml:121
+msgid "This event is set to auto-clear."
+msgstr "Das Ereignis ist auf automatische Bestätigung gesetzt."
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index-plain.phtml:7
+#: ../../../../modules/eventdb/application/views/scripts/events/details-plain.phtml:6
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:15
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:48
+msgid "Timestamp"
+msgstr "Zeitstempel"
+
+#: ../../../../modules/eventdb/application/views/scripts/events/index-plain.phtml:12
+#: ../../../../modules/eventdb/application/views/scripts/events/details-plain.phtml:11
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:20
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:53
+#: ../../../../modules/eventdb/application/forms/Event/EventCommentForm.php:66
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:64
+#: ../../../../modules/eventdb/application/controllers/EventsController.php:82
+msgid "Type"
+msgstr "Typ"
+
+#: ../../../../modules/eventdb/application/views/scripts/event/index-plain.phtml:33
+msgid "User"
+msgstr "Benutzername"
+
+#: ../../../../modules/eventdb/library/Eventdb/Eventdb.php:141
+msgid "You need to configure a resource to access the EventDB database first"
+msgstr "Sie müssen zuerst die Datenbank der EventDB konfigurieren"
+
+#~ msgid "Backend"
+#~ msgstr "Datenbank"
diff --git a/application/views/helpers/Column.php b/application/views/helpers/Column.php
new file mode 100644
index 0000000..b343de4
--- /dev/null
+++ b/application/views/helpers/Column.php
@@ -0,0 +1,51 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+use Icinga\Module\Eventdb\Event;
+
+class Zend_View_Helper_Column extends Zend_View_Helper_Abstract
+{
+ public function column($column, Event $event, $classes = array())
+ {
+ switch ($column) {
+ case 'host_name':
+ $default = 'host_url';
+ break;
+ case 'message':
+ $default = 'message';
+ break;
+ default:
+ $default = null;
+ break;
+ }
+
+ if ($column === 'ack') {
+ $html = $event->$column ? $this->view->icon('ok', $this->view->translate('Acknowledged')) : '-';
+ } else {
+ $renderer = $this->view->columnConfig->get($column, 'renderer', $default);
+
+ switch ($renderer) {
+ case 'host_url':
+ $html = $this->view->qlink($event->$column, 'eventdb/event/host',
+ array('host' => $event->$column));
+ break;
+ case 'service_url':
+ $html = $this->view->qlink($event->$column, 'eventdb/event/service',
+ array('service' => $event->$column, 'host' => $event->host_name));
+ break;
+ case 'url':
+ $html = $this->view->qlink($event->$column, $event->$column);
+ break;
+ case 'message':
+ $html = $this->view->eventMessage($event->$column);
+ break;
+ default:
+ $html = $this->view->escape($event->$column);
+ break;
+ }
+ }
+
+ return '<td class="' . 'event-' . $this->view->escape($column) . ' '
+ . implode(' ', $classes) . '" data-base-target="_next">' . $html . '</td>';
+ }
+}
diff --git a/application/views/helpers/ColumnHeader.php b/application/views/helpers/ColumnHeader.php
new file mode 100644
index 0000000..3c7f7cd
--- /dev/null
+++ b/application/views/helpers/ColumnHeader.php
@@ -0,0 +1,17 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+class Zend_View_Helper_ColumnHeader extends Zend_View_Helper_Abstract
+{
+ public function columnHeader($columnHeader, $classes = array(), $plain = false)
+ {
+ $header = $this->view->columnConfig->get($columnHeader, 'label', ucwords(str_replace('_', ' ', $columnHeader)));
+ if ($plain) {
+ return $header;
+ }
+ $htm = '<th classes="' . implode(' ', $classes) . '">';
+ $htm .= $this->view->escape($header);
+ $htm .= '</th>';
+ return $htm;
+ }
+}
diff --git a/application/views/helpers/Event.php b/application/views/helpers/Event.php
new file mode 100644
index 0000000..f61a793
--- /dev/null
+++ b/application/views/helpers/Event.php
@@ -0,0 +1,12 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+use Icinga\Module\Eventdb\Event;
+
+class Zend_View_Helper_Event extends Zend_View_Helper_Abstract
+{
+ public function event($data)
+ {
+ return Event::fromData($data);
+ }
+}
diff --git a/application/views/helpers/EventMessage.php b/application/views/helpers/EventMessage.php
new file mode 100644
index 0000000..de52518
--- /dev/null
+++ b/application/views/helpers/EventMessage.php
@@ -0,0 +1,70 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+use Icinga\Application\Config;
+
+class Zend_View_Helper_EventMessage extends Zend_View_Helper_Abstract
+{
+ /**
+ * The RegExp for locating URLs.
+ *
+ * Modifications:
+ * - Don't allow ; in
+ *
+ * @source https://mathiasbynens.be/demo/url-regex
+ */
+ const URL_REGEX = '@(https?)://(-\.)?([^\s/?\.#-]+\.?)+(/[^\s;]*)?@i';
+
+ /**
+ * Purifier instance
+ *
+ * @var HTMLPurifier
+ */
+ protected static $purifier;
+
+ public function eventMessage($message)
+ {
+ $htm = $this->getPurifier()->purify($message);
+
+ // search for URLs and make them a link
+ $htm = preg_replace_callback(
+ static::URL_REGEX,
+ function ($match) {
+ return sprintf(
+ '<a href="%s" target="_blank">%s</a>',
+ htmlspecialchars($match[0]),
+ htmlspecialchars($match[0])
+ );
+ },
+ $htm
+ );
+
+ return $htm;
+ }
+
+ /**
+ * Get the purifier instance
+ *
+ * @return HTMLPurifier
+ */
+ protected function getPurifier()
+ {
+ if (self::$purifier === null) {
+ require_once 'HTMLPurifier/Bootstrap.php';
+ require_once 'HTMLPurifier.php';
+ require_once 'HTMLPurifier.autoload.php';
+
+ $config = HTMLPurifier_Config::createDefault();
+ $config->set('Core.EscapeNonASCIICharacters', true);
+ $config->set('HTML.Allowed', Config::module('eventdb')->get(
+ 'frontend',
+ 'allowed_html',
+ 'p,br,b,a[href|target],i,table,tr,td[colspan],div,*[class]'
+ ));
+ $config->set('Attr.AllowedFrameTargets', array('_blank'));
+ $config->set('Cache.DefinitionImpl', null);
+ self::$purifier = new HTMLPurifier($config);
+ }
+ return self::$purifier;
+ }
+}
diff --git a/application/views/scripts/config/index.phtml b/application/views/scripts/config/index.phtml
new file mode 100644
index 0000000..2c47663
--- /dev/null
+++ b/application/views/scripts/config/index.phtml
@@ -0,0 +1,21 @@
+<div class="controls">
+ <?= $tabs ?>
+</div>
+<div class="content">
+ <h2><?= $this->translate('Database backend') ?></h2>
+ <?= $this->qlink(
+ $this->translate('Create a New Resource'),
+ 'config/createresource',
+ null,
+ array(
+ 'class' => 'button-link',
+ 'data-base-target' => '_next',
+ 'icon' => 'plus',
+ 'title' => $this->translate('Create a new resource'),
+ )
+ ) ?>
+ <?= $backendConfig ?>
+
+ <h2><?= $this->translate('Configure module') ?></h2>
+ <?= $globalConfig ?>
+</div>
diff --git a/application/views/scripts/config/monitoring.phtml b/application/views/scripts/config/monitoring.phtml
new file mode 100644
index 0000000..1f6bbde
--- /dev/null
+++ b/application/views/scripts/config/monitoring.phtml
@@ -0,0 +1,7 @@
+<div class="controls">
+ <?= $tabs ?>
+</div>
+<div class="content">
+ <h2><?= $this->translate('Configure integration into the monitoring module') ?></h2>
+ <?= $form ?>
+</div>
diff --git a/application/views/scripts/event/index-plain.phtml b/application/views/scripts/event/index-plain.phtml
new file mode 100644
index 0000000..5b6ea8d
--- /dev/null
+++ b/application/views/scripts/event/index-plain.phtml
@@ -0,0 +1,62 @@
+<?php
+/** @var \Icinga\Module\Eventdb\Event $event */
+/** @var array $additionalColumns */
+/** @var \Icinga\Repository\RepositoryQuery $comments */
+/** @var \Icinga\Repository\RepositoryQuery $groupedEvents */
+
+$commentTypes = array(
+ $this->translate('Comment'),
+ $this->translate('Acknowledgement'),
+ $this->translate('Revocation'),
+);
+
+$displayColumns = array_merge(array('program', 'message', 'facility'), $additionalColumns);
+?>
+<?= $this->translate('Timestamp') ?>: <?= $event->created ?>
+
+<?= $this->translate('Priority') ?>: <?= strtoupper($event->getPriority()) ?>
+<?= $event->ack ? sprintf(' (%s)', $this->translate('Acknowledged')) : '' ?>
+
+<?= $this->translate('Type') ?>: <?= $event->getType() ?>
+
+<?php foreach ($displayColumns as $col): ?>
+<?= $this->columnHeader($col, null, true) ?>: <?= htmlspecialchars($event->offsetGet($col)) ?>
+
+<?php endforeach ?>
+
+<?php if ($comments->hasResult()): ?>
+[ <?= $this->translate('Comments') ?> ]
+
+<?php foreach ($comments as $comment): ?>
+<?= $commentTypes[$comment->type] ?>: <?= $comment->created ?>
+
+<?= $this->translate('User') ?>: <?= $comment->user ?>
+
+<?= $this->translate('Message') ?>: <?= $comment->message ?>
+
+
+<?php endforeach ?>
+
+<?php endif; ?>
+<?php if ($groupedEvents !== null && $groupedEvents->hasResult()): ?>
+[ <?= $this->translate('Grouped Events') ?> ]
+
+<?php foreach ($groupedEvents as $groupedEventData):
+ /** @var \Icinga\Module\Eventdb\Event $groupedEvent */
+ $groupedEvent = $this->event($groupedEventData);
+?>
+<?= $this->translate('Timestamp') ?>: <?= $event->created ?>
+
+<?= $this->translate('Priority') ?>: <?= strtoupper($event->getPriority()) ?>
+<?= $event->ack ? sprintf(' (%s)', $this->translate('Acknowledged')) : '' ?>
+
+<?= $this->translate('Type') ?>: <?= $event->getType() ?>
+
+<?php foreach (array('host_name', 'program', 'message') as $col): ?>
+<?= $this->columnHeader($col, null, true) ?>: <?= htmlspecialchars($event->offsetGet($col)) ?>
+
+<?php endforeach ?>
+
+<?php endforeach ?>
+<?php endif; ?>
+
diff --git a/application/views/scripts/event/index.phtml b/application/views/scripts/event/index.phtml
new file mode 100644
index 0000000..83dcf01
--- /dev/null
+++ b/application/views/scripts/event/index.phtml
@@ -0,0 +1,174 @@
+<?php
+/** @var \Icinga\Module\Eventdb\Event $event */
+/** @var array $additionalColumns */
+/** @var \Icinga\Repository\RepositoryQuery $comments */
+/** @var \Icinga\Repository\RepositoryQuery $groupedEvents */
+
+$commentIcons = array(
+ $this->icon('comment', $this->translate('Comment')),
+ $this->icon('ok', $this->translate('Acknowledgement')),
+ $this->icon('cancel', $this->translate('Revocation'))
+);
+
+if (! $this->compact): ?>
+<div class="controls">
+ <?= $this->tabs ?>
+</div>
+<?php endif ?>
+<div class="content">
+ <table class="event-summary-table">
+ <tr>
+ <td rowspan="2" class="priority-col <?= $event->getPriority() ?> <?= $event->ack ? 'ack' : '' ?>">
+ <div class="priority-label"><?= strtoupper($event->getPriority()) ?></div>
+ <div class="event-meta"><span class="timeago" title="<?= $event->created ?>"><?= $this->timeAgo(strtotime($event->created)) ?></span></div>
+ </td>
+ <td rowspan="2" class="icon-col">
+ <?= $this->icon($event->getTypeIcon(), $event->getType()) ?>
+ <?php if ($event->ack) { echo $this->icon('ok', $this->translate('Acknowledged')); } ?>
+ <?php if ($event->group_autoclear) { echo $this->icon('reschedule', $this->translate('Auto-Clear')); } ?>
+ </td>
+ <?= $this->column('host_name', $event, array('selectable')) ?>
+ </tr>
+ <tr>
+ <?= $this->column('host_address', $event, array('selectable')) ?>
+ </tr>
+ </table>
+ <h2><?= $this->translate('Details') ?></h2>
+ <table class="name-value-table">
+ <?php
+ $displayColumns = array_merge(array('program', 'message', 'facility'), $additionalColumns);
+ foreach ($displayColumns as $column):
+ if ($column === 'message') continue;
+ ?>
+ <tr>
+ <?= $this->columnHeader($column) ?>
+ <?= $this->column($column, $event) ?>
+ </tr>
+ <?php endforeach ?>
+ </table>
+ <?php if ($event->message): ?>
+ <h2><?= $this->translate('Message') ?></h2>
+ <div class="event-message detail preformatted"><?= $this->eventMessage($event->message) ?></div>
+ <?php endif; ?>
+
+ <?php
+ foreach ($extensionsHtml as $extensionHtml) {
+ echo $extensionHtml;
+ }
+ ?>
+
+ <h2><?= $this->translate('Actions') ?></h2>
+ <table class="name-value-table" data-base-target="_next">
+ <tr>
+ <th><?= $this->translate('Other events for') ?></th>
+ <td><?= $this->qlink(
+ $this->translate('Host'),
+ 'eventdb/events',
+ array('host_name' => $event->host_name),
+ array(
+ 'icon' => 'search',
+ 'class' => 'action-link'
+ )
+ ) ?>
+ <?php if ($event->program): ?>
+ <?= $this->qlink(
+ $this->translate('Program'),
+ 'eventdb/events',
+ array(
+ 'program' => $event->program,
+ ),
+ array(
+ 'icon' => 'search',
+ 'class' => 'action-link'
+ )
+ ) ?>
+ <?= $this->qlink(
+ $this->translate('Program and Host'),
+ 'eventdb/events',
+ array(
+ 'host_name' => $event->host_name,
+ 'program' => $event->program,
+ ),
+ array(
+ 'icon' => 'search',
+ 'class' => 'action-link'
+ )
+ ) ?>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <tr>
+ <tr>
+ <th><?= $this->translate('Monitoring') ?></th>
+ <td>
+ <?= $this->qlink(
+ $this->translate('Host service status'),
+ 'eventdb/event/host',
+ array('host' => $event->host_name),
+ array(
+ 'icon' => 'search',
+ 'class' => 'action-link'
+ )
+ ) ?>
+ </td>
+ </tr>
+ </table>
+
+ <?php if (isset($commentForm)): ?>
+ <h2><?= $this->translate('Add comment / acknowledge') ?></h2>
+ <?php if ($event->group_autoclear): ?>
+ <div class="warning">
+ <?= $this->translate('This event is set to auto-clear.') ?>
+ <?= $this->translate('Please only acknowledge manually, if you know what that means.') ?>
+ </div>
+ <?php endif; ?>
+ <div class="comment-form"><?= $commentForm ?></div>
+ <?php endif ?>
+
+ <h2><?= $this->translate('Comments') ?></h2>
+ <?php if (! $comments->hasResult()): ?>
+ <p><?= $this->translate('No comments recorded for this event yet.') ?></p>
+ <?php else: ?>
+ <table class="common-table comments-table">
+ <tbody>
+ <?php foreach ($comments as $comment): ?>
+ <tr>
+ <td class="comment-created timeago" title="<?= $comment->created ?>"><?= $this->timeAgo(strtotime($comment->created)) ?></td>
+ <td class="comment-type"><?= $commentIcons[$comment->type] ?></td>
+ <td class="comment-user"><?= $this->escape($comment->user) ?></td>
+ <td class="comment-message"><?= $this->escape($comment->message) ?></td>
+ </tr>
+ <?php endforeach ?>
+ </tbody>
+ </table>
+ <?php endif; ?>
+
+ <?php if ($groupedEvents !== null && $groupedEvents->hasResult()): ?>
+ <h2><?= $this->translate('Grouped Events') ?></h2>
+ <table class="common-table events-table" data-base-target="_next">
+ <tbody>
+ <?php foreach ($groupedEvents as $groupedEventData):
+ /** @var \Icinga\Module\Eventdb\Event $groupedEvent */
+ $groupedEvent = $this->event($groupedEventData);
+ ?>
+ <tr>
+ <td class="priority-col <?= $groupedEvent->getPriority() ?> <?= $groupedEvent->ack ? 'ack' : '' ?>">
+ <div class="priority-label"><?= strtoupper($groupedEvent->getPriority()) ?></div>
+ <div class="event-meta"><span class="timeago" title="<?= $groupedEvent->created ?>"><?= $this->timeAgo(strtotime($groupedEvent->created)) ?></span></div>
+ </td>
+ <td class="icon-col">
+ <?= $this->icon($groupedEvent->getTypeIcon(), $groupedEvent->getType()) ?>
+ <?php if ($groupedEvent->ack) { echo $this->icon('ok', $this->translate('Acknowledged')); } ?>
+ <?php if ($groupedEvent->group_autoclear) { $autoClear = true; echo $this->icon('reschedule', $this->translate('Auto-Clear')); } ?>
+ </td>
+ <?= $this->column('host_name', $groupedEvent) ?>
+ <?= $this->column('program', $groupedEvent) ?>
+ <?= $this->column('message', $groupedEvent) ?>
+ </tr>
+ <?php endforeach ?>
+ </tbody>
+ </table>
+ <?php endif; ?>
+
+</div>
+
diff --git a/application/views/scripts/events/details-plain.phtml b/application/views/scripts/events/details-plain.phtml
new file mode 100644
index 0000000..d5eb724
--- /dev/null
+++ b/application/views/scripts/events/details-plain.phtml
@@ -0,0 +1,18 @@
+<?php foreach($events as $eventData):
+ /** @var \Icinga\Module\Eventdb\Event $event */
+ $event = $this->event($eventData);
+ $url = $this->url('eventdb/event', array('id' => $event->id));
+?>
+<?= $this->translate('Timestamp') ?>: <?= $event->created ?>
+
+<?= $this->translate('Priority') ?>: <?= strtoupper($event->getPriority()) ?>
+<?= $event->ack ? sprintf(' (%s)', $this->translate('Acknowledged')) : '' ?>
+
+<?= $this->translate('Type') ?>: <?= $event->getType() ?>
+
+<?php foreach (array('host_name', 'program', 'message') as $col): ?>
+<?= $this->columnHeader($col, null, true) ?>: <?= htmlspecialchars($event->offsetGet($col)) ?>
+
+<?php endforeach ?>
+
+<?php endforeach ?>
diff --git a/application/views/scripts/events/details.phtml b/application/views/scripts/events/details.phtml
new file mode 100644
index 0000000..ee9f3cd
--- /dev/null
+++ b/application/views/scripts/events/details.phtml
@@ -0,0 +1,50 @@
+<?php
+/** @var array $events */
+
+if (! $this->compact):
+?>
+<div class="controls">
+ <?= $this->tabs ?>
+</div>
+<?php endif ?>
+<div class="content">
+ <table class="common-table event-summary-table table-row-selectable" data-base-target="_next">
+ <?php $autoClear = false; foreach($events as $eventData):
+ /** @var \Icinga\Module\Eventdb\Event $event */
+ $event = $this->event($eventData);
+ $url = $this->url('eventdb/event', array('id' => $event->id));
+ ?>
+ <tr href="<?= $url ?>">
+ <td class="priority-col <?= $event->getPriority() ?> <?= $event->ack ? 'ack' : '' ?>">
+ <div class="priority-label"><?= strtoupper($event->getPriority()) ?></div>
+ <div class="event-meta"><span class="timeago" title="<?= $event->created ?>"><?= $this->timeAgo(strtotime($event->created)) ?></span></div>
+ </td>
+ <td class="icon-col">
+ <?= $this->icon($event->getTypeIcon(), $event->getType()) ?>
+ <?php if ($event->ack) { echo $this->icon('ok', $this->translate('Acknowledged')); } ?>
+ <?php if ($event->group_autoclear) { $autoClear = true; echo $this->icon('reschedule', $this->translate('Auto-Clear')); } ?>
+ </td>
+ <?= $this->column('host_name', $event) ?>
+ <?= $this->column('program', $event) ?>
+ <?= $this->column('message', $event) ?>
+ </tr>
+ <?php endforeach; ?>
+ </table>
+
+ <?php
+ foreach ($extensionsHtml as $extensionHtml) {
+ echo $extensionHtml;
+ }
+ ?>
+
+ <?php if (isset($commentForm)): ?>
+ <h3><?= $this->translate('Add comment / acknowledge') ?></h3>
+ <?php if ($autoClear): ?>
+ <div class="warning">
+ <?= $this->translate('At least one event is set to auto-clear.') ?>
+ <?= $this->translate('Please only acknowledge manually, if you know what that means.') ?>
+ </div>
+ <?php endif; ?>
+ <div class="comment-form"><?= $commentForm ?></div>
+ <?php endif ?>
+</div>
diff --git a/application/views/scripts/events/index-plain.phtml b/application/views/scripts/events/index-plain.phtml
new file mode 100644
index 0000000..55f4c2e
--- /dev/null
+++ b/application/views/scripts/events/index-plain.phtml
@@ -0,0 +1,19 @@
+<?php /** @var \Icinga\Repository\RepositoryQuery $events */
+if (! $events->hasResult()): ?>
+<?= $this->translate('No events recorded yet.') ?>
+<?php else:
+$displayColumns = array_merge(array('host_name', 'program', 'message', 'facility'), $additionalColumns);
+foreach ($events as $eventData): /** @var \Icinga\Module\Eventdb\Event $event */ $event = $this->event($eventData); ?>
+<?= $this->translate('Timestamp') ?>: <?= $event->created ?>
+
+<?= $this->translate('Priority') ?>: <?= strtoupper($event->getPriority()) ?>
+<?= $event->ack ? sprintf(' (%s)', $this->translate('Acknowledged')) : '' ?>
+
+<?= $this->translate('Type') ?>: <?= $event->getType() ?>
+
+<?php foreach ($displayColumns as $col): ?>
+<?= $this->columnHeader($col, null, true) ?>: <?= htmlspecialchars($event->offsetGet($col)) ?>
+
+<?php endforeach ?>
+
+<?php endforeach; endif; ?>
diff --git a/application/views/scripts/events/index.phtml b/application/views/scripts/events/index.phtml
new file mode 100644
index 0000000..f1e4da7
--- /dev/null
+++ b/application/views/scripts/events/index.phtml
@@ -0,0 +1,93 @@
+<?php if (! $this->compact): ?>
+<div class="controls">
+ <?= $this->tabs ?>
+ <?php
+ $helpMessage = $this->translate(
+ 'Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to'
+ . ' select a range of rows',
+ 'Multi-selection help'
+ );
+ ?>
+ <div class="selection-info" title="<?= $this->escape($helpMessage) ?>">
+ <?= sprintf(
+ /// TRANSLATORS: Please leave %s as it is because the selection counter is wrapped in a span tag for updating
+ /// the counter via JavaScript
+ $this->translate('%s row(s) selected', 'Multi-selection count'),
+ '<span class="selection-info-count">0</span>'
+ ) ?>
+ </div>
+ <?= $this->paginator ?>
+ <div class="sort-controls-container">
+ <?= $this->limiter ?>
+ <?= $this->sortBox ?>
+ </div>
+ <?= $this->filterEditor ?>
+ <div class="quick-filter-controls">
+ <?= $this->severityFilterForm ?>
+ <?= $this->ackFilterForm ?>
+ </div>
+</div>
+<?php endif ?>
+<div class="content">
+<?php /** @var \Icinga\Repository\RepositoryQuery $events */if (! $events->hasResult()): ?>
+ <p><?= $this->translate('No events recorded yet.') ?></p>
+</div>
+<?php return; endif; $displayColumns = array_merge(array('host_name', 'program', 'message', 'facility'), $additionalColumns); ?>
+ <table class="common-table table-row-selectable multiselect table-responsive events-table"
+ data-base-target="_next"
+ data-icinga-multiselect-url="<?= $this->href('eventdb/events/details') ?>"
+ data-icinga-multiselect-controllers="<?= $this->href('eventdb/events') ?>"
+ data-icinga-multiselect-data="id">
+ <?php if (! $this->compact): ?>
+ <thead>
+ <tr>
+ <th></th>
+ <th></th>
+ <?php foreach ($displayColumns as $displayColumn): ?>
+ <?= $this->columnHeader($displayColumn) ?>
+ <?php endforeach ?>
+ </tr>
+ </thead>
+ <?php endif; ?>
+ <tbody>
+ <?php
+ foreach ($events as $eventData):
+ /** @var \Icinga\Module\Eventdb\Event $event */
+ $event = $this->event($eventData);
+ $created = $event->created;
+ $createdTs = strtotime($created);
+ $url = $this->url('eventdb/event', array('id' => $event->id));
+ $classes = array('priority-col', $event->getPriority());
+ if ($event->ack) {
+ $classes[] = 'ack';
+ }
+ ?>
+ <tr href="<?= $url ?>">
+ <td class="<?= implode(' ', $classes) ?>">
+ <div class="priority-label"><?= strtoupper($event->getPriority()) ?></div>
+ <div class="event-meta"><a href="<?= $url ?>" class="timeago" title="<?= $created ?>"><?= $this->timeAgo($createdTs) ?></a></div>
+ </td>
+ <td class="icon-col">
+ <?= $this->icon($event->getTypeIcon(), $event->getType()) ?>
+ <?php if ($event->ack) { echo $this->icon('ok', $this->translate('Acknowledged')); } ?>
+ <?php if ($event->group_autoclear) { echo $this->icon('reschedule', $this->translate('Auto-Clear')); } ?>
+ </td>
+ <?php foreach ($displayColumns as $displayColumn): ?>
+ <?= $this->column($displayColumn, $event) ?>
+ <?php endforeach ?>
+ </tr>
+ <?php endforeach ?>
+ </tbody>
+ </table>
+<?php if ($this->compact && $events->hasMore()): ?>
+ <?= $this->qlink(
+ $this->translate('Show More'),
+ $this->url()->without(array('view', 'limit')),
+ null,
+ array(
+ 'data-base-target' => '_next',
+ 'class' => 'action-link'
+ )
+ ) ?>
+<?php endif; ?>
+</div>
diff --git a/application/views/scripts/format/text.phtml b/application/views/scripts/format/text.phtml
new file mode 100644
index 0000000..647914b
--- /dev/null
+++ b/application/views/scripts/format/text.phtml
@@ -0,0 +1,13 @@
+<?php
+/** @var string $text */
+/** @var string|null $partial */
+if (! $this->compact): ?>
+<div class="controls"><?= $this->tabs ?></div>
+<?php endif ?>
+<div class="content">
+<?php if ($partial !== null): ?>
+ <pre class="copyable"><?= $this->partial($partial . '.phtml', null, $this) ?></pre>
+<?php else: ?>
+ <pre class="copyable"><?= htmlspecialchars($text) ?></pre>
+<?php endif ?>
+</div>