Skip to content

Automatic refresh issue - 'refreshMSeconds' has already been declared #213

@ahouston

Description

@ahouston

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:

  1. Prevents the rest of monitor.js from executing
  2. Breaks the refresh timer (timeStep), event handlers, and tooltip bindings
  3. Stops auto-refresh entirely

To Reproduce
Steps to reproduce the behavior:

  1. Go to monitor.php
  2. Click on the Refresh dropdown
  3. Open browser developer console
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions