diff --git a/application/controllers/EventRuleController.php b/application/controllers/EventRuleController.php index 8f2c38e86..fe002f48b 100644 --- a/application/controllers/EventRuleController.php +++ b/application/controllers/EventRuleController.php @@ -6,11 +6,14 @@ 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\Model\Incident; use Icinga\Module\Notifications\Model\Rule; use Icinga\Module\Notifications\Web\Control\SearchBar\ExtraTagSuggestions; use Icinga\Module\Notifications\Web\Form\EventRuleDecorator; +use Icinga\Web\Notification; use Icinga\Web\Session; use ipl\Html\Attributes; use ipl\Html\Form; @@ -52,90 +55,92 @@ public function indexAction(): void $this->controls->addAttributes(['class' => 'event-rule-detail']); $config = $this->sessionNamespace->get($ruleId); - + $discardChangesButton = null; if ($config === null) { $config = $this->fromDb($ruleId); - $this->sessionNamespace->set($ruleId, $config); } -// $config = $this->fromDb($ruleId); -// -// if ($filter === '' && isset($config['object_filter'])) { -// $filter = $config['object_filter']; -// } + $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) { + $form->insertOrAddRule($config['id'], $config); + $this->sessionNamespace->delete($config['id']); + Notification::success((sprintf(t('Successfully saved event rule %s'), $config['name']))); + + $this->sendExtraUpdates(['#col1']); + $this->redirectNow(Links::eventRule($config['id'])); + }) + ->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); + $this->redirectNow(Links::eventRule($ruleId)); + }) + ->on(EventRuleConfigForm::ON_CHANGE, function (EventRuleConfigForm $form) use ($config) { + $formValues = $form->getValues(); + $config = array_merge($config, $form->getValues()); + $this->sessionNamespace->set($config['id'], $config); + }) + ->handleRequest($this->getServerRequest()); + + $cache = $this->sessionNamespace->get($ruleId); + if ($cache !== null) { + $this->addContent(Html::tag('div', ['class' => 'cache-notice'], t('There are unsaved changes.'))); + $discardChangesButton = (new SubmitButtonElement( + 'discard_changes', + [ + 'label' => t('Discard Changes'), + 'form' => 'event-rule-config-form', + 'class' => 'btn-discard-changes', + 'formnovalidate' => true, + ] + )); + } + + $buttonsWrapper = new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']])); $eventRuleConfigSubmitButton = (new SubmitButtonElement( 'save', [ 'label' => t('Save'), 'form' => 'event-rule-config-form' ] - ))->setWrapper(new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]))); - - $discardChangesButton = (new SubmitButtonElement( - 'discard_changes', - [ - 'label' => t('Discard Changes'), - 'form' => 'event-rule-config-form', - 'formnovalidate' => true, - ] - )) - ->setWrapper(new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]))); - + )); $deleteButton = (new SubmitButtonElement( 'delete', [ - 'label' => t('Delete'), - 'form' => 'event-rule-config-form', - 'class' => 'btn-remove', + 'label' => t('Delete'), + 'form' => 'event-rule-config-form', + 'class' => 'btn-remove', 'formnovalidate' => true ] - )) - ->setWrapper(new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]))); + )); -// $eventRuleDecorator = new EventRuleDecorator(); -// $eventRuleDecorator->decorate($eventRuleConfigSubmitButton); -// $eventRuleDecorator->decorate($discardChangesButton); + $buttonsWrapper->add( + [$eventRuleConfigSubmitButton, $discardChangesButton, $deleteButton] + ); - $eventRuleConfig = (new EventRuleConfigForm( - $config['object_filter'] ?? '', - Url::fromPath('notifications/event-rule/search-editor', ['id' => $ruleId]) - )) - ->registerElement($eventRuleConfigSubmitButton) - ->registerElement($discardChangesButton) - ->registerElement($deleteButton); - - $eventRuleConfig->populate($config); - $eventRuleConfig - ->on(Form::ON_SUCCESS, function (EventRuleConfigForm $form) use ($deleteButton, $eventRuleConfigSubmitButton, $config) { - $pressedButton = $form->getPressedSubmitElement(); - if ($pressedButton) { - var_dump($pressedButton->getName());die; - if ($pressedButton->getName() === 'delete') { - $this->sessionNamespace->delete($config['id']); - } else { - $db = Database::get(); - $ruleId = (int) $config['id']; - if ($ruleId !== -1) { -// var_dump($config);die; - $db->update('rule', [ - 'name' => $config['name'], - 'timeperiod_id' => $config['timeperiod_id'] ?? null, - 'object_filter' => $config['object_filter'] ?? null, - 'is_active' => $config['is_active'] ?? 'n' - ], ['id = ?' => $ruleId]); - - $form->insertOrAddRule($ruleId, $config); - } - } - } - }) - ->on(Form::ON_SENT, function (Form $form) use ($config, $ruleId) { - $config = array_merge($config, $form->getValues()); - $this->sessionNamespace->set($ruleId, $config); - }); + if ($ruleId > 0) { + $incidents = Incident::on(Database::get()) + ->with('rule') + ->filter(Filter::equal('rule.id', $ruleId)); - $eventRuleConfig->handleRequest($this->getServerRequest()); + if ($incidents->count() > 0) { + $deleteButton->addAttributes(['disabled' => true]); + } + } $eventRuleForm = Html::tag('div', ['class' => 'event-rule-form'], [ Html::tag('h2', $config['name'] ?? ''), @@ -148,10 +153,8 @@ public function indexAction(): void ))->openInModal() ]); $this->addControl($eventRuleForm); - $this->addControl($eventRuleConfigSubmitButton); - $this->addControl($discardChangesButton); - $this->addControl($deleteButton); + $this->addControl($buttonsWrapper); $this->addContent($eventRuleConfig); } @@ -284,19 +287,10 @@ public function editAction(): void ->on(Form::ON_SUCCESS, function ($form) use ($ruleId, $config) { $config['name'] = $form->getValue('name'); $config['is_active'] = $form->getValue('is_active'); - - $db = Database::get(); $params = []; if ($ruleId === '-1') { $params = $config; } else { - $db->update('rule', [ - 'name' => $config['name'], - 'timeperiod_id' => $config['timeperiod_id'] ?? null, - 'object_filter' => $config['object_filter'] ?? null, - 'is_active' => $config['is_active'] ?? 'n' - ], ['id = ?' => $ruleId]); - $params['id'] = $ruleId; } @@ -307,6 +301,7 @@ public function editAction(): void $this->sendExtraUpdates(['#col1']); } + $this->sessionNamespace->set($ruleId, $config); $this->getResponse()->setHeader('X-Icinga-Container', 'col2'); $this->redirectNow($redirectUrl); })->handleRequest($this->getServerRequest()); diff --git a/application/controllers/EventRulesController.php b/application/controllers/EventRulesController.php index 7a132e3f4..daed6ff2c 100644 --- a/application/controllers/EventRulesController.php +++ b/application/controllers/EventRulesController.php @@ -5,12 +5,14 @@ namespace Icinga\Module\Notifications\Controllers; use Icinga\Module\Notifications\Common\Database; +use Icinga\Module\Notifications\Common\Links; use Icinga\Module\Notifications\Forms\EventRuleConfigForm; use Icinga\Module\Notifications\Model\Rule; use Icinga\Module\Notifications\Web\Control\SearchBar\ObjectSuggestions; use Icinga\Module\Notifications\Web\Form\EventRuleDecorator; use Icinga\Module\Notifications\Widget\EventRuleConfig; use Icinga\Module\Notifications\Widget\ItemList\EventRuleList; +use Icinga\Web\Notification; use Icinga\Web\Session; use ipl\Html\Attributes; use ipl\Html\Form; @@ -109,96 +111,57 @@ public function addAction(): void $this->getTabs()->setRefreshUrl(Url::fromPath('notifications/event-rules/add')); $this->controls->addAttributes(['class' => 'event-rule-detail']); + $ruleId = (int) $this->params->getRequired('id'); $params = $this->params->toArray(false); - $config = $params; -// array_shift($config); + $config = $this->sessionNamespace->get($ruleId); - var_dump($config); - $filter = $config['object_filter'] ?? ''; -// $eventRuleConfig = new EventRuleConfig(Url::fromPath('notifications/event-rules/add-search-editor'), $config); - $eventRuleForm = Html::tag('div', ['class' => 'event-rule-form'], [ - Html::tag('h2', $config['name'] ?? ''), - (new Link( - new Icon('edit'), - Url::fromPath('notifications/event-rule/edit', [ - 'id' => -1 - ]), - ['class' => 'control-button'] - ))->openInModal() - ]); + if ($config === null) { + $config = $params; + } $eventRuleConfigSubmitButton = (new SubmitButtonElement( 'save', [ - 'label' => t('Add Rule'), - 'form' => 'event-rule-config-form', - 'formmethod' => 'POST' - ] - ))->setWrapper(new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]))); - - $delete = (new SubmitButtonElement( - 'discard_changes', - [ - 'label' => t('Delete'), + 'label' => t('Save'), 'form' => 'event-rule-config-form', - 'formmethod' => 'POST' + 'formnovalidate' => true ] ))->setWrapper(new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]))); - $eventRuleDecorator = new EventRuleDecorator(); - $eventRuleDecorator->decorate($eventRuleConfigSubmitButton); - $eventRuleConfig = (new EventRuleConfigForm( - $filter, - Url::fromPath('notifications/event-rules/add-search-editor', $params) + $config, + Url::fromPath( + 'notifications/event-rules/search-editor', + ['id' => $ruleId] + ) )) ->registerElement($eventRuleConfigSubmitButton) + ->populate($config); + + $eventRuleConfig ->on(Form::ON_SENT, function (Form $form) use ($config) { + $config = array_merge($config, $form->getValues()); $this->sessionNamespace->set(-1, $config); }) - ->on(Form::ON_SUCCESS, function (EventRuleConfigForm $form) use ($eventRuleConfigSubmitButton, $config) { - var_dump($config);die; + ->on(Form::ON_SUCCESS, function (EventRuleConfigForm $form) use ($config) { $form->insertOrAddRule((int) $config['id'], $config); + Notification::success(sprintf(t('Successfully add event rule %s'), $config['name'])); + $this->sessionNamespace->delete($config['id']); + $this->redirectNow('__CLOSE__'); }) ->handleRequest($this->getServerRequest()); - // Notification::success($this->translate('Successfully added rule.')); - - -// $saveForm = (new SaveEventRuleForm()) -// ->on(SaveEventRuleForm::ON_SUCCESS, function ($saveForm) use ($eventRuleConfig, $config) { -// if (! $eventRuleConfig->isValid()) { -// $eventRuleConfig->addAttributes(['class' => 'invalid']); -// return; -// } -// -// $id = $saveForm->addRule($config); -// Notification::success($this->translate('Successfully added rule.')); -// $this->sendExtraUpdates(['#col1']); -// $this->redirectNow(Links::eventRule($id)); -// })->handleRequest($this->getServerRequest()); -// -// $eventRuleConfig->on(EventRuleConfig::ON_CHANGE, function ($eventRuleConfig) { -// $this->sessionNamespace->set(-1, $eventRuleConfig->getConfig()); -// -// $this->redirectNow(Url::fromPath('notifications/event-rules/add', ['use_cache' => true])); -// }); -// -// foreach ($eventRuleConfig->getForms() as $f) { -// $f->handleRequest($this->getServerRequest()); -// -// if (! $f->hasBeenSent()) { -// // Force validation of populated values in case we display an unsaved rule -// $f->validatePartial(); -// } -// } -// -// $eventRuleFormAndSave = Html::tag('div', ['class' => 'event-rule-and-save-forms']); -// $eventRuleFormAndSave->add([ -// $eventRuleForm, -// $saveForm -// ]); + $eventRuleForm = Html::tag('div', ['class' => 'event-rule-form'], [ + Html::tag('h2', $config['name'] ?? ''), + (new Link( + new Icon('edit'), + Url::fromPath('notifications/event-rule/edit', [ + 'id' => -1 + ]), + ['class' => 'control-button'] + ))->openInModal() + ]); $this->addControl($eventRuleForm); $this->addControl($eventRuleConfigSubmitButton); @@ -215,13 +178,39 @@ public function completeAction(): void public function searchEditorAction(): void { - $editor = $this->createSearchEditor( - Rule::on(Database::get()), - [ - LimitControl::DEFAULT_LIMIT_PARAM, - SortControl::DEFAULT_SORT_PARAM, - ] - ); + $ruleId = $this->params->shiftRequired('id'); + + $eventRule = $this->sessionNamespace->get($ruleId); + + if ($eventRule === null) { + $eventRule = $this->fromDb($ruleId); + } + + $editor = new SearchEditor(); + + $editor->setQueryString($eventRule['object_filter'] ?? ''); + $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') + ->redirectAndExit( + Url::fromPath( + 'notifications/event-rules/add', + ['id' => $ruleId] + ) + ); + }); + + $editor->handleRequest($this->getServerRequest()); $this->getDocument()->add($editor); $this->setTitle($this->translate('Adjust Filter')); @@ -229,20 +218,35 @@ public function searchEditorAction(): void public function addSearchEditorAction(): void { - $params = $this->params->toArray(false); + $ruleId = $this->params->shiftRequired('id'); + + $eventRule = $this->sessionNamespace->get($ruleId); + + if ($eventRule === null) { + $eventRule = $this->fromDb($ruleId); + } - $editor = EventRuleConfig::createSearchEditor() - ->setQueryString($params['object_filter'] ?? ''); + $editor = new SearchEditor(); - $editor->on(SearchEditor::ON_SUCCESS, function (SearchEditor $form) use ($params) { - $params['object_filter'] = EventRuleConfig::createFilterString($form->getFilter()); + $editor->setQueryString($eventRule['object_filter'] ?? ''); + $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') ->redirectAndExit( Url::fromPath( 'notifications/event-rules/add', - $params + ['id' => $ruleId] ) ); }); @@ -253,6 +257,25 @@ public function addSearchEditorAction(): void $this->setTitle($this->translate('Adjust Filter')); } + public static function createFilterString($filters): string + { + foreach ($filters as $filter) { + if ($filter instanceof Filter\Chain) { + self::createFilterString($filter); + } elseif (empty($filter->getValue())) { + $filter->setValue(true); + } + } + + if ($filters instanceof Filter\Condition && empty($filters->getValue())) { + $filters->setValue(true); + } + + $filterStr = QueryString::render($filters); + + return ! empty($filterStr) ? $filterStr : ''; + } + /** * Get the filter created from query string parameters * diff --git a/application/forms/EventRuleConfigElements/EscalationCondition.php b/application/forms/EventRuleConfigElements/EscalationCondition.php index a07ddb242..00b2086ae 100644 --- a/application/forms/EventRuleConfigElements/EscalationCondition.php +++ b/application/forms/EventRuleConfigElements/EscalationCondition.php @@ -42,6 +42,10 @@ protected function assemble() $this->registerElement($addCondition); $conditionCount = (int) $this->getValue('condition-count'); + $this->addElement( + 'hidden', + 'id' + ); if ($addCondition->hasBeenPressed()) { $conditionCount += 1; @@ -55,11 +59,6 @@ protected function assemble() $typeName = 'type_' . $i; $valName = 'val_' . $i; - $this->addElement( - 'hidden', - 'id_' . $i - ); - $col = $this->createElement( 'select', $colName, @@ -232,58 +231,39 @@ protected function createRemoveButton(int $count): FormElement return $removeButton; } - public function getCondition() + public function getValue($name = null, $default = null) { - $filter = Filter::any(); - $count = (int) $this->getValue('condition-count'); + if ($name === 'condition') { + $filter = Filter::any(); + $count = (int) $this->getValue('condition-count'); - if ($count > 0) { // if count is 0, loop runs in reverse direction - foreach (range(1, $count) as $count) { - $chosenType = $this->getValue('column_' . $count, 'placeholder'); + if ($count > 0) { // if count is 0, loop runs in reverse direction + foreach (range(1, $count) as $count) { + $chosenType = $this->getValue('column_' . $count, 'placeholder'); - $filterStr = $chosenType - . $this->getValue('operator_' . $count) - . ($this->getValue('val_' . $count) ?? ($chosenType === 'incident_severity' ? 'ok' : '')); + $filterStr = $chosenType + . $this->getValue('operator_' . $count) + . ($this->getValue('val_' . $count) ?? ($chosenType === 'incident_severity' ? 'ok' : '')); - $filter->add(QueryString::parse($filterStr)); + $filter->add(QueryString::parse($filterStr)); + } } + + return (new FilterRenderer($filter)) + ->render(); } - return (new FilterRenderer($filter)) - ->render(); + return parent::getValue($name, $default); } - public function populate($values) + public function renderUnwrapped() { - foreach ($values as $key => $condition) { - if (! is_int($key)) { - // csrf token and uid - continue; - } - - $count = $key + 1; - if (empty($condition)) { // when other conditions are removed and only 1 pending with no values - $values['column' . $count] = null; - $values['operator' . $count] = null; - $values['value' . $count] = null; + $this->ensureAssembled(); - continue; - } - - $filter = QueryString::parse($condition); - - $values['column' . $count] = $filter->getColumn() === 'placeholder' ? null : $filter->getColumn(); - $values['operator' . $count] = QueryString::getRuleSymbol($filter); - $values['value' . $count] = $filter->getValue(); + if ($this->isEmpty()) { + return ''; } - return parent::populate($values); - } - - private function generateFakeEscalationId(): string - { - return bin2hex(random_bytes(4)); + return parent::renderUnwrapped(); } - - } diff --git a/application/forms/EventRuleConfigElements/EscalationRecipient.php b/application/forms/EventRuleConfigElements/EscalationRecipient.php index 19d33c255..7bdc26f8f 100644 --- a/application/forms/EventRuleConfigElements/EscalationRecipient.php +++ b/application/forms/EventRuleConfigElements/EscalationRecipient.php @@ -48,13 +48,11 @@ protected function assemble() $removePosition = null; foreach (range(1, $recipientCount) as $i) { - $escalationRecipientId = $this->createElement( + $this->addElement( 'hidden', 'id_' . $i ); - $this->registerElement($escalationRecipientId); - $col = $this->createElement( 'select', 'column_' . $i, @@ -172,7 +170,14 @@ protected function fetchOptions(): array return $options; } - protected function createRemoveButton(int $count): ?FormElement + /** + * Create remove button for the recipient in the given position + * + * @param int $pos + * + * @return FormElement|null + */ + protected function createRemoveButton(int $pos): ?FormElement { if ((int) $this->getValue('recipient-count') === 1) { return null; @@ -180,7 +185,7 @@ protected function createRemoveButton(int $count): ?FormElement $removeButton = $this->createElement( 'submitButton', - 'remove_' . $count, + 'remove_' . $pos, [ 'class' => ['remove-button', 'control-button', 'spinner'], 'label' => new Icon('minus'), @@ -194,7 +199,12 @@ protected function createRemoveButton(int $count): ?FormElement return $removeButton; } - public function getRecipients() + /** + * Get recipients of the escalation + * + * @return array> + */ + public function getRecipients(): array { $count = (int) $this->getValue('recipient-count'); @@ -220,4 +230,15 @@ public function getRecipients() return $values; } + + public function renderUnwrapped() + { + $this->ensureAssembled(); + + if ($this->isEmpty()) { + return ''; + } + + return parent::renderUnwrapped(); + } } diff --git a/application/forms/EventRuleConfigForm.php b/application/forms/EventRuleConfigForm.php index 9b5b3ee8a..e9c39b3a5 100644 --- a/application/forms/EventRuleConfigForm.php +++ b/application/forms/EventRuleConfigForm.php @@ -14,8 +14,6 @@ use Icinga\Web\Session; use ipl\Html\Contract\FormElement; use ipl\Html\Form; -use ipl\Html\FormElement\ButtonElement; -use ipl\Html\FormElement\SubmitButtonElement; use ipl\Html\Html; use ipl\Html\HtmlElement; use ipl\Html\ValidHtml; @@ -35,6 +33,12 @@ class EventRuleConfigForm extends Form use FormUid; use Translation; + public const ON_DELETE = 'delete'; + + public const ON_DISCARD = 'discard'; + + public const ON_CHANGE = 'change'; + /** @var HtmlElement[] */ protected $escalations = []; @@ -47,16 +51,22 @@ class EventRuleConfigForm extends Form /** @var ValidHtml[] */ protected $options; - /** @var string */ - protected $filter; + /** @var array */ + protected $config; /** @var Url */ protected $searchEditorUrl; - public function __construct(string $filter, Url $searchEditorUrl) + public function __construct(array $config, Url $searchEditorUrl) { - $this->filter = $filter; + $this->config = $config; $this->searchEditorUrl = $searchEditorUrl; + $this->on(self::ON_SENT, function () { + $config = array_merge($this->config, $this->getValues()); + if ($config !== $this->config) { + $this->emit(self::ON_CHANGE, [$this]); + } + }); } public function hasBeenSubmitted() @@ -64,8 +74,13 @@ public function hasBeenSubmitted() $pressedButton = $this->getPressedSubmitElement(); if ($pressedButton) { - var_dump($pressedButton->getName()); - if (in_array($pressedButton->getName(), ['save', 'discard_changes', 'delete'])) { + $buttonName = $pressedButton->getName(); + + if ($buttonName === 'delete') { + $this->emit(self::ON_DELETE, [$this]); + } elseif ($buttonName === 'discard_changes') { + $this->emit(self::ON_DISCARD, [$this]); + } elseif ($buttonName === 'save') { return true; } } @@ -80,7 +95,7 @@ protected function assemble() // Duplicate submit button for save $this->addElement( - 'submit', + 'submitButton', 'save', [ 'hidden' => true, @@ -89,41 +104,25 @@ protected function assemble() ); $this->addElement( - 'hidden', - 'id' + 'submitButton', + 'delete', + [ + 'hidden' => true, + 'class' => 'primary-submit-btn-duplicate' + ] ); -// $this->addElement( -// 'submit', -// 'delete', -// [ -// 'class' => ['submit-btn-duplicate'], -// 'hidden' => true -// ] -// ); - -// /** @var ?SubmitButtonElement $discard */ -// $discard = $this->getElement('config-change'); -// if ($discard) { -// if ($discard->hasBeenPressed()) { -// var_dump($discard->getValueAttribute()); -// var_dump('discard presssed'); -// die; -// } -// } -// $ruleId = (int) $this->getValue('rule_id'); - -// if ($ruleId > 0) -// -// var_dump(); - -// var_dump($this->getElement('discard_changes')); -// $this->getElement('save') -// ->getWrapper() -// ->prepend($deleteButton); + $this->addElement( + 'submitButton', + 'discard_changes', + [ + 'hidden' => true, + 'class' => 'primary-submit-btn-duplicate' + ] + ); $configFilter = (new EventRuleConfigFilter('config-filter')) - ->setObjectFilter($this->filter) + ->setObjectFilter($this->config['object_filter'] ?? '') ->setSearchEditorUrl($this->searchEditorUrl); $this->registerElement($configFilter); $configFilter->ensureAssembled(); @@ -134,7 +133,8 @@ protected function assemble() [ 'class' => ['add-button', 'control-button', 'spinner'], 'label' => new Icon('plus'), - 'title' => $this->translate('Add Escalation') + 'title' => $this->translate('Add Escalation'), + 'formnovalidate' => true ] ); @@ -166,8 +166,6 @@ protected function assemble() $this->registerElement($escalationCondition); $this->registerElement($escalationRecipient); - $escalationCondition->ensureAssembled(); - $escalationRecipient->ensureAssembled(); $this->escalations[$i] = Html::tag( 'li', @@ -183,7 +181,6 @@ protected function assemble() } $this->handleRemove(); - $this->add(Html::tag( 'ul', ['class' => 'filter-wrapper'], @@ -225,7 +222,10 @@ public function handleRemove() { $pressedButton = $this->getPressedSubmitElement(); - if ($pressedButton && str_contains($pressedButton->getName(), 'remove-escalation')) { + if ( + $pressedButton + && strpos($pressedButton->getName(), 'remove-escalation') !== false + ) { $this->clearPopulatedValue('escalation-count'); $position = (int) substr($pressedButton, strpos($pressedButton, "_") + 1); unset($this->escalations[$position]); @@ -259,83 +259,78 @@ public function handleRemove() public function populate($values) { - if (isset($values['rule_escalation'])) { - $formValues = []; - $formValues['escalation-count'] = count($values['rule_escalation']); - - foreach ($values['rule_escalation'] as $position => $escalation) { -// var_dump($escalation);die; - $conditions = explode('|', $escalation['condition'] ?? ''); - $conditionFormValues = []; - $conditionFormValues['condition-count'] = count($conditions); - - foreach ($conditions as $key => $condition) { - if ($condition === '') { - $conditionFormValues['condition-count'] = 0; - continue; - } + if (! isset($values['rule_escalation'])) { + return parent::populate($values); + } - $count = $key + 1; - if (empty($condition)) { // when other conditions are removed and only 1 pending with no values - $conditionFormValues['column' . $count] = null; - $conditionFormValues['operator' . $count] = null; - $conditionFormValues['value' . $count] = null; + $formValues = []; + $formValues['escalation-count'] = count($values['rule_escalation']); - continue; - } + foreach ($values['rule_escalation'] as $position => $escalation) { + $conditions = explode('|', $escalation['condition'] ?? ''); + $conditionFormValues = []; + $conditionFormValues['condition-count'] = count($conditions); - $filter = QueryString::parse($condition); + $conditionFormValues['id'] = $escalation['id']; + foreach ($conditions as $key => $condition) { + if ($condition === '') { + $conditionFormValues['condition-count'] = 0; + continue; + } - $conditionFormValues['column_' . $count] = $filter->getColumn() === 'placeholder' - ? null - : $filter->getColumn(); + $count = $key + 1; + if (empty($condition)) { // when other conditions are removed and only 1 pending with no values + $conditionFormValues['column_' . $count] = null; + $conditionFormValues['operator_' . $count] = null; + $conditionFormValues['value_' . $count] = null; - if ($conditionFormValues['column_' . $count]) { - $conditionFormValues['type_' . $count] = $conditionFormValues['column_' . $count]; - } + continue; + } + + $filter = QueryString::parse($condition); + $conditionFormValues['column_' . $count] = $filter->getColumn() === 'placeholder' + ? null + : $filter->getColumn(); - $conditionFormValues['operator_' . $count] = QueryString::getRuleSymbol($filter); - $conditionFormValues['val_' . $count] = $filter->getValue(); + if ($conditionFormValues['column_' . $count]) { + $conditionFormValues['type_' . $count] = $conditionFormValues['column_' . $count]; } - $formValues['escalation-condition_' . $position] = $conditionFormValues; - - $recipientFormValues = []; - $recipientFormValues['recipient-count'] = count($escalation['recipients']); - - foreach ($escalation['recipients'] as $key => $recipient) { - if (is_array($recipient)) { - $count = 0; - foreach ($recipient as $elementName => $elementValue) { - if ($elementValue === null) { - continue; - } - - $count = $key + 1; - $selectedOption = str_replace('id', $elementValue, $elementName, $replaced); - if ($replaced && $elementName !== 'channel_id') { - $recipientFormValues['column_' . $count] = $selectedOption; - } elseif ($elementName === 'channel_id') { - $recipientFormValues['val_' . $count] = $elementValue; - } + $conditionFormValues['operator_' . $count] = QueryString::getRuleSymbol($filter); + $conditionFormValues['val_' . $count] = $filter->getValue(); + } + + $formValues['escalation-condition_' . $position] = $conditionFormValues; + $recipientFormValues = []; + $recipientFormValues['recipient-count'] = count($escalation['recipients']); + + foreach ($escalation['recipients'] as $key => $recipient) { + if (is_array($recipient)) { + $count = 0; + foreach ($recipient as $elementName => $elementValue) { + if ($elementValue === null) { + continue; } - if (isset($recipient['id'])) { - $recipientFormValues['id_' . $count] = $recipient['id']; + $count = $key + 1; + $selectedOption = str_replace('id', $elementValue, $elementName, $replaced); + if ($replaced && $elementName !== 'channel_id') { + $recipientFormValues['column_' . $count] = $selectedOption; + } elseif ($elementName === 'channel_id') { + $recipientFormValues['val_' . $count] = $elementValue; } } - } - $formValues['escalation-recipient_' . $position] = $recipientFormValues; + if (isset($recipient['id'])) { + $recipientFormValues['id_' . $count] = (int) $recipient['id']; + } + } } - parent::populate($formValues); - } else { - parent::populate($values); + $formValues['escalation-recipient_' . $position] = $recipientFormValues; } - - return $this; + return parent::populate($formValues); } public function getValues() @@ -348,8 +343,8 @@ public function getValues() if ($name[0] === 'escalation-condition') { /** @var EscalationCondition $element */ $escalations[$name[1]]['condition-count'] = (int) $element->getValue('condition-count'); - $escalations[$name[1]]['condition'] = $element->getCondition(); - $escalations[$name[1]]['id'] = $element->getValue('id_' . $name[1]); + $escalations[$name[1]]['condition'] = $element->getValue('condition'); + $escalations[$name[1]]['id'] = (int) $element->getValue('id'); } elseif ($name[0] === 'escalation-recipient') { /** @var EscalationRecipient $element */ $escalations[$name[1]]['recipient-count'] = (int) $element->getValue('recipient-count'); @@ -368,8 +363,7 @@ public function getValues() protected function createRemoveButton(int $count): FormElement { -// $escalationId = $this->config['rule_escalation'][$position]['id']; - $escalationId = 1; + $escalationId = $this->config['rule_escalation'][$count]['id'] ?? null; $incident = Incident::on(Database::get()) ->with('rule_escalation'); @@ -398,15 +392,15 @@ protected function createRemoveButton(int $count): FormElement $button ->getAttributes() - ->registerAttributeCallback('disabled', function () { -// return $this->disableRemoveEscalation; + ->registerAttributeCallback('disabled', function () use ($disableRemoveButton) { + return $disableRemoveButton; }) - ->registerAttributeCallback('title', function () { -// if ($this->disableRemoveEscalation) { -// return $this->translate( -// 'There exist active incidents for this escalation and hence cannot be removed' -// ); -// } + ->registerAttributeCallback('title', function () use ($disableRemoveButton) { + if ($disableRemoveButton) { + return $this->translate( + 'There exist active incidents for this escalation and hence cannot be removed' + ); + } return $this->translate('Remove escalation'); }); @@ -583,4 +577,45 @@ function (array $element) use ($recipientId) { } } } + + public function isValidEvent($event) + { + if (in_array($event, [self::ON_CHANGE, self::ON_DELETE, self::ON_DISCARD])) { + return true; + } + + return parent::isValidEvent($event); + } + + /** + * Remove the given event rule + * + * @param int $id + * + * @return void + */ + public function removeRule(int $id): void + { + $db = Database::get(); + + $db->beginTransaction(); + + $escalations = RuleEscalation::on($db) + ->columns('id') + ->filter(Filter::equal('rule_id', $id)); + + $escalationsToRemove = []; + foreach ($escalations as $escalation) { + $escalationsToRemove[] = $escalation->id; + } + + if (! empty($escalationsToRemove)) { + $db->delete('rule_escalation_recipient', ['rule_escalation_id IN (?)' => $escalationsToRemove]); + } + + $db->delete('rule_escalation', ['rule_id = ?' => $id]); + $db->delete('rule', ['id = ?' => $id]); + + $db->commitTransaction(); + } } diff --git a/public/css/detail/event-rule-detail.less b/public/css/detail/event-rule-detail.less index c7da0c23b..1569c3727 100644 --- a/public/css/detail/event-rule-detail.less +++ b/public/css/detail/event-rule-detail.less @@ -464,4 +464,32 @@ display: inline-flex; float: right; width: fit-content; + flex-direction: row-reverse; + + button[type="submit"]:not(:first-child) { + margin-right: 1em; + + &:disabled { + background: @gray-light; + color: @disabled-gray; + cursor: not-allowed; + border: transparent; + } + + &.btn-remove { + border: none; + .button(@body-bg-color, @color-critical, @color-critical-accentuated); + + &:disabled { + background: none; + color: @disabled-gray; + border: none; + cursor: not-allowed; + } + } + + &.btn-discard-changes { + .event-rule-button(); + } + } } diff --git a/public/css/event-rule-config.less b/public/css/event-rule-config.less index 4a4453d80..07a4bf842 100644 --- a/public/css/event-rule-config.less +++ b/public/css/event-rule-config.less @@ -57,6 +57,13 @@ margin-bottom: 2em; .remove-button { align-self: flex-start; + + &:disabled { + background: @gray-light; + color: @disabled-gray; + cursor: not-allowed; + border-color: transparent; + } } .horizontal-line {