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?> 26<script type="text/x-jquery-tmpl" id="host-interface-row-tmpl"> 27<div class="<?= ZBX_STYLE_HOST_INTERFACE_ROW ?> <?= ZBX_STYLE_LIST_ACCORDION_ITEM ?> <?= ZBX_STYLE_LIST_ACCORDION_ITEM_CLOSED ?>" id="interface_row_#{iface.interfaceid}" data-type="#{iface.type}" data-interfaceid="#{iface.interfaceid}"> 28 <input type="hidden" name="interfaces[#{iface.interfaceid}][items]" value="#{iface.items}" /> 29 <input type="hidden" name="interfaces[#{iface.interfaceid}][isNew]" value="#{iface.isNew}" /> 30 <input type="hidden" name="interfaces[#{iface.interfaceid}][interfaceid]" value="#{iface.interfaceid}" /> 31 <input type="hidden" id="interface_type_#{iface.interfaceid}" name="interfaces[#{iface.interfaceid}][type]" value="#{iface.type}" /> 32 33 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?>"> 34 <button type="button" class="<?= ZBX_STYLE_HOST_INTERFACE_BTN_TOGGLE ?>"></button> 35 </div> 36 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_TYPE ?>"> 37 #{iface.type_name} 38 </div> 39 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_IP ?>"> 40 <?= (new CTextBox('interfaces[#{iface.interfaceid}][ip]', '#{iface.ip}', false, DB::getFieldLength('interface', 'ip'))) 41 ->addClass(ZBX_STYLE_HOST_INTERFACE_INPUT_EXPAND) 42 ->setWidth(ZBX_TEXTAREA_INTERFACE_IP_WIDTH) 43 ?> 44 </div> 45 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_DNS ?>"> 46 <?= (new CTextBox('interfaces[#{iface.interfaceid}][dns]', '#{iface.dns}', false, DB::getFieldLength('interface', 'dns'))) 47 ->addClass(ZBX_STYLE_HOST_INTERFACE_INPUT_EXPAND) 48 ->setWidth(ZBX_TEXTAREA_INTERFACE_DNS_WIDTH) 49 ?> 50 </div> 51 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_USEIP ?>"> 52 <?= (new CRadioButtonList('interfaces[#{iface.interfaceid}][useip]', null)) 53 ->addValue('IP', INTERFACE_USE_IP, 'interfaces[#{iface.interfaceid}][useip]['.INTERFACE_USE_IP.']') 54 ->addValue('DNS', INTERFACE_USE_DNS, 'interfaces[#{iface.interfaceid}][useip]['.INTERFACE_USE_DNS.']') 55 ->addClass(ZBX_STYLE_HOST_INTERFACE_CELL_USEIP.' '.ZBX_STYLE_HOST_INTERFACE_INPUT_EXPAND) 56 ->setModern(true) 57 ?> 58 </div> 59 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_PORT ?>"> 60 <?= (new CTextBox('interfaces[#{iface.interfaceid}][port]', '#{iface.port}', false, DB::getFieldLength('interface', 'port'))) 61 ->setWidth(ZBX_TEXTAREA_INTERFACE_PORT_WIDTH) 62 ->addClass(ZBX_STYLE_HOST_INTERFACE_INPUT_EXPAND) 63 ->setAriaRequired() 64 ?> 65 </div> 66 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_DEFAULT ?>"> 67 <input type="radio" class="<?= ZBX_STYLE_CHECKBOX_RADIO ?> <?= ZBX_STYLE_HOST_INTERFACE_BTN_MAIN_INTERFACE ?>" id="interface_main_#{iface.interfaceid}" name="mainInterfaces[#{iface.type}]" value="#{iface.interfaceid}"> 68 <label class="checkboxLikeLabel" for="interface_main_#{iface.interfaceid}" style="height: 16px; width: 16px;"><span></span></label> 69 </div> 70 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_ACTION ?>"> 71 <button type="button" class="<?= ZBX_STYLE_BTN_LINK ?> <?= ZBX_STYLE_HOST_INTERFACE_BTN_REMOVE ?>"><?= _('Remove') ?></button> 72 </div> 73 <div class="<?= ZBX_STYLE_HOST_INTERFACE_CELL ?> <?= ZBX_STYLE_HOST_INTERFACE_CELL_DETAILS ?> <?= ZBX_STYLE_LIST_ACCORDION_ITEM_BODY ?>"> 74 <?= (new CFormList('snmp_details_#{iface.interfaceid}')) 75 ->cleanItems() 76 ->addRow((new CLabel(_('SNMP version'), 'label_interfaces_#{iface.interfaceid}_details_version')) 77 ->setAsteriskMark(), 78 (new CSelect('interfaces[#{iface.interfaceid}][details][version]')) 79 ->addOptions(CSelect::createOptionsFromArray([ 80 SNMP_V1 => _('SNMPv1'), 81 SNMP_V2C => _('SNMPv2'), 82 SNMP_V3 => _('SNMPv3') 83 ])) 84 ->setValue(SNMP_V2C) 85 ->setFocusableElementId('label_interfaces_#{iface.interfaceid}_details_version') 86 ->setId('interfaces_#{iface.interfaceid}_details_version'), 87 'row_snmp_version_#{iface.interfaceid}' 88 ) 89 ->addRow((new CLabel(_('SNMP community'), 'interfaces[#{iface.interfaceid}][details][community]'))->setAsteriskMark(), 90 (new CTextBox('interfaces[#{iface.interfaceid}][details][community]', '#{iface.details.community}', false, DB::getFieldLength('interface_snmp', 'community'))) 91 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) 92 ->setAriaRequired(), 93 'row_snmp_community_#{iface.interfaceid}' 94 ) 95 ->addRow(new CLabel(_('Context name'), 'interfaces[#{iface.interfaceid}][details][contextname]'), 96 (new CTextBox('interfaces[#{iface.interfaceid}][details][contextname]', '#{iface.details.contextname}', false, DB::getFieldLength('interface_snmp', 'contextname'))) 97 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH), 98 'row_snmpv3_contextname_#{iface.interfaceid}' 99 ) 100 ->addRow(new CLabel(_('Security name'), 'interfaces[#{iface.interfaceid}][details][securityname]'), 101 (new CTextBox('interfaces[#{iface.interfaceid}][details][securityname]', '#{iface.details.securityname}', false, DB::getFieldLength('interface_snmp', 'securityname'))) 102 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH), 103 'row_snmpv3_securityname_#{iface.interfaceid}' 104 ) 105 ->addRow(new CLabel(_('Security level'), 'label_interfaces_#{iface.interfaceid}_details_securitylevel'), 106 (new CSelect('interfaces[#{iface.interfaceid}][details][securitylevel]')) 107 ->addOptions(CSelect::createOptionsFromArray([ 108 ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV => 'noAuthNoPriv', 109 ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV => 'authNoPriv', 110 ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV => 'authPriv' 111 ])) 112 ->setValue(ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV) 113 ->setFocusableElementId('label_interfaces_#{iface.interfaceid}_details_securitylevel') 114 ->setId('interfaces_#{iface.interfaceid}_details_securitylevel'), 115 'row_snmpv3_securitylevel_#{iface.interfaceid}' 116 ) 117 ->addRow(new CLabel(_('Authentication protocol'), 'label-authprotocol-#{iface.interfaceid}'), 118 (new CSelect('interfaces[#{iface.interfaceid}][details][authprotocol]')) 119 ->setFocusableElementId('label-authprotocol-#{iface.interfaceid}') 120 ->addOptions(CSelect::createOptionsFromArray(getSnmpV3AuthProtocols())), 121 'row_snmpv3_authprotocol_#{iface.interfaceid}' 122 ) 123 ->addRow(new CLabel(_('Authentication passphrase'), 'interfaces[#{iface.interfaceid}][details][authpassphrase]'), 124 (new CTextBox('interfaces[#{iface.interfaceid}][details][authpassphrase]', '#{iface.details.authpassphrase}', false, DB::getFieldLength('interface_snmp', 'authpassphrase'))) 125 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) 126 ->disableAutocomplete(), 127 'row_snmpv3_authpassphrase_#{iface.interfaceid}' 128 ) 129 ->addRow(new CLabel(_('Privacy protocol'), 'label-privprotocol-#{iface.interfaceid}'), 130 (new CSelect('interfaces[#{iface.interfaceid}][details][privprotocol]')) 131 ->setFocusableElementId('label-privprotocol-#{iface.interfaceid}') 132 ->addOptions(CSelect::createOptionsFromArray(getSnmpV3PrivProtocols())), 133 'row_snmpv3_privprotocol_#{iface.interfaceid}' 134 ) 135 ->addRow(new CLabel(_('Privacy passphrase'), 'interfaces[#{iface.interfaceid}][details][privpassphrase]'), 136 (new CTextBox('interfaces[#{iface.interfaceid}][details][privpassphrase]', '#{iface.details.privpassphrase}', false, DB::getFieldLength('interface_snmp', 'privpassphrase'))) 137 ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) 138 ->disableAutocomplete(), 139 'row_snmpv3_privpassphrase_#{iface.interfaceid}' 140 ) 141 ->addRow('', (new CCheckBox('interfaces[#{iface.interfaceid}][details][bulk]', SNMP_BULK_ENABLED))->setLabel(_('Use bulk requests'), 'interfaces[#{iface.interfaceid}][details][bulk]'), 142 'row_snmp_bulk_#{iface.interfaceid}' 143 ); 144 ?> 145 </div> 146</div> 147</script> 148 149<script type="text/javascript"> 150 'use strict'; 151 152 class HostInterfaceManager { 153 constructor(data) { 154 // Constants. 155 this.TEMPLATE = new Template(document.getElementById('host-interface-row-tmpl').innerHTML); 156 this.DEFAULT_PORTS = { 157 agent: 10050, 158 snmp: 161, 159 jmx: 12345, 160 ipmi: 623 161 }; 162 this.CONTAINER_IDS = { 163 <?= INTERFACE_TYPE_AGENT ?>: '#agentInterfaces', 164 <?= INTERFACE_TYPE_SNMP ?>: '#SNMPInterfaces', 165 <?= INTERFACE_TYPE_JMX ?>: '#JMXInterfaces', 166 <?= INTERFACE_TYPE_IPMI ?>: '#IPMIInterfaces' 167 }; 168 this.INTERFACE_TYPES = { 169 'agent': '<?= INTERFACE_TYPE_AGENT ?>', 170 'snmp': '<?= INTERFACE_TYPE_SNMP ?>', 171 'jmx': '<?= INTERFACE_TYPE_JMX ?>', 172 'ipmi': '<?= INTERFACE_TYPE_IPMI ?>' 173 }; 174 this.INTERFACE_NAMES = { 175 <?= INTERFACE_TYPE_AGENT ?>: '<?= _('Agent') ?>', 176 <?= INTERFACE_TYPE_SNMP ?>: '<?= _('SNMP') ?>', 177 <?= INTERFACE_TYPE_JMX ?>: '<?= _('JMX') ?>', 178 <?= INTERFACE_TYPE_IPMI ?>: '<?= _('IPMI') ?>' 179 }; 180 181 this.allow_empty_message = true; 182 this.$noInterfacesMsg = jQuery('<div>', {class: '<?= ZBX_STYLE_GREY ?>'}) 183 .text('<?= _('No interfaces are defined.') ?>') 184 .css('padding', '5px 0px') 185 .insertAfter(jQuery('.<?= ZBX_STYLE_HOST_INTERFACE_CONTAINER_HEADER ?>')); 186 187 // Variables. 188 this.interfaces = {}; 189 190 this.data = data; 191 } 192 193 /** 194 * Setter for interface store. 195 * 196 * @param object new_data 197 */ 198 set data(new_data) { 199 if (typeof new_data !== 'object') { 200 throw new Error('Incorrect data.'); 201 } 202 203 Object 204 .entries(new_data) 205 .forEach(([_, value]) => { 206 if (!('interfaceid' in value)) { 207 value.interfaceid = this.generateId(); 208 } 209 210 this.interfaces[value.interfaceid] = value; 211 }); 212 213 return this; 214 } 215 216 /** 217 * Getter for interface store. 218 */ 219 get data() { 220 return this.interfaces; 221 } 222 223 setAllowEmptyMessage(value) { 224 this.allow_empty_message = value; 225 } 226 227 setSnmpFields(elem, iface) { 228 if (iface.type != <?= INTERFACE_TYPE_SNMP ?>) { 229 return elem 230 .querySelector('.<?= ZBX_STYLE_HOST_INTERFACE_CELL_DETAILS ?>') 231 .remove(); 232 } 233 234 elem 235 .querySelector(`#interfaces_${iface.interfaceid}_details_version`) 236 .value = iface.details.version; 237 238 if (iface.details.securitylevel !== undefined) { 239 elem 240 .querySelector(`#interfaces_${iface.interfaceid}_details_securitylevel`) 241 .value = iface.details.securitylevel; 242 } 243 244 if (iface.details.privprotocol !== undefined) { 245 elem.querySelector(`[name="interfaces[${iface.interfaceid}][details][privprotocol]"]`).value 246 = iface.details.privprotocol; 247 } 248 249 if (iface.details.authprotocol !== undefined) { 250 elem.querySelector(`[name="interfaces[${iface.interfaceid}][details][authprotocol]"]`).value 251 = iface.details.authprotocol; 252 } 253 254 if (iface.details.bulk == <?= SNMP_BULK_ENABLED ?>) { 255 elem 256 .querySelector(`#interfaces_${iface.interfaceid}_details_bulk`) 257 .checked = true; 258 } 259 260 new CViewSwitcher(`interfaces_${iface.interfaceid}_details_version`, 'change', 261 { 262 <?= SNMP_V1 ?>: [`row_snmp_community_${iface.interfaceid}`], 263 <?= SNMP_V2C ?>: [`row_snmp_community_${iface.interfaceid}`], 264 <?= SNMP_V3 ?>: [ 265 `row_snmpv3_contextname_${iface.interfaceid}`, 266 `row_snmpv3_securityname_${iface.interfaceid}`, 267 `row_snmpv3_securitylevel_${iface.interfaceid}`, 268 `row_snmpv3_authprotocol_${iface.interfaceid}`, 269 `row_snmpv3_authpassphrase_${iface.interfaceid}`, 270 `row_snmpv3_privprotocol_${iface.interfaceid}`, 271 `row_snmpv3_privpassphrase_${iface.interfaceid}`, 272 ] 273 } 274 ); 275 276 jQuery(`#interfaces_${iface.interfaceid}_details_version`).on('change', function() { 277 jQuery(`#interfaces_${iface.interfaceid}_details_securitylevel`).off('change'); 278 279 if (jQuery(this).val() == <?= SNMP_V3 ?>) { 280 new CViewSwitcher(`interfaces_${iface.interfaceid}_details_securitylevel`, 'change', 281 { 282 <?= ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV ?>: [], 283 <?= ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV ?>: [ 284 'row_snmpv3_authprotocol_' + iface.interfaceid, 285 'row_snmpv3_authpassphrase_' + iface.interfaceid, 286 ], 287 <?= ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV ?>: [ 288 'row_snmpv3_authprotocol_' + iface.interfaceid, 289 'row_snmpv3_authpassphrase_' + iface.interfaceid, 290 'row_snmpv3_privprotocol_' + iface.interfaceid, 291 'row_snmpv3_privpassphrase_' + iface.interfaceid 292 ] 293 } 294 ); 295 } 296 }).trigger('change'); 297 } 298 299 generateId() { 300 let id = 1; 301 302 while (this.data[id] !== undefined) { 303 id++; 304 } 305 306 return id; 307 } 308 309 getNewData(type) { 310 return { 311 interfaceid: this.generateId(), 312 isNew: true, 313 useip: 1, 314 type: this.INTERFACE_TYPES[type], 315 type_name: this.INTERFACE_NAMES[this.INTERFACE_TYPES[type]], 316 port: this.DEFAULT_PORTS[type], 317 ip: '127.0.0.1', 318 main: '0', 319 details: { 320 version: <?= SNMP_V2C ?>, 321 community: '{$SNMP_COMMUNITY}', 322 bulk: <?= SNMP_BULK_ENABLED ?>, 323 securitylevel: <?= ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV ?>, 324 authprotocol: <?= ITEM_SNMPV3_AUTHPROTOCOL_MD5 ?>, 325 privprotocol: <?= ITEM_SNMPV3_PRIVPROTOCOL_DES ?> 326 } 327 }; 328 } 329 330 getInterfaces() { 331 let types = { 332 <?= INTERFACE_TYPE_AGENT ?>: {main: null, all: []}, 333 <?= INTERFACE_TYPE_SNMP ?>: {main: null, all: []}, 334 <?= INTERFACE_TYPE_JMX ?>: {main: null, all: []}, 335 <?= INTERFACE_TYPE_IPMI ?>: {main: null, all: []} 336 }; 337 338 Object 339 .entries(this.data) 340 .forEach(([_, value]) => { 341 types[value.type].all.push(value.interfaceid); 342 343 if (value.main == <?= INTERFACE_PRIMARY ?>) { 344 if (types[value.type].main !== null) { 345 throw new Error('Multiple default interfaces for same type.'); 346 } 347 348 types[value.type].main = value.interfaceid; 349 } 350 }); 351 352 return types; 353 } 354 355 renderRow(iface) { 356 const container = document.querySelector(this.CONTAINER_IDS[iface.type]); 357 const disabled = (typeof iface.items !== 'undefined' && iface.items > 0); 358 359 iface.type_name = this.INTERFACE_NAMES[iface.type]; 360 361 /* 362 * New line break css selector :empty. Trim used to avoid this. 363 * Template added with new line. Because template <script> tag it contain for code readability. 364 */ 365 container.insertAdjacentHTML('beforeend', this.TEMPLATE.evaluate({iface: iface}).trim()); 366 367 const elem = document.getElementById(`interface_row_${iface.interfaceid}`); 368 369 // Select proper use ip radio element. 370 elem 371 .querySelector(`#interfaces_${iface.interfaceid}_useip_${iface.useip}`) 372 .checked = true; 373 374 if (disabled) { 375 elem 376 .querySelector('.<?= ZBX_STYLE_HOST_INTERFACE_BTN_REMOVE ?>') 377 .disabled = true; 378 } 379 380 this.setSnmpFields(elem, iface); 381 382 // Set onclick actions. 383 elem 384 .querySelector('.<?= ZBX_STYLE_HOST_INTERFACE_BTN_REMOVE ?>') 385 .addEventListener('click', () => this.removeById(iface.interfaceid)); 386 387 elem 388 .querySelector('.<?= ZBX_STYLE_HOST_INTERFACE_BTN_MAIN_INTERFACE ?>') 389 .addEventListener('click', () => this.setMainInterfaceById(iface.interfaceid)); 390 391 [...elem.querySelectorAll('.<?= ZBX_STYLE_HOST_INTERFACE_CELL_USEIP ?> input')].map( 392 (el) => el.addEventListener('click', (event) => this.setUseIp(elem, event.currentTarget.value)) 393 ); 394 395 return true; 396 } 397 398 removeById(id) { 399 const elem = document.getElementById(`interface_row_${id}`); 400 401 if (!elem) { 402 return false; 403 } 404 405 elem.remove(); 406 delete this.data[id]; 407 408 this.resetMainInterfaces(); 409 this.renderLayout(); 410 411 return true; 412 } 413 414 createRowByTypeName(type) { 415 const new_data = this.getNewData(type); 416 let data = {}; 417 418 data[new_data.interfaceid] = new_data; 419 420 this.data = data; 421 this.renderRow(new_data); 422 423 this.resetMainInterfaces(); 424 this.renderLayout(); 425 426 if (new_data.type == <?= INTERFACE_TYPE_SNMP ?>) { 427 const elem = document.getElementById(`interface_row_${new_data.interfaceid}`); 428 const index = [...elem.parentElement.children].indexOf(elem) 429 430 jQuery(this.CONTAINER_IDS[<?= INTERFACE_TYPE_SNMP ?>]).zbx_vertical_accordion('expandNth', index); 431 } 432 433 return true; 434 } 435 436 resetMainInterfaces() { 437 const interfaces = this.getInterfaces(); 438 439 for (let type in interfaces) { 440 if (!interfaces.hasOwnProperty(type)) { 441 continue; 442 } 443 444 let type_interfaces = interfaces[type]; 445 446 if (!type_interfaces.main && type_interfaces.all.length) { 447 for (let i = 0; i < type_interfaces.all.length; i++) { 448 if (this.data[type_interfaces.all[i]].main == <?= INTERFACE_PRIMARY ?>) { 449 interfaces[type].main = this.data[type_interfaces.all[i]].interfaceid; 450 } 451 } 452 453 if (!type_interfaces.main) { 454 type_interfaces.main = type_interfaces.all[0]; 455 this.data[type_interfaces.main].main = '<?= INTERFACE_PRIMARY ?>'; 456 } 457 } 458 } 459 460 for (let type in interfaces) { 461 if (interfaces.hasOwnProperty(type)) { 462 let type_interfaces = interfaces[type]; 463 464 if (type_interfaces.main) { 465 document 466 .getElementById(`interface_main_${type_interfaces.main}`) 467 .checked = true; 468 } 469 } 470 } 471 472 return true; 473 } 474 475 setMainInterfaceById(id) { 476 const interfaces = this.getInterfaces(); 477 const type = this.data[id].type; 478 const old = interfaces[type].main; 479 480 if (id != old) { 481 this.data[id].main = '<?= INTERFACE_PRIMARY ?>'; 482 this.data[old].main = '<?= INTERFACE_SECONDARY ?>'; 483 } 484 485 return true; 486 } 487 488 setUseIp(elem, use_ip) { 489 const interfaceid = elem.dataset.interfaceid; 490 491 this.data[interfaceid].useip = use_ip; 492 493 [...elem.querySelectorAll('input[name$="[ip]"], input[name$="[dns]"]')].map((el) => { 494 el.removeAttribute('aria-required') 495 return el; 496 }); 497 498 elem 499 .querySelector((use_ip == <?= INTERFACE_USE_IP ?>) ? '[name$="[ip]"]' : '[name$="[dns]"]') 500 .setAttribute('aria-required', true); 501 502 return true; 503 } 504 505 addAgent() { 506 this.createRowByTypeName('agent'); 507 } 508 509 addSnmp() { 510 this.createRowByTypeName('snmp'); 511 } 512 513 addJmx() { 514 this.createRowByTypeName('jmx'); 515 } 516 517 addIpmi() { 518 this.createRowByTypeName('ipmi'); 519 } 520 521 render() { 522 for (let i in this.data) { 523 if (this.data.hasOwnProperty(i)) { 524 this.renderRow(this.data[i]); 525 } 526 } 527 528 this.resetMainInterfaces(); 529 this.renderLayout(); 530 531 // Add accordion functionality to SNMP interfaces. 532 jQuery(this.CONTAINER_IDS[<?= INTERFACE_TYPE_SNMP ?>]) 533 .zbx_vertical_accordion({handler: '.<?= ZBX_STYLE_HOST_INTERFACE_BTN_TOGGLE ?>'}); 534 535 // Add event to expand SNMP interface accordion if focused or clicked on inputs. 536 jQuery(this.CONTAINER_IDS[<?= INTERFACE_TYPE_SNMP ?>]).on("focus", ".<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>:not(.<?= ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED ?>) .<?= ZBX_STYLE_HOST_INTERFACE_INPUT_EXPAND ?>", (event) => { 537 var index = jQuery(event.currentTarget).closest('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>').index(); 538 539 jQuery(this.CONTAINER_IDS[<?= INTERFACE_TYPE_SNMP ?>]).zbx_vertical_accordion("expandNth", index); 540 }); 541 542 return true; 543 } 544 545 renderLayout() { 546 if (Object.keys(this.data).length > 0) { 547 jQuery('.<?= ZBX_STYLE_HOST_INTERFACE_CONTAINER ?>').show(); 548 this.$noInterfacesMsg.hide(); 549 } 550 else { 551 jQuery('.<?= ZBX_STYLE_HOST_INTERFACE_CONTAINER ?>').hide(); 552 this.$noInterfacesMsg.toggle(this.allow_empty_message); 553 } 554 } 555 556 /** 557 * Converts form field to readonly. 558 * 559 * @param {Element} el Native JavaScript element for form field. 560 */ 561 static setReadonly(el) { 562 const tag_name = el.tagName; 563 564 if (tag_name === 'INPUT') { 565 const type = el.getAttribute('type'); 566 567 switch (type) { 568 case 'text': 569 el.readOnly = true; 570 break; 571 case 'radio': 572 case 'checkbox': 573 const {checked, name, value} = el; 574 el.disabled = true; 575 576 if (checked) { 577 const input = document.createElement('input'); 578 input.type = 'hidden'; 579 input.name = name; 580 input.value = value; 581 582 el.insertAdjacentElement('beforebegin', input); 583 } 584 585 break; 586 } 587 } 588 else if (tag_name === 'Z-SELECT') { 589 el.readOnly = true; 590 } 591 } 592 593 static makeReadonly() { 594 [...document.querySelectorAll('.<?= ZBX_STYLE_HOST_INTERFACE_ROW ?>')].map((row) => { 595 [...row.querySelectorAll('input, z-select')].map((el) => { 596 this.setReadonly(el); 597 }); 598 599 [...row.querySelectorAll('.<?= ZBX_STYLE_HOST_INTERFACE_BTN_REMOVE ?>')].map((el) => el.remove()); 600 }); 601 602 return true; 603 } 604 } 605 606 jQuery(document).ready(function() { 607 'use strict'; 608 609 jQuery('#tls_connect, #tls_in_psk, #tls_in_cert').change(function() { 610 // If certificate is selected or checked. 611 if (jQuery('input[name=tls_connect]:checked').val() == <?= HOST_ENCRYPTION_CERTIFICATE ?> 612 || jQuery('#tls_in_cert').is(':checked')) { 613 jQuery('#tls_issuer, #tls_subject').closest('li').show(); 614 } 615 else { 616 jQuery('#tls_issuer, #tls_subject').closest('li').hide(); 617 } 618 619 // If PSK is selected or checked. 620 if (jQuery('input[name=tls_connect]:checked').val() == <?= HOST_ENCRYPTION_PSK ?> 621 || jQuery('#tls_in_psk').is(':checked')) { 622 jQuery('#tls_psk, #tls_psk_identity, .tls_psk').closest('li').show(); 623 } 624 else { 625 jQuery('#tls_psk, #tls_psk_identity, .tls_psk').closest('li').hide(); 626 } 627 }); 628 629 // radio button of inventory modes was clicked 630 jQuery('input[name=inventory_mode]').click(function() { 631 // action depending on which button was clicked 632 var inventoryFields = jQuery('#inventorylist :input:gt(2)'); 633 634 switch (jQuery(this).val()) { 635 case '<?= HOST_INVENTORY_DISABLED ?>': 636 inventoryFields.prop('disabled', true); 637 jQuery('.populating_item').hide(); 638 break; 639 case '<?= HOST_INVENTORY_MANUAL ?>': 640 inventoryFields.prop('disabled', false); 641 jQuery('.populating_item').hide(); 642 break; 643 case '<?= HOST_INVENTORY_AUTOMATIC ?>': 644 inventoryFields.prop('disabled', false); 645 inventoryFields.filter('.linked_to_item').prop('disabled', true); 646 jQuery('.populating_item').show(); 647 break; 648 } 649 }); 650 651 // Refresh field visibility on document load. 652 if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_NONE ?>) == <?= HOST_ENCRYPTION_NONE ?>) { 653 jQuery('#tls_in_none').prop('checked', true); 654 } 655 if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_PSK ?>) == <?= HOST_ENCRYPTION_PSK ?>) { 656 jQuery('#tls_in_psk').prop('checked', true); 657 } 658 if ((jQuery('#tls_accept').val() & <?= HOST_ENCRYPTION_CERTIFICATE ?>) == <?= HOST_ENCRYPTION_CERTIFICATE ?>) { 659 jQuery('#tls_in_cert').prop('checked', true); 660 } 661 662 jQuery('input[name=tls_connect]').trigger('change'); 663 664 // Depending on checkboxes, create a value for hidden field 'tls_accept'. 665 jQuery('#hosts-form').submit(function() { 666 var tls_accept = 0x00; 667 668 if (jQuery('#tls_in_none').is(':checked')) { 669 tls_accept |= <?= HOST_ENCRYPTION_NONE ?>; 670 } 671 if (jQuery('#tls_in_psk').is(':checked')) { 672 tls_accept |= <?= HOST_ENCRYPTION_PSK ?>; 673 } 674 if (jQuery('#tls_in_cert').is(':checked')) { 675 tls_accept |= <?= HOST_ENCRYPTION_CERTIFICATE ?>; 676 } 677 678 jQuery('#tls_accept').val(tls_accept); 679 }); 680 }); 681</script> 682