You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
zabbix/ui/include/views/js/configuration.host.discover...

1193 lines
37 KiB

<?php
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/**
* @var CView $this
*/
?>
<script type="text/x-jquery-tmpl" id="lldoverride-row-templated">
<?= (new CRow([
'',
(new CSpan('1:'))->setAttribute('data-row-num', ''),
(new CCol((new CLink('#{name}', 'javascript:lldoverrides.overrides.open(#{no});')))),
'#{stop_verbose}',
(new CCol(
(new CButtonLink(_('Remove')))
->addClass('element-table-remove')
->setEnabled(false)
))->addClass(ZBX_STYLE_NOWRAP)
]))->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="lldoverride-row">
<?= (new CRow([
(new CCol((new CDiv())->addClass(ZBX_STYLE_DRAG_ICON)))->addClass(ZBX_STYLE_TD_DRAG_ICON),
(new CCol((new CSpan('1:'))->setAttribute('data-row-num', '')))
->setWidth('15'),
(new CCol((new CLink('#{name}', 'javascript:lldoverrides.overrides.open(#{no});'))))
->setWidth('350'),
(new CCol('#{stop_verbose}'))
->setWidth('100'),
(new CCol(
(new CButtonLink(_('Remove')))->addClass('element-table-remove')
))
->addClass(ZBX_STYLE_NOWRAP)
->setWidth('50')
]))
->addClass('sortable')
->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="override-filters-row">
<?=
(new CRow([[
new CSpan('#{formulaId}'),
new CVar('overrides_filters[#{rowNum}][formulaid]', '#{formulaId}')
],
(new CTextBox('overrides_filters[#{rowNum}][macro]', '', false,
DB::getFieldLength('lld_override_condition', 'macro')))
->setWidth(ZBX_TEXTAREA_MACRO_WIDTH)
->addClass(ZBX_STYLE_UPPERCASE)
->addClass('macro')
->setAttribute('placeholder', '{#MACRO}')
->setAttribute('data-formulaid', '#{formulaId}'),
(new CSelect('overrides_filters[#{rowNum}][operator]'))
->setValue(CONDITION_OPERATOR_REGEXP)
->addClass('js-operator')
->addOptions(CSelect::createOptionsFromArray([
CONDITION_OPERATOR_REGEXP => _('matches'),
CONDITION_OPERATOR_NOT_REGEXP => _('does not match'),
CONDITION_OPERATOR_EXISTS => _('exists'),
CONDITION_OPERATOR_NOT_EXISTS => _('does not exist')
])),
(new CDiv(
(new CTextBox('overrides_filters[#{rowNum}][value]', '', false,
DB::getFieldLength('lld_override_condition', 'value')))
->addClass('js-value')
->setWidth(ZBX_TEXTAREA_MACRO_VALUE_WIDTH)
->setAttribute('placeholder', _('regular expression'))
))->setWidth(ZBX_TEXTAREA_MACRO_VALUE_WIDTH),
(new CCol(
(new CButton('overrides_filters#{rowNum}_remove', _('Remove')))
->addClass(ZBX_STYLE_BTN_LINK)
->addClass('element-table-remove')
))->addClass(ZBX_STYLE_NOWRAP)
]))
->addClass('form_row')
->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="lldoverride-operation-row-templated">
<?= (new CRow([
['#{condition_object} #{condition_operator} ', italic('#{value}')],
(new CCol(
(new CButtonLink(_('View')))
->addClass('element-table-open')
->onClick('lldoverrides.operations.open(#{no});')
))->addClass(ZBX_STYLE_NOWRAP)
]))->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="lldoverride-operation-row">
<?= (new CRow([
['#{condition_object} #{condition_operator} ', italic('#{value}')],
(new CHorList([
(new CButtonLink(_('Edit')))
->addClass('element-table-open')
->onClick('lldoverrides.operations.open(#{no});'),
(new CButtonLink(_('Remove')))->addClass('element-table-remove')
]))->addClass(ZBX_STYLE_NOWRAP)
]))->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="lldoverride-custom-intervals-row">
<?= (new CRow([
(new CRadioButtonList('opperiod[delay_flex][#{rowNum}][type]', 0))
->addValue(_('Flexible'), ITEM_DELAY_FLEXIBLE)
->addValue(_('Scheduling'), ITEM_DELAY_SCHEDULING)
->setModern(true),
[
(new CTextBox('opperiod[delay_flex][#{rowNum}][delay]'))
->setAttribute('placeholder', ZBX_ITEM_FLEXIBLE_DELAY_DEFAULT),
(new CTextBox('opperiod[delay_flex][#{rowNum}][schedule]'))
->setAttribute('placeholder', ZBX_ITEM_SCHEDULING_DEFAULT)
->setAttribute('style', 'display: none;')
],
(new CTextBox('opperiod[delay_flex][#{rowNum}][period]'))
->setAttribute('placeholder', ZBX_DEFAULT_INTERVAL),
(new CButton('opperiod[delay_flex][#{rowNum}][remove]', _('Remove')))
->addClass(ZBX_STYLE_BTN_LINK)
->addClass('element-table-remove')
]))
->addClass('form_row')
->toString()
?>
</script>
<script type="text/x-jquery-tmpl" id="lldoverride-tag-row">
<?= renderTagTableRow('#{rowNum}', '', '', ZBX_TAG_MANUAL, ['field_name' => 'optag', 'add_post_js' => false]) ?>
</script>
<script type="text/javascript">
jQuery(function($) {
window.lldoverrides = {
templated: <?= $data['limited'] ? 1 : 0 ?>,
ZBX_STYLE_DRAG_ICON: <?= zbx_jsvalue(ZBX_STYLE_DRAG_ICON) ?>,
ZBX_STYLE_TD_DRAG_ICON: <?= zbx_jsvalue(ZBX_STYLE_TD_DRAG_ICON) ?>,
ZBX_STYLE_DISABLED: <?= zbx_jsvalue(ZBX_STYLE_DISABLED) ?>,
msg: {
yes: <?= json_encode(_('Yes')) ?>,
no: <?= json_encode(_('No')) ?>,
item_prototype: <?= json_encode(_('Item prototype')) ?>,
trigger_prototype: <?= json_encode(_('Trigger prototype')) ?>,
graph_prototype: <?= json_encode(_('Graph prototype')) ?>,
host_prototype: <?= json_encode(_('Host prototype')) ?>,
equals: <?= json_encode(_('equals')) ?>,
does_not_equal: <?= json_encode(_('does not equal')) ?>,
contains: <?= json_encode(_('contains')) ?>,
does_not_contain: <?= json_encode(_('does not contain')) ?>,
matches: <?= json_encode(_('matches')) ?>,
does_not_match: <?= json_encode(_('does not match')) ?>
}
};
window.lldoverrides.override_row_template = new Template(jQuery(lldoverrides.templated
? '#lldoverride-row-templated'
: '#lldoverride-row'
).html());
window.lldoverrides.operations_row_template = new Template(jQuery(lldoverrides.templated
? '#lldoverride-operation-row-templated'
: '#lldoverride-operation-row'
).html());
window.lldoverrides.overrides = new Overrides($('#overridesTab'),
<?= json_encode(array_values($data['overrides'])) ?>
);
window.lldoverrides.actions = ['opstatus', 'opdiscover', 'opperiod', 'ophistory', 'optrends', 'opseverity',
'optag', 'optemplate', 'opinventory'
];
window.lldoverrides.$form = $('form[name="itemForm"]').on('submit', function(e) {
var hidden_form = this.querySelector('#hidden-form');
hidden_form && hidden_form.remove();
hidden_form = document.createElement('div');
hidden_form.id = 'hidden-form';
hidden_form.appendChild(lldoverrides.overrides.toFragment());
this.appendChild(hidden_form);
});
});
/**
* Returns common $.sortable options.
*
* @return {object}
*/
function sortableOpts() {
return {
items: 'tbody tr.sortable',
axis: 'y',
containment: 'parent',
cursor: 'grabbing',
handle: 'div.' + lldoverrides.ZBX_STYLE_DRAG_ICON,
tolerance: 'pointer',
opacity: 0.6,
start: function(e, ui) {
ui.placeholder.height(ui.item.height());
}
};
}
/**
* Writes data index as new nodes attribute. Bind remove event.
*/
function dynamicRowsBindNewRow($el) {
$el.on('dynamic_rows.beforeadd', function(e, dynamic_rows) {
e.new_node.setAttribute('data-index', e.data_index);
e.new_node.querySelector('.element-table-remove')
.addEventListener('click', dynamic_rows.removeRow.bind(dynamic_rows, e.data_index));
// Because IE does not have NodeList.prototype.forEach method.
Array.prototype.forEach.call(e.new_node.querySelectorAll('input'), function(input_node) {
input_node.addEventListener('keyup', function(e) {
$el.trigger('dynamic_rows.updated', dynamic_rows);
});
});
});
}
/**
* Implements disabling sortable if less than two data rows.
*/
function dynamicRowsBindSortableDisable($el) {
$el.on('dynamic_rows.updated', function(e, dynamic_rows) {
if (dynamic_rows.length < 2) {
dynamic_rows.$element.sortable('option', 'disabled', true);
dynamic_rows.$element.find('.' + lldoverrides.ZBX_STYLE_DRAG_ICON)
.addClass(lldoverrides.ZBX_STYLE_DISABLED);
}
else {
dynamic_rows.$element.sortable('option', 'disabled', false);
dynamic_rows.$element.find('.' + lldoverrides.ZBX_STYLE_DRAG_ICON)
.removeClass(lldoverrides.ZBX_STYLE_DISABLED);
}
});
}
/**
* A helper method for creating hidden input nodes.
*
* @param {string} name
* @param {string} value
* @param {string} prefix
*
* @return {object} Return input element node.
*/
function hiddenInput(name, value, prefix) {
var input = window.document.createElement('input');
input.type = 'hidden';
input.value = value;
input.name = prefix ? prefix + '[' + name + ']' : name;
return input;
}
/**
* @param {object} $element
* @param {object} options
* @param {array} data
*/
function DynamicRows($element, options, data) {
if (!(options.add_before instanceof Node)) {
throw 'Error: options.add_before must be instanceof Node.';
}
if (!(options.template instanceof Template)) {
throw 'Error: options.template must be instanceof Template.';
}
this.data = {};
this.$element = $element;
this.options = jQuery.extend({}, {
// Please note, this option does not work if data_index option is in use.
ensure_min_rows: 0,
// If this option is used, it represents key of data object whose value will be used as data_index.
data_index: null
}, options);
this.data_index = 0;
this.length = 0;
data && this.setData(data);
}
/**
* All events are dispatched on $element. Second argument is instance, first argument is event object.
*
* @param {string} evt_key
* @param {object} evt_data Optional object to be merged into event data.
*
* @return {object} Returns a jQuery.Event object.
*/
DynamicRows.prototype.dispatch = function(evt_key, evt_data) {
var evt = jQuery.Event('dynamic_rows.' + evt_key, evt_data);
this.$element.trigger(evt, [this]);
return evt;
}
/**
* Adds a row before the given row.
*
* @param {object} data Data to be passed into template.
* @param {number} data_index Optional index, if data with given index exists, then in place update will happen.
* In case of update all events dispatched as if add new was performed.
*/
DynamicRows.prototype.addRow = function(row_data, data_index) {
if (this.options.disabled) {
return;
}
if (!data_index) {
data_index = this.options.data_index
? row_data[this.options.data_index]
: ++this.data_index;
}
var new_row = {
node: this.createRowNode(row_data),
data: row_data || {}
};
var evt_before_add = this.dispatch('beforeadd', {
new_data: new_row.data,
new_node: new_row.node,
add_before: this.options.add_before,
data_index: data_index
});
if (evt_before_add.isDefaultPrevented()) {
return;
}
if (this.data[data_index]) {
evt_before_add.add_before.parentNode.replaceChild(evt_before_add.new_node, this.data[data_index].node);
}
else {
evt_before_add.add_before.parentNode.insertBefore(evt_before_add.new_node, evt_before_add.add_before);
this.length++;
}
this.data[data_index] = new_row;
this.dispatch('updated');
};
/**
* Replaces current data with new one.
* Be aware that min rows are ensured and events are triggered only for add.
* Removing happens outside this API, to not to call.
*
* @param {array} data Array of data for row templates.
*
* @return {object} Returns the DynamicRows object.
*/
DynamicRows.prototype.setData = function(data) {
if (!(data instanceof Array)) {
throw 'Expected Array.';
}
for (var i in this.data) {
this.unlinkIndex(i);
}
data.forEach(function(obj) {
this.addRow(obj);
}.bind(this));
this.ensureMinRows();
return this;
};
/**
* Adds empty rows if needed.
*/
DynamicRows.prototype.ensureMinRows = function() {
var rows_to_add = this.options.ensure_min_rows - this.length;
while (rows_to_add > 0) {
rows_to_add--;
this.addRow();
}
};
/**
* Renders Node from template.
*
* @param {object} data Data to be passed into template.
*
* @return {object}
*/
DynamicRows.prototype.createRowNode = function(data) {
var evt = this.dispatch('beforerender', {view_data: data});
var html_str = this.options.template.evaluate(evt.view_data);
return jQuery(html_str).get(0);
};
/**
* Removes data at given index. Method is to be used by plugin internally, does not dispatch events.
*
* @param {number} data_index
*
* @return {object} Object that just got removed.
*/
DynamicRows.prototype.unlinkIndex = function(data_index) {
this.data[data_index].node.remove();
var ref = this.data[data_index];
delete this.data[data_index];
this.length--;
return ref;
}
/**
* Removes the given row.
*
* @param {number} data_index
*/
DynamicRows.prototype.removeRow = function(data_index) {
if (this.options.disabled) {
return;
}
var removed_row = this.unlinkIndex(data_index);
this.dispatch('afterremove', {removed_row: removed_row, data_index: data_index});
this.dispatch('updated');
this.ensureMinRows();
};
/**
* Represents overrides tab in discovery rules layout.
*
* @param {object} $tab
* @param {array} overrides Initial overrides objects data array.
*/
function Overrides($tab, overrides) {
this.data = {};
this.new_id = 0;
this.sort_index = [];
overrides.forEach(function(override, no) {
this.data[no + 1] = new Override(override);
this.sort_index.push(no + 1);
}.bind(this));
this.$container = jQuery('.lld-overrides-table', $tab);
this.$container.find('.element-table-add').on('click', this.openNew.bind(this));
this.$container.on('dynamic_rows.beforerender', function(e, dynamic_rows) {
e.view_data.stop_verbose = (e.view_data.stop === '1') ? lldoverrides.msg.yes : lldoverrides.msg.no;
});
this.overrides_dynamic_rows = new DynamicRows(this.$container, {
add_before: this.$container.find('.element-table-add').closest('tr')[0],
template: lldoverrides.override_row_template
});
if (!lldoverrides.templated) {
this.$container.sortable(sortableOpts());
this.$container.sortable('option', 'update', this.onSortOrderChange.bind(this));
this.$container.on('dynamic_rows.afterremove', function(e, dynamic_rows) {
delete this.data[e.data_index];
this.onSortOrderChange();
}.bind(this));
dynamicRowsBindSortableDisable(this.$container);
dynamicRowsBindNewRow(this.$container);
}
else {
this.$container.on('dynamic_rows.beforeadd', function(e, dynamic_rows) {
e.new_node.setAttribute('data-index', e.data_index);
});
}
this.renderData();
}
/**
* The parts of form that are easier to maintain in functional objects are transformed into hidden input fields.
*
* @return {object} Returns DocumentFragment object.
*/
Overrides.prototype.toFragment = function() {
var frag = document.createDocumentFragment(),
iter_step = 0;
this.sort_index.forEach(function(id) {
var override = this.data[id],
prefix_override = 'overrides[' + (iter_step++) + ']',
prefix_filter = prefix_override + '[filter]',
iter_filters = 0,
iter_operations = 0;
frag.appendChild(hiddenInput('step', iter_step, prefix_override));
frag.appendChild(hiddenInput('name', override.data.name, prefix_override));
frag.appendChild(hiddenInput('stop', override.data.stop, prefix_override));
frag.appendChild(hiddenInput('evaltype', override.data.overrides_evaltype, prefix_filter));
frag.appendChild(hiddenInput('formula', override.data.overrides_formula, prefix_filter));
override.data.overrides_filters.forEach(function(override_filter) {
var prefix = prefix_filter + '[conditions][' + (iter_filters++) + ']';
frag.appendChild(hiddenInput('formulaid', override_filter.formulaid, prefix));
frag.appendChild(hiddenInput('macro', override_filter.macro, prefix));
frag.appendChild(hiddenInput('value', override_filter.value, prefix));
frag.appendChild(hiddenInput('operator', override_filter.operator, prefix));
});
override.data.operations.forEach(function(operation) {
var prefix = prefix_override + '[operations][' + (iter_operations++) + ']';
frag.appendChild(hiddenInput('operationobject', operation.operationobject, prefix));
frag.appendChild(hiddenInput('operator', operation.operator, prefix));
frag.appendChild(hiddenInput('value', operation.value, prefix));
if ('opstatus' in operation) {
frag.appendChild(hiddenInput('status', operation.opstatus.status, prefix + '[opstatus]'));
}
if ('opdiscover' in operation) {
frag.appendChild(hiddenInput('discover', operation.opdiscover.discover, prefix + '[opdiscover]'));
}
if ('opperiod' in operation) {
frag.appendChild(hiddenInput('delay', operation.opperiod.delay, prefix + '[opperiod]'));
}
if ('ophistory' in operation) {
frag.appendChild(hiddenInput('history', operation.ophistory.history, prefix + '[ophistory]'));
}
if ('optrends' in operation) {
frag.appendChild(hiddenInput('trends', operation.optrends.trends, prefix + '[optrends]'));
}
if ('opseverity' in operation) {
frag.appendChild(hiddenInput('severity', operation.opseverity.severity, prefix + '[opseverity]'));
}
if ('optag' in operation) {
var iter_tags = 0;
operation.optag.forEach(function(tag) {
var prefix_tag = prefix + '[optag][' + (iter_tags++) + ']';
frag.appendChild(hiddenInput('tag', tag.tag, prefix_tag));
if (('value' in tag) && 'value' !== '') {
frag.appendChild(hiddenInput('value', tag.value, prefix_tag));
}
});
}
if ('optemplate' in operation) {
var iter_templates = 0;
operation.optemplate.forEach(function(template) {
var prefix_template = prefix + '[optemplate][' + (iter_templates++) + ']';
frag.appendChild(hiddenInput('templateid', template.templateid, prefix_template));
});
}
if ('opinventory' in operation) {
frag.appendChild(hiddenInput('inventory_mode', operation.opinventory.inventory_mode,
prefix + '[opinventory]'
));
}
});
}.bind(this));
return frag;
};
/**
* This method maintains property for iterating overrides in the order that rows have in DOM at the moment,
* also updates visual counter in DOM for override rows.
*/
Overrides.prototype.onSortOrderChange = function() {
var order = [];
this.$container.find('[data-index]').each(function(index) {
this.querySelector('[data-row-num]').innerText = (index + 1) + ':';
order.push(this.attributes.getNamedItem('data-index').value);
});
this.sort_index = order;
};
/**
* Used to validate override names with server, on PopUp form validate event.
*
* @return {array} Array of strings.
*/
Overrides.prototype.getOverrideNames = function() {
var names = [];
for (var no in this.data) {
names.push(this.data[no].data.name);
}
return names;
};
/**
* This method hydrates the parsed html PopUp form with data from specific override.
*
* @param {number} no Override index.
*/
Overrides.prototype.onStepOverlayReadyCb = function(no) {
var override_ref = this.data[no] ? this.data[no] : this.new_override;
this.edit_form = new OverrideEditForm(jQuery('#lldoverride_form'), override_ref);
};
/**
* Creates new override id and opens form for it.
*/
Overrides.prototype.openNew = function() {
this.new_id -= 1;
this.new_override = new Override({no: this.new_id});
this.new_override.open(this.new_id, this.$container.find('.element-table-add'));
};
/**
* Renders overrides in DOM.
*/
Overrides.prototype.renderData = function() {
this.sort_index.forEach(function(data_index) {
this.overrides_dynamic_rows.addRow(this.data[data_index].data, data_index);
}.bind(this));
this.onSortOrderChange();
}
/**
* Opens popup for an override.
*
* @param {number} no
*/
Overrides.prototype.open = function(no) {
this.data[no].open(no, this.$container.find('[data-index="' + no + '"] a'));
};
/**
* This object represents an override of web scenario.
*
* @param {object} data Optional override initial data.
*/
function Override(data) {
var defaults = {
name: '',
stop: '0',
filter: {
'evaltype': '0',
'formula': '',
'conditions': []
},
operations: []
};
this.data = jQuery.extend(true, defaults, data);
this.data.no = this.data.step;
this.data.overrides_evaltype = this.data.filter.evaltype;
this.data.overrides_formula = this.data.filter.formula;
this.data.overrides_filters = this.data.filter.conditions;
delete this.data.filter;
/*
* Used to add proper letter, when creating new dynamic row for filter. If no filters are configured,
* one empty row is created by View.
*/
this.filter_counter = (this.data.overrides_filters.length > 0) ? this.data.overrides_filters.length : 1;
}
/**
* Merges old data with new data.
*/
Override.prototype.update = function(data) {
jQuery.extend(this.data, data);
};
/**
* Opens override popup - edit or create form.
* Note: a callback this.onStepOverlayReadyCb is called from within popup form once it is parsed.
*
* @param {number} step Override index.
* @param {Node} trigger_element A node to set focus to, when popup is closed.
*/
Override.prototype.open = function(no, trigger_element) {
return PopUp('popup.lldoverride', {
no: no,
templated: lldoverrides.templated,
name: this.data.name,
old_name: this.data.name,
stop: this.data.stop,
overrides_evaltype: this.data.overrides_evaltype,
overrides_formula: this.data.overrides_formula,
overrides_filters: this.data.overrides_filters,
operations: this.data.operations,
overrides_names: lldoverrides.overrides.getOverrideNames()
}, {dialogue_class: 'modal-popup-generic', trigger_element});
};
/**
* Represents popup form.
*
* @param {object} $form
* @param {object} override_ref Reference to override instance from Overrides object.
*/
function OverrideEditForm($form, override_ref) {
this.$form = $form;
this.override = override_ref;
// Initiate Filters dynamic rows and evaltype.
this.filterDynamicRows();
this.operations = new Operations(this.$form, this.override.data.operations);
// This will be used for link on edit button.
window.lldoverrides.operations = this.operations;
}
OverrideEditForm.prototype.updateExpression = function() {
var filters = [];
jQuery('#overrides_filters .macro').each(function(index, macroInput) {
macroInput = jQuery(macroInput);
macroInput.val(macroInput.val().toUpperCase());
filters.push({
id: macroInput.data('formulaid'),
type: macroInput.val()
});
});
jQuery('#overrides_expression').html(getConditionFormula(filters, +jQuery('#overrides-evaltype').val()));
};
OverrideEditForm.prototype.filterDynamicRows = function() {
var that = this;
jQuery('#overrides_filters')
.dynamicRows({
template: '#override-filters-row',
counter: this.override.filter_counter,
allow_empty: true,
dataCallback: function(data) {
data.formulaId = num2letter(data.rowNum);
that.override.filter_counter++;
return data;
}
})
.bind('tableupdate.dynamicRows', function(event, options) {
jQuery('#overrideRow').toggle(jQuery(options.row, jQuery(this)).length > 1);
if (jQuery('#overrides-evaltype').val() != <?= CONDITION_EVAL_TYPE_EXPRESSION ?>) {
that.updateExpression();
}
})
.on('change', '.macro', function() {
if (jQuery('#overrides-evaltype').val() != <?= CONDITION_EVAL_TYPE_EXPRESSION ?>) {
that.updateExpression();
}
})
.on('afteradd.dynamicRows', (event) => {
[...event.currentTarget.querySelectorAll('.js-operator')]
.pop()
.addEventListener('change', view.toggleConditionValue);
})
.ready(function() {
jQuery('#overrideRow').toggle(jQuery('.form_row', jQuery('#overrides_filters')).length > 1);
overlays_stack.end().centerDialog();
});
jQuery('#overrides-evaltype').change(function() {
var show_formula = (jQuery(this).val() == <?= CONDITION_EVAL_TYPE_EXPRESSION ?>);
jQuery('#overrides_expression').toggle(!show_formula);
jQuery('#overrides_formula').toggle(show_formula);
if (!show_formula) {
that.updateExpression();
}
overlays_stack.end().centerDialog();
});
jQuery('#overrides-evaltype').trigger('change');
[...document.getElementById('overrides_filters').querySelectorAll('.js-operator')].map((elem) => {
elem.addEventListener('change', view.toggleConditionValue);
});
};
/**
* This method is bound via popup button attribute. It posts serialized version of current form to be validated.
* Note that we do not bother posting dynamic fields, since they are not validated at this point.
*
* @param {object} overlay
*/
OverrideEditForm.prototype.validate = function(overlay) {
var url = new Curl(this.$form.attr('action'));
url.setArgument('validate', 1);
this.$form.trimValues(['input[type="text"]']);
this.$form.parent().find('.msg-bad, .msg-good').remove();
overlay.setLoading();
overlay.xhr = jQuery.ajax({
url: url.getUrl(),
data: this.$form.serializeJSON(),
dataType: 'json',
type: 'post'
})
.always(function() {
overlay.unsetLoading();
})
.done(function(ret) {
if ('error' in ret) {
const message_box = makeMessageBox('bad', ret.error.messages, ret.error.title);
return message_box.insertBefore(this.$form);
}
if (!lldoverrides.overrides.data[ret.params.no]) {
lldoverrides.overrides.sort_index.push(ret.params.no);
lldoverrides.overrides.data[ret.params.no] = this.override;
}
this.operations.sort_index.forEach(function(data_index) {
ret.params.operations.push(this.operations.data[data_index].data);
}.bind(this));
lldoverrides.overrides.data[ret.params.no].update(ret.params);
lldoverrides.overrides.renderData();
overlayDialogueDestroy(overlay.dialogueid);
}.bind(this));
};
function Operations($form, operations) {
var that = this;
this.data = {};
this.new_id = 0;
this.sort_index = [];
operations.sort((a, b) => {
const a_operator = this.operatorName(a.operator);
const b_operator = this.operatorName(b.operator);
if (a.operationobject < b.operationobject
|| (a.operationobject === b.operationobject && a_operator < b_operator)
|| (a.operationobject === b.operationobject && a_operator === b_operator && a.value < b.value)) {
return -1;
}
if (a.operationobject > b.operationobject
|| (a.operationobject === b.operationobject && a_operator > b_operator)
|| (a.operationobject === b.operationobject && a_operator === b_operator && a.value > b.value)) {
return 1;
}
return 0;
});
operations.forEach(function(operation, no) {
this.data[no + 1] = new Operation(operation, no + 1);
this.sort_index.push(no + 1);
}.bind(this));
this.$container = jQuery('.lld-overrides-operations-table', $form);
this.$container.find('.element-table-add').on('click', this.openNew.bind(this));
this.$container.on('dynamic_rows.beforerender', function(e, dynamic_rows) {
e.view_data.condition_object = that.operationobjectName(e.view_data.operationobject);
e.view_data.condition_operator = that.operatorName(e.view_data.operator);
});
this.operations_dynamic_rows = new DynamicRows(this.$container, {
add_before: this.$container.find('.element-table-add').closest('tr')[0],
template: lldoverrides.operations_row_template
});
if (!lldoverrides.templated) {
this.$container.on('dynamic_rows.afterremove', function(e, dynamic_rows) {
delete this.data[e.data_index];
var index = this.sort_index.indexOf(e.data_index);
if (index > -1) {
this.sort_index.splice(index, 1);
}
}.bind(this));
dynamicRowsBindNewRow(this.$container);
}
else {
this.$container.on('dynamic_rows.beforeadd', function(e, dynamic_rows) {
e.new_node.setAttribute('data-index', e.data_index);
});
}
this.renderData();
};
Operations.prototype.operationobjectName = function(operationobject) {
var operationobject_name = '';
if (operationobject === '<?= OPERATION_OBJECT_ITEM_PROTOTYPE ?>') {
operationobject_name = window.lldoverrides.msg.item_prototype;
}
else if (operationobject === '<?= OPERATION_OBJECT_TRIGGER_PROTOTYPE ?>') {
operationobject_name = window.lldoverrides.msg.trigger_prototype;
}
else if (operationobject === '<?= OPERATION_OBJECT_GRAPH_PROTOTYPE ?>') {
operationobject_name = window.lldoverrides.msg.graph_prototype;
}
else if (operationobject === '<?= OPERATION_OBJECT_HOST_PROTOTYPE ?>') {
operationobject_name = window.lldoverrides.msg.host_prototype;
}
return operationobject_name;
};
Operations.prototype.operatorName = function(operator) {
var operator_name = '';
if (operator === '<?= CONDITION_OPERATOR_EQUAL ?>') {
operator_name = window.lldoverrides.msg.equals;
}
else if (operator === '<?= CONDITION_OPERATOR_NOT_EQUAL ?>') {
operator_name = window.lldoverrides.msg.does_not_equal;
}
else if (operator === '<?= CONDITION_OPERATOR_LIKE ?>') {
operator_name = window.lldoverrides.msg.contains;
}
else if (operator === '<?= CONDITION_OPERATOR_NOT_LIKE ?>') {
operator_name = window.lldoverrides.msg.does_not_contain;
}
else if (operator === '<?= CONDITION_OPERATOR_REGEXP ?>') {
operator_name = window.lldoverrides.msg.matches;
}
else if (operator === '<?= CONDITION_OPERATOR_NOT_REGEXP ?>') {
operator_name = window.lldoverrides.msg.does_not_match;
}
return operator_name;
};
/**
* This method hydrates the parsed html PopUp form with data from specific override.
*
* @param {number} no Override index.
*/
Operations.prototype.onOperationOverlayReadyCb = function(no) {
var operation_ref = this.data[no] ? this.data[no] : this.new_operation;
this.edit_form = new OperationEditForm(jQuery('#lldoperation_form'), operation_ref);
};
/**
* Creates new override id and opens form for it.
*/
Operations.prototype.openNew = function() {
this.new_id -= 1;
this.new_operation = new Operation({no: this.new_id});
this.new_operation.open(this.new_id, this.$container.find('.element-table-add'));
};
/**
* Renders overrides in DOM.
*/
Operations.prototype.renderData = function() {
this.sort_index.forEach(function(data_index) {
this.operations_dynamic_rows.addRow(this.data[data_index].data, data_index);
}.bind(this));
}
/**
* Opens popup for a override.
*
* @param {number} no
*/
Operations.prototype.open = function(no) {
this.data[no].open(no, this.$container.find('[data-index="' + no + '"] .element-table-open'));
};
function Operation(data, no) {
this.data = data;
this.data.no = no;
}
/**
* Replaces data with new one.
*/
Operation.prototype.update = function(data) {
this.data = data;
};
/**
* Opens override popup - edit or create form.
* Note: a callback this.onStepOverlayReadyCb is called from within popup form once it is parsed.
*
* @param {number} step Override index.
* @param {Node} trigger_element A node to set focus to, when popup is closed.
*/
Operation.prototype.open = function(no, trigger_element) {
var parameters = {
no: no,
templated: lldoverrides.templated,
operationobject: this.data.operationobject,
operator: this.data.operator,
value: this.data.value
};
window.lldoverrides.actions.forEach(function(action) {
if (action in this.data) {
parameters[action] = this.data[action];
}
}.bind(this));
return PopUp('popup.lldoperation', parameters, {dialogue_class: 'modal-popup-generic', trigger_element});
};
/**
* Represents popup form.
*
* @param {object} $form
* @param {object} operation_ref Reference to override instance from Overrides object.
*/
function OperationEditForm($form, operation_ref) {
this.$form = $form;
this.operation = operation_ref;
var that = this,
$custom_intervals = jQuery('#lld_overrides_custom_intervals', this.$form);
$custom_intervals.on('click', 'input[type="radio"]', function() {
var rowNum = jQuery(this).attr('id').split('_')[3];
if (jQuery(this).val() == <?= ITEM_DELAY_FLEXIBLE; ?>) {
jQuery('#opperiod_delay_flex_' + rowNum + '_schedule', $custom_intervals).hide();
jQuery('#opperiod_delay_flex_' + rowNum + '_delay', $custom_intervals).show();
jQuery('#opperiod_delay_flex_' + rowNum + '_period', $custom_intervals).show();
}
else {
jQuery('#opperiod_delay_flex_' + rowNum + '_delay', $custom_intervals).hide();
jQuery('#opperiod_delay_flex_' + rowNum + '_period', $custom_intervals).hide();
jQuery('#opperiod_delay_flex_' + rowNum + '_schedule', $custom_intervals).show();
}
});
$custom_intervals.dynamicRows({template: '#lldoverride-custom-intervals-row', allow_empty: true});
jQuery('#ophistory_history_mode', this.$form)
.change(function() {
if (jQuery('[name="ophistory[history_mode]"][value=' + <?= ITEM_STORAGE_OFF ?> + ']').is(':checked')) {
jQuery('#ophistory_history', that.$form).prop('disabled', true).hide();
}
else {
jQuery('#ophistory_history', that.$form).prop('disabled', false).show();
}
})
.trigger('change');
jQuery('#optrends_trends_mode', this.$form)
.change(function() {
if (jQuery('[name="optrends[trends_mode]"][value=' + <?= ITEM_STORAGE_OFF ?> + ']').is(':checked')) {
jQuery('#optrends_trends', that.$form).prop('disabled', true).hide();
}
else {
jQuery('#optrends_trends', that.$form).prop('disabled', false).show();
}
})
.trigger('change');
jQuery('.tags-table .<?= ZBX_STYLE_TEXTAREA_FLEXIBLE ?>', this.$form).textareaFlexible();
jQuery('.tags-table', this.$form)
.dynamicRows({template: '#lldoverride-tag-row', allow_empty: true})
.on('click', 'button.element-table-add', function() {
jQuery('.tags-table .<?= ZBX_STYLE_TEXTAREA_FLEXIBLE ?>', this.$form).textareaFlexible();
});
// Override actions available per override object.
var available_actions = {
'<?= OPERATION_OBJECT_ITEM_PROTOTYPE ?>': ['opstatus', 'opdiscover', 'opperiod', 'ophistory', 'optrends',
'optag'],
'<?= OPERATION_OBJECT_TRIGGER_PROTOTYPE ?>': ['opstatus', 'opdiscover', 'opseverity', 'optag'],
'<?= OPERATION_OBJECT_GRAPH_PROTOTYPE ?>': ['opdiscover'],
'<?= OPERATION_OBJECT_HOST_PROTOTYPE ?>': ['opstatus', 'opdiscover', 'optemplate', 'optag', 'opinventory']
};
jQuery('#operationobject', this.$form)
.change(function() {
window.lldoverrides.actions.forEach(function(action) {
if (available_actions[this.value].indexOf(action) !== -1) {
that.showActionRow(action + '_row');
}
else {
that.hideActionRow(action + '_row');
}
}.bind(this));
});
};
OperationEditForm.prototype.initHideActionRows = function() {
jQuery('#operationobject', this.$form).trigger('change');
};
OperationEditForm.prototype.showActionRow = function(row_id) {
var obj = document.getElementById(row_id);
if (is_null(obj)) {
throw 'Cannot find action row with id [' + row_id + ']';
}
// Show it only if it was previously hidden.
if (obj.originalObject) {
obj.parentNode.replaceChild(obj.originalObject, obj);
}
};
OperationEditForm.prototype.hideActionRow = function(row_id) {
var obj = document.getElementById(row_id);
if (is_null(obj)) {
throw 'Cannot find action row with id [' + row_id +']';
}
// Hide it only if it was previously visible.
if (!('originalObject' in obj)) {
try {
var new_obj = document.createElement('li');
new_obj.setAttribute('id', obj.id);
}
catch(e) {
throw 'Cannot create new element';
}
new_obj.originalObject = obj;
obj.parentNode.replaceChild(new_obj, obj);
}
};
/**
* This method is bound via popup button attribute. It posts serialized version of current form to be validated.
* Note that we do not bother posting dynamic fields, since they are not validated at this point.
*
* @param {object} overlay
*/
OperationEditForm.prototype.validate = function(overlay) {
var url = new Curl(this.$form.attr('action'));
url.setArgument('validate', 1);
this.$form.trimValues(['input[type="text"]', 'textarea']);
this.$form.parent().find('.msg-bad, .msg-good').remove();
overlay.setLoading();
overlay.xhr = jQuery.ajax({
url: url.getUrl(),
data: this.$form.serialize(),
dataType: 'json',
type: 'post'
})
.always(function() {
overlay.unsetLoading();
})
.done(function(ret) {
if ('error' in ret) {
const message_box = makeMessageBox('bad', ret.error.messages, ret.error.title);
return message_box.insertBefore(this.$form);
}
if (!lldoverrides.operations.data[ret.params.no]) {
lldoverrides.operations.sort_index.push(ret.params.no);
lldoverrides.operations.data[ret.params.no] = this.operation;
}
lldoverrides.operations.data[ret.params.no].update(ret.params);
lldoverrides.operations.renderData();
overlayDialogueDestroy(overlay.dialogueid);
}.bind(this));
};
</script>