<?php declare(strict_types = 0); /* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ /** * @var CView $this */ ?> window.drule_edit_popup = new class { init({druleid, dchecks, drule}) { this.overlay = overlays_stack.getById('discoveryForm'); this.dialogue = this.overlay.$dialogue[0]; this.form = this.overlay.$dialogue.$body[0].querySelector('form'); this.druleid = druleid; this.dchecks = dchecks; this.drule = drule; this.dcheckid = getUniqueId(); this.available_device_types = [<?= SVC_AGENT ?>, <?= SVC_SNMPv1 ?>, <?= SVC_SNMPv2c ?>, <?= SVC_SNMPv3 ?>]; document.getElementById('discovery_by').addEventListener('change', () => this.#updateForm()); // Append existing discovery checks to check table. if (typeof dchecks === 'object') { dchecks = Object.values(dchecks); } for (const dcheck of dchecks) { this.#addCheck(dcheck); } this.#addRadioButtonValues(drule); this.#initActionButtons(); this.#updateForm(); this.form.style.display = ''; this.overlay.recoverFocus(); } #initActionButtons() { this.dialogue.addEventListener('click', (e) => { if (e.target.classList.contains('js-check-add')) { this.#editCheck(); } else if (e.target.classList.contains('js-remove')) { this.#removeDCheckRow(e.target.closest('tr').id); e.target.closest('tr').remove(); } else if (e.target.classList.contains('js-edit')) { this.#editCheck(e.target.closest('tr')); } }); const max_sessions = this.form.querySelector('#concurrency_max_type'); max_sessions.onchange = () => { this.#updateForm(); }; max_sessions.dispatchEvent(new Event('change')); } #updateForm() { const discovery_by = this.form.querySelector('[name="discovery_by"]:checked').value; this.form.querySelector('.js-field-proxy').style.display = discovery_by == <?= ZBX_DISCOVERY_BY_PROXY ?> ? '' : 'none'; const concurrency_max_type = this.form.querySelector('[name="concurrency_max_type"]:checked').value; const concurrency_max = this.form.querySelector('#concurrency_max'); const is_custom = concurrency_max_type == <?= ZBX_DISCOVERY_CHECKS_CUSTOM ?>; concurrency_max.classList.toggle('<?= ZBX_STYLE_DISPLAY_NONE ?>', !is_custom); if (is_custom) { concurrency_max.focus(); } } #updateCheck(row, input) { delete input.dchecks; input.warning = row.querySelector('.btn-icon')?.getAttribute('data-hintbox-contents'); this.#addCheck(input, row, true); row.remove(); this.#updateCheckWarningIcon(input); this.#addInputFields(input); } #editCheck(row = null) { let params = { dcheckid: this.dcheckid }; if (row !== null) { params = { dcheckid: this.dcheckid, update: 1 }; const hidden_inputs = row.querySelectorAll('input[type="hidden"]'); for (let i = 0; i < hidden_inputs.length; i++) { const input = hidden_inputs[i]; const name = input.getAttribute('name').match(/\[([^\]]+)]$/); if (name) { params[name[1]] = input.value; } } } const overlay = PopUp('discovery.check.edit', params, { dialogueid: 'discovery-check', dialogue_class: 'modal-popup-medium' }); overlay.$dialogue[0].addEventListener('check.submit', (e) => { if (row !== null) { this.#updateCheck(row, e.detail); } else { this.dcheckid = getUniqueId() this.#addCheck(e.detail, null); } }); } #addRadioButtonValues(drule) { jQuery('input:radio[name="uniqueness_criteria"][value='+jQuery.escapeSelector(drule.uniqueness_criteria)+']') .attr('checked', 'checked'); jQuery('input:radio[name="host_source"][value='+jQuery.escapeSelector(drule.host_source)+']') .attr('checked', 'checked'); jQuery('input:radio[name="name_source"][value='+jQuery.escapeSelector(drule.name_source)+']') .attr('checked', 'checked'); document.querySelectorAll('#host_source, #name_source').forEach((element) => { element.addEventListener('change', (e) => { this.#updateRadioButtonValues(e); }); }); } #updateRadioButtonValues(event) { let target = event.target; let name = target.getAttribute('name'); if (typeof target.dataset.id !== 'undefined') { document.querySelectorAll(`[name^=dchecks][name$="[${name}]"]`) .forEach(function (dcheck) { dcheck.value = (name === 'name_source') ? <?= ZBX_DISCOVERY_UNSPEC ?> : <?= ZBX_DISCOVERY_DNS ?>; }); document.querySelector(`[name="dchecks[${target.dataset.id}][${name}]"]`); document .querySelector(`[name="dchecks[${target.dataset.id}][${name}]"]`).value = <?= ZBX_DISCOVERY_VALUE ?>; } else { document.querySelectorAll(`[name^=dchecks][name$="[${name}]"]`) .forEach(function (dcheck) { dcheck.value = target.value; }); } } #addCheck(input, row = null, update = false) { delete input.dchecks; if (update === false) { if (typeof input.host_source === 'undefined') { const checked_host_source = document.querySelector('[name="host_source"]:checked:not([data-id])'); input.host_source = checked_host_source === null ? '<?= ZBX_DISCOVERY_DNS ?>' : checked_host_source.value; } if (typeof input.name_source === 'undefined') { const checked_name_source = document.querySelector('[name="name_source"]:checked:not([data-id])'); input.name_source = checked_name_source === null ? '<?= ZBX_DISCOVERY_UNSPEC ?>' : checked_name_source.value; } } else { if (this.available_device_types.includes(parseInt(input.type))) { input.host_source = document.querySelector('input[name=host_source]:checked').value; input.name_source = document.querySelector('input[name=name_source]:checked').value; input.uniqueness_criteria = document.querySelector('input[name=uniqueness_criteria]:checked').value; } } if (input.type == <?= SVC_ICMPPING ?>) { input.allow_redirect = typeof input.allow_redirect === 'undefined' ? 0 : input.allow_redirect; } const template = new Template(document.getElementById('dcheck-row-tmpl').innerHTML); if (row !== null) { row.insertAdjacentHTML('afterend', template.evaluate(input)); this.#addInputFields(input); } else { document .querySelector('#dcheckList tbody') .insertAdjacentHTML('beforeend', template.evaluate(input)); this.#updateCheckWarningIcon(input); this.#addInputFields(input); } this.#updateRadioButtonRows(input, update, row); } #updateCheckWarningIcon(input) { const row = document.getElementById(`dcheckRow_${input.dcheckid}`); const warning_icon = row.querySelector('.btn-icon'); if (input.dcheckid.includes('new')) { warning_icon.remove(); } this.dchecks.forEach(dcheck => { if (dcheck.dcheckid === input.dcheckid) { dcheck.warning === '' ? warning_icon.remove() : row.querySelector('.js-remove').disabled = true; } }); } #addInputFields(input) { for (let field_name in input) { if (input.hasOwnProperty(field_name)) { const input_element = document.createElement('input'); input_element.name = `dchecks[${input.dcheckid}][${field_name}]`; input_element.type = 'hidden'; input_element.value = input[field_name]; const dcheck_cell = document.getElementById(`dcheckCell_${input.dcheckid}`); dcheck_cell.appendChild(input_element); } } } #updateRadioButtonRows(input, update, row = null) { const templates = { unique_template: ['#unique-row-tmpl', '#device-uniqueness-list', 'uniqueness_criteria_', 'ip'], host_template: ['#host-source-row-tmpl', '#host_source', 'host_source_', 'chk_dns'], name_template: ['#name-source-row-tmpl', '#name_source', 'name_source_', 'chk_host'] }; const need_to_add_row = this.available_device_types.includes(parseInt(input.type)); for (const [template, list, key, def] of Object.values(templates)) { if (need_to_add_row) { if (update === false) { const template_html = document.querySelector(template).innerHTML; document.querySelector(list) .insertAdjacentHTML('beforeend', new Template(template_html).evaluate(input)); } else { const template_html = document.querySelector(template).innerHTML; const list_item = document.querySelector(`${list} input[value$="${input.dcheckid}"]`) ?.closest('li'); if (list_item) { list_item.outerHTML = new Template(template_html).evaluate(input); } else { document.querySelector(list).insertAdjacentHTML('beforeend', new Template(template_html).evaluate(input) ); } } } else { const dcheck_checkbox = document.querySelector(`${list} input[value$="${input.dcheckid}"]`); if (dcheck_checkbox !== null) { if (dcheck_checkbox.checked) { document.querySelector(`#${key}${def}`).checked = true; } dcheck_checkbox.closest('li')?.remove(); } } } if (update === false) { this.#addRadioButtonValues(this.drule); } else { this.#addRadioButtonValues(input); const setInputSource = (field, default_value) => { const checked_source = document.querySelector(`input[name="${field}"]:checked`); if (typeof checked_source.dataset.id !== 'undefined') { if (checked_source.dataset.id === input.dcheckid) { input[field] = <?= ZBX_DISCOVERY_VALUE ?>; } else { input[field] = default_value; } } else { input[field] = checked_source.value; } }; setInputSource('host_source', <?= ZBX_DISCOVERY_DNS ?>); setInputSource('name_source', <?= ZBX_DISCOVERY_UNSPEC ?>); delete input.uniqueness_criteria; } } #removeDCheckRow(dcheckid) { dcheckid = dcheckid.substring(dcheckid.indexOf('_') + 1); const elements = { uniqueness_criteria_: 'ip', host_source_: 'chk_dns', name_source_: 'chk_host' }; for (const [key, def] of Object.entries(elements)) { const obj = document.querySelector(`#${key}${dcheckid}`); if (obj !== null) { if (obj.checked) { document.querySelector(`#${key}${def}`).checked = true; } document.querySelector(`#${key}row_${dcheckid}`).remove(); } } } clone({title, buttons}) { this.druleid = null; // Remove all warning icons and enable all Remove buttons in Checks table. const table = document.getElementById('dcheckList'); table.querySelectorAll('.js-remove').forEach(element => element.disabled = false); table.querySelectorAll('.btn-icon').forEach(element => element.remove()); this.overlay.setProperties({title, buttons}); this.overlay.unsetLoading(); this.overlay.recoverFocus(); this.overlay.containFocus(); } delete() { const curl = new Curl('zabbix.php'); curl.setArgument('action', 'discovery.delete'); curl.setArgument(CSRF_TOKEN_NAME, <?= json_encode(CCsrfTokenHelper::get('discovery')) ?>); this.#post(curl.getUrl(), {druleids: [this.druleid]}, (response) => { overlayDialogueDestroy(this.overlay.dialogueid); this.dialogue.dispatchEvent(new CustomEvent('dialogue.submit', {detail: response.success})); }); } submit() { const fields = getFormFields(this.form); ['name', 'iprange', 'delay'].forEach( field => fields[field] = fields[field].trim() ); const curl = new Curl('zabbix.php'); curl.setArgument('action', this.druleid === null ? 'discovery.create' : 'discovery.update'); this.#post(curl.getUrl(), fields, (response) => { overlayDialogueDestroy(this.overlay.dialogueid); this.dialogue.dispatchEvent(new CustomEvent('dialogue.submit', {detail: response.success})); }); } #post(url, data, success_callback) { fetch(url, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }) .then((response) => response.json()) .then((response) => { if ('error' in response) { throw {error: response.error}; } return response; }) .then(success_callback) .catch((exception) => { for (const element of this.form.parentNode.children) { if (element.matches('.msg-good, .msg-bad, .msg-warning')) { element.parentNode.removeChild(element); } } let title, messages; if (typeof exception === 'object' && 'error' in exception) { title = exception.error.title; messages = exception.error.messages; } else { messages = [<?= json_encode(_('Unexpected server error.')) ?>]; } const message_box = makeMessageBox('bad', messages, title)[0]; this.form.parentNode.insertBefore(message_box, this.form); }) .finally(() => { this.overlay.unsetLoading(); }); } }