Skip to content

Commit 81f6608

Browse files
committed
Build a single form for the event rule configuration
1 parent e3ccb69 commit 81f6608

22 files changed

+2405
-634
lines changed

application/controllers/EventRuleController.php

Lines changed: 145 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@
77
use Icinga\Module\Notifications\Common\Auth;
88
use Icinga\Module\Notifications\Common\Database;
99
use Icinga\Module\Notifications\Common\Links;
10+
use Icinga\Module\Notifications\Forms\EventRuleConfigForm;
1011
use Icinga\Module\Notifications\Forms\EventRuleForm;
11-
use Icinga\Module\Notifications\Forms\SaveEventRuleForm;
1212
use Icinga\Module\Notifications\Model\Incident;
13-
use Icinga\Module\Notifications\Model\ObjectExtraTag;
1413
use Icinga\Module\Notifications\Model\Rule;
1514
use Icinga\Module\Notifications\Web\Control\SearchBar\ExtraTagSuggestions;
16-
use Icinga\Module\Notifications\Widget\EventRuleConfig;
15+
use Icinga\Module\Notifications\Web\Form\EventRuleDecorator;
1716
use Icinga\Web\Notification;
1817
use Icinga\Web\Session;
18+
use ipl\Html\Attributes;
1919
use ipl\Html\Form;
20+
use ipl\Html\FormElement\ButtonElement;
21+
use ipl\Html\FormElement\SubmitButtonElement;
2022
use ipl\Html\Html;
23+
use ipl\Html\HtmlElement;
2124
use ipl\Stdlib\Filter;
2225
use ipl\Web\Compat\CompatController;
2326
use ipl\Web\Control\SearchEditor;
27+
use ipl\Web\Filter\QueryString;
2428
use ipl\Web\Url;
2529
use ipl\Web\Widget\Icon;
2630
use ipl\Web\Widget\Link;
@@ -32,6 +36,9 @@ class EventRuleController extends CompatController
3236
/** @var Session\SessionNamespace */
3337
private $sessionNamespace;
3438

39+
/** @var ?string Event rule config filter */
40+
protected $filter;
41+
3542
public function init()
3643
{
3744
$this->sessionNamespace = Session::getSession()->getNamespace('notifications');
@@ -42,71 +49,105 @@ public function indexAction(): void
4249
$this->assertPermission('notifications/config/event-rules');
4350

4451
$this->addTitleTab(t('Event Rule'));
45-
4652
$this->controls->addAttributes(['class' => 'event-rule-detail']);
4753

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

50-
$cache = $this->sessionNamespace->get($ruleId);
60+
$discardChangesButton = null;
61+
if ($config === null) {
62+
$config = $this->fromDb($ruleId);
63+
}
64+
65+
$eventRuleConfig = (new EventRuleConfigForm(
66+
$config,
67+
Url::fromPath(
68+
'notifications/event-rule/search-editor',
69+
['id' => $config['id']]
70+
)
71+
))->populate($config);
72+
$eventRuleConfig
73+
->on(Form::ON_SUCCESS, function (EventRuleConfigForm $form) use ($config) {
74+
/** @var string $ruleId */
75+
$ruleId = $config['id'];
76+
$form->insertOrAddRule($ruleId, $config);
77+
$this->sessionNamespace->delete($ruleId);
78+
Notification::success((sprintf(t('Successfully saved event rule %s'), $config['name'])));
5179

52-
if ($cache) {
80+
$this->sendExtraUpdates(['#col1']);
81+
$this->redirectNow(Links::eventRule((int) $ruleId));
82+
})
83+
->on(EventRuleConfigForm::ON_DELETE, function (EventRuleConfigForm $form) use ($config) {
84+
$ruleId = $config['id'];
85+
$form->removeRule($ruleId);
86+
$this->sessionNamespace->delete($ruleId);
87+
Notification::success(sprintf(t('Successfully deleted event rule %s'), $config['name']));
88+
$this->redirectNow('__CLOSE__');
89+
})
90+
->on(EventRuleConfigForm::ON_DISCARD, function () use ($config) {
91+
$ruleId = $config['id'];
92+
$this->sessionNamespace->delete($ruleId);
93+
Notification::success(sprintf(t('Successfully discarded changes to event rule %s'), $config['name']));
94+
$this->redirectNow(Links::eventRule((int) $ruleId));
95+
})
96+
->on(EventRuleConfigForm::ON_CHANGE, function (EventRuleConfigForm $form) use ($config) {
97+
$config = array_merge($config, $form->getValues());
98+
$this->sessionNamespace->set($config['id'], $config);
99+
})
100+
->handleRequest($this->getServerRequest());
101+
102+
$cache = $this->sessionNamespace->get((string) $ruleId);
103+
if ($cache !== null) {
53104
$this->addContent(Html::tag('div', ['class' => 'cache-notice'], t('There are unsaved changes.')));
54-
$eventRuleConfig = new EventRuleConfig(
55-
Url::fromPath('notifications/event-rule/search-editor', ['id' => $ruleId]),
56-
$cache
57-
);
58-
} else {
59-
$eventRuleConfig = new EventRuleConfig(
60-
Url::fromPath('notifications/event-rule/search-editor', ['id' => $ruleId]),
61-
$this->fromDb($ruleId)
62-
);
105+
$discardChangesButton = (new SubmitButtonElement(
106+
'discard_changes',
107+
[
108+
'label' => t('Discard Changes'),
109+
'form' => 'event-rule-config-form',
110+
'class' => 'btn-discard-changes',
111+
'formnovalidate' => true,
112+
]
113+
));
63114
}
64115

65-
$disableRemoveButton = false;
66-
if (ctype_digit($ruleId)) {
116+
117+
$buttonsWrapper = new HtmlElement('div', Attributes::create(['class' => ['icinga-controls', 'save-config']]));
118+
$eventRuleConfigSubmitButton = (new SubmitButtonElement(
119+
'save',
120+
[
121+
'label' => t('Save'),
122+
'form' => 'event-rule-config-form'
123+
]
124+
));
125+
$deleteButton = (new SubmitButtonElement(
126+
'delete',
127+
[
128+
'label' => t('Delete'),
129+
'form' => 'event-rule-config-form',
130+
'class' => 'btn-remove',
131+
'formnovalidate' => true
132+
]
133+
));
134+
135+
$buttonsWrapper->add(
136+
[$eventRuleConfigSubmitButton, $discardChangesButton, $deleteButton]
137+
);
138+
139+
if ($ruleId > 0) {
67140
$incidents = Incident::on(Database::get())
68141
->with('rule')
69142
->filter(Filter::equal('rule.id', $ruleId));
70143

71144
if ($incidents->count() > 0) {
72-
$disableRemoveButton = true;
145+
$deleteButton->addAttributes(['disabled' => true]);
73146
}
74147
}
75148

76-
$saveForm = (new SaveEventRuleForm())
77-
->setShowRemoveButton()
78-
->setShowDismissChangesButton($cache !== null)
79-
->setRemoveButtonDisabled($disableRemoveButton)
80-
->setSubmitButtonDisabled($cache === null)
81-
->setSubmitLabel($this->translate('Save Changes'))
82-
->on(SaveEventRuleForm::ON_SUCCESS, function ($form) use ($ruleId, $eventRuleConfig) {
83-
if ($form->getPressedSubmitElement()->getName() === 'discard_changes') {
84-
$this->sessionNamespace->delete($ruleId);
85-
Notification::success($this->translate('Successfully discarded the pending changes.'));
86-
$this->redirectNow(Links::eventRule($ruleId));
87-
}
88-
89-
if (! $eventRuleConfig->isValid()) {
90-
$eventRuleConfig->addAttributes(['class' => 'invalid']);
91-
return;
92-
}
93-
94-
$form->editRule($ruleId, $this->sessionNamespace->get($ruleId));
95-
$this->sessionNamespace->delete($ruleId);
96-
97-
Notification::success($this->translate('Successfully updated rule.'));
98-
$this->sendExtraUpdates(['#col1']);
99-
$this->redirectNow(Links::eventRule($ruleId));
100-
})->on(SaveEventRuleForm::ON_REMOVE, function ($form) use ($ruleId) {
101-
$form->removeRule($ruleId);
102-
$this->sessionNamespace->delete($ruleId);
103-
104-
Notification::success($this->translate('Successfully removed rule.'));
105-
$this->redirectNow('__CLOSE__');
106-
})->handleRequest($this->getServerRequest());
107-
108149
$eventRuleForm = Html::tag('div', ['class' => 'event-rule-form'], [
109-
Html::tag('h2', $eventRuleConfig->getConfig()['name'] ?? ''),
150+
Html::tag('h2', $config['name'] ?? ''),
110151
(new Link(
111152
new Icon('edit'),
112153
Url::fromPath('notifications/event-rule/edit', [
@@ -115,30 +156,9 @@ public function indexAction(): void
115156
['class' => 'control-button']
116157
))->openInModal()
117158
]);
159+
$this->addControl($eventRuleForm);
118160

119-
$eventRuleFormAndSave = Html::tag('div', ['class' => 'event-rule-and-save-forms']);
120-
$eventRuleFormAndSave->add([
121-
$eventRuleForm,
122-
$saveForm
123-
]);
124-
125-
$eventRuleConfig
126-
->on(EventRuleConfig::ON_CHANGE, function ($eventRuleConfig) use ($ruleId, $saveForm) {
127-
$this->sessionNamespace->set($ruleId, $eventRuleConfig->getConfig());
128-
$saveForm->setSubmitButtonDisabled(false);
129-
$this->redirectNow(Links::eventRule($ruleId));
130-
});
131-
132-
foreach ($eventRuleConfig->getForms() as $form) {
133-
$form->handleRequest($this->getServerRequest());
134-
135-
if (! $form->hasBeenSent()) {
136-
// Force validation of populated values in case we display an unsaved rule
137-
$form->validatePartial();
138-
}
139-
}
140-
141-
$this->addControl($eventRuleFormAndSave);
161+
$this->addControl($buttonsWrapper);
142162
$this->addContent($eventRuleConfig);
143163
}
144164

@@ -167,7 +187,7 @@ public function fromDb(int $ruleId): array
167187
}
168188

169189
foreach ($re->rule_escalation_recipient as $recipient) {
170-
$config[$re->getTableName()][$re->position]['recipient'][] = iterator_to_array($recipient);
190+
$config[$re->getTableName()][$re->position]['recipients'][] = iterator_to_array($recipient);
171191
}
172192
}
173193

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

191-
192211
/**
193212
* searchEditorAction for Object Extra Tags
194213
*
@@ -198,16 +217,29 @@ public function completeAction(): void
198217
*/
199218
public function searchEditorAction(): void
200219
{
220+
/** @var string $ruleId */
201221
$ruleId = $this->params->shiftRequired('id');
202222

203-
$eventRule = $this->sessionNamespace->get($ruleId) ?? $this->fromDb($ruleId);
223+
$eventRule = $this->sessionNamespace->get($ruleId);
204224

205-
$editor = EventRuleConfig::createSearchEditor()
206-
->setQueryString($eventRule['object_filter'] ?? '');
225+
if ($eventRule === null) {
226+
$eventRule = $this->fromDb((int) $ruleId);
227+
}
207228

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

231+
/** @var string $objectFilter */
232+
$objectFilter = $eventRule['object_filter'] ?? '';
233+
$editor->setQueryString($objectFilter);
234+
$editor->setAction(Url::fromRequest()->getAbsoluteUrl());
235+
$editor->setSuggestionUrl(Url::fromPath(
236+
"notifications/event-rule/complete",
237+
['_disableLayout' => true, 'showCompact' => true, 'id' => Url::fromRequest()->getParams()->get('id')]
238+
));
239+
240+
$editor->on(SearchEditor::ON_SUCCESS, function (SearchEditor $form) use ($ruleId, $eventRule) {
241+
$filter = self::createFilterString($form->getFilter());
242+
$eventRule['object_filter'] = $filter;
211243
$this->sessionNamespace->set($ruleId, $eventRule);
212244
$this->getResponse()
213245
->setHeader('X-Icinga-Container', '_self')
@@ -225,48 +257,60 @@ public function searchEditorAction(): void
225257
$this->setTitle($this->translate('Adjust Filter'));
226258
}
227259

260+
/**
261+
* Create filter string from the given filter rule
262+
*
263+
* @param Filter\Rule $filters
264+
*
265+
* @return string
266+
*/
267+
public static function createFilterString(Filter\Rule $filters): string
268+
{
269+
if ($filters instanceof Filter\Chain) {
270+
foreach ($filters as $filter) {
271+
self::createFilterString($filter);
272+
}
273+
} elseif ($filters instanceof Filter\Condition && empty($filters->getValue())) {
274+
$filters->setValue(true);
275+
}
276+
277+
$filterStr = QueryString::render($filters);
278+
279+
return ! empty($filterStr) ? $filterStr : '';
280+
}
281+
228282
public function editAction(): void
229283
{
230284
/** @var string $ruleId */
231285
$ruleId = $this->params->getRequired('id');
232-
/** @var ?array<string, mixed> $cache */
233-
$cache = $this->sessionNamespace->get($ruleId);
234-
235-
if ($this->params->has('clearCache')) {
236-
$this->sessionNamespace->delete($ruleId);
237-
$cache = [];
238-
}
239286

240-
if (isset($cache) || $ruleId === '-1') {
241-
$config = $cache ?? [];
287+
if ($ruleId === '-1') {
288+
$config = ['id' => $ruleId];
242289
} else {
243290
$config = $this->fromDb((int) $ruleId);
244291
}
245292

246293
$eventRuleForm = (new EventRuleForm())
247294
->populate($config)
248295
->setAction(Url::fromRequest()->getAbsoluteUrl())
249-
->on(Form::ON_SUCCESS, function ($form) use ($ruleId, $cache, $config) {
296+
->on(Form::ON_SUCCESS, function ($form) use ($ruleId, $config) {
250297
$config['name'] = $form->getValue('name');
251298
$config['is_active'] = $form->getValue('is_active');
252-
253-
if ($cache || $ruleId === '-1') {
254-
$this->sessionNamespace->set($ruleId, $config);
299+
$params = [];
300+
if ($ruleId === '-1') {
301+
$params = $config;
255302
} else {
256-
(new SaveEventRuleForm())->editRule((int) $ruleId, $config);
303+
$params['id'] = $ruleId;
257304
}
258305

259306
if ($ruleId === '-1') {
260-
$redirectUrl = Url::fromPath('notifications/event-rules/add', [
261-
'use_cache' => true
262-
]);
307+
$redirectUrl = Url::fromPath('notifications/event-rules/add', $params);
263308
} else {
264-
$redirectUrl = Url::fromPath('notifications/event-rule', [
265-
'id' => $ruleId
266-
]);
309+
$redirectUrl = Url::fromPath('notifications/event-rule', $params);
267310
$this->sendExtraUpdates(['#col1']);
268311
}
269312

313+
$this->sessionNamespace->set($ruleId, $config);
270314
$this->getResponse()->setHeader('X-Icinga-Container', 'col2');
271315
$this->redirectNow($redirectUrl);
272316
})->handleRequest($this->getServerRequest());

0 commit comments

Comments
 (0)