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 22function italic($str) { 23 if (is_array($str)) { 24 foreach ($str as $key => $val) { 25 if (is_string($val)) { 26 $em = new CTag('em', true); 27 $em->addItem($val); 28 $str[$key] = $em; 29 } 30 } 31 } 32 elseif (is_string($str)) { 33 $em = new CTag('em', true, ''); 34 $em->addItem($str); 35 $str = $em; 36 } 37 return $str; 38} 39 40function bold($str) { 41 if (is_array($str)) { 42 foreach ($str as $key => $val) { 43 if (is_string($val)) { 44 $str[$key] = new CTag('b', true, $val); 45 } 46 } 47 48 return $str; 49 } 50 51 return new CTag('b', true, $str); 52} 53 54function make_decoration($haystack, $needle, $class = null) { 55 $result = $haystack; 56 57 $tmpHaystack = mb_strtolower($haystack); 58 $tmpNeedle = mb_strtolower($needle); 59 $pos = mb_strpos($tmpHaystack, $tmpNeedle); 60 61 if ($pos !== false) { 62 $start = CHtml::encode(mb_substr($haystack, 0, $pos)); 63 $end = CHtml::encode(mb_substr($haystack, $pos + mb_strlen($needle))); 64 $found = CHtml::encode(mb_substr($haystack, $pos, mb_strlen($needle))); 65 66 if (is_null($class)) { 67 $result = [$start, bold($found), $end]; 68 } 69 else { 70 $result = [$start, (new CSpan($found))->addClass($class), $end]; 71 } 72 } 73 74 return $result; 75} 76 77function prepareUrlParam($value, $name = null) { 78 if (is_array($value)) { 79 $result = ''; 80 81 foreach ($value as $key => $param) { 82 $result .= prepareUrlParam($param, isset($name) ? $name.'['.$key.']' : $key); 83 } 84 } 85 else { 86 $result = '&'.$name.'='.urlencode($value); 87 } 88 89 return $result; 90} 91 92/** 93 * Get ready for url params. 94 * 95 * @param mixed $param param name or array with data depend from $getFromRequest 96 * @param bool $getFromRequest detect data source - input array or $_REQUEST variable 97 * @param string $name if $_REQUEST variable is used this variable not used 98 * 99 * @return string 100 */ 101function url_param($param, $getFromRequest = true, $name = null) { 102 if (is_array($param)) { 103 if ($getFromRequest) { 104 fatal_error(_('URL parameter cannot be array.')); 105 } 106 } 107 else { 108 if (is_null($name)) { 109 if (!$getFromRequest) { 110 fatal_error(_('URL parameter name is empty.')); 111 } 112 113 $name = $param; 114 } 115 } 116 117 if ($getFromRequest) { 118 $value =& $_REQUEST[$param]; 119 } 120 else { 121 $value =& $param; 122 } 123 124 return isset($value) ? prepareUrlParam($value, $name) : ''; 125} 126 127function url_params(array $params) { 128 $result = ''; 129 130 foreach ($params as $param) { 131 $result .= url_param($param); 132 } 133 134 return $result; 135} 136 137function BR() { 138 return new CTag('br'); 139} 140 141function get_icon($type, $params = []) { 142 switch ($type) { 143 case 'favourite': 144 if (CFavorite::exists($params['fav'], $params['elid'], $params['elname'])) { 145 $icon = (new CRedirectButton(SPACE, null)) 146 ->addClass(ZBX_STYLE_BTN_REMOVE_FAV) 147 ->setTitle(_('Remove from favourites')) 148 ->onClick('rm4favorites("'.$params['elname'].'", "'.$params['elid'].'");'); 149 } 150 else { 151 $icon = (new CRedirectButton(SPACE, null)) 152 ->addClass(ZBX_STYLE_BTN_ADD_FAV) 153 ->setTitle(_('Add to favourites')) 154 ->onClick('add2favorites("'.$params['elname'].'", "'.$params['elid'].'");'); 155 } 156 $icon->setId('addrm_fav'); 157 158 return $icon; 159 160 case 'kioskmode': 161 if ($params['mode'] == ZBX_LAYOUT_KIOSKMODE) { 162 $icon = (new CButton(null, ' ')) 163 ->setTitle(_('Normal view')) 164 ->setAttribute('data-layout-mode', ZBX_LAYOUT_NORMAL) 165 ->addClass(ZBX_LAYOUT_MODE) 166 ->addClass(ZBX_STYLE_BTN_DASHBRD_NORMAL) 167 ->addClass(ZBX_STYLE_BTN_MIN); 168 } 169 else { 170 $icon = (new CButton(null, ' ')) 171 ->setTitle(_('Kiosk mode')) 172 ->setAttribute('data-layout-mode', ZBX_LAYOUT_KIOSKMODE) 173 ->addClass(ZBX_LAYOUT_MODE) 174 ->addClass(ZBX_STYLE_BTN_KIOSK); 175 } 176 177 return $icon; 178 179 case 'screenconf': 180 return (new CRedirectButton(SPACE, null)) 181 ->addClass(ZBX_STYLE_BTN_CONF) 182 ->setTitle(_('Refresh interval')); 183 184 case 'overviewhelp': 185 return (new CRedirectButton(SPACE, null)) 186 ->addClass(ZBX_STYLE_BTN_INFO); 187 } 188} 189 190/** 191 * Create CDiv with host/template information and references to it's elements 192 * 193 * @param string $currentElement 194 * @param int $hostid 195 * @param int $lld_ruleid 196 * 197 * @return object 198 */ 199function get_header_host_table($current_element, $hostid, $lld_ruleid = 0) { 200 $options = [ 201 'output' => [ 202 'hostid', 'status', 'name', 'maintenance_status', 'flags', 'available', 'snmp_available', 203 'jmx_available', 'ipmi_available', 'error', 'snmp_error', 'jmx_error', 'ipmi_error' 204 ], 205 'selectHostDiscovery' => ['ts_delete'], 206 'hostids' => [$hostid], 207 'editable' => true 208 ]; 209 if ($lld_ruleid == 0) { 210 $options['selectApplications'] = API_OUTPUT_COUNT; 211 $options['selectItems'] = API_OUTPUT_COUNT; 212 $options['selectTriggers'] = API_OUTPUT_COUNT; 213 $options['selectGraphs'] = API_OUTPUT_COUNT; 214 $options['selectDiscoveries'] = API_OUTPUT_COUNT; 215 $options['selectHttpTests'] = API_OUTPUT_COUNT; 216 } 217 218 // get hosts 219 $db_host = API::Host()->get($options); 220 221 if (!$db_host) { 222 $options = [ 223 'output' => ['templateid', 'name', 'flags'], 224 'templateids' => [$hostid], 225 'editable' => true 226 ]; 227 if ($lld_ruleid == 0) { 228 $options['selectApplications'] = API_OUTPUT_COUNT; 229 $options['selectItems'] = API_OUTPUT_COUNT; 230 $options['selectTriggers'] = API_OUTPUT_COUNT; 231 $options['selectGraphs'] = API_OUTPUT_COUNT; 232 $options['selectScreens'] = API_OUTPUT_COUNT; 233 $options['selectDiscoveries'] = API_OUTPUT_COUNT; 234 $options['selectHttpTests'] = API_OUTPUT_COUNT; 235 } 236 237 // get templates 238 $db_host = API::Template()->get($options); 239 240 $is_template = true; 241 } 242 else { 243 $is_template = false; 244 } 245 246 if (!$db_host) { 247 return null; 248 } 249 250 $db_host = reset($db_host); 251 252 // get lld-rules 253 if ($lld_ruleid != 0) { 254 $db_discovery_rule = API::DiscoveryRule()->get([ 255 'output' => ['name'], 256 'selectItems' => API_OUTPUT_COUNT, 257 'selectTriggers' => API_OUTPUT_COUNT, 258 'selectGraphs' => API_OUTPUT_COUNT, 259 'selectHostPrototypes' => API_OUTPUT_COUNT, 260 'itemids' => [$lld_ruleid], 261 'editable' => true 262 ]); 263 $db_discovery_rule = reset($db_discovery_rule); 264 } 265 266 /* 267 * list and host (template) name 268 */ 269 $list = (new CList()) 270 ->addClass(ZBX_STYLE_OBJECT_GROUP) 271 ->addClass(ZBX_STYLE_FILTER_BREADCRUMB); 272 273 $breadcrumbs = (new CListItem(null)) 274 ->setAttribute('role', 'navigation') 275 ->setAttribute('aria-label', _x('Hierarchy', 'screen reader')); 276 277 if ($is_template) { 278 $template = new CSpan( 279 new CLink($db_host['name'], 'templates.php?form=update&templateid='.$db_host['templateid']) 280 ); 281 282 if ($current_element === '') { 283 $template->addClass(ZBX_STYLE_SELECTED); 284 } 285 286 $breadcrumbs->addItem([ 287 new CSpan(new CLink(_('All templates'), new CUrl('templates.php'))), 288 '/', 289 $template 290 ]); 291 292 $db_host['hostid'] = $db_host['templateid']; 293 $list->addItem($breadcrumbs); 294 } 295 else { 296 switch ($db_host['status']) { 297 case HOST_STATUS_MONITORED: 298 if ($db_host['maintenance_status'] == HOST_MAINTENANCE_STATUS_ON) { 299 $status = (new CSpan(_('In maintenance')))->addClass(ZBX_STYLE_ORANGE); 300 } 301 else { 302 $status = (new CSpan(_('Enabled')))->addClass(ZBX_STYLE_GREEN); 303 } 304 break; 305 case HOST_STATUS_NOT_MONITORED: 306 $status = (new CSpan(_('Disabled')))->addClass(ZBX_STYLE_RED); 307 break; 308 default: 309 $status = _('Unknown'); 310 break; 311 } 312 313 $host = new CSpan(new CLink(CHtml::encode($db_host['name']), 314 'hosts.php?form=update&hostid='.$db_host['hostid'] 315 )); 316 317 if ($current_element === '') { 318 $host->addClass(ZBX_STYLE_SELECTED); 319 } 320 321 $breadcrumbs->addItem([ 322 new CSpan(new CLink(_('All hosts'), new CUrl('hosts.php'))), 323 '/', 324 $host 325 ]); 326 $list->addItem($breadcrumbs); 327 $list->addItem($status); 328 $list->addItem(getHostAvailabilityTable($db_host)); 329 330 if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_CREATED && $db_host['hostDiscovery']['ts_delete'] != 0) { 331 $info_icons = [getHostLifetimeIndicator(time(), $db_host['hostDiscovery']['ts_delete'])]; 332 $list->addItem(makeInformationList($info_icons)); 333 } 334 } 335 336 $content_menu = (new CList()) 337 ->setAttribute('role', 'navigation') 338 ->setAttribute('aria-label', _('Content menu')); 339 340 /* 341 * the count of rows 342 */ 343 if ($lld_ruleid == 0) { 344 // applications 345 $applications = new CSpan([ 346 new CLink(_('Applications'), 347 (new CUrl('applications.php')) 348 ->setArgument('filter_set', '1') 349 ->setArgument('filter_hostids', [$db_host['hostid']]) 350 ), 351 CViewHelper::showNum($db_host['applications']) 352 ]); 353 if ($current_element == 'applications') { 354 $applications->addClass(ZBX_STYLE_SELECTED); 355 } 356 $content_menu->addItem($applications); 357 358 // items 359 $items = new CSpan([ 360 new CLink(_('Items'), 361 (new CUrl('items.php')) 362 ->setArgument('filter_set', '1') 363 ->setArgument('filter_hostids', [$db_host['hostid']]) 364 ), 365 CViewHelper::showNum($db_host['items']) 366 ]); 367 if ($current_element == 'items') { 368 $items->addClass(ZBX_STYLE_SELECTED); 369 } 370 $content_menu->addItem($items); 371 372 // triggers 373 $triggers = new CSpan([ 374 new CLink(_('Triggers'), 375 (new CUrl('triggers.php')) 376 ->setArgument('filter_set', '1') 377 ->setArgument('filter_hostids', [$db_host['hostid']]) 378 ), 379 CViewHelper::showNum($db_host['triggers']) 380 ]); 381 if ($current_element == 'triggers') { 382 $triggers->addClass(ZBX_STYLE_SELECTED); 383 } 384 $content_menu->addItem($triggers); 385 386 // graphs 387 $graphs = new CSpan([ 388 new CLink(_('Graphs'), (new CUrl('graphs.php')) 389 ->setArgument('filter_set', '1') 390 ->setArgument('filter_hostids', [$db_host['hostid']]) 391 ), 392 CViewHelper::showNum($db_host['graphs']) 393 ]); 394 if ($current_element == 'graphs') { 395 $graphs->addClass(ZBX_STYLE_SELECTED); 396 } 397 $content_menu->addItem($graphs); 398 399 // screens 400 if ($is_template) { 401 $screens = new CSpan([ 402 new CLink(_('Screens'), 'screenconf.php?templateid='.$db_host['hostid']), 403 CViewHelper::showNum($db_host['screens']) 404 ]); 405 if ($current_element == 'screens') { 406 $screens->addClass(ZBX_STYLE_SELECTED); 407 } 408 $content_menu->addItem($screens); 409 } 410 411 // discovery rules 412 $lld_rules = new CSpan([ 413 new CLink(_('Discovery rules'), (new CUrl('host_discovery.php')) 414 ->setArgument('filter_set', '1') 415 ->setArgument('filter_hostids', [$db_host['hostid']]) 416 ), 417 CViewHelper::showNum($db_host['discoveries']) 418 ]); 419 if ($current_element == 'discoveries') { 420 $lld_rules->addClass(ZBX_STYLE_SELECTED); 421 } 422 $content_menu->addItem($lld_rules); 423 424 // web scenarios 425 $http_tests = new CSpan([ 426 new CLink(_('Web scenarios'), 427 (new CUrl('httpconf.php')) 428 ->setArgument('filter_set', '1') 429 ->setArgument('filter_hostids', [$db_host['hostid']]) 430 ), 431 CViewHelper::showNum($db_host['httpTests']) 432 ]); 433 if ($current_element == 'web') { 434 $http_tests->addClass(ZBX_STYLE_SELECTED); 435 } 436 $content_menu->addItem($http_tests); 437 } 438 else { 439 $discovery_rule = (new CSpan())->addItem( 440 new CLink( 441 CHtml::encode($db_discovery_rule['name']), 442 'host_discovery.php?form=update&itemid='.$db_discovery_rule['itemid'] 443 ) 444 ); 445 446 if ($current_element == 'discoveries') { 447 $discovery_rule->addClass(ZBX_STYLE_SELECTED); 448 } 449 450 $list->addItem([ 451 (new CSpan())->addItem( 452 new CLink(_('Discovery list'), (new CUrl('host_discovery.php')) 453 ->setArgument('filter_set', '1') 454 ->setArgument('filter_hostids', [$db_host['hostid']]) 455 ) 456 ), 457 '/', 458 $discovery_rule 459 ]); 460 461 // item prototypes 462 $item_prototypes = new CSpan([ 463 new CLink(_('Item prototypes'), 'disc_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid']), 464 CViewHelper::showNum($db_discovery_rule['items']) 465 ]); 466 if ($current_element == 'items') { 467 $item_prototypes->addClass(ZBX_STYLE_SELECTED); 468 } 469 $content_menu->addItem($item_prototypes); 470 471 // trigger prototypes 472 $trigger_prototypes = new CSpan([ 473 new CLink(_('Trigger prototypes'), 474 'trigger_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid'] 475 ), 476 CViewHelper::showNum($db_discovery_rule['triggers']) 477 ]); 478 if ($current_element == 'triggers') { 479 $trigger_prototypes->addClass(ZBX_STYLE_SELECTED); 480 } 481 $content_menu->addItem($trigger_prototypes); 482 483 // graph prototypes 484 $graph_prototypes = new CSpan([ 485 new CLink(_('Graph prototypes'), 'graphs.php?parent_discoveryid='.$db_discovery_rule['itemid']), 486 CViewHelper::showNum($db_discovery_rule['graphs']) 487 ]); 488 if ($current_element == 'graphs') { 489 $graph_prototypes->addClass(ZBX_STYLE_SELECTED); 490 } 491 $content_menu->addItem($graph_prototypes); 492 493 // host prototypes 494 if ($db_host['flags'] == ZBX_FLAG_DISCOVERY_NORMAL) { 495 $host_prototypes = new CSpan([ 496 new CLink(_('Host prototypes'), 'host_prototypes.php?parent_discoveryid='.$db_discovery_rule['itemid']), 497 CViewHelper::showNum($db_discovery_rule['hostPrototypes']) 498 ]); 499 if ($current_element == 'hosts') { 500 $host_prototypes->addClass(ZBX_STYLE_SELECTED); 501 } 502 $content_menu->addItem($host_prototypes); 503 } 504 } 505 506 $list->addItem($content_menu); 507 508 return $list; 509} 510 511/** 512 * Create breadcrumbs header object with sysmap parents information. 513 * 514 * @param int $sysmapid Used as value for sysmaid in map link generation. 515 * @param string $name Used as label for map link generation. 516 * @param int $severity_min Used as value for severity_min in map link generation. 517 * 518 * @return object 519 */ 520function get_header_sysmap_table($sysmapid, $name, $severity_min) { 521 $list = (new CList()) 522 ->setAttribute('role', 'navigation') 523 ->setAttribute('aria-label', _x('Hierarchy', 'screen reader')) 524 ->addClass(ZBX_STYLE_OBJECT_GROUP) 525 ->addClass(ZBX_STYLE_FILTER_BREADCRUMB) 526 ->addItem([ 527 (new CSpan())->addItem(new CLink(_('All maps'), new CUrl('sysmaps.php'))), 528 '/', 529 (new CSpan()) 530 ->addClass(ZBX_STYLE_SELECTED) 531 ->addItem( 532 new CLink($name, (new CUrl('zabbix.php')) 533 ->setArgument('action', 'map.view') 534 ->setArgument('sysmapid', $sysmapid) 535 ->setArgument('severity_min', $severity_min) 536 ) 537 ) 538 ]); 539 540 // get map parent maps 541 $parent_sysmaps = get_parent_sysmaps($sysmapid); 542 if ($parent_sysmaps) { 543 $parent_maps = (new CList()) 544 ->setAttribute('role', 'navigation') 545 ->setAttribute('aria-label', _('Upper level maps')) 546 ->addClass(ZBX_STYLE_FILTER_BREADCRUMB) 547 ->addClass(ZBX_STYLE_OBJECT_GROUP) 548 ->addItem((new CSpan())->addItem(_('Upper level maps').':')); 549 550 foreach ($parent_sysmaps as $parent_sysmap) { 551 $parent_maps->addItem((new CSpan())->addItem( 552 new CLink($parent_sysmap['name'], (new CUrl('zabbix.php')) 553 ->setArgument('action', 'map.view') 554 ->setArgument('sysmapid', $parent_sysmap['sysmapid']) 555 ->setArgument('severity_min', $severity_min) 556 )) 557 ); 558 } 559 560 return new CHorList([$list, $parent_maps]); 561 } 562 563 return $list; 564} 565 566/** 567 * Renders a form footer with the given buttons. 568 * 569 * @param CButtonInterface $main_button main button that will be displayed on the left 570 * @param CButtonInterface[] $other_buttons 571 * 572 * @return CDiv 573 * 574 * @throws InvalidArgumentException if an element of $other_buttons contain something other than CButtonInterface 575 */ 576function makeFormFooter(CButtonInterface $main_button = null, array $other_buttons = []) { 577 foreach ($other_buttons as $other_button) { 578 $other_button->addClass(ZBX_STYLE_BTN_ALT); 579 } 580 581 if ($main_button !== null) { 582 array_unshift($other_buttons, $main_button); 583 } 584 585 return (new CList()) 586 ->addClass(ZBX_STYLE_TABLE_FORMS) 587 ->addItem([ 588 (new CDiv())->addClass(ZBX_STYLE_TABLE_FORMS_TD_LEFT), 589 (new CDiv($other_buttons)) 590 ->addClass(ZBX_STYLE_TABLE_FORMS_TD_RIGHT) 591 ->addClass('tfoot-buttons') 592 ]); 593} 594 595/** 596 * Returns zbx, snmp, jmx, ipmi availability status icons and the discovered host lifetime indicator. 597 * 598 * @param array $host an array of host data 599 * 600 * @return CDiv 601 */ 602function getHostAvailabilityTable($host) { 603 $container = (new CDiv())->addClass(ZBX_STYLE_STATUS_CONTAINER); 604 605 foreach (['zbx' => '', 'snmp' => 'snmp_', 'jmx' => 'jmx_', 'ipmi' => 'ipmi_'] as $type => $prefix) { 606 switch ($host[$prefix.'available']) { 607 case HOST_AVAILABLE_TRUE: 608 $ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_GREEN); 609 break; 610 case HOST_AVAILABLE_FALSE: 611 $ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_RED); 612 613 if ($host[$prefix.'error'] !== '') { 614 $ai 615 ->addClass(ZBX_STYLE_CURSOR_POINTER) 616 ->setHint($host[$prefix.'error'], ZBX_STYLE_RED); 617 } 618 619 break; 620 case HOST_AVAILABLE_UNKNOWN: 621 $ai = (new CSpan($type))->addClass(ZBX_STYLE_STATUS_GREY); 622 break; 623 } 624 $container->addItem($ai); 625 } 626 627 return $container; 628} 629 630/** 631 * Returns the discovered host group lifetime indicator. 632 * 633 * @param string $current_time current Unix timestamp 634 * @param array $ts_delete deletion timestamp of the host group 635 * 636 * @return CDiv 637 */ 638function getHostGroupLifetimeIndicator($current_time, $ts_delete) { 639 // Check if the element should've been deleted in the past. 640 if ($current_time > $ts_delete) { 641 $warning = _( 642 'The host group is not discovered anymore and will be deleted the next time discovery rule is processed.' 643 ); 644 } 645 else { 646 $warning = _s( 647 'The host group is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 648 zbx_date2age($current_time, $ts_delete), 649 zbx_date2str(DATE_FORMAT, $ts_delete), 650 zbx_date2str(TIME_FORMAT, $ts_delete) 651 ); 652 } 653 654 return makeWarningIcon($warning); 655} 656 657/** 658 * Returns the discovered host lifetime indicator. 659 * 660 * @param string $current_time current Unix timestamp 661 * @param array $ts_delete deletion timestamp of the host 662 * 663 * @return CDiv 664 */ 665function getHostLifetimeIndicator($current_time, $ts_delete) { 666 // Check if the element should've been deleted in the past. 667 if ($current_time > $ts_delete) { 668 $warning = _( 669 'The host is not discovered anymore and will be deleted the next time discovery rule is processed.' 670 ); 671 } 672 else { 673 $warning = _s( 674 'The host is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 675 zbx_date2age($current_time, $ts_delete), 676 zbx_date2str(DATE_FORMAT, $ts_delete), 677 zbx_date2str(TIME_FORMAT, $ts_delete) 678 ); 679 } 680 681 return makeWarningIcon($warning); 682} 683 684/** 685 * Returns the discovered application lifetime indicator. 686 * 687 * @param string $current_time current Unix timestamp 688 * @param array $ts_delete deletion timestamp of the application 689 * 690 * @return CDiv 691 */ 692function getApplicationLifetimeIndicator($current_time, $ts_delete) { 693 // Check if the element should've been deleted in the past. 694 if ($current_time > $ts_delete) { 695 $warning = _( 696 'The application is not discovered anymore and will be deleted the next time discovery rule is processed.' 697 ); 698 } 699 else { 700 $warning = _s( 701 'The application is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 702 zbx_date2age($current_time, $ts_delete), 703 zbx_date2str(DATE_FORMAT, $ts_delete), 704 zbx_date2str(TIME_FORMAT, $ts_delete) 705 ); 706 } 707 708 return makeWarningIcon($warning); 709} 710 711/** 712 * Returns the discovered graph lifetime indicator. 713 * 714 * @param string $current_time current Unix timestamp 715 * @param array $ts_delete deletion timestamp of the graph 716 * 717 * @return CDiv 718 */ 719function getGraphLifetimeIndicator($current_time, $ts_delete) { 720 // Check if the element should've been deleted in the past. 721 if ($current_time > $ts_delete) { 722 $warning = _( 723 'The graph is not discovered anymore and will be deleted the next time discovery rule is processed.' 724 ); 725 } 726 else { 727 $warning = _s( 728 'The graph is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 729 zbx_date2age($current_time, $ts_delete), 730 zbx_date2str(DATE_FORMAT, $ts_delete), 731 zbx_date2str(TIME_FORMAT, $ts_delete) 732 ); 733 } 734 735 return makeWarningIcon($warning); 736} 737 738/** 739 * Returns the discovered trigger lifetime indicator. 740 * 741 * @param string $current_time current Unix timestamp 742 * @param array $ts_delete deletion timestamp of the trigger 743 * 744 * @return CDiv 745 */ 746function getTriggerLifetimeIndicator($current_time, $ts_delete) { 747 // Check if the element should've been deleted in the past. 748 if ($current_time > $ts_delete) { 749 $warning = _( 750 'The trigger is not discovered anymore and will be deleted the next time discovery rule is processed.' 751 ); 752 } 753 else { 754 $warning = _s( 755 'The trigger is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 756 zbx_date2age($current_time, $ts_delete), 757 zbx_date2str(DATE_FORMAT, $ts_delete), 758 zbx_date2str(TIME_FORMAT, $ts_delete) 759 ); 760 } 761 762 return makeWarningIcon($warning); 763} 764 765/** 766 * Returns the discovered item lifetime indicator. 767 * 768 * @param string $current_time current Unix timestamp 769 * @param array $ts_delete deletion timestamp of the item 770 * 771 * @return CDiv 772 */ 773function getItemLifetimeIndicator($current_time, $ts_delete) { 774 // Check if the element should've been deleted in the past. 775 if ($current_time > $ts_delete) { 776 $warning = _( 777 'The item is not discovered anymore and will be deleted the next time discovery rule is processed.' 778 ); 779 } 780 else { 781 $warning = _s( 782 'The item is not discovered anymore and will be deleted in %1$s (on %2$s at %3$s).', 783 zbx_date2age($current_time, $ts_delete), 784 zbx_date2str(DATE_FORMAT, $ts_delete), 785 zbx_date2str(TIME_FORMAT, $ts_delete) 786 ); 787 } 788 789 return makeWarningIcon($warning); 790} 791 792function makeServerStatusOutput() { 793 return (new CTag('output', true)) 794 ->setId('msg-global-footer') 795 ->addClass(ZBX_STYLE_MSG_GLOBAL_FOOTER) 796 ->addClass(ZBX_STYLE_MSG_WARNING); 797} 798 799/** 800* Make logo of the specified type. 801* 802* @param int $type LOGO_TYPE_NORMAL | LOGO_TYPE_SIDEBAR | LOGO_TYPE_SIDEBAR_COMPACT. 803* 804* @return CTag 805*/ 806function makeLogo(int $type): ?CTag { 807 static $zabbix_logo_classes = [ 808 LOGO_TYPE_NORMAL => ZBX_STYLE_ZABBIX_LOGO, 809 LOGO_TYPE_SIDEBAR => ZBX_STYLE_ZABBIX_SIDEBAR_LOGO, 810 LOGO_TYPE_SIDEBAR_COMPACT => ZBX_STYLE_ZABBIX_SIDEBAR_LOGO_COMPACT 811 ]; 812 813 $brand_logo = CBrandHelper::getLogo($type); 814 815 if ($brand_logo !== null) { 816 return (new CImg($brand_logo)); 817 } 818 else { 819 return (new CDiv())->addClass($zabbix_logo_classes[$type]); 820 } 821} 822 823/** 824 * Renders a page footer. 825 * 826 * @param bool $with_version 827 * 828 * @return CDiv 829 */ 830function makePageFooter($with_version = true) { 831 return (new CTag('footer', true, CBrandHelper::getFooterContent($with_version))) 832 ->setAttribute('role', 'contentinfo'); 833} 834 835/** 836 * Get drop-down submenu item list for the Administration->General section. 837 * 838 * @return array Menu definition for CWidget::setTitleSubmenu. 839 */ 840function getAdministrationGeneralSubmenu() { 841 $gui_url = (new CUrl('zabbix.php')) 842 ->setArgument('action', 'gui.edit') 843 ->getUrl(); 844 845 $autoreg_url = (new CUrl('zabbix.php')) 846 ->setArgument('action', 'autoreg.edit') 847 ->getUrl(); 848 849 $housekeeping_url = (new CUrl('zabbix.php')) 850 ->setArgument('action', 'housekeeping.edit') 851 ->getUrl(); 852 853 $image_url = (new CUrl('zabbix.php')) 854 ->setArgument('action', 'image.list') 855 ->getUrl(); 856 857 $iconmap_url = (new CUrl('zabbix.php')) 858 ->setArgument('action', 'iconmap.list') 859 ->getUrl(); 860 861 $regex_url = (new CUrl('zabbix.php')) 862 ->setArgument('action', 'regex.list') 863 ->getUrl(); 864 865 $macros_url = (new CUrl('zabbix.php')) 866 ->setArgument('action', 'macros.edit') 867 ->getUrl(); 868 869 $valuemap_url = (new CUrl('zabbix.php')) 870 ->setArgument('action', 'valuemap.list') 871 ->getUrl(); 872 873 $workingtime_url = (new CUrl('zabbix.php')) 874 ->setArgument('action', 'workingtime.edit') 875 ->getUrl(); 876 877 $trigseverity_url = (new CUrl('zabbix.php')) 878 ->setArgument('action', 'trigseverity.edit') 879 ->getUrl(); 880 881 $trigdisplay_url = (new CUrl('zabbix.php')) 882 ->setArgument('action', 'trigdisplay.edit') 883 ->getUrl(); 884 885 $modules_url = (new CUrl('zabbix.php')) 886 ->setArgument('action', 'module.list') 887 ->getUrl(); 888 889 $miscconfig_url = (new CUrl('zabbix.php')) 890 ->setArgument('action', 'miscconfig.edit') 891 ->getUrl(); 892 893 return [ 894 'main_section' => [ 895 'items' => [ 896 $gui_url => _('GUI'), 897 $autoreg_url => _('Autoregistration'), 898 $housekeeping_url => _('Housekeeping'), 899 $image_url => _('Images'), 900 $iconmap_url => _('Icon mapping'), 901 $regex_url => _('Regular expressions'), 902 $macros_url => _('Macros'), 903 $valuemap_url => _('Value mapping'), 904 $workingtime_url => _('Working time'), 905 $trigseverity_url => _('Trigger severities'), 906 $trigdisplay_url => _('Trigger displaying options'), 907 $modules_url => _('Modules'), 908 $miscconfig_url => _('Other') 909 ] 910 ] 911 ]; 912} 913 914/** 915 * Renders an icon list. 916 * 917 * @param array $info_icons The list of information icons. 918 * 919 * @return CDiv|string 920 */ 921function makeInformationList($info_icons) { 922 return $info_icons ? (new CDiv($info_icons))->addClass(ZBX_STYLE_REL_CONTAINER) : ''; 923} 924 925/** 926 * Renders an information icon like green [i] with message. 927 * 928 * @param string $message 929 * 930 * @return CSpan 931 */ 932function makeInformationIcon($message) { 933 return (new CSpan()) 934 ->addClass(ZBX_STYLE_ICON_INFO) 935 ->addClass(ZBX_STYLE_STATUS_GREEN) 936 ->setHint($message, ZBX_STYLE_HINTBOX_WRAP); 937} 938 939/** 940 * Renders an icon for host in maintenance. 941 * 942 * @param int $type Type of the maintenance. 943 * @param string $name Name of the maintenance. 944 * @param string $description Description of the maintenance. 945 * 946 * @return CSpan 947 */ 948function makeMaintenanceIcon($type, $name, $description) { 949 $hint = $name.' ['.($type 950 ? _('Maintenance without data collection') 951 : _('Maintenance with data collection')).']'; 952 953 if ($description !== '') { 954 $hint .= "\n".$description; 955 } 956 957 return (new CSpan()) 958 ->addClass(ZBX_STYLE_ICON_MAINT) 959 ->addClass(ZBX_STYLE_CURSOR_POINTER) 960 ->setHint($hint); 961} 962 963/** 964 * Renders an icon for suppressed problem. 965 * 966 * @param array $icon_data 967 * @param string $icon_data[]['suppress_until'] Time until the problem is suppressed. 968 * @param string $icon_data[]['maintenance_name'] Name of the maintenance. 969 * 970 * @return CSpan 971 */ 972function makeSuppressedProblemIcon(array $icon_data) { 973 $suppress_until = max(zbx_objectValues($icon_data, 'suppress_until')); 974 975 CArrayHelper::sort($icon_data, ['maintenance_name']); 976 $maintenance_names = implode(', ', zbx_objectValues($icon_data, 'maintenance_name')); 977 978 return (new CSpan()) 979 ->addClass(ZBX_STYLE_ICON_INVISIBLE) 980 ->addClass(ZBX_STYLE_CURSOR_POINTER) 981 ->setHint( 982 _s('Suppressed till: %1$s', ($suppress_until < strtotime('tomorrow')) 983 ? zbx_date2str(TIME_FORMAT, $suppress_until) 984 : zbx_date2str(DATE_TIME_FORMAT, $suppress_until) 985 ). 986 "\n". 987 _s('Maintenance: %1$s', $maintenance_names) 988 ); 989} 990 991/** 992 * Renders an action icon. 993 * 994 * @param array $icon_data 995 * @param string $icon_data[icon] Icon style. 996 * @param array $icon_data[hint] Hintbox content (optional). 997 * @param bool $icon_data[button] Use button element (optional). 998 * @param int $icon_data[num] Number displayed over the icon (optional). 999 * 1000 * @return CTag Returns CSpan or CButton depending on boolean $icon_data['button'] parameter 1001 */ 1002function makeActionIcon(array $icon_data): CTag { 1003 1004 if (array_key_exists('button', $icon_data) && $icon_data['button']) { 1005 $icon = (new CButton(null))->addClass($icon_data['icon']); 1006 } 1007 else { 1008 $icon = (new CSpan())->addClass($icon_data['icon']); 1009 } 1010 1011 if (array_key_exists('num', $icon_data)) { 1012 if ($icon_data['num'] > 99) { 1013 $icon_data['num'] = '99+'; 1014 } 1015 $icon->setAttribute('data-count', $icon_data['num']); 1016 } 1017 1018 if (array_key_exists('hint', $icon_data)) { 1019 $icon 1020 ->addClass(ZBX_STYLE_CURSOR_POINTER) 1021 ->setHint($icon_data['hint'], '', true, 'max-width: '.ZBX_ACTIONS_POPUP_MAX_WIDTH.'px;'); 1022 } 1023 elseif (array_key_exists('title', $icon_data)) { 1024 $icon->setTitle($icon_data['title']); 1025 } 1026 1027 if (array_key_exists('aria-label', $icon_data)) { 1028 $icon 1029 ->addItem($icon_data['aria-label']) 1030 ->addClass(ZBX_STYLE_INLINE_SR_ONLY); 1031 } 1032 1033 return $icon; 1034} 1035 1036/** 1037 * Renders an icon for a description. 1038 * 1039 * @param string $description 1040 * 1041 * @return CSpan 1042 */ 1043function makeDescriptionIcon($description) { 1044 return (new CSpan()) 1045 ->addClass(ZBX_STYLE_ICON_DESCRIPTION) 1046 ->addClass(ZBX_STYLE_CURSOR_POINTER) 1047 ->setHint(zbx_str2links($description), ZBX_STYLE_HINTBOX_WRAP); 1048} 1049 1050/** 1051 * Renders an error icon like red [i] with error message 1052 * 1053 * @param string $error 1054 * 1055 * @return CSpan 1056 */ 1057function makeErrorIcon($error) { 1058 return (new CSpan()) 1059 ->addClass(ZBX_STYLE_ICON_INFO) 1060 ->addClass(ZBX_STYLE_STATUS_RED) 1061 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP." ".ZBX_STYLE_RED); 1062} 1063 1064/** 1065 * Renders an unknown icon like grey [i] with error message 1066 * 1067 * @param string $error 1068 * 1069 * @return CSpan 1070 */ 1071function makeUnknownIcon($error) { 1072 return (new CSpan()) 1073 ->addClass(ZBX_STYLE_ICON_INFO) 1074 ->addClass(ZBX_STYLE_STATUS_DARK_GREY) 1075 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP." ".ZBX_STYLE_RED); 1076} 1077 1078/** 1079 * Renders a warning icon like yellow [i] with error message 1080 * 1081 * @param string $error 1082 * 1083 * @return CSpan 1084 */ 1085function makeWarningIcon($error) { 1086 return (new CSpan()) 1087 ->addClass(ZBX_STYLE_ICON_INFO) 1088 ->addClass(ZBX_STYLE_STATUS_YELLOW) 1089 ->setHint($error, ZBX_STYLE_HINTBOX_WRAP); 1090} 1091 1092/** 1093 * Returns css for trigger severity backgrounds. 1094 * 1095 * @param array $config 1096 * @param array $config[severity_color_0] 1097 * @param array $config[severity_color_1] 1098 * @param array $config[severity_color_2] 1099 * @param array $config[severity_color_3] 1100 * @param array $config[severity_color_4] 1101 * @param array $config[severity_color_5] 1102 * 1103 * @return string 1104 */ 1105function getTriggerSeverityCss($config) { 1106 $css = ''; 1107 1108 $severities = [ 1109 ZBX_STYLE_NA_BG => $config['severity_color_0'], 1110 ZBX_STYLE_INFO_BG => $config['severity_color_1'], 1111 ZBX_STYLE_WARNING_BG => $config['severity_color_2'], 1112 ZBX_STYLE_AVERAGE_BG => $config['severity_color_3'], 1113 ZBX_STYLE_HIGH_BG => $config['severity_color_4'], 1114 ZBX_STYLE_DISASTER_BG => $config['severity_color_5'] 1115 ]; 1116 1117 foreach ($severities as $class => $color) { 1118 $css .= '.'.$class.', .'.$class.' input[type="radio"]:checked + label, .'.$class.':before, .flh-'.$class. 1119 ', .status-'.$class.', .status-'.$class.':before { background-color: #'.$color.' }'."\n"; 1120 } 1121 1122 return $css; 1123} 1124 1125/** 1126 * Returns css for trigger status colors, if those are customized. 1127 * 1128 * @param array $config 1129 * @param array $config[custom_color] 1130 * @param array $config[problem_unack_color] 1131 * @param array $config[problem_ack_color] 1132 * @param array $config[ok_unack_color] 1133 * @param array $config[ok_ack_color] 1134 * 1135 * @return string 1136 */ 1137function getTriggerStatusCss($config) { 1138 $css = ''; 1139 1140 if ($config['custom_color'] == EVENT_CUSTOM_COLOR_ENABLED) { 1141 $event_statuses = [ 1142 ZBX_STYLE_PROBLEM_UNACK_FG => $config['problem_unack_color'], 1143 ZBX_STYLE_PROBLEM_ACK_FG => $config['problem_ack_color'], 1144 ZBX_STYLE_OK_UNACK_FG => $config['ok_unack_color'], 1145 ZBX_STYLE_OK_ACK_FG => $config['ok_ack_color'] 1146 ]; 1147 1148 foreach ($event_statuses as $class => $color) { 1149 $css .= '.' . $class . ' {color: #' . $color . ';}' . "\n"; 1150 } 1151 } 1152 1153 return $css; 1154} 1155