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.
1001 lines
27 KiB
1001 lines
27 KiB
/*
|
|
** 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.
|
|
**/
|
|
|
|
|
|
class CWidgetNavTree extends CWidget {
|
|
|
|
static EVENT_MARK = 'widget-navtree.mark';
|
|
static EVENT_SELECT = 'widget-navtree.select';
|
|
|
|
static WIDGET_MAP_EVENT_SUBMAP_SELECT = 'widget-map.submap-select';
|
|
|
|
static hasReferenceField() {
|
|
return true;
|
|
}
|
|
|
|
onInitialize() {
|
|
this._severity_levels = null;
|
|
this._navtree = [];
|
|
this._maps = [];
|
|
this._navtree_items_opened = [];
|
|
this._navtree_item_selected = null;
|
|
this._maps_accessible = null;
|
|
this._show_unavailable = false;
|
|
this._problems = null;
|
|
this._max_depth = null;
|
|
this._last_id = null;
|
|
|
|
this._has_contents = false;
|
|
|
|
this._registerContentsEvents();
|
|
}
|
|
|
|
onActivate() {
|
|
if (this._has_contents) {
|
|
if (this._target.querySelector('.root') === null) {
|
|
this._makeTree();
|
|
this._activateTree();
|
|
}
|
|
|
|
this._activateContentsEvents();
|
|
}
|
|
}
|
|
|
|
onDeactivate() {
|
|
this._deactivateContentsEvents();
|
|
}
|
|
|
|
announceWidgets(widgets) {
|
|
super.announceWidgets(widgets);
|
|
this._deactivateContentsEvents();
|
|
|
|
this._maps = [];
|
|
|
|
for (const widget of widgets) {
|
|
if (this._fields.reference === widget._fields.filter_widget_reference) {
|
|
this._maps.push(widget);
|
|
}
|
|
}
|
|
|
|
if (this._has_contents) {
|
|
this._activateContentsEvents();
|
|
}
|
|
}
|
|
|
|
getDataCopy({is_single_copy}) {
|
|
this._deactivateContentsEvents();
|
|
this._setTreeHandlers();
|
|
this._updateWidgetFields();
|
|
this._activateContentsEvents();
|
|
|
|
return super.getDataCopy({is_single_copy});
|
|
}
|
|
|
|
onEdit() {
|
|
if (this._has_contents) {
|
|
this._deactivateContentsEvents();
|
|
this._removeTree();
|
|
}
|
|
|
|
if (this._has_contents && this._state === WIDGET_STATE_ACTIVE) {
|
|
this._makeTree();
|
|
this._activateTree();
|
|
this._activateContentsEvents();
|
|
}
|
|
}
|
|
|
|
processUpdateResponse(response) {
|
|
if (this._has_contents) {
|
|
this._deactivateContentsEvents();
|
|
this._removeTree();
|
|
|
|
this._has_contents = false;
|
|
}
|
|
|
|
super.processUpdateResponse(response);
|
|
|
|
if (response.navtree_data !== undefined) {
|
|
this._has_contents = true;
|
|
|
|
this._severity_levels = response.navtree_data.severity_levels;
|
|
this._navtree = response.navtree_data.navtree;
|
|
this._navtree_items_opened = response.navtree_data.navtree_items_opened;
|
|
this._navtree_item_selected = response.navtree_data.navtree_item_selected;
|
|
this._maps_accessible = response.navtree_data.maps_accessible;
|
|
this._show_unavailable = response.navtree_data.show_unavailable;
|
|
this._problems = response.navtree_data.problems;
|
|
this._max_depth = response.navtree_data.max_depth;
|
|
|
|
this._makeTree();
|
|
|
|
this._activateTree();
|
|
this._activateContentsEvents();
|
|
}
|
|
}
|
|
|
|
_registerContentsEvents() {
|
|
this._events = {
|
|
...this._events,
|
|
|
|
addChild: (e) => {
|
|
const button = e.target;
|
|
const depth = parseInt(button.closest('.tree-list').getAttribute('data-depth'));
|
|
const parent = button.getAttribute('data-id');
|
|
|
|
this._itemEditDialog(0, parent, depth + 1, button);
|
|
},
|
|
|
|
addMaps: (e) => {
|
|
const button = e.target;
|
|
const depth = parseInt(button.closest('.tree-list').getAttribute('data-depth'));
|
|
const id = button.getAttribute('data-id');
|
|
|
|
if (typeof window.addPopupValues === 'function') {
|
|
window.old_addPopupValues = window.addPopupValues;
|
|
}
|
|
|
|
window.addPopupValues = (data) => {
|
|
this._deactivateContentsEvents();
|
|
|
|
const root = this._target.querySelector(`.tree-item[data-id="${id}"] > ul.tree-list`);
|
|
|
|
if (root !== null) {
|
|
for (const item of data.values) {
|
|
root.appendChild(this._makeTreeItem({
|
|
id: this._getNextId(),
|
|
name: item.name,
|
|
sysmapid: item.id,
|
|
parent: id
|
|
}, depth + 1));
|
|
}
|
|
|
|
const tree_item = root.closest('.tree-item');
|
|
|
|
tree_item.classList.remove('closed');
|
|
tree_item.classList.add('opened');
|
|
}
|
|
|
|
this._setTreeHandlers();
|
|
this._updateWidgetFields();
|
|
|
|
if (typeof old_addPopupValues === 'function') {
|
|
window.addPopupValues = old_addPopupValues;
|
|
delete window.old_addPopupValues;
|
|
}
|
|
|
|
this._activateContentsEvents();
|
|
};
|
|
|
|
return PopUp('popup.generic', {
|
|
srctbl: 'sysmaps',
|
|
srcfld1: 'sysmapid',
|
|
srcfld2: 'name',
|
|
multiselect: '1'
|
|
}, {dialogue_class: 'modal-popup-generic', trigger_element: e.target});
|
|
},
|
|
|
|
editItem: (e) => {
|
|
const button = e.target;
|
|
|
|
const id = button.getAttribute('data-id');
|
|
const parent = this._target.querySelector(`input[name="navtree.parent.${id}"]`).value;
|
|
const depth = parseInt(button.closest('[data-depth]').getAttribute('data-depth'));
|
|
|
|
this._itemEditDialog(id, parent, depth, button);
|
|
},
|
|
|
|
removeItem: (e) => {
|
|
const button = e.target;
|
|
|
|
this._deactivateContentsEvents();
|
|
|
|
this._target.querySelector(`[data-id="${button.getAttribute('data-id')}"]`).remove();
|
|
this._setTreeHandlers();
|
|
|
|
this._updateWidgetFields();
|
|
|
|
this._activateContentsEvents();
|
|
},
|
|
|
|
select: (e) => {
|
|
const link = e.target;
|
|
|
|
const itemid = link.closest('.tree-item').getAttribute('data-id');
|
|
|
|
if (this._markTreeItemSelected(itemid)) {
|
|
this._openBranch(this._navtree_item_selected);
|
|
|
|
updateUserProfile('web.dashboard.widget.navtree.item.selected', this._navtree_item_selected,
|
|
[this._widgetid]
|
|
);
|
|
|
|
this.fire(CWidgetNavTree.EVENT_SELECT, {
|
|
sysmapid: this._navtree[this._navtree_item_selected].sysmapid,
|
|
itemid: this._navtree_item_selected
|
|
});
|
|
}
|
|
|
|
e.preventDefault();
|
|
},
|
|
|
|
selectSubmap: (e) => {
|
|
if (e.detail.back) {
|
|
if (e.detail.parent_itemid !== null) {
|
|
this._markTreeItemSelected(e.detail.parent_itemid);
|
|
}
|
|
}
|
|
else {
|
|
for (let [itemid, item] of Object.entries(this._navtree)) {
|
|
if (item.sysmapid != e.detail.sysmapid || item.parent != e.detail.parent_itemid) {
|
|
continue;
|
|
}
|
|
|
|
if (this._markTreeItemSelected(itemid)) {
|
|
this._openBranch(this._navtree_item_selected);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_activateTree() {
|
|
if (this._is_edit_mode) {
|
|
this._makeSortable();
|
|
}
|
|
else {
|
|
this._parseProblems();
|
|
|
|
if (this._navtree_item_selected === null
|
|
|| !jQuery(`.tree-item[data-id=${this._navtree_item_selected}]`).is(':visible')) {
|
|
this._navtree_item_selected = jQuery('.tree-item:visible', jQuery(this._target))
|
|
.not('[data-sysmapid="0"]')
|
|
.first()
|
|
.data('id');
|
|
}
|
|
|
|
let sysmapid = 0;
|
|
|
|
if (this._markTreeItemSelected(this._navtree_item_selected)) {
|
|
sysmapid = this._navtree[this._navtree_item_selected].sysmapid;
|
|
}
|
|
|
|
this.fire(CWidgetNavTree.EVENT_SELECT, {sysmapid, itemid: this._navtree_item_selected});
|
|
}
|
|
}
|
|
|
|
_activateContentsEvents() {
|
|
if (this._state === WIDGET_STATE_ACTIVE && this._has_contents) {
|
|
if (this._is_edit_mode) {
|
|
for (const button of this._target.querySelectorAll('.js-add-child')) {
|
|
button.addEventListener('click', this._events.addChild);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-add-maps')) {
|
|
button.addEventListener('click', this._events.addMaps);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-edit')) {
|
|
button.addEventListener('click', this._events.editItem);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-remove')) {
|
|
button.addEventListener('click', this._events.removeItem);
|
|
}
|
|
}
|
|
else {
|
|
for (const link of this._target.querySelectorAll('a[data-sysmapid]')) {
|
|
link.addEventListener('click', this._events.select);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!this._is_edit_mode) {
|
|
for (const widget of this._maps) {
|
|
widget.on(CWidgetNavTree.WIDGET_MAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap);
|
|
}
|
|
}
|
|
}
|
|
|
|
_deactivateContentsEvents() {
|
|
if (this._has_contents) {
|
|
if (this._is_edit_mode) {
|
|
for (const button of this._target.querySelectorAll('.js-add-child')) {
|
|
button.removeEventListener('click', this._events.addChild);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-add-maps')) {
|
|
button.removeEventListener('click', this._events.addMaps);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-edit')) {
|
|
button.removeEventListener('click', this._events.editItem);
|
|
}
|
|
|
|
for (const button of this._target.querySelectorAll('.js-remove')) {
|
|
button.removeEventListener('click', this._events.removeItem);
|
|
}
|
|
}
|
|
else {
|
|
for (const link of this._target.querySelectorAll('a[data-sysmapid]')) {
|
|
link.removeEventListener('click', this._events.select);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!this._is_edit_mode) {
|
|
for (const widget of this._maps) {
|
|
widget.off(CWidgetNavTree.WIDGET_MAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap);
|
|
}
|
|
}
|
|
}
|
|
|
|
_buildTree(parent_id = 0) {
|
|
const tree = [];
|
|
|
|
for (const i in this._navtree) {
|
|
const tree_item = {
|
|
id: i,
|
|
name: this._navtree[i].name,
|
|
order: this._navtree[i].order,
|
|
parent: this._navtree[i].parent,
|
|
sysmapid: this._navtree[i].sysmapid
|
|
};
|
|
|
|
if (tree_item.id > this._last_id) {
|
|
this._last_id = tree_item.id;
|
|
}
|
|
|
|
if (tree_item.parent == parent_id) {
|
|
const children = this._buildTree(tree_item.id);
|
|
|
|
if (children.length > 0) {
|
|
tree_item.children = children;
|
|
}
|
|
|
|
tree_item.item_active = (tree_item.sysmapid == 0 || this._maps_accessible.includes(tree_item.sysmapid));
|
|
tree_item.item_visible = (this._show_unavailable || tree_item.item_active);
|
|
|
|
tree.push(tree_item);
|
|
}
|
|
}
|
|
|
|
tree.sort((a, b) => {
|
|
return a.order - b.order;
|
|
});
|
|
|
|
return tree;
|
|
}
|
|
|
|
_makeTree() {
|
|
const tree = this._buildTree();
|
|
|
|
let root = this._makeTreeBranch();
|
|
root.classList.add('root');
|
|
|
|
this._target.querySelector('.tree').appendChild(root);
|
|
|
|
if (this._is_edit_mode) {
|
|
const root_item = this._makeTreeItem({name: t('root'), id: 0}, 0, false);
|
|
|
|
root.appendChild(root_item);
|
|
|
|
if (tree.length > 0) {
|
|
if (root_item.classList.contains('closed')) {
|
|
root_item.classList.add('opened');
|
|
root_item.classList.remove('closed');
|
|
}
|
|
}
|
|
|
|
root = document.getElementById(`${this._unique_id}_children-of-0`);
|
|
}
|
|
|
|
for (const item of tree) {
|
|
root.appendChild(this._makeTreeItem(item));
|
|
}
|
|
|
|
this._setTreeHandlers();
|
|
}
|
|
|
|
_makeTreeBranch(parent_id = null) {
|
|
const ul = document.createElement('ul');
|
|
|
|
if (parent_id !== null) {
|
|
ul.id = `${this._unique_id}_children-of-${parent_id}`;
|
|
}
|
|
|
|
ul.classList.add('tree-list');
|
|
|
|
return ul;
|
|
}
|
|
|
|
_makeTreeItem(item, depth = 1, editable = true) {
|
|
const li_item = document.createElement('li');
|
|
|
|
li_item.classList.add('tree-item');
|
|
|
|
if (!editable || this._navtree_items_opened.includes(item.id)) {
|
|
li_item.classList.add('opened');
|
|
}
|
|
else {
|
|
li_item.classList.add('closed');
|
|
}
|
|
|
|
if (!editable) {
|
|
li_item.classList.add('root-item');
|
|
}
|
|
|
|
if (this._is_edit_mode && item.sysmapid == 0) {
|
|
li_item.classList.add('no-map');
|
|
}
|
|
|
|
const ul = this._makeTreeBranch(item.id);
|
|
|
|
if (item.children !== undefined && this._max_depth > depth) {
|
|
let child_items_visible = 0;
|
|
|
|
for (const child of item.children) {
|
|
if (typeof child !== 'object') {
|
|
continue;
|
|
}
|
|
|
|
ul.appendChild(this._makeTreeItem(child, depth + 1));
|
|
|
|
if (child.id > this._last_id) {
|
|
this._last_id = child.id;
|
|
}
|
|
|
|
if (child.item_visible === true) {
|
|
child_items_visible++;
|
|
}
|
|
}
|
|
|
|
if (item.children.length > 0 && child_items_visible > 0) {
|
|
li_item.classList.add('is-parent');
|
|
}
|
|
}
|
|
|
|
if (!this._is_edit_mode && item.sysmapid != 0 && !item.item_active) {
|
|
li_item.classList.add('inaccessible');
|
|
}
|
|
|
|
let link;
|
|
|
|
if (!this._is_edit_mode && item.sysmapid != 0 && item.item_active) {
|
|
link = document.createElement('a');
|
|
|
|
link.href = '#';
|
|
link.setAttribute('data-sysmapid', item.sysmapid);
|
|
}
|
|
else {
|
|
link = document.createElement('span');
|
|
}
|
|
|
|
link.title = item.name;
|
|
link.innerText = item.name;
|
|
link.classList.add('item-name');
|
|
|
|
li_item.id = `${this._unique_id}_tree-item-${item.id}`;
|
|
li_item.setAttribute('data-id', item.id);
|
|
|
|
if (item.sysmapid != 0) {
|
|
li_item.setAttribute('data-sysmapid', item.sysmapid);
|
|
}
|
|
|
|
if (item.item_visible === false) {
|
|
li_item.style.display = 'none';
|
|
}
|
|
|
|
const tree_row = document.createElement('div');
|
|
tree_row.classList.add('tree-row');
|
|
li_item.appendChild(tree_row);
|
|
|
|
const content = document.createElement('div');
|
|
content.classList.add('content');
|
|
tree_row.appendChild(content);
|
|
|
|
const margin_lvl = document.createElement('div');
|
|
margin_lvl.classList.add('margin-lvl');
|
|
content.appendChild(margin_lvl);
|
|
|
|
if (this._is_edit_mode) {
|
|
const tools = document.createElement('div');
|
|
tools.classList.add('tools');
|
|
tree_row.appendChild(tools);
|
|
|
|
const button_add_child = document.createElement('button');
|
|
button_add_child.type = 'button';
|
|
button_add_child.title = t('Add child element');
|
|
button_add_child.classList.add(ZBX_STYLE_BTN_ICON, ZBX_ICON_PLUS, 'js-add-child');
|
|
button_add_child.setAttribute('data-id', item.id);
|
|
tools.appendChild(button_add_child);
|
|
|
|
const button_add_maps = document.createElement('button');
|
|
button_add_maps.type = 'button';
|
|
button_add_maps.title = t('Add multiple maps');
|
|
button_add_maps.classList.add(ZBX_STYLE_BTN_ICON, ZBX_ICON_COPY, 'js-add-maps');
|
|
button_add_maps.setAttribute('data-id', item.id);
|
|
tools.appendChild(button_add_maps);
|
|
|
|
if (editable) {
|
|
const button_edit = document.createElement('button');
|
|
button_edit.type = 'button';
|
|
button_edit.title = t('Edit');
|
|
button_edit.classList.add(ZBX_STYLE_BTN_ICON, ZBX_ICON_PENCIL, 'js-edit');
|
|
button_edit.setAttribute('data-id', item.id);
|
|
tools.appendChild(button_edit);
|
|
|
|
const button_remove = document.createElement('button');
|
|
button_remove.type = 'button';
|
|
button_remove.title = t('Remove');
|
|
button_remove.classList.add(ZBX_STYLE_BTN_ICON, ZBX_ICON_REMOVE_SMALL, 'js-remove');
|
|
button_remove.setAttribute('data-id', item.id);
|
|
tools.appendChild(button_remove);
|
|
|
|
const drag = document.createElement('div');
|
|
drag.classList.add('drag-icon');
|
|
content.appendChild(drag);
|
|
}
|
|
}
|
|
else {
|
|
const problems = document.createElement('div');
|
|
problems.classList.add('problem-icon-list');
|
|
tree_row.appendChild(problems);
|
|
}
|
|
|
|
const arrow = document.createElement('div');
|
|
arrow.classList.add('arrow');
|
|
content.appendChild(arrow);
|
|
|
|
if (editable) {
|
|
const arrow_btn = document.createElement('button');
|
|
const arrow_span = document.createElement('span');
|
|
|
|
arrow_btn.type = 'button';
|
|
arrow_btn.classList.add('treeview');
|
|
arrow_span.classList.add(li_item.classList.contains('opened') ? 'arrow-down' : 'arrow-right');
|
|
arrow_btn.appendChild(arrow_span);
|
|
arrow.appendChild(arrow_btn);
|
|
arrow_btn.addEventListener('click', () => {
|
|
const branch = arrow_btn.closest('[data-id]');
|
|
|
|
let closed_state = '1';
|
|
|
|
if (branch.classList.contains('opened')) {
|
|
arrow_btn.querySelector('span').classList.add('arrow-right');
|
|
arrow_btn.querySelector('span').classList.remove('arrow-down');
|
|
|
|
branch.classList.add('closed');
|
|
branch.classList.remove('opened');
|
|
}
|
|
else {
|
|
arrow_btn.querySelector('span').classList.add('arrow-down');
|
|
arrow_btn.querySelector('span').classList.remove('arrow-right');
|
|
|
|
branch.classList.add('opened');
|
|
branch.classList.remove('closed');
|
|
|
|
closed_state = '0';
|
|
}
|
|
|
|
if (this._widgetid !== null) {
|
|
updateUserProfile(`web.dashboard.widget.navtree.item-${branch.getAttribute('data-id')}.toggle`,
|
|
closed_state, [this._widgetid]
|
|
);
|
|
|
|
const index = this._navtree_items_opened.indexOf(branch.getAttribute('data-id'));
|
|
|
|
if (index > -1) {
|
|
if (closed_state === '1') {
|
|
this._navtree_items_opened.splice(index, 1);
|
|
}
|
|
else {
|
|
this._navtree_items_opened.push(branch.getAttribute('data-id'));
|
|
}
|
|
}
|
|
else if (index === -1 && closed_state === '0') {
|
|
this._navtree_items_opened.push(branch.getAttribute('data-id'));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
content.appendChild(link);
|
|
li_item.appendChild(ul);
|
|
|
|
if (this._is_edit_mode && editable) {
|
|
const name_fld = document.createElement('input');
|
|
name_fld.id = `${this._unique_id}_navtree.name.${item.id}`;
|
|
name_fld.type = 'hidden';
|
|
name_fld.name = `navtree.name.${item.id}`;
|
|
name_fld.value = item.name;
|
|
li_item.appendChild(name_fld);
|
|
|
|
const parent_fld = document.createElement('input');
|
|
parent_fld.id = `${this._unique_id}_navtree.parent.${item.id}`;
|
|
parent_fld.type = 'hidden';
|
|
parent_fld.name = `navtree.parent.${item.id}`;
|
|
parent_fld.value = item.parent || 0;
|
|
li_item.appendChild(parent_fld);
|
|
|
|
const mapid_fld = document.createElement('input');
|
|
mapid_fld.id = `${this._unique_id}_navtree.sysmapid.${item.id}`;
|
|
mapid_fld.type = 'hidden';
|
|
mapid_fld.name = `navtree.sysmapid.${item.id}`;
|
|
mapid_fld.value = item.sysmapid;
|
|
li_item.appendChild(mapid_fld);
|
|
}
|
|
|
|
return li_item;
|
|
}
|
|
|
|
_removeTree() {
|
|
const root = this._target.querySelector('.root');
|
|
|
|
if (root !== null) {
|
|
root.remove();
|
|
}
|
|
}
|
|
|
|
_setTreeHandlers() {
|
|
// Add .is-parent class for branches with sub-items.
|
|
jQuery('.tree-list', jQuery(this._target)).not('.ui-sortable, .root').each(function() {
|
|
if (jQuery('>li', jQuery(this)).not('.inaccessible').length) {
|
|
jQuery(this).closest('.tree-item').addClass('is-parent');
|
|
}
|
|
else {
|
|
jQuery(this).closest('.tree-item').removeClass('is-parent');
|
|
}
|
|
});
|
|
|
|
// Set [data-depth] for list and each sublist.
|
|
jQuery('.tree-list', jQuery(this._target)).each(function() {
|
|
jQuery(this).attr('data-depth', jQuery(this).parents('.tree-list').length);
|
|
});
|
|
|
|
// Change arrow style.
|
|
jQuery('.is-parent', jQuery(this._target)).each(function() {
|
|
const $arrow = jQuery('> .tree-row > .content > .arrow > .treeview > span', jQuery(this));
|
|
|
|
if (jQuery(this).hasClass('opened')) {
|
|
$arrow.removeClass('arrow-right').addClass('arrow-down');
|
|
}
|
|
else {
|
|
$arrow.removeClass('arrow-down a1').addClass('arrow-right');
|
|
}
|
|
});
|
|
|
|
for (const tree_element of document.querySelectorAll('.tree-list')) {
|
|
for (const button of tree_element.querySelectorAll('.js-add-child, .js-add-maps')) {
|
|
button.disabled = tree_element.dataset.depth >= this._max_depth;
|
|
}
|
|
}
|
|
}
|
|
|
|
_markTreeItemSelected(itemid) {
|
|
const selected_item = document.getElementById(`${this._unique_id}_tree-item-${itemid}`);
|
|
const item = this._navtree[itemid];
|
|
|
|
if (item === undefined || selected_item === null || item === this._navtree_item_selected) {
|
|
return false;
|
|
}
|
|
|
|
this._navtree_item_selected = itemid;
|
|
|
|
let step_in_path = selected_item.closest('.tree-item');
|
|
|
|
this._target.querySelectorAll('.selected').forEach((selected) => {
|
|
selected.classList.remove('selected');
|
|
});
|
|
|
|
while (step_in_path !== null) {
|
|
step_in_path.classList.add('selected');
|
|
step_in_path = step_in_path.parentNode.closest('.tree-item');
|
|
}
|
|
|
|
updateUserProfile('web.dashboard.widget.navtree.item.selected', this._navtree_item_selected, [this._widgetid]);
|
|
|
|
this.fire(CWidgetNavTree.EVENT_MARK, {itemid: this._navtree_item_selected});
|
|
|
|
return true;
|
|
}
|
|
|
|
_openBranch(itemid) {
|
|
if (!jQuery(`.tree-item[data-id=${itemid}]`).is(':visible')) {
|
|
const selector = '> .tree-row > .content > .arrow > .treeview > span';
|
|
|
|
let branch_to_open = jQuery(`.tree-item[data-id=${itemid}]`).closest('.tree-list').not('.root');
|
|
|
|
while (branch_to_open.length) {
|
|
branch_to_open.closest('.tree-item.is-parent')
|
|
.removeClass('closed')
|
|
.addClass('opened');
|
|
|
|
jQuery(selector, branch_to_open.closest('.tree-item.is-parent'))
|
|
.removeClass('arrow-right')
|
|
.addClass('arrow-down');
|
|
|
|
branch_to_open = branch_to_open.closest('.tree-item.is-parent')
|
|
.closest('.tree-list').not('.root');
|
|
}
|
|
}
|
|
}
|
|
|
|
_getNextId() {
|
|
this._last_id++;
|
|
|
|
while (jQuery(`[name="navtree.name.${this._last_id}"]`).length) {
|
|
this._last_id++;
|
|
}
|
|
|
|
return this._last_id;
|
|
}
|
|
|
|
_makeSortable() {
|
|
jQuery('.root-item > .tree-list', jQuery(this._target))
|
|
.sortable_tree({
|
|
max_depth: this._max_depth,
|
|
stop: () => {
|
|
this._setTreeHandlers();
|
|
this._updateWidgetFields();
|
|
}
|
|
})
|
|
.disableSelection();
|
|
}
|
|
|
|
_parseProblems() {
|
|
if (this._severity_levels === null) {
|
|
return false;
|
|
}
|
|
|
|
const empty_template = {};
|
|
|
|
for (const [severity, _] in Object.entries(this._severity_levels)) {
|
|
empty_template[severity] = 0;
|
|
}
|
|
|
|
for (const [itemid, problems] of Object.entries(this._problems)) {
|
|
for (const [severity, value] of Object.entries(problems || empty_template)) {
|
|
if (value) {
|
|
this._target.querySelectorAll(`.tree-item[data-id="${itemid}"]`).forEach((item) => {
|
|
item.setAttribute(`data-problems${severity}`, value);
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const [severity, value] of Object.entries(this._severity_levels)) {
|
|
for (const problem of this._target.querySelectorAll(`[data-problems${severity}]`)) {
|
|
const indicator = document.createElement('span');
|
|
|
|
indicator.title = value.name;
|
|
indicator.classList.add('problem-icon-list-item', value.style_class);
|
|
indicator.innerText = problem.getAttribute(`data-problems${severity}`);
|
|
|
|
problem.querySelector('.tree-row > .problem-icon-list')
|
|
.appendChild(indicator)
|
|
}
|
|
}
|
|
}
|
|
|
|
_itemEditDialog(id, parent, depth, trigger_elmnt) {
|
|
const url = new Curl('zabbix.php');
|
|
const item_edit = id != 0;
|
|
|
|
url.setArgument('action', 'widget.navtree.item.edit');
|
|
|
|
jQuery.ajax({
|
|
url: url.getUrl(),
|
|
method: 'POST',
|
|
data: {
|
|
name: item_edit ? this._target.querySelector(`[name="navtree.name.${id}"]`).value : '',
|
|
sysmapid: item_edit ? this._target.querySelector(`[name="navtree.sysmapid.${id}"]`).value : 0,
|
|
depth: depth
|
|
},
|
|
dataType: 'json',
|
|
success: (resp) => {
|
|
if (resp.debug !== undefined) {
|
|
resp.body += resp.debug;
|
|
}
|
|
|
|
overlayDialogue({
|
|
'title': t('Edit tree element'),
|
|
'class': 'modal-popup',
|
|
'content': resp.body,
|
|
'buttons': [
|
|
{
|
|
'title': item_edit ? t('Apply') : t('Add'),
|
|
'class': 'dialogue-widget-save',
|
|
'action': (overlay) => {
|
|
const form = document.getElementById('widget-dialogue-form');
|
|
const form_inputs = form.elements;
|
|
const url = new Curl('zabbix.php');
|
|
|
|
url.setArgument('action', 'widget.navtree.item.update');
|
|
|
|
overlay.setLoading();
|
|
|
|
overlay.xhr = $.ajax({
|
|
url: url.getUrl(),
|
|
method: 'POST',
|
|
data: {
|
|
name: form_inputs.name.value.trim(),
|
|
sysmapid: form_inputs.sysmapid !== undefined
|
|
? form_inputs.sysmapid.value
|
|
: '0',
|
|
add_submaps: form_inputs.add_submaps !== undefined
|
|
&& form_inputs.add_submaps.checked ? 1 : 0,
|
|
depth: depth
|
|
},
|
|
dataType: 'json',
|
|
complete: () => {
|
|
overlay.unsetLoading();
|
|
},
|
|
success: (resp) => {
|
|
form.querySelectorAll('.msg-bad').forEach((msg) => {
|
|
msg.remove();
|
|
})
|
|
|
|
if ('error' in resp) {
|
|
const message_box = makeMessageBox('bad', resp.error.messages,
|
|
resp.error.title
|
|
)[0];
|
|
|
|
form.insertAdjacentElement('afterbegin', message_box);
|
|
|
|
return false;
|
|
}
|
|
else {
|
|
this._deactivateContentsEvents();
|
|
|
|
if (item_edit) {
|
|
const $row = jQuery(`[data-id="${id}"]`, jQuery(this._target));
|
|
|
|
jQuery(`[name="navtree.name.${id}"]`, $row).val(resp.name);
|
|
jQuery(`[name="navtree.sysmapid.${id}"]`, $row)
|
|
.val(resp['sysmapid']);
|
|
jQuery('> .tree-row > .content > .item-name', $row)
|
|
.empty()
|
|
.attr('title', resp['name'])
|
|
.append(jQuery('<span>').text(resp.name));
|
|
$row.toggleClass('no-map', resp.sysmapid == 0);
|
|
}
|
|
else {
|
|
const root = this._target
|
|
.querySelector(`.tree-item[data-id="${parent}"]>ul.tree-list`);
|
|
|
|
id = this._getNextId();
|
|
|
|
if (root !== null) {
|
|
root.append(this._makeTreeItem({
|
|
id: id,
|
|
name: resp['name'],
|
|
sysmapid: resp['sysmapid'],
|
|
parent: parent
|
|
}, depth + 1));
|
|
|
|
root.closest('.tree-item').classList.remove('closed');
|
|
root.closest('.tree-item').classList.add('opened', 'is-parent');
|
|
}
|
|
}
|
|
|
|
const add_child_level = (sysmapid, itemid, depth) => {
|
|
if (resp.hierarchy[sysmapid] !== undefined
|
|
&& depth <= this._max_depth) {
|
|
const root = this._target
|
|
.querySelector(`.tree-item[data-id="${itemid}"]>ul.tree-list`);
|
|
|
|
$.each(resp.hierarchy[sysmapid], (i, submapid) => {
|
|
if (resp.submaps[submapid] === undefined) {
|
|
return;
|
|
}
|
|
|
|
const submap_item = resp.submaps[submapid];
|
|
const submap_itemid = this._getNextId();
|
|
|
|
root.append(this._makeTreeItem({
|
|
id: submap_itemid,
|
|
name: submap_item['name'],
|
|
sysmapid: submap_item['sysmapid'],
|
|
parent: itemid
|
|
}));
|
|
add_child_level(submapid, submap_itemid, depth + 1);
|
|
});
|
|
|
|
root.closest('.tree-item').classList.remove('closed');
|
|
root.closest('.tree-item').classList.add('opened', 'is-parent');
|
|
}
|
|
};
|
|
|
|
add_child_level(resp['sysmapid'], id, depth + 1);
|
|
|
|
overlayDialogueDestroy(overlay.dialogueid);
|
|
this._updateWidgetFields();
|
|
this._setTreeHandlers();
|
|
this._activateContentsEvents();
|
|
}
|
|
}
|
|
});
|
|
|
|
return false;
|
|
},
|
|
'isSubmit': true
|
|
},
|
|
{
|
|
'title': t('Cancel'),
|
|
'class': 'btn-alt',
|
|
'action': () => {}
|
|
}
|
|
],
|
|
'dialogueid': 'navtreeitem',
|
|
'script_inline': resp.script_inline
|
|
}, trigger_elmnt);
|
|
}
|
|
});
|
|
}
|
|
|
|
_updateWidgetFields() {
|
|
const prefix = `${this.getUniqueId()}_`;
|
|
|
|
if (!this._is_edit_mode) {
|
|
return false;
|
|
}
|
|
|
|
for (const name in this._fields) {
|
|
if (/^navtree\.(name|order|parent|sysmapid)\.\d+$/.test(name)) {
|
|
delete this._fields[name]
|
|
}
|
|
}
|
|
|
|
jQuery('input[name^="navtree.name."]', jQuery(this._body)).each((index, field) => {
|
|
const id = field.getAttribute('name').substr(13);
|
|
|
|
if (id) {
|
|
const parent = document.getElementById(`${prefix}navtree.parent.${id}`).value;
|
|
const sysmapid = document.getElementById(`${prefix}navtree.sysmapid.${id}`).value;
|
|
const element = document.getElementById(`${prefix}children-of-${parent}`);
|
|
|
|
let order = 0;
|
|
|
|
if (element !== null) {
|
|
const sibling = element.childNodes;
|
|
|
|
while (sibling[order] !== undefined && sibling[order].getAttribute('data-id') != id) {
|
|
order++;
|
|
}
|
|
}
|
|
|
|
this._fields[`navtree.name.${id}`] = field.value;
|
|
|
|
if (parent != 0) {
|
|
this._fields[`navtree.parent.${id}`] = parent;
|
|
}
|
|
|
|
if (order != 0) {
|
|
this._fields[`navtree.order.${id}`] = order + 1;
|
|
}
|
|
|
|
if (sysmapid != 0) {
|
|
this._fields[`navtree.sysmapid.${id}`] = sysmapid;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|