77use Icinga \Module \Notifications \Common \Auth ;
88use Icinga \Module \Notifications \Common \Database ;
99use Icinga \Module \Notifications \Common \Links ;
10+ use Icinga \Module \Notifications \Forms \EventRuleConfigForm ;
1011use Icinga \Module \Notifications \Forms \EventRuleForm ;
11- use Icinga \Module \Notifications \Forms \SaveEventRuleForm ;
1212use Icinga \Module \Notifications \Model \Incident ;
13- use Icinga \Module \Notifications \Model \ObjectExtraTag ;
1413use Icinga \Module \Notifications \Model \Rule ;
1514use Icinga \Module \Notifications \Web \Control \SearchBar \ExtraTagSuggestions ;
16- use Icinga \Module \Notifications \Widget \ EventRuleConfig ;
15+ use Icinga \Module \Notifications \Web \ Form \ EventRuleDecorator ;
1716use Icinga \Web \Notification ;
1817use Icinga \Web \Session ;
18+ use ipl \Html \Attributes ;
1919use ipl \Html \Form ;
20+ use ipl \Html \FormElement \ButtonElement ;
21+ use ipl \Html \FormElement \SubmitButtonElement ;
2022use ipl \Html \Html ;
23+ use ipl \Html \HtmlElement ;
2124use ipl \Stdlib \Filter ;
2225use ipl \Web \Compat \CompatController ;
2326use ipl \Web \Control \SearchEditor ;
27+ use ipl \Web \Filter \QueryString ;
2428use ipl \Web \Url ;
2529use ipl \Web \Widget \Icon ;
2630use 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