mirror of
https://github.com/Cacti/plugin_monitor.git
synced 2026-11-02 18:17:54 +09:00
* fix: require POST for state-changing monitor actions csrf-magic only validates POST, so save, saveDb, remove, the mute toggles and the card-order save now fall through to the normal page draw when sent by GET, and monitor.js sends remove and the mute toggles as POST with the CSRF token. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix: save dashboards only as their owner saveSettings() took the owner from an unvalidated user request variable and let sql_save() overwrite any dashboard id. It now always uses the session user and refuses to update a dashboard the user does not own, matching removeDashboard() and saveCardOrder(). Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
518 lines
12 KiB
JavaScript
518 lines
12 KiB
JavaScript
var refreshMSeconds = 99999999;
|
|
var myTimer;
|
|
|
|
var monitorCfg = globalThis.monitorPageConfig || {};
|
|
var mbColor = monitorCfg.mbColor || '';
|
|
var monitorFont = monitorCfg.monitorFont || '10px';
|
|
var dozoomRefresh = Boolean(monitorCfg.doZoomRefresh);
|
|
var monitorMessages = monitorCfg.messages || {};
|
|
var monitorNewForm = monitorCfg.newForm || '';
|
|
var monitorNewTitle = monitorCfg.newTitle || '';
|
|
|
|
function setZoomErrorBackgrounds() {
|
|
if (mbColor !== '') {
|
|
$('.monitor_container').css('background-color', mbColor);
|
|
$('.cactiConsoleContentArea').css('background-color', mbColor);
|
|
}
|
|
}
|
|
|
|
// Multi-select filters (Events, Template) return an array when themed by
|
|
// select2; a plain hidden input returns a comma string. Normalize to a comma
|
|
// string for request/POST serialization.
|
|
function serializeMultiVal(value) {
|
|
if (Array.isArray(value)) {
|
|
return value.join(',');
|
|
}
|
|
|
|
return value || '';
|
|
}
|
|
|
|
function setIntervalX(callback, delay, repetitions) {
|
|
let x = 0;
|
|
const intervalID = globalThis.setInterval(() => {
|
|
callback();
|
|
if (++x === repetitions) {
|
|
globalThis.clearInterval(intervalID);
|
|
setZoomErrorBackgrounds();
|
|
}
|
|
}, delay);
|
|
}
|
|
|
|
if (mbColor === '') {
|
|
$('.monitor_container').css('background-color', '');
|
|
$('.cactiConsoleContentArea').css('background-color', '');
|
|
} else {
|
|
let monoe = false;
|
|
|
|
setZoomErrorBackgrounds();
|
|
$('.monitor_errorzoom_title').css('font-size', monitorFont);
|
|
|
|
setIntervalX(() => {
|
|
if (monoe) {
|
|
if (mbColor !== '') {
|
|
$('.monitor_container').css('background-color', '');
|
|
$('.cactiConsoleContentArea').css('background-color', '');
|
|
}
|
|
|
|
monoe = false;
|
|
} else {
|
|
setZoomErrorBackgrounds();
|
|
monoe = true;
|
|
}
|
|
}, 600, 8);
|
|
}
|
|
|
|
function timeStep() {
|
|
const value = Number($('#timer').html()) - 1;
|
|
|
|
if (value <= 0) {
|
|
applyFilter('refresh');
|
|
} else {
|
|
$('#timer').html(value);
|
|
// What is a second, well if you are an
|
|
// imperial storm tropper, it's just a little more than a second.
|
|
myTimer = setTimeout(timeStep, 1284);
|
|
}
|
|
}
|
|
|
|
function muteUnmuteAudio(mute) {
|
|
if (mute) {
|
|
$('audio').each(function() {
|
|
this.pause();
|
|
this.currentTime = 0;
|
|
});
|
|
} else if ($('#downhosts').val() === 'true') {
|
|
$('audio').each(function() {
|
|
this.play();
|
|
});
|
|
}
|
|
}
|
|
|
|
function closeTip() {
|
|
$(document).tooltip('close');
|
|
}
|
|
|
|
function saveCardOrder(grid) {
|
|
const grouping = grid.data('grouping');
|
|
|
|
const order = grid
|
|
.find('.monitorGroupCard')
|
|
.map((i, el) => $(el).data('group'))
|
|
.get();
|
|
|
|
const post = {
|
|
action: 'ajax_saveorder',
|
|
grouping,
|
|
dashboard: $('#dashboard').val(),
|
|
order,
|
|
__csrf_magic: csrfMagicToken
|
|
};
|
|
|
|
$.post('monitor.php?header=false', post);
|
|
}
|
|
|
|
function openHostPanel(id) {
|
|
if (id === undefined || id === null || id === '') {
|
|
return;
|
|
}
|
|
|
|
let dlg = $('#monitorPanelDialog');
|
|
|
|
if (dlg.length === 0) {
|
|
dlg = $('<div id="monitorPanelDialog"></div>').appendTo('body');
|
|
}
|
|
|
|
dlg.html(`<div class='monitorPanelLoading'>${monitorMessages.loading || 'Loading...'}</div>`);
|
|
|
|
const maxHeight = Math.max(360, $(globalThis).height() - 80);
|
|
|
|
dlg.dialog({
|
|
title: monitorMessages.deviceDetails || 'Device Details',
|
|
width: 720,
|
|
height: 'auto',
|
|
maxHeight: maxHeight,
|
|
modal: false,
|
|
closeOnEscape: true,
|
|
position: { my: 'center top', at: 'center top+80', of: globalThis },
|
|
open() {
|
|
// Pause the refresh countdown so the page does not reload underneath
|
|
// the open dialog.
|
|
clearTimeout(myTimer);
|
|
},
|
|
close() {
|
|
myTimer = setTimeout(timeStep, 1000);
|
|
}
|
|
});
|
|
|
|
$.get(`monitor.php?action=ajax_hostpanel&header=false&id=${id}`, (data) => {
|
|
dlg.html(data);
|
|
});
|
|
}
|
|
|
|
function applyFilter(action = '') {
|
|
clearTimeout(myTimer);
|
|
$('.mon_icon').unbind();
|
|
|
|
let strURL;
|
|
|
|
if (action === 'dashboard') {
|
|
strURL = `monitor.php?action=dbchange&header=false&dashboard=${$('#dashboard').val()}`;
|
|
} else {
|
|
strURL = 'monitor.php?header=false';
|
|
|
|
if (action !== '') {
|
|
strURL += `&action=${action}`;
|
|
}
|
|
|
|
strURL += `&refresh=${$('#refresh').val()}`;
|
|
strURL += `&grouping=${$('#grouping').val()}`;
|
|
strURL += `&tree=${$('#tree').val()}`;
|
|
strURL += `&site=${$('#site').val()}`;
|
|
strURL += `&template=${serializeMultiVal($('#template').val())}`;
|
|
strURL += `&view=${$('#view').val()}`;
|
|
strURL += `&rows=${$('#rows').val()}`;
|
|
strURL += `&crit=${$('#crit').val()}`;
|
|
strURL += `&size=${$('#size').val()}`;
|
|
strURL += `&trim=${$('#trim').val()}`;
|
|
strURL += `&mute=${$('#mute').val()}`;
|
|
strURL += `&rfilter=${base64_encode($('#rfilter').val())}`;
|
|
strURL += `&status=${$('#status').val()}`;
|
|
|
|
const events = $('#events').val();
|
|
strURL += `&events=${events ? events.join(',') : ''}`;
|
|
}
|
|
|
|
if (action === 'ajax_mute_all' || action === 'ajax_unmute_all') {
|
|
postIt(strURL, { __csrf_magic: csrfMagicToken });
|
|
} else {
|
|
loadIt(strURL);
|
|
}
|
|
}
|
|
|
|
function saveFilter() {
|
|
const url = 'monitor.php?action=save&header=false';
|
|
|
|
const post = {
|
|
dashboard: $('#dashboard').val(),
|
|
refresh: $('#refresh').val(),
|
|
grouping: $('#grouping').val(),
|
|
tree: $('#tree').val(),
|
|
site: $('#site').val(),
|
|
template: serializeMultiVal($('#template').val()),
|
|
events: serializeMultiVal($('#events').val()),
|
|
view: $('#view').val(),
|
|
rows: $('#rows').val(),
|
|
crit: $('#crit').val(),
|
|
rfilter: base64_encode($('#rfilter').val()),
|
|
trim: $('#trim').val(),
|
|
mute: $('#mute').val(),
|
|
size: $('#size').val(),
|
|
status: $('#status').val(),
|
|
__csrf_magic: csrfMagicToken
|
|
};
|
|
|
|
$.post(url, post).done(() => {
|
|
$('#text').show().text(monitorMessages.filterSaved || '').fadeOut(2000);
|
|
});
|
|
}
|
|
|
|
function saveNewDashboard(action) {
|
|
const dashboard = action === 'new' ? '-1' : $('#dashboard').val();
|
|
const url = 'monitor.php?header=false';
|
|
|
|
const post = {
|
|
action: 'saveDb',
|
|
dashboard,
|
|
name: $('#name').val(),
|
|
refresh: $('#refresh').val(),
|
|
grouping: $('#grouping').val(),
|
|
tree: $('#tree').val(),
|
|
site: $('#site').val(),
|
|
template: serializeMultiVal($('#template').val()),
|
|
events: serializeMultiVal($('#events').val()),
|
|
view: $('#view').val(),
|
|
rows: $('#rows').val(),
|
|
crit: $('#crit').val(),
|
|
rfilter: base64_encode($('#rfilter').val()),
|
|
trim: $('#trim').val(),
|
|
size: $('#size').val(),
|
|
mute: $('#mute').val(),
|
|
status: $('#status').val(),
|
|
__csrf_magic: csrfMagicToken
|
|
};
|
|
|
|
$('#newdialog').dialog('close');
|
|
postIt(url, post);
|
|
}
|
|
|
|
function removeDashboard() {
|
|
const post = {
|
|
action: 'remove',
|
|
dashboard: $('#dashboard').val(),
|
|
__csrf_magic: csrfMagicToken
|
|
};
|
|
|
|
postIt('monitor.php?header=false', post);
|
|
}
|
|
|
|
function loadIt(url) {
|
|
if (typeof loadUrl === 'undefined') {
|
|
loadPageNoHeader(url);
|
|
} else {
|
|
loadUrl({ url });
|
|
}
|
|
}
|
|
|
|
function postIt(url, post, returnLocation) {
|
|
if (typeof postUrl === 'undefined') {
|
|
loadPageUsingPost(url, post);
|
|
} else {
|
|
postUrl(
|
|
{
|
|
url,
|
|
tabId: returnLocation,
|
|
type: 'loadPageUsingPost'
|
|
},
|
|
post
|
|
);
|
|
}
|
|
}
|
|
|
|
function saveDashboard(action) {
|
|
const btnDialog = {
|
|
Cancel: {
|
|
text: monitorMessages.cancel || 'Cancel',
|
|
id: 'btnCancel',
|
|
click() {
|
|
$(this).dialog('close');
|
|
}
|
|
},
|
|
Save: {
|
|
text: monitorMessages.save || 'Save',
|
|
id: 'btnSave',
|
|
click() {
|
|
saveNewDashboard(action);
|
|
}
|
|
}
|
|
};
|
|
|
|
if ($('#newdialog').length === 0) {
|
|
$('body').append(monitorNewForm);
|
|
}
|
|
|
|
$('#newdialog').dialog({
|
|
title: monitorNewTitle,
|
|
minHeight: 80,
|
|
minWidth: 500,
|
|
buttons: btnDialog,
|
|
position: { at: 'center top+240px', of: globalThis },
|
|
open() {
|
|
$('#name').val($('#dashboard option:selected').text());
|
|
$('#btnSave').addClass('ui-state-active');
|
|
$('#name').focus();
|
|
$('#new_dashboard')
|
|
.off('submit')
|
|
.on('submit', (event) => {
|
|
event.preventDefault();
|
|
saveNewDashboard('new');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
$(() => {
|
|
if (dozoomRefresh) {
|
|
applyFilter('refresh');
|
|
}
|
|
|
|
const selectmenu = $('#grouping').selectmenu('instance') !== undefined;
|
|
|
|
if ($('#view').val() === 'list') {
|
|
$('#grouping').prop('disabled', true);
|
|
if (selectmenu) {
|
|
$('#grouping').selectmenu('disable');
|
|
}
|
|
} else {
|
|
$('#grouping').prop('disabled', false);
|
|
if (selectmenu) {
|
|
$('#grouping').selectmenu('enable');
|
|
}
|
|
}
|
|
|
|
clearTimeout(myTimer);
|
|
|
|
$('#go').click((event) => {
|
|
event.preventDefault();
|
|
applyFilter('go');
|
|
});
|
|
|
|
$('#clear').click(() => {
|
|
loadIt('monitor.php?clear=1&header=false');
|
|
});
|
|
|
|
$('#sound').click(() => {
|
|
if ($('#mute').val() === 'false') {
|
|
$('#mute').val('true');
|
|
muteUnmuteAudio(true);
|
|
applyFilter('ajax_mute_all');
|
|
} else {
|
|
$('#mute').val('false');
|
|
muteUnmuteAudio(false);
|
|
applyFilter('ajax_unmute_all');
|
|
}
|
|
});
|
|
|
|
$('#devices').click(() => {
|
|
document.location = urlPath + 'host.php';
|
|
});
|
|
|
|
$('#refresh, #view, #rows, #trim, #crit, #grouping, #size, #status, #tree, #site').change(() => {
|
|
applyFilter('change');
|
|
});
|
|
|
|
// Events and Template multi-selects: let the user tick several boxes with
|
|
// the dropdown staying open (reloading mid-selection would close it, since
|
|
// the filter is re-rendered), then apply once when the dropdown closes. A
|
|
// plain multiple select (no select2) has no dropdown to keep open, so it
|
|
// applies on change.
|
|
$('#events, #template').on('select2:close', () => {
|
|
applyFilter('change');
|
|
});
|
|
|
|
$('#events, #template').on('change', function () {
|
|
if (!$(this).data('select2')) {
|
|
applyFilter('change');
|
|
}
|
|
});
|
|
|
|
$('#dashboard').change(() => {
|
|
applyFilter('dashboard');
|
|
});
|
|
|
|
$('#save').click(() => {
|
|
saveFilter();
|
|
});
|
|
|
|
$('#new').click(() => {
|
|
saveDashboard('new');
|
|
});
|
|
|
|
$('#rename').click(() => {
|
|
saveDashboard('rename');
|
|
});
|
|
|
|
$('#delete').click(() => {
|
|
removeDashboard();
|
|
});
|
|
|
|
$('.monitorFilterForm').submit((event) => {
|
|
event.preventDefault();
|
|
applyFilter('change');
|
|
});
|
|
|
|
$(document).on('click', '.monitorActions', (event) => {
|
|
event.preventDefault();
|
|
openHostPanel($(event.currentTarget).data('id'));
|
|
});
|
|
|
|
$(document).on('click', '.monitorFilterPill', (event) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
const pill = $(event.currentTarget);
|
|
const filter = pill.data('filter');
|
|
const value = String(pill.data('value'));
|
|
const sel = $('#' + filter);
|
|
|
|
if (!sel.length) {
|
|
return;
|
|
}
|
|
|
|
if (sel.prop('multiple')) {
|
|
// Additive multi-select (Events): toggle this value in or out of the
|
|
// current selection, sync the select2 widget without firing the
|
|
// generic change (which is debounced), then apply immediately.
|
|
let current = sel.val() || [];
|
|
|
|
if (current.indexOf(value) >= 0) {
|
|
current = current.filter((v) => v !== value);
|
|
} else {
|
|
current = current.concat([value]);
|
|
}
|
|
|
|
sel.val(current).trigger('change.select2');
|
|
applyFilter();
|
|
} else {
|
|
// Single-select (Criticality / Show): toggle on, or clear to default.
|
|
// The bound change handler applies the filter.
|
|
sel.val(String(sel.val()) === value ? '-1' : value).trigger('change');
|
|
}
|
|
});
|
|
|
|
// The filter pills carry role="button" and tabindex="0"; activate them from
|
|
// the keyboard (Enter / Space) by reusing the click handler above, so they
|
|
// are operable without a mouse.
|
|
$(document).on('keydown', '.monitorFilterPill', (event) => {
|
|
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar' || event.keyCode === 13 || event.keyCode === 32) {
|
|
event.preventDefault();
|
|
$(event.currentTarget).trigger('click');
|
|
}
|
|
});
|
|
|
|
if ($.fn.sortable) {
|
|
$('.monitorGroupGrid').sortable({
|
|
items: '.monitorGroupCard',
|
|
handle: '.monitorGroupDrag',
|
|
placeholder: 'monitorGroupPlaceholder',
|
|
forcePlaceholderSize: true,
|
|
tolerance: 'pointer',
|
|
update(event, ui) {
|
|
saveCardOrder($(event.target));
|
|
}
|
|
});
|
|
}
|
|
|
|
$('.monitor_device_frame').find('i').tooltip({
|
|
items: '.mon_icon',
|
|
open(event, ui) {
|
|
ajaxAnchors();
|
|
|
|
if (event.originalEvent === undefined) {
|
|
return false;
|
|
}
|
|
},
|
|
close(event, ui) {
|
|
ui.tooltip.hover(
|
|
function() {
|
|
$(this).stop(true).fadeTo(400, 1);
|
|
},
|
|
function() {
|
|
$(this).fadeOut('400');
|
|
}
|
|
);
|
|
},
|
|
position: { my: 'left:15 top', at: 'right center' },
|
|
content(callback) {
|
|
const id = $(this).attr('id');
|
|
const size = $('#size').val();
|
|
$.get(`monitor.php?action=ajax_status&size=${size}&id=${id}`, (data) => {
|
|
callback(data);
|
|
});
|
|
}
|
|
});
|
|
|
|
myTimer = setTimeout(timeStep, 1000);
|
|
|
|
$(globalThis).resize(() => {
|
|
$(document).tooltip('option', 'position', { my: 'left:15 top', at: 'right center' });
|
|
});
|
|
|
|
if ($('#mute').val() === 'true') {
|
|
muteUnmuteAudio(true);
|
|
} else {
|
|
muteUnmuteAudio(false);
|
|
}
|
|
|
|
$('#main').css('margin-right', '15px');
|
|
});
|