2026-02-15 23:57:01 +01:00
// Console output handler (websocket log stream and rendering).
2026-01-14 21:47:17 +01:00
"use strict" ;
2026-02-15 23:57:01 +01:00
// =========================================================================
// Global Variables
// =========================================================================
2026-01-14 21:47:17 +01:00
let consoleOutputContainer = null ;
let consoleOutputElement = null ;
2026-02-15 23:57:01 +01:00
let maxConsoleLines = 1000 ;
let wasConsoleEnabledOnLoad = false ;
// =========================================================================
// Initialization
// =========================================================================
2026-01-14 21:47:17 +01:00
2026-02-15 23:57:01 +01:00
// Initialize the console output container and connect to the websocket
2026-01-14 21:47:17 +01:00
function initConsoleOutput ( ) {
consoleOutputContainer = document . getElementById ( 'consoleOutputContainer' ) ;
consoleOutputElement = document . getElementById ( 'consoleOutputWindow' ) ;
2026-02-15 23:57:01 +01:00
2026-01-14 21:47:17 +01:00
if ( ! consoleOutputContainer || ! consoleOutputElement ) {
return ;
}
if ( typeof wsManager !== 'undefined' && wsManager ) {
wsManager . onConsoleLog ( function ( message , timestamp ) {
appendConsoleLog ( message , timestamp ) ;
} ) ;
} else {
2026-02-15 23:57:01 +01:00
// Wait for websocket manager to be available
2026-01-14 21:47:17 +01:00
const wsCheckInterval = setInterval ( function ( ) {
if ( typeof wsManager !== 'undefined' && wsManager ) {
wsManager . onConsoleLog ( function ( message , timestamp ) {
appendConsoleLog ( message , timestamp ) ;
} ) ;
clearInterval ( wsCheckInterval ) ;
}
} , 100 ) ;
2026-02-15 23:57:01 +01:00
// Timeout after 5 seconds if websocket manager is not available
2026-01-14 21:47:17 +01:00
setTimeout ( function ( ) {
clearInterval ( wsCheckInterval ) ;
} , 5000 ) ;
}
}
2026-02-15 23:57:01 +01:00
// Toggle the console output container
2026-01-14 21:47:17 +01:00
function toggleConsoleOutput ( userClicked ) {
const checkbox = document . getElementById ( 'consoleOutput' ) ;
const container = document . getElementById ( 'consoleOutputContainer' ) ;
2026-02-15 23:57:01 +01:00
2026-01-14 21:47:17 +01:00
if ( ! checkbox || ! container ) {
return ;
}
2026-02-15 23:57:01 +01:00
2026-01-14 21:47:17 +01:00
if ( checkbox . checked ) {
2026-02-15 23:57:01 +01:00
// Show the console output container
2026-01-14 21:47:17 +01:00
container . classList . remove ( 'hidden' ) ;
if ( ! consoleOutputElement ) {
initConsoleOutput ( ) ;
} else {
if ( typeof wsManager !== 'undefined' && wsManager ) {
if ( ! wsManager . consoleLogCallbacks ) {
wsManager . consoleLogCallbacks = [ ] ;
}
let callbackExists = false ;
for ( let i = 0 ; i < wsManager . consoleLogCallbacks . length ; i ++ ) {
if ( wsManager . consoleLogCallbacks [ i ] . toString ( ) . includes ( 'appendConsoleLog' ) ) {
callbackExists = true ;
break ;
}
}
if ( ! callbackExists ) {
wsManager . onConsoleLog ( function ( message , timestamp ) {
appendConsoleLog ( message , timestamp ) ;
} ) ;
}
}
}
2026-02-15 23:57:01 +01:00
2026-01-14 21:47:17 +01:00
const consoleEl = document . getElementById ( 'consoleOutputWindow' ) ;
2026-02-15 23:57:01 +01:00
// Show save hint only if user just clicked to enable (not on page load)
2026-01-14 21:47:17 +01:00
if ( consoleEl && userClicked && ! wasConsoleEnabledOnLoad ) {
const placeholder = consoleEl . querySelector ( '.text-gray-500' ) ;
if ( placeholder && placeholder . textContent === 'Console output will appear here...' ) {
placeholder . remove ( ) ;
}
const hintDiv = document . createElement ( 'div' ) ;
hintDiv . className = 'text-yellow-400 italic text-center py-4' ;
hintDiv . id = 'consoleSaveHint' ;
const hintText = typeof t !== 'undefined' ? t ( 'settings.console.save_hint' , 'Please save your settings first before logs will be displayed here.' ) : 'Please save your settings first before logs will be displayed here.' ;
hintDiv . textContent = hintText ;
consoleEl . appendChild ( hintDiv ) ;
} else if ( consoleEl ) {
const placeholder = consoleEl . querySelector ( '.text-gray-500' ) ;
2026-02-15 23:57:01 +01:00
// Remove placeholder if it exists
2026-01-14 21:47:17 +01:00
if ( placeholder && placeholder . textContent === 'Console output will appear here...' ) {
placeholder . remove ( ) ;
}
}
} else {
2026-02-15 23:57:01 +01:00
// Hide the console output container
2026-01-14 21:47:17 +01:00
container . classList . add ( 'hidden' ) ;
}
}
2026-02-15 23:57:01 +01:00
// Auto-start console if enabled on load
if ( typeof window !== 'undefined' ) {
if ( document . readyState === 'loading' ) {
document . addEventListener ( 'DOMContentLoaded' , function ( ) {
const checkbox = document . getElementById ( 'consoleOutput' ) ;
if ( checkbox && checkbox . checked ) {
wasConsoleEnabledOnLoad = true ;
toggleConsoleOutput ( false ) ;
}
initConsoleOutput ( ) ;
} ) ;
} else {
const checkbox = document . getElementById ( 'consoleOutput' ) ;
if ( checkbox && checkbox . checked ) {
wasConsoleEnabledOnLoad = true ;
toggleConsoleOutput ( false ) ;
}
initConsoleOutput ( ) ;
}
}
// =========================================================================
// Log Rendering / Core Functionality
// =========================================================================
2026-01-14 21:47:17 +01:00
function appendConsoleLog ( message , timestamp ) {
if ( ! consoleOutputElement ) {
consoleOutputElement = document . getElementById ( 'consoleOutputWindow' ) ;
}
if ( ! consoleOutputElement ) {
return ;
}
2026-02-15 23:57:01 +01:00
// Remove placeholder if it exists
2026-01-14 21:47:17 +01:00
const placeholder = consoleOutputElement . querySelector ( '.text-gray-500' ) ;
if ( placeholder && placeholder . textContent === 'Console output will appear here...' ) {
placeholder . remove ( ) ;
}
2026-02-15 23:57:01 +01:00
// Remove save hint if it exists
2026-01-14 21:47:17 +01:00
const saveHint = document . getElementById ( 'consoleSaveHint' ) ;
if ( saveHint ) {
saveHint . remove ( ) ;
}
2026-02-15 23:57:01 +01:00
// Create new log line element with timestamp
2026-01-14 21:47:17 +01:00
const logLine = document . createElement ( 'div' ) ;
logLine . className = 'text-green-400 leading-relaxed' ;
let timeStr = '' ;
if ( timestamp ) {
try {
const date = new Date ( timestamp ) ;
timeStr = '<span class="text-gray-500">[' + date . toLocaleTimeString ( ) + ']</span> ' ;
2026-02-15 23:57:01 +01:00
} catch ( e ) { }
2026-01-14 21:47:17 +01:00
}
2026-02-15 23:57:01 +01:00
// Escape message to prevent XSS
2026-01-14 21:47:17 +01:00
let escapedMessage = message ;
if ( typeof escapeHtml === 'function' ) {
escapedMessage = escapeHtml ( escapedMessage ) ;
} else {
escapedMessage = escapedMessage
. replace ( /&/g , '&' )
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /"/g , '"' )
. replace ( /'/g , ''' ) ;
}
2026-02-15 23:57:01 +01:00
// Set different colors for different log levels using patterns below.
// Default is green.
2026-01-14 21:47:17 +01:00
let logClass = 'text-green-400' ;
2026-02-10 22:52:38 +01:00
var isConfigDump = /SSH command output\b/ . test ( message ) && /Fail2Ban-UI Managed Configuration|jail\.local|action_mwlg/ . test ( message ) ;
if ( ! isConfigDump ) {
if ( /❌/ . test ( message ) || /\b(?:error|fatal)\s*:/i . test ( message ) || /\bfailed\s+to\b/i . test ( message ) ) {
logClass = 'text-red-400' ;
} else if ( /⚠️/ . test ( message ) || /\b(?:warning|warn)\s*:/i . test ( message ) ) {
logClass = 'text-yellow-400' ;
} else if ( /✅/ . test ( message ) || /\b(?:info|debug)\s*:/i . test ( message ) || /\bsuccessfully\b/i . test ( message ) ) {
logClass = 'text-blue-400' ;
}
2026-01-14 21:47:17 +01:00
}
logLine . className = logClass + ' leading-relaxed' ;
2026-02-15 23:57:01 +01:00
// Build complete log line with timestamp and message
2026-01-14 21:47:17 +01:00
logLine . innerHTML = timeStr + escapedMessage ;
2026-02-15 23:57:01 +01:00
// Add log line to console
2026-01-14 21:47:17 +01:00
consoleOutputElement . appendChild ( logLine ) ;
2026-02-15 23:57:01 +01:00
2026-01-14 21:47:17 +01:00
const lines = consoleOutputElement . children ;
if ( lines . length > maxConsoleLines ) {
consoleOutputElement . removeChild ( lines [ 0 ] ) ;
}
consoleOutputElement . scrollTop = consoleOutputElement . scrollHeight ;
}
2026-02-15 23:57:01 +01:00
// Clear the console
2026-01-14 21:47:17 +01:00
function clearConsole ( ) {
if ( ! consoleOutputElement ) {
consoleOutputElement = document . getElementById ( 'consoleOutputWindow' ) ;
}
if ( consoleOutputElement ) {
consoleOutputElement . textContent = '' ;
}
}