Describe the bug
The auto-refresh function in the Monitor web ui isn't working due to a javascript error.
Please note - the below is from an AI agent investigation with Cloud Opus 4.6 Reasoning as the model - please treat this as indicative only.
The fix supplied appears to work fine on a dev machine.
Root Cause
The error Identifier 'refreshMSeconds' has already been declared occurs because plugins/monitor/js/monitor.js uses let and const for top-level variable declarations (lines 1-10):
let refreshMSeconds = 99999999;
let myTimer;
const monitorCfg = globalThis.monitorPageConfig || {};
const mbColor = monitorCfg.mbColor || '';
const monitorFont = monitorCfg.monitorFont || '10px';
const dozoomRefresh = Boolean(monitorCfg.doZoomRefresh);
const monitorMessages = monitorCfg.messages || {};
const monitorNewForm = monitorCfg.newForm || '';
const monitorNewTitle = monitorCfg.newTitle || '';
When the monitor page auto-refreshes (or any filter change triggers a reload), Cacti's SPA-style navigation calls loadPageNoHeader() which fetches the page content via AJAX. jQuery's html() method finds the <script src="monitor.js"> tag in the response and re-evaluates it via DOMEval/globalEval (which creates a new <script> element in the DOM). Since let and const do not allow redeclaration in the same global scope, the second evaluation throws a SyntaxError, which:
- Prevents the rest of
monitor.js from executing
- Breaks the refresh timer (
timeStep), event handlers, and tooltip bindings
- Stops auto-refresh entirely
To Reproduce
Steps to reproduce the behavior:
- Go to monitor.php
- Click on the
Refresh dropdown
- Open browser developer console
- See error
VM860:1 Uncaught SyntaxError: Failed to execute 'appendChild' on 'Node': Identifier 'refreshMSeconds' has already been declared
at DOMEval (jquery.js?d16de7de202afe54100a95dea1d4b134:130:12)
at jQuery.globalEval (jquery.js?d16de7de202afe54100a95dea1d4b134:374:3)
at Object.dataFilter (jquery.js?d16de7de202afe54100a95dea1d4b134:9715:11)
at ajaxConvert (jquery.js?d16de7de202afe54100a95dea1d4b134:9044:17)
at done (jquery.js?d16de7de202afe54100a95dea1d4b134:9577:15)
at XMLHttpRequest.<anonymous> (jquery.js?d16de7de202afe54100a95dea1d4b134:9888:9)
at Object.send (jquery.js?d16de7de202afe54100a95dea1d4b134:9940:10)
at jQuery.ajax (jquery.js?d16de7de202afe54100a95dea1d4b134:9521:15)
at jQuery._evalUrl (jquery.js?d16de7de202afe54100a95dea1d4b134:9698:16)
at domManip (jquery.js?d16de7de202afe54100a95dea1d4b134:5940:16)
DOMEval @ jquery.js?d16de7de202afe54100a95dea1d4b134:130
globalEval @ jquery.js?d16de7de202afe54100a95dea1d4b134:374
dataFilter @ jquery.js?d16de7de202afe54100a95dea1d4b134:9715
ajaxConvert @ jquery.js?d16de7de202afe54100a95dea1d4b134:9044
done @ jquery.js?d16de7de202afe54100a95dea1d4b134:9577
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:9888
send @ jquery.js?d16de7de202afe54100a95dea1d4b134:9940
ajax @ jquery.js?d16de7de202afe54100a95dea1d4b134:9521
jQuery._evalUrl @ jquery.js?d16de7de202afe54100a95dea1d4b134:9698
domManip @ jquery.js?d16de7de202afe54100a95dea1d4b134:5940
append @ jquery.js?d16de7de202afe54100a95dea1d4b134:6088
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:6182
access @ jquery.js?d16de7de202afe54100a95dea1d4b134:3905
html @ jquery.js?d16de7de202afe54100a95dea1d4b134:6149
(anonymous) @ layout.js?94d503e3cce423e300150577f523ffea:2408
fire @ jquery.js?d16de7de202afe54100a95dea1d4b134:3223
fireWith @ jquery.js?d16de7de202afe54100a95dea1d4b134:3353
done @ jquery.js?d16de7de202afe54100a95dea1d4b134:9627
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:9888
PendingScript
DOMEval @ jquery.js?d16de7de202afe54100a95dea1d4b134:130
globalEval @ jquery.js?d16de7de202afe54100a95dea1d4b134:374
dataFilter @ jquery.js?d16de7de202afe54100a95dea1d4b134:9715
ajaxConvert @ jquery.js?d16de7de202afe54100a95dea1d4b134:9044
done @ jquery.js?d16de7de202afe54100a95dea1d4b134:9577
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:9888
send @ jquery.js?d16de7de202afe54100a95dea1d4b134:9940
ajax @ jquery.js?d16de7de202afe54100a95dea1d4b134:9521
jQuery._evalUrl @ jquery.js?d16de7de202afe54100a95dea1d4b134:9698
domManip @ jquery.js?d16de7de202afe54100a95dea1d4b134:5940
append @ jquery.js?d16de7de202afe54100a95dea1d4b134:6088
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:6182
access @ jquery.js?d16de7de202afe54100a95dea1d4b134:3905
html @ jquery.js?d16de7de202afe54100a95dea1d4b134:6149
(anonymous) @ layout.js?94d503e3cce423e300150577f523ffea:2408
fire @ jquery.js?d16de7de202afe54100a95dea1d4b134:3223
fireWith @ jquery.js?d16de7de202afe54100a95dea1d4b134:3353
done @ jquery.js?d16de7de202afe54100a95dea1d4b134:9627
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:9888
XMLHttpRequest.send
send @ jquery.js?d16de7de202afe54100a95dea1d4b134:9940
ajax @ jquery.js?d16de7de202afe54100a95dea1d4b134:9521
jQuery.<computed> @ jquery.js?d16de7de202afe54100a95dea1d4b134:9677
loadPageNoHeader @ layout.js?94d503e3cce423e300150577f523ffea:2381
loadIt @ monitor.js:178
applyFilter @ monitor.js:114
(anonymous) @ monitor.js:284
dispatch @ jquery.js?d16de7de202afe54100a95dea1d4b134:5145
elemData.handle @ jquery.js?d16de7de202afe54100a95dea1d4b134:4949
trigger @ jquery.js?d16de7de202afe54100a95dea1d4b134:8629
(anonymous) @ jquery.js?d16de7de202afe54100a95dea1d4b134:8707
each @ jquery.js?d16de7de202afe54100a95dea1d4b134:383
each @ jquery.js?d16de7de202afe54100a95dea1d4b134:205
trigger @ jquery.js?d16de7de202afe54100a95dea1d4b134:8706
jQuery.fn.<computed> @ jquery.js?d16de7de202afe54100a95dea1d4b134:10579
change @ main.js?d1d2bccf5ee320c86c27f0a05e89e01a:88
_trigger @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:717
_select @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:14353
(anonymous) @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:143
select @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:14008
_trigger @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:717
select @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:5499
(anonymous) @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:143
click .ui-menu-item @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:4898
handlerProxy @ jquery-ui.js?bb9963f8eb6cb3e33d6f59112ddb2231:626
dispatch @ jquery.js?d16de7de202afe54100a95dea1d4b134:5145
elemData.handle @ jquery.js?d16de7de202afe54100a95dea1d4b134:4949
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Plugin (please complete the following information):
- Version:
commit 8c03d4782384e1a7b3250413c84fd34fd68759aa (HEAD -> develop, origin/develop, origin/HEAD)
- Source: github devel latest
Desktop (please complete the following information):
- OS: Windows 11
- Browser Chrome
- Version 146.0.7680.178 (Official Build) (64-bit)
Additional context
How Core Cacti Handles This
In include/global_session.php line 143, refreshMSeconds is originally declared with var:
var refreshMSeconds=<?php print $myrefresh['seconds']*1000;?>;
Every other page in Cacti that overrides refresh behavior uses either var (which allows redeclaration) or bare assignment:
Fix
Change all top-level let/const declarations in plugins/monitor/js/monitor.js (lines 1-10) to use var, which JavaScript allows to be redeclared in the same scope without error:
let refreshMSeconds = 99999999; --> var refreshMSeconds = 99999999;
let myTimer; --> var myTimer;
- All
const declarations (monitorCfg, mbColor, monitorFont, dozoomRefresh, monitorMessages, monitorNewForm, monitorNewTitle) --> var
Describe the bug
The auto-refresh function in the Monitor web ui isn't working due to a javascript error.
Please note - the below is from an AI agent investigation with Cloud Opus 4.6 Reasoning as the model - please treat this as indicative only.
The fix supplied appears to work fine on a dev machine.
Root Cause
The error
Identifier 'refreshMSeconds' has already been declaredoccurs becauseplugins/monitor/js/monitor.jsusesletandconstfor top-level variable declarations (lines 1-10):When the monitor page auto-refreshes (or any filter change triggers a reload), Cacti's SPA-style navigation calls
loadPageNoHeader()which fetches the page content via AJAX. jQuery'shtml()method finds the<script src="monitor.js">tag in the response and re-evaluates it viaDOMEval/globalEval(which creates a new<script>element in the DOM). Sinceletandconstdo not allow redeclaration in the same global scope, the second evaluation throws aSyntaxError, which:monitor.jsfrom executingtimeStep), event handlers, and tooltip bindingsTo Reproduce
Steps to reproduce the behavior:
RefreshdropdownExpected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Plugin (please complete the following information):
commit 8c03d4782384e1a7b3250413c84fd34fd68759aa (HEAD -> develop, origin/develop, origin/HEAD)Desktop (please complete the following information):
Additional context
How Core Cacti Handles This
In
include/global_session.phpline 143,refreshMSecondsis originally declared withvar:Every other page in Cacti that overrides refresh behavior uses either
var(which allows redeclaration) or bare assignment:graph.php:var refreshMSeconds=9999999;utilities.php:refreshMSeconds=$('#refresh').val()*1000;lib/html.php:var refreshMSeconds = ...;Fix
Change all top-level
let/constdeclarations inplugins/monitor/js/monitor.js(lines 1-10) to usevar, which JavaScript allows to be redeclared in the same scope without error:let refreshMSeconds = 99999999;-->var refreshMSeconds = 99999999;let myTimer;-->var myTimer;constdeclarations (monitorCfg,mbColor,monitorFont,dozoomRefresh,monitorMessages,monitorNewForm,monitorNewTitle) -->var