Skip to content

Commit

Permalink
Build a single form for the event rule configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
raviks789 committed Mar 6, 2024
1 parent e3ccb69 commit 81f6608
Show file tree
Hide file tree
Showing 22 changed files with 2,405 additions and 634 deletions.
246 changes: 145 additions & 101 deletions application/controllers/EventRuleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,24 @@
use Icinga\Module\Notifications\Common\Auth;
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Common\Links;
use Icinga\Module\Notifications\Forms\EventRuleConfigForm;
use Icinga\Module\Notifications\Forms\EventRuleForm;
use Icinga\Module\Notifications\Forms\SaveEventRuleForm;
use Icinga\Module\Notifications\Model\Incident;
use Icinga\Module\Notifications\Model\ObjectExtraTag;
use Icinga\Module\Notifications\Model\Rule;
use Icinga\Module\Notifications\Web\Control\SearchBar\ExtraTagSuggestions;
use Icinga\Module\Notifications\Widget\EventRuleConfig;
use Icinga\Module\Notifications\Web\Form\EventRuleDecorator;
use Icinga\Web\Notification;
use Icinga\Web\Session;
use ipl\Html\Attributes;
use ipl\Html\Form;
use ipl\Html\FormElement\ButtonElement;
use ipl\Html\FormElement\SubmitButtonElement;
use ipl\Html\Html;
use ipl\Html\HtmlElement;
use ipl\Stdlib\Filter;
use ipl\Web\Compat\CompatController;
use ipl\Web\Control\SearchEditor;
use ipl\Web\Filter\QueryString;
use ipl\Web\Url;
use ipl\Web\Widget\Icon;
use ipl\Web\Widget\Link;
Expand All @@ -32,6 +36,9 @@ class EventRuleController extends CompatController
/** @var Session\SessionNamespace */
private $sessionNamespace;

/** @var ?string Event rule config filter */
protected $filter;

public function init()
{
$this->sessionNamespace = Session::getSession()->getNamespace('notifications');
Expand All @@ -42,71 +49,105 @@ public function indexAction(): void
$this->assertPermission('notifications/config/event-rules');

$this->addTitleTab(t('Event Rule'));

$this->controls->addAttributes(['class' => 'event-rule-detail']);

/** @var int $ruleId */
$ruleId = $this->params->getRequired('id');
/** @var array<string, mixed>|null $config */
$config = $this->sessionNamespace->get((string) $ruleId);
$this->controls->addAttributes(['class' => 'event-rule-detail']);

$cache = $this->sessionNamespace->get($ruleId);
$discardChangesButton = null;
if ($config === null) {
$config = $this->fromDb($ruleId);
}

$eventRuleConfig = (new EventRuleConfigForm(
$config,
Url::fromPath(
'notifications/event-rule/search-editor',
['id' => $config['id']]
)
))->populate($config);
$eventRuleConfig
->on(Form::ON_SUCCESS, function (EventRuleConfigForm $form) use ($config) {
/** @var string $ruleId */
$ruleId = $config['id'];
$form->insertOrAddRule($ruleId, $config);
$this->sessionNamespace->delete($ruleId);
Notification::success((sprintf(t('Successfully saved event rule %s'), $config['name'])));

if ($cache) {
$this->sendExtraUpdates(['#col1']);
$this->redirectNow(Links::eventRule((int) $ruleId));
})
->on(EventRuleConfigForm::ON_DELETE, function (EventRuleConfigForm $form) use ($config) {
$ruleId = $config['id'];
$form->removeRule($ruleId);
$this->sessionNamespace->delete($ruleId);
Notification::success(sprintf(t('Successfully deleted event rule %s'), $config['name']));
$this->redirectNow('__CLOSE__');
})
->on(EventRuleConfigForm::ON_DISCARD, function () use ($config) {
$ruleId = $config['id'];
$this->sessionNamespace->delete($ruleId);
Notification::success(sprintf(t('Successfully discarded changes to event rule %s'), $config['name']));
$this->redirectNow(Links::eventRule((int) $ruleId));
})
->on(EventRuleConfigForm::ON_CHANGE, function (EventRuleConfigForm $form) use ($config) {
$config = array_merge($config, $form->getValues());
$this->sessionNamespace->set($config['id'], $config);
})
->handleRequest($this->getServerRequest());

$cache = $this->sessionNamespace->get((string) $ruleId);
if ($cache !== null) {
$this->addContent(Html::tag('div', ['class' => 'cache-notice'], t('There are unsaved changes.')));
$eventRuleConfig = new EventRuleConfig(
Url::fromPath('notifications/event-rule/search-editor', ['id' => $ruleId]),
$cache
);
} else {
$eventRuleConfig = new EventRuleConfig(
Url::fromPath('notifications/event-rule/search-editor', ['id' => $ruleId]),
$this->fromDb($ruleId)
);
$discardChangesButton = (new SubmitButtonElement(
'discard_changes',
[
'label' => t('Discard Changes'),
'form' => 'event-rule-config-form',
'class' => 'btn-discard-changes',
'formnovalidate' => true,
]
));
}

$disableRemoveButton = false;
if (ctype_digit($ruleId)) {

$buttonsWrapper = new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]));
$eventRuleConfigSubmitButton = (new SubmitButtonElement(
'save',
[
'label' => t('Save'),
'form' => 'event-rule-config-form'
]
));
$deleteButton = (new SubmitButtonElement(
'delete',
[
'label' => t('Delete'),
'form' => 'event-rule-config-form',
'class' => 'btn-remove',
'formnovalidate' => true
]
));

$buttonsWrapper->add(
[$eventRuleConfigSubmitButton, $discardChangesButton, $deleteButton]
);

if ($ruleId > 0) {
$incidents = Incident::on(Database::get())
->with('rule')
->filter(Filter::equal('rule.id', $ruleId));

if ($incidents->count() > 0) {
$disableRemoveButton = true;
$deleteButton->addAttributes(['disabled' => true]);
}
}

$saveForm = (new SaveEventRuleForm())
->setShowRemoveButton()
->setShowDismissChangesButton($cache !== null)
->setRemoveButtonDisabled($disableRemoveButton)
->setSubmitButtonDisabled($cache === null)
->setSubmitLabel($this->translate('Save Changes'))
->on(SaveEventRuleForm::ON_SUCCESS, function ($form) use ($ruleId, $eventRuleConfig) {
if ($form->getPressedSubmitElement()->getName() === 'discard_changes') {
$this->sessionNamespace->delete($ruleId);
Notification::success($this->translate('Successfully discarded the pending changes.'));
$this->redirectNow(Links::eventRule($ruleId));
}

if (! $eventRuleConfig->isValid()) {
$eventRuleConfig->addAttributes(['class' => 'invalid']);
return;
}

$form->editRule($ruleId, $this->sessionNamespace->get($ruleId));
$this->sessionNamespace->delete($ruleId);

Notification::success($this->translate('Successfully updated rule.'));
$this->sendExtraUpdates(['#col1']);
$this->redirectNow(Links::eventRule($ruleId));
})->on(SaveEventRuleForm::ON_REMOVE, function ($form) use ($ruleId) {
$form->removeRule($ruleId);
$this->sessionNamespace->delete($ruleId);

Notification::success($this->translate('Successfully removed rule.'));
$this->redirectNow('__CLOSE__');
})->handleRequest($this->getServerRequest());

$eventRuleForm = Html::tag('div', ['class' => 'event-rule-form'], [
Html::tag('h2', $eventRuleConfig->getConfig()['name'] ?? ''),
Html::tag('h2', $config['name'] ?? ''),
(new Link(
new Icon('edit'),
Url::fromPath('notifications/event-rule/edit', [
Expand All @@ -115,30 +156,9 @@ public function indexAction(): void
['class' => 'control-button']
))->openInModal()
]);
$this->addControl($eventRuleForm);

$eventRuleFormAndSave = Html::tag('div', ['class' => 'event-rule-and-save-forms']);
$eventRuleFormAndSave->add([
$eventRuleForm,
$saveForm
]);

$eventRuleConfig
->on(EventRuleConfig::ON_CHANGE, function ($eventRuleConfig) use ($ruleId, $saveForm) {
$this->sessionNamespace->set($ruleId, $eventRuleConfig->getConfig());
$saveForm->setSubmitButtonDisabled(false);
$this->redirectNow(Links::eventRule($ruleId));
});

foreach ($eventRuleConfig->getForms() as $form) {
$form->handleRequest($this->getServerRequest());

if (! $form->hasBeenSent()) {
// Force validation of populated values in case we display an unsaved rule
$form->validatePartial();
}
}

$this->addControl($eventRuleFormAndSave);
$this->addControl($buttonsWrapper);
$this->addContent($eventRuleConfig);
}

Expand Down Expand Up @@ -167,7 +187,7 @@ public function fromDb(int $ruleId): array
}

foreach ($re->rule_escalation_recipient as $recipient) {
$config[$re->getTableName()][$re->position]['recipient'][] = iterator_to_array($recipient);
$config[$re->getTableName()][$re->position]['recipients'][] = iterator_to_array($recipient);
}
}

Expand All @@ -188,7 +208,6 @@ public function completeAction(): void
$this->getDocument()->add($suggestions);
}


/**
* searchEditorAction for Object Extra Tags
*
Expand All @@ -198,16 +217,29 @@ public function completeAction(): void
*/
public function searchEditorAction(): void
{
/** @var string $ruleId */
$ruleId = $this->params->shiftRequired('id');

$eventRule = $this->sessionNamespace->get($ruleId) ?? $this->fromDb($ruleId);
$eventRule = $this->sessionNamespace->get($ruleId);

$editor = EventRuleConfig::createSearchEditor()
->setQueryString($eventRule['object_filter'] ?? '');
if ($eventRule === null) {
$eventRule = $this->fromDb((int) $ruleId);
}

$editor->on(SearchEditor::ON_SUCCESS, function (SearchEditor $form) use ($ruleId, $eventRule) {
$eventRule['object_filter'] = EventRuleConfig::createFilterString($form->getFilter());
$editor = new SearchEditor();

/** @var string $objectFilter */
$objectFilter = $eventRule['object_filter'] ?? '';
$editor->setQueryString($objectFilter);
$editor->setAction(Url::fromRequest()->getAbsoluteUrl());
$editor->setSuggestionUrl(Url::fromPath(
"notifications/event-rule/complete",
['_disableLayout' => true, 'showCompact' => true, 'id' => Url::fromRequest()->getParams()->get('id')]
));

$editor->on(SearchEditor::ON_SUCCESS, function (SearchEditor $form) use ($ruleId, $eventRule) {
$filter = self::createFilterString($form->getFilter());
$eventRule['object_filter'] = $filter;
$this->sessionNamespace->set($ruleId, $eventRule);
$this->getResponse()
->setHeader('X-Icinga-Container', '_self')
Expand All @@ -225,48 +257,60 @@ public function searchEditorAction(): void
$this->setTitle($this->translate('Adjust Filter'));
}

/**
* Create filter string from the given filter rule
*
* @param Filter\Rule $filters
*
* @return string
*/
public static function createFilterString(Filter\Rule $filters): string
{
if ($filters instanceof Filter\Chain) {
foreach ($filters as $filter) {
self::createFilterString($filter);
}
} elseif ($filters instanceof Filter\Condition && empty($filters->getValue())) {
$filters->setValue(true);
}

$filterStr = QueryString::render($filters);

return ! empty($filterStr) ? $filterStr : '';
}

public function editAction(): void
{
/** @var string $ruleId */
$ruleId = $this->params->getRequired('id');
/** @var ?array<string, mixed> $cache */
$cache = $this->sessionNamespace->get($ruleId);

if ($this->params->has('clearCache')) {
$this->sessionNamespace->delete($ruleId);
$cache = [];
}

if (isset($cache) || $ruleId === '-1') {
$config = $cache ?? [];
if ($ruleId === '-1') {
$config = ['id' => $ruleId];
} else {
$config = $this->fromDb((int) $ruleId);
}

$eventRuleForm = (new EventRuleForm())
->populate($config)
->setAction(Url::fromRequest()->getAbsoluteUrl())
->on(Form::ON_SUCCESS, function ($form) use ($ruleId, $cache, $config) {
->on(Form::ON_SUCCESS, function ($form) use ($ruleId, $config) {
$config['name'] = $form->getValue('name');
$config['is_active'] = $form->getValue('is_active');

if ($cache || $ruleId === '-1') {
$this->sessionNamespace->set($ruleId, $config);
$params = [];
if ($ruleId === '-1') {
$params = $config;
} else {
(new SaveEventRuleForm())->editRule((int) $ruleId, $config);
$params['id'] = $ruleId;
}

if ($ruleId === '-1') {
$redirectUrl = Url::fromPath('notifications/event-rules/add', [
'use_cache' => true
]);
$redirectUrl = Url::fromPath('notifications/event-rules/add', $params);
} else {
$redirectUrl = Url::fromPath('notifications/event-rule', [
'id' => $ruleId
]);
$redirectUrl = Url::fromPath('notifications/event-rule', $params);
$this->sendExtraUpdates(['#col1']);
}

$this->sessionNamespace->set($ruleId, $config);
$this->getResponse()->setHeader('X-Icinga-Container', 'col2');
$this->redirectNow($redirectUrl);
})->handleRequest($this->getServerRequest());
Expand Down
Loading

0 comments on commit 81f6608

Please sign in to comment.