<?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/>. **/ use Widgets\SvgGraph\Includes\CWidgetFieldDataSet; ?> window.widget_svggraph_form = new class { /** * @type {Map<HTMLLIElement, CSortable>} */ #single_items_sortable = new Map(); /** * @type {number} */ #dataset_row_unique_id = 0; init({form_tabs_id, color_palette, templateid}) { colorPalette.setThemeColors(color_palette); this._$overlay_body = jQuery('.overlay-dialogue-body'); this._form = document.getElementById('widget-dialogue-form'); this._templateid = templateid; this._dataset_wrapper = document.getElementById('data_sets'); this._any_ds_aggregation_function_enabled = false; this.#dataset_row_unique_id = this._dataset_wrapper.querySelectorAll('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>').length; this._$overlay_body.on('scroll', () => { const $preview = jQuery('.<?= ZBX_STYLE_SVG_GRAPH_PREVIEW ?>', this._$overlay_body); if (!$preview.length) { this._$overlay_body.off('scroll'); return; } if ($preview.offset().top < this._$overlay_body.offset().top && this._$overlay_body.height() > 400) { jQuery('#svg-graph-preview').css('top', this._$overlay_body.offset().top - $preview.offset().top ); jQuery('.graph-widget-config-tabs .ui-tabs-nav').css('top', $preview.height()); } else { jQuery('#svg-graph-preview').css('top', 0); jQuery('.graph-widget-config-tabs .ui-tabs-nav').css('top', 0); } }); jQuery(`#${form_tabs_id}`) .on('tabsactivate', () => jQuery.colorpicker('hide')) .on('change', 'input, z-select, .multiselect', () => this.onGraphConfigChange()); this._datasetTabInit(); this._problemsTabInit(); this.onGraphConfigChange(); } onGraphConfigChange() { this._updateForm(); this._updatePreview(); } updateVariableOrder(obj, row_selector, var_prefix) { for (const k of [10000, 0]) { jQuery(row_selector, obj).each(function(i) { if (var_prefix === 'ds') { jQuery(this).attr('data-set', i); jQuery('.single-item-table', this).attr('data-set', i); } jQuery('.multiselect[data-params]', this).each(function() { const name = jQuery(this).multiSelect('getOption', 'name'); if (name !== null) { jQuery(this).multiSelect('modify', { name: name.replace(/([a-z]+\[)\d+(]\[[a-z_]+])/, `$1${k + i}$2`) }); } }); jQuery(`[name^="${var_prefix}["]`, this) .filter(function () { return jQuery(this).attr('name').match(/[a-z]+\[\d+]\[[a-z_]+]/); }) .each(function () { jQuery(this).attr('name', jQuery(this).attr('name').replace(/([a-z]+\[)\d+(]\[[a-z_]+])/, `$1${k + i}$2`) ); }); }); } } _datasetTabInit() { this._updateDatasetsLabel(); // Initialize vertical accordion. const $data_sets = jQuery(this._dataset_wrapper); $data_sets .on('focus', '.<?= CMultiSelect::ZBX_STYLE_CLASS ?> input.input', function(e) { const list_item = e.target.closest('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>'); if (list_item.classList.contains('<?= ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED ?>')) { return; } $data_sets.zbx_vertical_accordion('expandNth', [...list_item.parentElement.children].indexOf(list_item) ); }) .on('click', '.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>', function(e) { if (!e.target.classList.contains('color-picker-preview')) { jQuery.colorpicker('hide'); } const list_item = e.target.closest('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>'); if (list_item.classList.contains('<?= ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED ?>')) { return; } if (e.target.classList.contains('js-click-expand') || e.target.classList.contains('color-picker-preview')) { $data_sets.zbx_vertical_accordion('expandNth', [...list_item.parentElement.children].indexOf(list_item) ); } }) .on('collapse', function(event, data) { jQuery('textarea, .multiselect', data.section).scrollTop(0); jQuery(window).trigger('resize'); const dataset = data.section[0]; if (dataset.dataset.type == '<?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?>') { const message_block = dataset.querySelector('.no-items-message'); if (dataset.querySelectorAll('.single-item-table-row').length == 0) { message_block.style.display = 'block'; } } }) .on('expand', function(event, data) { jQuery(window).trigger('resize'); const dataset = data.section[0]; if (dataset.dataset.type == '<?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?>') { const message_block = dataset.querySelector('.no-items-message'); if (dataset.querySelectorAll('.single-item-table-row').length == 0) { message_block.style.display = 'none'; } widget_svggraph_form._initSingleItemSortable(dataset); } }) .zbx_vertical_accordion({handler: '.<?= ZBX_STYLE_LIST_ACCORDION_ITEM_TOGGLE ?>'}); // Initialize rangeControl UI elements. jQuery('.<?= CRangeControl::ZBX_STYLE_CLASS ?>', jQuery(this._dataset_wrapper)).rangeControl(); for (const colorpicker of jQuery('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { jQuery(colorpicker).colorpicker({ onUpdate: function(color) { jQuery('.<?= ZBX_STYLE_COLOR_PREVIEW_BOX ?>', jQuery(this).closest('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>') ).css('background-color', `#${color}`); }, appendTo: '.overlay-dialogue-body' }); } this._dataset_wrapper.addEventListener('click', (e) => { if (e.target.classList.contains('js-add-item')) { this._selectItems(); } if (e.target.classList.contains('js-add-widget')) { this._selectWidget(); } if (e.target.matches('.single-item-table-row .table-col-name a')) { this._editItem(e.target); } if (e.target.classList.contains('element-table-remove')) { this._removeSingleItem(e.target); } if (e.target.classList.contains('js-remove')) { this._removeDataSet(e.target); } }); document .getElementById('dataset-add') .addEventListener('click', () => { this._addDataset(<?= CWidgetFieldDataSet::DATASET_TYPE_PATTERN_ITEM ?>); }); document .getElementById('dataset-menu') .addEventListener('click', (e) => this._addDatasetMenu(e)); window.addPopupValues = (list) => { if (!isset('object', list) || list.object !== 'itemid') { return false; } for (let i = 0; i < list.values.length; i++) { this._addSingleItem({ itemid: list.values[i].itemid, name: list.values[i].name }); } this._initSingleItemSortable(this._getOpenedDataset()); this._updatePreview(); } this._updateSingleItemsReferences(); this._initDataSetSortable(); this._initSingleItemSortable(this._getOpenedDataset()); } _problemsTabInit() { const widget = document.getElementById('problems'); document.getElementById('show_problems') .addEventListener('click', (e) => { jQuery('#graph_item_problems, #problem_name, #problemhosts_select').prop('disabled', !e.target.checked); jQuery('#problemhosts_').multiSelect(e.target.checked ? 'enable' : 'disable'); jQuery('[name^="severities["]', jQuery(widget)).prop('disabled', !e.target.checked); jQuery('[name="evaltype"]', jQuery(widget)).prop('disabled', !e.target.checked); jQuery('input, button, z-select', jQuery('#tags_table_tags', jQuery(widget))).prop('disabled', !e.target.checked ); }); } _updateDatasetsLabel() { for (const dataset of this._dataset_wrapper.querySelectorAll('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>')) { this._updateDatasetLabel(dataset); } } _updateDatasetLabel(dataset) { const placeholder_text = <?= json_encode(_('Data set')) ?> + ` #${parseInt(dataset.dataset.set) + 1}`; const data_set_label = dataset.querySelector('.js-dataset-label'); const data_set_label_input = dataset.querySelector(`[name="ds[${dataset.dataset.set}][data_set_label]"]`); data_set_label.textContent = data_set_label_input.value !== '' ? data_set_label_input.value : placeholder_text; data_set_label_input.placeholder = placeholder_text; } _addDatasetMenu(e) { const menu = [ { items: [ { label: <?= json_encode(_('Item patterns')) ?>, clickCallback: () => { this._addDataset(<?= CWidgetFieldDataSet::DATASET_TYPE_PATTERN_ITEM ?>); } }, { label: <?= json_encode(_('Item list')) ?>, clickCallback: () => { this._addDataset(<?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?>); } } ] }, { items: [ { label: <?= json_encode(_('Clone')) ?>, disabled: this._getOpenedDataset() === null, clickCallback: () => { this._cloneDataset(); } } ] } ]; jQuery(e.target).menuPopup(menu, new jQuery.Event(e), { position: { of: e.target, my: 'left top', at: 'left bottom', within: 'body' } }); } _addDataset(type) { jQuery(this._dataset_wrapper).zbx_vertical_accordion('collapseAll'); const template = type == <?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?> ? new Template(jQuery('#dataset-single-item-tmpl').html()) : new Template(jQuery('#dataset-pattern-item-tmpl').html()); const used_colors = []; for (const color of this._form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { if (color.value !== '') { used_colors.push(color.value); } } const fragment = document.createRange().createContextualFragment(template.evaluate({ rowNum: this.#dataset_row_unique_id++, color: type == <?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?> ? '' : colorPalette.getNextColor(used_colors) })); this._dataset_wrapper.append(fragment); this.updateVariableOrder(this._dataset_wrapper, '.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>', 'ds'); this._updateDatasetsLabel(); const dataset = this._getOpenedDataset(); for (const colorpicker of dataset.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { jQuery(colorpicker).colorpicker({appendTo: '.overlay-dialogue-body'}); } for (const range_control of dataset.querySelectorAll('.<?= CRangeControl::ZBX_STYLE_CLASS ?>')) { jQuery(range_control).rangeControl(); } this._$overlay_body.scrollTop(Math.max(this._$overlay_body.scrollTop(), this._form.scrollHeight - this._$overlay_body.height() )); this._initDataSetSortable(); this._updateForm(); } _cloneDataset() { const dataset = this._getOpenedDataset(); this._addDataset(dataset.dataset.type); const cloned_dataset = this._getOpenedDataset(); if (dataset.dataset.type == <?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?>) { for (const row of dataset.querySelectorAll('.single-item-table-row')) { this._addSingleItem({ itemid: row.querySelector(`[name$='[itemids][]`).value, reference: row.querySelector(`[name$='[references][]`).value, name: row.querySelector('.table-col-name a').textContent }); } this._initSingleItemSortable(cloned_dataset); } else { if (this._templateid === null) { jQuery('.js-hosts-multiselect', cloned_dataset).multiSelect('addData', jQuery('.js-hosts-multiselect', dataset).multiSelect('getData') ); } jQuery('.js-items-multiselect', cloned_dataset).multiSelect('addData', jQuery('.js-items-multiselect', dataset).multiSelect('getData') ); } for (const input of dataset.querySelectorAll('[name^=ds]')) { const cloned_name = input.name.replace(/([a-z]+\[)\d+(]\[[a-z_]+])/, `$1${cloned_dataset.getAttribute('data-set')}$2` ); if (input.tagName.toLowerCase() === 'z-select') { cloned_dataset.querySelector(`[name="${cloned_name}"]`).value = input.value; } else if (input.type === 'text') { cloned_dataset.querySelector(`[name="${cloned_name}"]`).value = input.value; if (input.classList.contains('<?= CRangeControl::ZBX_STYLE_CLASS ?>')) { // Fire change event to redraw range input. cloned_dataset.querySelector(`[name="${cloned_name}"]`).dispatchEvent(new Event('change')); } } else if (input.type === 'checkbox' || input.type === 'radio') { // Click to fire events. cloned_dataset.querySelector(`[name="${cloned_name}"][value="${input.value}"]`).checked = input.checked; } } this._updateDatasetLabel(cloned_dataset); this._updatePreview(); } _removeDataSet(obj) { const dataset_remove = obj.closest('.list-accordion-item'); dataset_remove.remove(); if (this.#single_items_sortable.has(dataset_remove)) { this.#single_items_sortable.get(dataset_remove).enable(false); this.#single_items_sortable.delete(dataset_remove); } this.updateVariableOrder(jQuery(this._dataset_wrapper), '.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>', 'ds'); this._updateDatasetsLabel(); const dataset = this._getOpenedDataset(); if (dataset !== null) { this._updateSingleItemsOrder(dataset); this._initSingleItemSortable(dataset); } this._initDataSetSortable(); this.onGraphConfigChange(); } _getOpenedDataset() { return this._dataset_wrapper.querySelector('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED ?>[data-set]'); } _initDataSetSortable() { if (this._sortable_data_set === undefined) { this._sortable_data_set = new CSortable(document.querySelector('#data_sets'), { selector_handle: '.js-main-drag-icon, .js-dataset-label' }); this._sortable_data_set.on(CSortable.EVENT_SORT, () => { this.updateVariableOrder(this._dataset_wrapper, '.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>', 'ds'); this._updateDatasetsLabel(); this._updatePreview(); }); } } _selectItems() { if (this._templateid === null) { PopUp('popup.generic', { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', dstfrm: this._form.id, numeric: 1, writeonly: 1, multiselect: 1, with_webitems: 1, real_hosts: 1, resolve_macros: 1 }, {dialogue_class: 'modal-popup-generic'}); } else { PopUp('popup.generic', { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', dstfrm: this._form.id, numeric: 1, writeonly: 1, multiselect: 1, with_webitems: 1, hostid: this._templateid, hide_host_filter: 1 }, {dialogue_class: 'modal-popup-generic'}); } } _editItem(target) { const dataset = this._getOpenedDataset(); const dataset_index = dataset.getAttribute('data-set'); const row = target.closest('.single-item-table-row'); const row_index = row.rowIndex; const itemid_input = row.querySelector('input[name$="[itemids][]"'); if (itemid_input.value !== '0') { const excludeids = []; for (const input of dataset.querySelectorAll('.single-item-table-row input[name$="[itemids][]"]')) { if (input.value !== '0') { excludeids.push(input.value); } } if (this._templateid === null) { PopUp('popup.generic', { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', dstfrm: widget_svggraph_form._form.id, dstfld1: `items_${dataset_index}_${row_index}_itemid`, dstfld2: `items_${dataset_index}_${row_index}_name`, numeric: 1, writeonly: 1, with_webitems: 1, real_hosts: 1, resolve_macros: 1, excludeids }, {dialogue_class: 'modal-popup-generic'}); } else { PopUp('popup.generic', { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', dstfrm: widget_svggraph_form._form.id, dstfld1: `items_${dataset_index}_${row_index}_itemid`, dstfld2: `items_${dataset_index}_${row_index}_name`, numeric: 1, writeonly: 1, with_webitems: 1, hostid: this._templateid, hide_host_filter: 1, excludeids }, {dialogue_class: 'modal-popup-generic'}); } } else { const exclude_typed_references = []; for (const input of dataset.querySelectorAll('.single-item-table-row input[name$="[references][]"]')) { if (input.value !== '') { exclude_typed_references.push(input.value); } } this._selectWidget(row, exclude_typed_references); } } _selectWidget(row = null, exclude_typed_references = []) { const widgets = ZABBIX.Dashboard.getReferableWidgets({ type: CWidgetsData.DATA_TYPE_ITEM_ID, widget_context: ZABBIX.Dashboard.getEditingWidgetContext() }); widgets.sort((a, b) => a.getHeaderName().localeCompare(b.getHeaderName())); const result = []; for (const widget of widgets) { const typed_reference = CWidgetBase.createTypedReference({ reference: widget.getFields().reference, type: CWidgetsData.DATA_TYPE_ITEM_ID }); if (exclude_typed_references.includes(typed_reference)) { continue; } result.push({ id: CWidgetBase.createTypedReference({ reference: widget.getFields().reference, type: CWidgetsData.DATA_TYPE_ITEM_ID }), name: widget.getHeaderName() }); } const popup = new CWidgetSelectPopup(result); popup.on('dialogue.submit', (e) => { if (row === null) { this._addSingleItem({ reference: e.detail.reference, name: e.detail.name }); } else { const name_col = row.querySelector('.table-col-name'); const name_col_link = name_col.querySelector('a'); const references_input = row.querySelector('input[name$="[references][]"'); name_col.classList.remove('unavailable-widget'); name_col_link.textContent = e.detail.name; references_input.value = e.detail.reference; } }); } _addSingleItem({itemid = '0', reference = '', name} = {}) { const dataset = this._getOpenedDataset(); const dataset_index = dataset.getAttribute('data-set'); const items_tbody = dataset.querySelector('.single-item-table tbody'); if (itemid !== '0') { if (items_tbody.querySelector(`input[name$="[itemids][]"][value="${itemid}"]`) !== null) { return; } } else { if (items_tbody.querySelector(`input[name$="[references][]"][value="${reference}"]`) !== null) { return; } } const items_new_index = items_tbody.rows.length + 1; const template = new Template(jQuery('#dataset-item-row-tmpl').html()); const row = template.evaluateToElement({ dsNum: dataset_index, rowNum: items_new_index, itemid, reference, name }); if (itemid === '0') { row.querySelector('.table-col-name .reference-hint').classList.remove(ZBX_STYLE_DISPLAY_NONE); } items_tbody.appendChild(row); const used_colors = []; for (const color of this._form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { if (color.value !== '') { used_colors.push(color.value); } } jQuery(`#items_${dataset_index}_${items_new_index}_color`) .val(colorPalette.getNextColor(used_colors)) .colorpicker(); } _removeSingleItem(element) { element.closest('.single-item-table-row').remove(); const dataset = this._getOpenedDataset(); this._updateSingleItemsOrder(dataset); this._initSingleItemSortable(dataset); this._updatePreview(); } _initSingleItemSortable(dataset) { const rows_container = dataset.querySelector('.single-item-table tbody'); if (rows_container === null) { return; } if (this.#single_items_sortable.has(dataset)) { return; } const sortable = new CSortable(rows_container, { selector_handle: '.table-col-handle' }); sortable.on(CSortable.EVENT_SORT, () => { this._updateSingleItemsOrder(dataset); this._updatePreview(); }); this.#single_items_sortable.set(dataset, sortable); } _updateSingleItemsReferences() { const widgets = ZABBIX.Dashboard .getReferableWidgets({ type: CWidgetsData.DATA_TYPE_ITEM_ID, widget_context: ZABBIX.Dashboard.getEditingWidgetContext() }) .reduce((map, widget) => map.set(widget.getFields().reference, widget.getHeaderName()), new Map()); for (const dataset of this._dataset_wrapper.querySelectorAll('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>')) { for (const row of dataset.querySelectorAll('.single-item-table-row')) { const itemid_input = row.querySelector('input[name$="[itemids][]"'); const reference_input = row.querySelector('input[name$="[references][]"'); if (itemid_input.value !== '0') { continue; } const name_col = row.querySelector('.table-col-name'); const name_col_link = name_col.querySelector('a'); const name_col_hint = name_col.querySelector('.reference-hint'); const {reference} = CWidgetBase.parseTypedReference(reference_input.value); if (reference !== '') { name_col_link.textContent = widgets.get(reference); } else { name_col.classList.add('unavailable-widget'); name_col_link.textContent = <?= json_encode(_('Unavailable widget')) ?>; } name_col_hint.classList.remove(ZBX_STYLE_DISPLAY_NONE); } } } _updateSingleItemsOrder(dataset) { jQuery.colorpicker('destroy', jQuery('.single-item-table .<?= ZBX_STYLE_COLOR_PICKER ?> input', dataset)); const dataset_index = dataset.getAttribute('data-set'); for (const row of dataset.querySelectorAll('.single-item-table-row')) { const prefix = `items_${dataset_index}_${row.rowIndex}`; row.querySelector('.table-col-no span').textContent = `${row.rowIndex}:`; row.querySelector('.table-col-name a').id = `${prefix}_name`; row.querySelector('.table-col-action input[name$="[itemids][]"]').id = `${prefix}_itemid`; row.querySelector('.table-col-action input[name$="[references][]"]').id = `${prefix}_reference`; const colorpicker = row.querySelector('.single-item-table .<?= ZBX_STYLE_COLOR_PICKER ?> input'); colorpicker.id = `${prefix}_color`; jQuery(colorpicker).colorpicker({appendTo: '.overlay-dialogue-body'}); } } _updateForm() { const axes_used = {<?= GRAPH_YAXIS_SIDE_LEFT ?>: 0, <?= GRAPH_YAXIS_SIDE_RIGHT ?>: 0}; for (const element of this._form.querySelectorAll('[type=radio], [type=hidden]')) { if (element.name.match(/ds\[\d+]\[axisy]/) && element.checked) { axes_used[element.value]++; } } for (const element of this._form.querySelectorAll('[type=hidden]')) { if (element.name.match(/or\[\d+]\[axisy]/)) { axes_used[element.value]++; } } const dataset = this._getOpenedDataset(); if (dataset !== null) { this._updateDatasetLabel(dataset); const dataset_index = dataset.getAttribute('data-set'); const draw_type = dataset.querySelector(`[name="ds[${dataset_index}][type]"]:checked`); const is_stacked = dataset.querySelector(`[type=checkbox][name="ds[${dataset_index}][stacked]"]`).checked; // Data set tab. const aggregate_function_select = dataset.querySelector(`[name="ds[${dataset_index}][aggregate_function]"]`); const approximation_select = dataset.querySelector(`[name="ds[${dataset_index}][approximation]"]`); let stacked_enabled = true; let width_enabled = true; let pointsize_enabled = true; let fill_enabled = true; let missingdata_enabled = true; let aggregate_none_enabled = true; let approximation_all_enabled = true; switch (draw_type.value) { case '<?= SVG_GRAPH_TYPE_LINE ?>': pointsize_enabled = false; if (is_stacked) { approximation_all_enabled = false; } break; case '<?= SVG_GRAPH_TYPE_POINTS ?>': stacked_enabled = false; width_enabled = false; fill_enabled = false; missingdata_enabled = false; approximation_all_enabled = false; break; case '<?= SVG_GRAPH_TYPE_STAIRCASE ?>': pointsize_enabled = false; approximation_all_enabled = false; break; case '<?= SVG_GRAPH_TYPE_BAR ?>': width_enabled = false; pointsize_enabled = false; fill_enabled = false; missingdata_enabled = false; if (is_stacked) { aggregate_none_enabled = false; } approximation_all_enabled = false; break; } dataset.querySelector(`[type=checkbox][name="ds[${dataset_index}][stacked]"]`).disabled = !stacked_enabled; jQuery(`[name="ds[${dataset_index}][width]"]`, dataset).rangeControl(width_enabled ? 'enable' : 'disable'); jQuery(`[name="ds[${dataset_index}][pointsize]"]`, dataset).rangeControl( pointsize_enabled ? 'enable' : 'disable' ); jQuery(`[name="ds[${dataset_index}][fill]"]`, dataset).rangeControl(fill_enabled ? 'enable' : 'disable'); for (const element of dataset.querySelectorAll(`[name="ds[${dataset_index}][missingdatafunc]"]`)) { element.disabled = !missingdata_enabled; } aggregate_function_select.getOptionByValue(<?= AGGREGATE_NONE ?>).disabled = !aggregate_none_enabled; if (!aggregate_none_enabled && aggregate_function_select.value == <?= AGGREGATE_NONE ?>) { aggregate_function_select.value = <?= AGGREGATE_AVG ?>; } const aggregation_enabled = aggregate_function_select.value != <?= AGGREGATE_NONE ?>; dataset.querySelector(`[name="ds[${dataset_index}][aggregate_interval]"]`).disabled = !aggregation_enabled; for (const element of dataset.querySelectorAll(`[name="ds[${dataset_index}][aggregate_grouping]"]`)) { element.disabled = !aggregation_enabled; } approximation_select.getOptionByValue(<?= APPROXIMATION_ALL ?>).disabled = !approximation_all_enabled; if (!approximation_all_enabled && approximation_select.value == <?= APPROXIMATION_ALL ?>) { approximation_select.value = <?= APPROXIMATION_AVG ?>; } } const all_datasets = this._dataset_wrapper.querySelectorAll('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>'); this._any_ds_aggregation_function_enabled = false; for (const ds of all_datasets) { const ds_index = ds.getAttribute('data-set'); const aggregate_function_select = ds.querySelector(`[name="ds[${ds_index}][aggregate_function]"]`); if (aggregate_function_select.value != <?= AGGREGATE_NONE ?>) { this._any_ds_aggregation_function_enabled = true; break; } } // Displaying options tab. const percentile_left_checkbox = document.getElementById('percentile_left'); percentile_left_checkbox.disabled = !axes_used[<?= GRAPH_YAXIS_SIDE_LEFT ?>]; document.getElementById('percentile_left_value').disabled = !percentile_left_checkbox.checked || !axes_used[<?= GRAPH_YAXIS_SIDE_LEFT ?>]; const percentile_right_checkbox = document.getElementById('percentile_right'); percentile_right_checkbox.disabled = !axes_used[<?= GRAPH_YAXIS_SIDE_RIGHT ?>]; document.getElementById('percentile_right_value').disabled = !percentile_right_checkbox.checked || !axes_used[<?= GRAPH_YAXIS_SIDE_RIGHT ?>]; // Axes tab. const lefty_checkbox = document.getElementById('lefty'); lefty_checkbox.disabled = !axes_used[<?= GRAPH_YAXIS_SIDE_LEFT ?>]; const lefty_on = !lefty_checkbox.disabled && lefty_checkbox.checked; if (lefty_checkbox.disabled) { lefty_checkbox.checked = true; } for (const element of document.querySelectorAll('#lefty_min, #lefty_max, #lefty_units')) { element.disabled = !lefty_on; } document.getElementById('lefty_static_units').disabled = !lefty_on || document.getElementById('lefty_units').value != <?= SVG_GRAPH_AXIS_UNITS_STATIC ?>; const righty_checkbox = document.getElementById('righty'); righty_checkbox.disabled = !axes_used[<?= GRAPH_YAXIS_SIDE_RIGHT ?>]; const righty_on = !righty_checkbox.disabled && righty_checkbox.checked; if (righty_checkbox.disabled) { righty_checkbox.checked = true; } for (const element of document.querySelectorAll('#righty_min, #righty_max, #righty_units')) { element.disabled = !righty_on; } document.getElementById('righty_static_units').disabled = !righty_on || document.getElementById('righty_units').value != <?= SVG_GRAPH_AXIS_UNITS_STATIC ?>; // Legend tab. const show_legend = document.getElementById('legend').checked; const legend_statistic = document.getElementById('legend_statistic'); legend_statistic.disabled = !show_legend; document.getElementById('legend_aggregation').disabled = !show_legend || !this._any_ds_aggregation_function_enabled; for (const input of this._form.querySelectorAll('[name=legend_lines_mode]')) { input.disabled = !show_legend; } jQuery('#legend_lines').rangeControl(show_legend ? 'enable' : 'disable'); jQuery('#legend_columns').rangeControl(show_legend && !legend_statistic.checked ? 'enable' : 'disable'); document.querySelector('[for=legend_lines]') .textContent = document.querySelector('[name=legend_lines_mode]:checked').value === '1' ? <?= json_encode(_('Maximum number of rows')) ?> : <?= json_encode(_('Number of rows')) ?>; // Trigger event to update tab indicators. document.getElementById('tabs').dispatchEvent(new Event(TAB_INDICATOR_UPDATE_EVENT)); } #update_preview_abort_controller = null; #update_preview_loading_timeout = null; _updatePreview() { if (this.#update_preview_abort_controller !== null) { this.#update_preview_abort_controller.abort(); } if (this.#update_preview_loading_timeout !== null) { clearTimeout(this.#update_preview_loading_timeout); } const preview = document.getElementById('svg-graph-preview'); const preview_container = preview.parentElement; const preview_computed_style = getComputedStyle(preview); const contents_width = Math.floor(parseFloat(preview_computed_style.width)); const contents_height = Math.floor(parseFloat(preview_computed_style.height)) - 10; const fields = getFormFields(this._form); fields.override_hostid = this.#resolveOverrideHostId(); fields.time_period = this.#resolveTimePeriod(fields.time_period); if (fields.ds !== undefined) { for (const [dataset_key, dataset] of Object.entries(fields.ds)) { if (dataset.dataset_type != '<?= CWidgetFieldDataSet::DATASET_TYPE_SINGLE_ITEM ?>') { continue; } const dataset_new = { ...dataset, itemids: [], color: [] }; if (dataset.itemids !== undefined) { for (const [item_index, itemid] of dataset.itemids.entries()) { if (itemid === '0') { const resolved_itemid = this.#resolveWidget(dataset.references[item_index]); if (resolved_itemid !== null) { dataset_new.itemids.push(resolved_itemid); dataset_new.color.push(dataset.color[item_index]); } } else { dataset_new.itemids.push(itemid); dataset_new.color.push(dataset.color[item_index]); } } } delete dataset_new.references; fields.ds[dataset_key] = dataset_new; } } const data = { templateid: this._templateid ?? undefined, fields, preview: 1, contents_width, contents_height }; const curl = new Curl('zabbix.php'); curl.setArgument('action', 'widget.svggraph.view'); this.#update_preview_loading_timeout = setTimeout(() => { this.#update_preview_loading_timeout = null; preview_container.classList.add('is-loading'); }, 1000); const abort_controller = new AbortController(); this.#update_preview_abort_controller = abort_controller; fetch(curl.getUrl(), { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data), signal: abort_controller.signal }) .then((response) => response.json()) .then((response) => { if ('error' in response) { throw {error: response.error}; } for (const element of this._form.parentNode.children) { if (element.matches('.msg-good, .msg-bad, .msg-warning')) { element.parentNode.removeChild(element); } } if (this.#update_preview_loading_timeout !== null) { clearTimeout(this.#update_preview_loading_timeout); this.#update_preview_loading_timeout = null; } preview_container.classList.remove('is-loading'); if ('body' in response) { preview.innerHTML = response.body; preview.setAttribute('unselectable', 'on'); preview.style.userSelect = 'none'; } }) .catch((exception) => { if (abort_controller.signal.aborted) { return; } for (const element of this._form.parentNode.children) { if (element.matches('.msg-good, .msg-bad, .msg-warning')) { element.parentNode.removeChild(element); } } if (this.#update_preview_loading_timeout !== null) { clearTimeout(this.#update_preview_loading_timeout); this.#update_preview_loading_timeout = null; } preview_container.classList.remove('is-loading'); let title; let messages = []; if (typeof exception === 'object' && 'error' in exception) { title = exception.error.title; messages = exception.error.messages; } else { title = <?= json_encode(_('Unexpected server error.')) ?>; } const message_box = makeMessageBox('bad', messages, title)[0]; this._form.parentNode.insertBefore(message_box, this._form); }); } #resolveWidget(typed_reference) { const {reference, type} = CWidgetBase.parseTypedReference(typed_reference); const data = ZABBIX.EventHub.getData({ context: 'dashboard', event_type: 'broadcast', reference, type }); if (data !== undefined && data.length === 1) { return data[0]; } return null; } #resolveTimePeriod(time_period_field) { if ('from' in time_period_field && 'to' in time_period_field) { return time_period_field; } let time_period; if (CWidgetBase.FOREIGN_REFERENCE_KEY in time_period_field) { const {reference} = CWidgetBase.parseTypedReference( time_period_field[CWidgetBase.FOREIGN_REFERENCE_KEY] ); time_period = ZABBIX.EventHub.getData({ context: 'dashboard', event_type: 'broadcast', reference, type: CWidgetsData.DATA_TYPE_TIME_PERIOD }); } if (time_period === undefined || time_period === null) { time_period = ZABBIX.EventHub.getData({ context: 'dashboard', event_type: 'broadcast', reference: CDashboard.REFERENCE_DASHBOARD, type: CWidgetsData.DATA_TYPE_TIME_PERIOD }); } return { from: time_period.from, to: time_period.to }; } #resolveOverrideHostId() { return ZABBIX.EventHub.getData({ context: 'dashboard', event_type: 'broadcast', reference: CDashboard.REFERENCE_DASHBOARD, type: CWidgetsData.DATA_TYPE_HOST_ID }); } };