1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * @var CView $this 24 */ 25 26require_once dirname(__FILE__).'/js/configuration.action.edit.js.php'; 27 28$widget = (new CWidget())->setTitle(_('Actions')); 29 30// create form 31$actionForm = (new CForm()) 32 ->setId('action-form') 33 ->setName('action.edit') 34 ->setAction((new CUrl('actionconf.php')) 35 ->setArgument('eventsource', $data['eventsource']) 36 ->getUrl() 37 ) 38 ->setAttribute('aria-labeledby', ZBX_STYLE_PAGE_TITLE) 39 ->addVar('form', $data['form']); 40 41if ($data['actionid']) { 42 $actionForm->addVar('actionid', $data['actionid']); 43} 44 45// Action tab. 46$action_tab = (new CFormList()) 47 ->addRow( 48 (new CLabel(_('Name'), 'name'))->setAsteriskMark(), 49 (new CTextBox('name', $data['action']['name'])) 50 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) 51 ->setAriaRequired() 52 ->setAttribute('autofocus', 'autofocus') 53 ); 54 55// Create condition table. 56$condition_table = (new CTable(_('No conditions defined.'))) 57 ->setId('conditionTable') 58 ->setAttribute('style', 'width: 100%;') 59 ->setHeader([_('Label'), _('Name'), _('Action')]); 60 61$i = 0; 62 63if ($data['action']['filter']['conditions']) { 64 $actionConditionStringValues = actionConditionValueToString([$data['action']]); 65 66 foreach ($data['action']['filter']['conditions'] as $cIdx => $condition) { 67 if (!isset($condition['conditiontype'])) { 68 $condition['conditiontype'] = 0; 69 } 70 if (!isset($condition['operator'])) { 71 $condition['operator'] = 0; 72 } 73 if (!isset($condition['value'])) { 74 $condition['value'] = ''; 75 } 76 if (!array_key_exists('value2', $condition)) { 77 $condition['value2'] = ''; 78 } 79 if (!str_in_array($condition['conditiontype'], $data['allowedConditions'])) { 80 continue; 81 } 82 83 $label = isset($condition['formulaid']) ? $condition['formulaid'] : num2letter($i); 84 85 $labelSpan = (new CSpan($label)) 86 ->addClass('label') 87 ->setAttribute('data-conditiontype', $condition['conditiontype']) 88 ->setAttribute('data-formulaid', $label); 89 90 $condition_table->addRow( 91 [ 92 $labelSpan, 93 (new CCol(getConditionDescription($condition['conditiontype'], $condition['operator'], 94 $actionConditionStringValues[0][$cIdx], $condition['value2'] 95 )))->addClass(ZBX_STYLE_TABLE_FORMS_OVERFLOW_BREAK), 96 (new CCol([ 97 (new CButton('remove', _('Remove'))) 98 ->onClick('javascript: removeCondition('.$i.');') 99 ->addClass(ZBX_STYLE_BTN_LINK) 100 ->removeId(), 101 new CVar('conditions['.$i.']', $condition) 102 ]))->addClass(ZBX_STYLE_NOWRAP) 103 ], 104 null, 'conditions_'.$i 105 ); 106 107 $i++; 108 } 109} 110 111$formula = (new CTextBox('formula', $data['action']['filter']['formula'])) 112 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) 113 ->setId('formula') 114 ->setAttribute('placeholder', 'A or (B and C) …'); 115 116$action_tab->addRow(new CLabel(_('Type of calculation'), 'label-evaltype'), [ 117 (new CSelect('evaltype')) 118 ->setId('evaltype') 119 ->setFocusableElementId('label-evaltype') 120 ->setValue($data['action']['filter']['evaltype']) 121 ->addOptions(CSelect::createOptionsFromArray([ 122 CONDITION_EVAL_TYPE_AND_OR => _('And/Or'), 123 CONDITION_EVAL_TYPE_AND => _('And'), 124 CONDITION_EVAL_TYPE_OR => _('Or'), 125 CONDITION_EVAL_TYPE_EXPRESSION => _('Custom expression') 126 ])), 127 (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), 128 (new CSpan())->setId('conditionLabel'), 129 $formula 130]); 131 132$condition_table->addRow([ 133 (new CSimpleButton(_('Add'))) 134 ->onClick('return PopUp("popup.condition.actions",'.json_encode([ 135 'type' => ZBX_POPUP_CONDITION_TYPE_ACTION, 136 'source' => $data['eventsource'] 137 ]).', null, this);') 138 ->addClass(ZBX_STYLE_BTN_LINK) 139]); 140 141$action_tab->addRow(_('Conditions'), 142 (new CDiv($condition_table)) 143 ->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) 144 ->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;') 145); 146 147$action_tab->addRow(_('Enabled'), 148 (new CCheckBox('status', ACTION_STATUS_ENABLED))->setChecked($data['action']['status'] == ACTION_STATUS_ENABLED) 149); 150 151// Operations tab. 152$operation_tab = new CFormList(); 153 154if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) { 155 $operation_tab->addRow((new CLabel(_('Default operation step duration'), 'esc_period'))->setAsteriskMark(), 156 (new CTextBox('esc_period', $data['action']['esc_period'])) 157 ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH) 158 ->setAriaRequired() 159 ); 160} 161 162if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) { 163 $operation_tab->addRow(_('Pause operations for suppressed problems'), 164 (new CCheckBox('pause_suppressed', ACTION_PAUSE_SUPPRESSED_TRUE)) 165 ->setChecked($data['action']['pause_suppressed'] == ACTION_PAUSE_SUPPRESSED_TRUE) 166 ); 167} 168 169// create operation table 170$operations_table = (new CTable()) 171 ->setId('op-table') 172 ->setAttribute('style', 'width: 100%;'); 173if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) { 174 $operations_table->setHeader([_('Steps'), _('Details'), _('Start in'), _('Duration'), _('Action')]); 175 $delays = count_operations_delay($data['action']['operations'], $data['action']['esc_period']); 176} 177else { 178 $operations_table->setHeader([_('Details'), _('Action')]); 179} 180 181if ($data['action']['operations']) { 182 $actionOperationDescriptions = getActionOperationDescriptions([$data['action']], ACTION_OPERATION); 183 184 $simple_interval_parser = new CSimpleIntervalParser(); 185 186 foreach ($data['action']['operations'] as $operationid => $operation) { 187 if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_OPERATION])) { 188 continue; 189 } 190 191 if (array_key_exists('opcommand', $operation)) { 192 $operation['opcommand'] += [ 193 'scriptid' => '0' 194 ]; 195 } 196 197 if (!isset($operation['opconditions'])) { 198 $operation['opconditions'] = []; 199 } 200 if (!isset($operation['mediatypeid'])) { 201 $operation['mediatypeid'] = 0; 202 } 203 204 $details = new CSpan($actionOperationDescriptions[0][$operationid]); 205 206 $operation_for_popup = array_merge($operation, ['id' => $operationid]); 207 foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) { 208 if (array_key_exists($var, $operation_for_popup)) { 209 $operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field); 210 } 211 } 212 213 if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) { 214 $esc_steps_txt = null; 215 $esc_period_txt = null; 216 $esc_delay_txt = null; 217 218 if ($operation['esc_step_from'] < 1) { 219 $operation['esc_step_from'] = 1; 220 } 221 222 $esc_steps_txt = $operation['esc_step_from'].' - '.$operation['esc_step_to']; 223 224 // display N-N as N 225 $esc_steps_txt = ($operation['esc_step_from'] == $operation['esc_step_to']) 226 ? $operation['esc_step_from'] 227 : $operation['esc_step_from'].' - '.$operation['esc_step_to']; 228 229 $esc_period_txt = ($simple_interval_parser->parse($operation['esc_period']) == CParser::PARSE_SUCCESS 230 && timeUnitToSeconds($operation['esc_period']) == 0) 231 ? _('Default') 232 : $operation['esc_period']; 233 234 $esc_delay_txt = ($delays[$operation['esc_step_from']] === null) 235 ? _('Unknown') 236 : ($delays[$operation['esc_step_from']] != 0 237 ? convertUnits(['value' => $delays[$operation['esc_step_from']], 'units' => 'uptime']) 238 : _('Immediately') 239 ); 240 241 $operation_row = [ 242 $esc_steps_txt, 243 $details, 244 $esc_delay_txt, 245 $esc_period_txt, 246 (new CCol( 247 new CHorList([ 248 (new CSimpleButton(_('Edit'))) 249 ->addClass(ZBX_STYLE_BTN_LINK) 250 ->addClass('js-edit-button') 251 ->setAttribute('data-operation', json_encode([ 252 'operationid' => $operationid, 253 'actionid' => $data['actionid'], 254 'eventsource' => $data['eventsource'], 255 'operationtype' => ACTION_OPERATION 256 ])), 257 [ 258 (new CButton('remove', _('Remove'))) 259 ->onClick('removeOperation('.$operationid.', '.ACTION_OPERATION.');') 260 ->addClass(ZBX_STYLE_BTN_LINK) 261 ->removeId(), 262 new CVar('operations['.$operationid.']', $operation), 263 new CVar('operations_for_popup['.ACTION_OPERATION.']['.$operationid.']', 264 json_encode($operation_for_popup) 265 ) 266 ] 267 ]) 268 ))->addClass(ZBX_STYLE_NOWRAP) 269 ]; 270 } 271 else { 272 $operation_row = [ 273 $details, 274 (new CCol( 275 new CHorList([ 276 (new CSimpleButton(_('Edit'))) 277 ->addClass(ZBX_STYLE_BTN_LINK) 278 ->addClass('js-edit-button') 279 ->setAttribute('data-operation', json_encode([ 280 'operationid' => $operationid, 281 'actionid' => $data['actionid'], 282 'eventsource' => $data['eventsource'], 283 'operationtype' => ACTION_OPERATION 284 ])), 285 [ 286 (new CButton('remove', _('Remove'))) 287 ->onClick('removeOperation('.$operationid.', '.ACTION_OPERATION.');') 288 ->addClass(ZBX_STYLE_BTN_LINK) 289 ->removeId(), 290 new CVar('operations['.$operationid.']', $operation), 291 new CVar('operations_for_popup['.ACTION_OPERATION.']['.$operationid.']', 292 json_encode($operation_for_popup) 293 ) 294 ] 295 ]) 296 ))->addClass(ZBX_STYLE_NOWRAP) 297 ]; 298 } 299 $operations_table->addRow($operation_row, null, 'operations_'.$operationid); 300 } 301} 302 303$operations_table->addRow( 304 (new CSimpleButton(_('Add'))) 305 ->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','.ACTION_OPERATION.')') 306 ->addClass(ZBX_STYLE_BTN_LINK) 307); 308 309$operation_tab->addRow(_('Operations'), 310 (new CDiv($operations_table)) 311 ->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) 312 ->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;') 313); 314 315// Recovery operation tab. 316if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS || $data['eventsource'] == EVENT_SOURCE_INTERNAL) { 317 // Create operation table. 318 $operations_table = (new CTable()) 319 ->setId('rec-table') 320 ->setAttribute('style', 'width: 100%;'); 321 $operations_table->setHeader([_('Details'), _('Action')]); 322 323 if ($data['action']['recovery_operations']) { 324 $actionOperationDescriptions = getActionOperationDescriptions([$data['action']], ACTION_RECOVERY_OPERATION); 325 326 foreach ($data['action']['recovery_operations'] as $operationid => $operation) { 327 if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_RECOVERY_OPERATION])) { 328 continue; 329 } 330 if (!isset($operation['opconditions'])) { 331 $operation['opconditions'] = []; 332 } 333 334 if (!array_key_exists('opmessage', $operation)) { 335 $operation['opmessage'] = []; 336 } 337 338 $operation['opmessage'] += [ 339 'mediatypeid' => '0', 340 'message' => '', 341 'subject' => '', 342 'default_msg' => '1' 343 ]; 344 345 $details = new CSpan($actionOperationDescriptions[0][$operationid]); 346 347 $operation_for_popup = array_merge($operation, ['id' => $operationid]); 348 foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) { 349 if (array_key_exists($var, $operation_for_popup)) { 350 $operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field); 351 } 352 } 353 354 $operations_table->addRow([ 355 $details, 356 (new CCol( 357 new CHorList([ 358 (new CSimpleButton(_('Edit'))) 359 ->addClass(ZBX_STYLE_BTN_LINK) 360 ->addClass('js-edit-button') 361 ->setAttribute('data-operation', json_encode([ 362 'operationid' => $operationid, 363 'actionid' => $data['actionid'], 364 'eventsource' => $data['eventsource'], 365 'operationtype' => ACTION_RECOVERY_OPERATION 366 ])), 367 [ 368 (new CButton('remove', _('Remove'))) 369 ->onClick( 370 'javascript: removeOperation('.$operationid.', '.ACTION_RECOVERY_OPERATION.');' 371 ) 372 ->addClass(ZBX_STYLE_BTN_LINK) 373 ->removeId(), 374 new CVar('recovery_operations['.$operationid.']', $operation), 375 new CVar('operations_for_popup['.ACTION_RECOVERY_OPERATION.']['.$operationid.']', 376 json_encode($operation_for_popup) 377 ) 378 ] 379 ]) 380 ))->addClass(ZBX_STYLE_NOWRAP) 381 ], null, 'recovery_operations_'.$operationid); 382 } 383 } 384 385 $operations_table->addRow( 386 (new CSimpleButton(_('Add'))) 387 ->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','. 388 ACTION_RECOVERY_OPERATION.')' 389 ) 390 ->addClass(ZBX_STYLE_BTN_LINK) 391 ); 392 393 $operation_tab->addRow(_('Recovery operations'), 394 (new CDiv($operations_table)) 395 ->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) 396 ->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;') 397 ); 398} 399 400// Acknowledge operations 401if ($data['eventsource'] == EVENT_SOURCE_TRIGGERS) { 402 $action_formname = $actionForm->getName(); 403 404 $operations_table = (new CTable()) 405 ->setId('ack-table') 406 ->setAttribute('style', 'width: 100%;'); 407 $operations_table->setHeader([_('Details'), _('Action')]); 408 409 if ($data['action']['ack_operations']) { 410 $operation_descriptions = getActionOperationDescriptions([$data['action']], ACTION_ACKNOWLEDGE_OPERATION); 411 412 foreach ($data['action']['ack_operations'] as $operationid => $operation) { 413 if (!str_in_array($operation['operationtype'], $data['allowedOperations'][ACTION_ACKNOWLEDGE_OPERATION])) { 414 continue; 415 } 416 $operation += [ 417 'opconditions' => [], 418 'mediatypeid' => 0 419 ]; 420 421 $details = new CSpan($operation_descriptions[0][$operationid]); 422 423 $operation_for_popup = array_merge($operation, ['id' => $operationid]); 424 foreach (['opcommand_grp' => 'groupid', 'opcommand_hst' => 'hostid'] as $var => $field) { 425 if (array_key_exists($var, $operation_for_popup)) { 426 $operation_for_popup[$var] = zbx_objectValues($operation_for_popup[$var], $field); 427 } 428 } 429 430 $operations_table->addRow([ 431 $details, 432 (new CCol( 433 new CHorList([ 434 (new CSimpleButton(_('Edit'))) 435 ->addClass(ZBX_STYLE_BTN_LINK) 436 ->addClass('js-edit-button') 437 ->setAttribute('data-operation', json_encode([ 438 'operationid' => $operationid, 439 'actionid' => $data['actionid'], 440 'eventsource' => $data['eventsource'], 441 'operationtype' => ACTION_ACKNOWLEDGE_OPERATION 442 ])), 443 [ 444 (new CButton('remove', _('Remove'))) 445 ->onClick('javascript: removeOperation('.$operationid.', '.ACTION_ACKNOWLEDGE_OPERATION. 446 ');' 447 ) 448 ->addClass(ZBX_STYLE_BTN_LINK) 449 ->removeId(), 450 new CVar('ack_operations['.$operationid.']', $operation), 451 new CVar('operations_for_popup['.ACTION_ACKNOWLEDGE_OPERATION.']['.$operationid.']', 452 json_encode($operation_for_popup) 453 ) 454 ] 455 ]) 456 ))->addClass(ZBX_STYLE_NOWRAP) 457 ], null, 'ack_operations_'.$operationid); 458 } 459 } 460 461 $operations_table->addRow( 462 (new CSimpleButton(_('Add'))) 463 ->onClick('operation_details.open(this,'.$data['actionid'].','.$data['eventsource'].','. 464 ACTION_ACKNOWLEDGE_OPERATION.')' 465 ) 466 ->addClass(ZBX_STYLE_BTN_LINK) 467 ); 468 469 $operation_tab->addRow(_('Update operations'), 470 (new CDiv($operations_table)) 471 ->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) 472 ->addStyle('min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;') 473 ); 474} 475 476// Append tabs to form. 477$action_tabs = (new CTabView()) 478 ->addTab('actionTab', _('Action'), $action_tab) 479 ->addTab('operationTab', _('Operations'), $operation_tab, TAB_INDICATOR_OPERATIONS); 480 481if (!hasRequest('form_refresh')) { 482 $action_tabs->setSelected(0); 483} 484 485// Append buttons to form. 486$others = []; 487if ($data['actionid']) { 488 $form_buttons = [ 489 new CSubmit('update', _('Update')), [ 490 new CButton('clone', _('Clone')), 491 new CButtonDelete( 492 _('Delete current action?'), 493 url_param('form').url_param('eventsource').url_param('actionid') 494 ), 495 new CButtonCancel(url_param('actiontype').url_param('eventsource')) 496 ] 497 ]; 498} 499else { 500 $form_buttons = [ 501 new CSubmit('add', _('Add')), 502 [new CButtonCancel(url_param('actiontype').url_param('eventsource'))] 503 ]; 504} 505 506$action_tabs->setFooter([ 507 (new CList()) 508 ->addClass(ZBX_STYLE_TABLE_FORMS) 509 ->addItem([ 510 new CDiv(''), 511 (new CDiv((new CLabel(_('At least one operation must exist.')))->setAsteriskMark())) 512 ->addClass(ZBX_STYLE_TABLE_FORMS_TD_RIGHT) 513 ]), 514 makeFormFooter($form_buttons[0], $form_buttons[1]) 515]); 516$actionForm->addItem($action_tabs); 517 518// Append form to widget. 519$widget->addItem($actionForm); 520 521$widget->show(); 522