update index.html

This commit is contained in:
2026-04-19 12:55:06 +02:00
parent ad77bb98a8
commit d01226cb5a
+92 -61
View File
@@ -101,8 +101,8 @@
<div id="top-bar"> <div id="top-bar">
<div class="title-brand">FLEET CONTROL CONSOLE</div> <div class="title-brand">FLEET CONTROL CONSOLE</div>
<div style="display: flex; align-items: center; gap: 12px;"> <div style="display: flex; align-items: center; gap: 12px;">
<button class="theme-switch" id="lang-btn" onclick="toggleLang()">🇮🇹 ITA</button> <button class="theme-switch" id="lang-btn" onclick="toggleLang()" data-i18n-title="ttLang">🇮🇹 ITA</button>
<button class="theme-switch" id="theme-btn" onclick="toggleTheme()">🌙 DARK</button> <button class="theme-switch" id="theme-btn" onclick="toggleTheme()" data-i18n-title="ttTheme">🌙 DARK</button>
<div id="auth-container" style="display:flex; align-items:center; gap:8px;"></div> <div id="auth-container" style="display:flex; align-items:center; gap:8px;"></div>
</div> </div>
</div> </div>
@@ -137,7 +137,7 @@
<div style="text-align: center; padding: 25px; color: var(--text-muted); font-size: 0.85rem; font-weight: 600; display: flex; justify-content: center; align-items: center; gap: 15px; flex-wrap: wrap;"> <div style="text-align: center; padding: 25px; color: var(--text-muted); font-size: 0.85rem; font-weight: 600; display: flex; justify-content: center; align-items: center; gap: 15px; flex-wrap: wrap;">
<span>&copy; 2026 <strong>IV3JDV @ ARIFVG</strong></span> <span>&copy; 2026 <strong>IV3JDV @ ARIFVG</strong></span>
<span style="opacity: 0.5;">|</span> <span style="opacity: 0.5;">|</span>
<a href="https://github.com/picchiosat/fleet-control-console" target="_blank" style="color: inherit; text-decoration: none; display: flex; align-items: center; gap: 6px; transition: color 0.2s;"> <a href="https://github.com/picchiosat/fleet-control-console" target="_blank" style="color: inherit; text-decoration: none; display: flex; align-items: center; gap: 6px; transition: color 0.2s;" title="View Source on GitHub">
<svg height="18" viewBox="0 0 16 16" width="18" style="fill: currentColor; vertical-align: middle;"> <svg height="18" viewBox="0 0 16 16" width="18" style="fill: currentColor; vertical-align: middle;">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path> <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
</svg> </svg>
@@ -152,7 +152,7 @@
<div class="modal-content" style="width:90%; max-width:400px;"> <div class="modal-content" style="width:90%; max-width:400px;">
<div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:20px;"> <div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:20px;">
<h2 style="margin:0; color:var(--primary);" data-i18n="loginTitle">🔒 System Login</h2> <h2 style="margin:0; color:var(--primary);" data-i18n="loginTitle">🔒 System Login</h2>
<button onclick="closeLoginModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);"></button> <button onclick="closeLoginModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);" title="Close"></button>
</div> </div>
<div style="display:flex; flex-direction:column; gap:15px;"> <div style="display:flex; flex-direction:column; gap:15px;">
<input type="text" id="modal-username" placeholder="Username" style="width:100%; padding:12px; font-size:1rem;" onkeypress="handleLoginEnter(event)"> <input type="text" id="modal-username" placeholder="Username" style="width:100%; padding:12px; font-size:1rem;" onkeypress="handleLoginEnter(event)">
@@ -166,7 +166,7 @@
<div class="modal-content" style="width:90%; max-width:900px;"> <div class="modal-content" style="width:90%; max-width:900px;">
<div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:20px;"> <div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:20px;">
<h2 style="margin:0;" data-i18n="adminTitle">🛠️ User & System Management</h2> <h2 style="margin:0;" data-i18n="adminTitle">🛠️ User & System Management</h2>
<button onclick="closeAdmin()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);"></button> <button onclick="closeAdmin()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);" title="Close"></button>
</div> </div>
<div style="display:flex; flex-wrap:wrap; gap:10px; margin-bottom:20px; background:rgba(0,0,0,0.05); padding:15px; border-radius:16px; align-items:center;"> <div style="display:flex; flex-wrap:wrap; gap:10px; margin-bottom:20px; background:rgba(0,0,0,0.05); padding:15px; border-radius:16px; align-items:center;">
@@ -205,7 +205,7 @@
<div class="modal-content" style="width:90%; max-width:550px;"> <div class="modal-content" style="width:90%; max-width:550px;">
<div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:15px;"> <div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:15px;">
<h2 style="margin:0; color:var(--accent);"><span data-i18n="modSvcTitle">⚙️ System Daemons:</span> <span id="svc-modal-title" style="color:var(--text-main);"></span></h2> <h2 style="margin:0; color:var(--accent);"><span data-i18n="modSvcTitle">⚙️ System Daemons:</span> <span id="svc-modal-title" style="color:var(--text-main);"></span></h2>
<button onclick="closeServicesModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);"></button> <button onclick="closeServicesModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);" title="Close"></button>
</div> </div>
<div id="services-list" style="max-height: 400px; overflow-y: auto; padding-right:10px;"></div> <div id="services-list" style="max-height: 400px; overflow-y: auto; padding-right:10px;"></div>
</div> </div>
@@ -215,7 +215,7 @@
<div class="modal-content" style="width:90%; max-width:500px;"> <div class="modal-content" style="width:90%; max-width:500px;">
<div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:15px;"> <div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid var(--border-color); padding-bottom:15px; margin-bottom:15px;">
<h2 style="margin:0; color:#8e44ad;" data-i18n="modFileTitle">📂 Configuration Files</h2> <h2 style="margin:0; color:#8e44ad;" data-i18n="modFileTitle">📂 Configuration Files</h2>
<button onclick="closeConfigsModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);"></button> <button onclick="closeConfigsModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);" title="Close"></button>
</div> </div>
<div id="configs-list" style="display:flex; flex-direction:column; gap:10px;"></div> <div id="configs-list" style="display:flex; flex-direction:column; gap:10px;"></div>
</div> </div>
@@ -225,7 +225,7 @@
<div class="modal-content" style="width:95%; max-width:900px; border: 1px solid var(--accent);"> <div class="modal-content" style="width:95%; max-width:900px; border: 1px solid var(--accent);">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;"> <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
<h3 style="margin:0; color:var(--accent);"><span data-i18n="modEditTitle">📝 INI File Editor:</span> <span id="editor-title" style="color:var(--text-main);"></span></h3> <h3 style="margin:0; color:var(--accent);"><span data-i18n="modEditTitle">📝 INI File Editor:</span> <span id="editor-title" style="color:var(--text-main);"></span></h3>
<button onclick="closeEditorModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);"></button> <button onclick="closeEditorModal()" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--danger);" title="Close"></button>
</div> </div>
<div style="background:rgba(239, 68, 68, 0.1); border-left:4px solid var(--danger); padding:10px; margin-bottom:15px; font-size:0.85rem; font-weight:bold; border-radius: 8px;" data-i18n="warnEdit"> <div style="background:rgba(239, 68, 68, 0.1); border-left:4px solid var(--danger); padding:10px; margin-bottom:15px; font-size:0.85rem; font-weight:bold; border-radius: 8px;" data-i18n="warnEdit">
⚠️ WARNING: This editor directly manipulates remote node parameters. ⚠️ WARNING: This editor directly manipulates remote node parameters.
@@ -238,6 +238,37 @@
</div> </div>
</div> </div>
<div id="alert-modal" class="modal-overlay" style="z-index: 5000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 2px solid var(--primary);" id="alert-box">
<h2 style="margin-top:0;" id="alert-title">️ INFO</h2>
<p style="margin-bottom:25px; color:var(--text-main); font-weight: 600;" id="alert-desc">Message</p>
<button onclick="document.getElementById('alert-modal').style.display='none'" class="btn-cmd" style="background:var(--primary); padding:12px; width:100%;">OK</button>
</div>
</div>
<div id="confirm-modal" class="modal-overlay" style="z-index: 4000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 2px solid var(--danger);" id="confirm-box">
<h2 style="margin-top:0;" id="confirm-title">⚠️ WARNING</h2>
<p style="margin-bottom:25px; color:var(--text-main); font-weight: 600;" id="confirm-desc">Are you sure?</p>
<div style="display:flex; flex-direction:column; gap:15px;">
<button id="confirm-yes-btn" onclick="executeConfirmAction()" class="btn-cmd" style="background:var(--danger); padding:15px; font-size:1.1rem; font-weight:800;">YES, PROCEED</button>
<button id="confirm-cancel-btn" onclick="document.getElementById('confirm-modal').style.display='none'" class="btn-cmd" style="background:var(--text-muted); padding:12px; margin-top:10px;">CANCEL</button>
</div>
</div>
</div>
<div id="password-modal" class="modal-overlay" style="z-index: 3000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 1px solid var(--accent);">
<h2 style="margin-top:0; color:var(--accent);">🔑 <span data-i18n="btnPass">PASSWORD CHANGE</span></h2>
<p style="margin-bottom:20px; color:var(--text-main); font-weight: 600;" data-i18n="promptPass">Enter the new password:</p>
<input type="password" id="new-password-input" style="width:100%; padding:12px; font-size:1rem; margin-bottom:20px; text-align:center;" placeholder="***">
<div style="display:flex; flex-direction:column; gap:10px;">
<button onclick="executePasswordChange()" class="btn-cmd" style="background:var(--success); padding:15px; font-size:1.1rem; font-weight:800;" data-i18n="titleSave">💾 SAVE</button>
<button onclick="closePasswordModal()" class="btn-cmd" style="background:var(--text-muted); padding:12px;" data-i18n="btnCancel">CANCEL</button>
</div>
</div>
</div>
<div id="override-modal" class="modal-overlay" style="z-index: 3000;"> <div id="override-modal" class="modal-overlay" style="z-index: 3000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center;"> <div class="modal-content" style="width:90%; max-width:400px; text-align:center;">
<h2 style="margin-top:0; color:var(--danger);">🚨 <span data-i18n="titleGlobal">GLOBAL OVERRIDE</span> 🚨</h2> <h2 style="margin-top:0; color:var(--danger);">🚨 <span data-i18n="titleGlobal">GLOBAL OVERRIDE</span> 🚨</h2>
@@ -272,37 +303,6 @@
</div> </div>
</div> </div>
<div id="alert-modal" class="modal-overlay" style="z-index: 5000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 2px solid var(--primary);" id="alert-box">
<h2 style="margin-top:0;" id="alert-title">️ INFO</h2>
<p style="margin-bottom:25px; color:var(--text-main); font-weight: 600;" id="alert-desc">Message</p>
<button onclick="document.getElementById('alert-modal').style.display='none'" class="btn-cmd" style="background:var(--primary); padding:12px; width:100%;">OK</button>
</div>
</div>
<div id="confirm-modal" class="modal-overlay" style="z-index: 4000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 2px solid var(--danger);" id="confirm-box">
<h2 style="margin-top:0;" id="confirm-title">⚠️ WARNING</h2>
<p style="margin-bottom:25px; color:var(--text-main); font-weight: 600;" id="confirm-desc">Are you sure?</p>
<div style="display:flex; flex-direction:column; gap:15px;">
<button id="confirm-yes-btn" onclick="executeConfirmAction()" class="btn-cmd" style="background:var(--danger); padding:15px; font-size:1.1rem; font-weight:800;">YES, PROCEED</button>
<button id="confirm-cancel-btn" onclick="document.getElementById('confirm-modal').style.display='none'" class="btn-cmd" style="background:var(--text-muted); padding:12px; margin-top:10px;">CANCEL</button>
</div>
</div>
</div>
<div id="password-modal" class="modal-overlay" style="z-index: 3000;">
<div class="modal-content" style="width:90%; max-width:400px; text-align:center; border: 1px solid var(--accent);">
<h2 style="margin-top:0; color:var(--accent);">🔑 <span data-i18n="btnPass">PASSWORD CHANGE</span></h2>
<p style="margin-bottom:20px; color:var(--text-main); font-weight: 600;" data-i18n="promptPass">Enter the new password:</p>
<input type="password" id="new-password-input" style="width:100%; padding:12px; font-size:1rem; margin-bottom:20px; text-align:center;" placeholder="***">
<div style="display:flex; flex-direction:column; gap:10px;">
<button onclick="executePasswordChange()" class="btn-cmd" style="background:var(--success); padding:15px; font-size:1.1rem; font-weight:800;" data-i18n="titleSave">💾 SAVE</button>
<button onclick="closePasswordModal()" class="btn-cmd" style="background:var(--text-muted); padding:12px;" data-i18n="btnCancel">CANCEL</button>
</div>
</div>
</div>
<script> <script>
// --- 1. TRANSLATION SYSTEM (i18n) --- // --- 1. TRANSLATION SYSTEM (i18n) ---
const i18n = { const i18n = {
@@ -329,7 +329,10 @@
msgConfigSaved: "Configuration saved!", msgConfigErr: "Error saving configuration", msgNetErr: "Network Error", msgOvrSel: "Select the profile to send to the ENTIRE network:", msgConfigSaved: "Configuration saved!", msgConfigErr: "Error saving configuration", msgNetErr: "Network Error", msgOvrSel: "Select the profile to send to the ENTIRE network:",
msgOvrOk: "Command successfully sent to the network!", msgMissUser: "Missing Username", msgMissPass: "Password required for new user", btnSvcKo: "⚠️ DAEMON KO", msgOvrOk: "Command successfully sent to the network!", msgMissUser: "Missing Username", msgMissPass: "Password required for new user", btnSvcKo: "⚠️ DAEMON KO",
phNewPass: "New pass (empty to keep)", phPass: "Password", phNewPass: "New pass (empty to keep)", phPass: "Password",
titleSwitch: "SWITCH PROFILE", confSwitch: "Are you sure you want to switch to", titleBoot: "SYSTEM REBOOT", confBoot: "Are you sure you want to REBOOT node " titleSwitch: "SWITCH PROFILE", confSwitch: "Are you sure you want to switch to", titleBoot: "SYSTEM REBOOT", confBoot: "Are you sure you want to REBOOT node ",
ttReqCfg: "Request immediate data update", ttGlobal: "Force profile switch on network", ttAdmin: "User and system management", ttPass: "Change your password", ttLogout: "Log out",
ttProfA: "Switch to Profile A", ttProfB: "Switch to Profile B", ttTgOn: "Enable Telegram notifications", ttTgOff: "Disable Telegram notifications", ttSvc: "Manage system daemons", ttFile: "Edit .ini configuration files", ttHat: "Send physical reset to modem", ttBoot: "Reboot node operating system",
ttSwitchTo: "Switch to profile: ", ttSvcStart: "Start service", ttSvcRestart: "Restart service", ttSvcEdit: "Edit configuration", ttSvcStop: "Stop service", ttLang: "Change language", ttTheme: "Change visual theme"
}, },
it: { it: {
themeLight: "☀️ CHIARO", themeDark: "🌙 SCURO", themeLight: "☀️ CHIARO", themeDark: "🌙 SCURO",
@@ -354,19 +357,33 @@
msgConfigSaved: "Configurazione salvata!", msgConfigErr: "Errore durante il salvataggio", msgNetErr: "Errore di rete", msgOvrSel: "Seleziona il profilo da inviare a TUTTA la rete:", msgConfigSaved: "Configurazione salvata!", msgConfigErr: "Errore durante il salvataggio", msgNetErr: "Errore di rete", msgOvrSel: "Seleziona il profilo da inviare a TUTTA la rete:",
msgOvrOk: "Comando inviato con successo a tutta la rete!", msgMissUser: "Username mancante", msgMissPass: "Password obbligatoria per il nuovo utente", btnSvcKo: "⚠️ DEMONE KO", msgOvrOk: "Comando inviato con successo a tutta la rete!", msgMissUser: "Username mancante", msgMissPass: "Password obbligatoria per il nuovo utente", btnSvcKo: "⚠️ DEMONE KO",
phNewPass: "Nuova pass (vuota per non cambiare)", phPass: "Password", phNewPass: "Nuova pass (vuota per non cambiare)", phPass: "Password",
titleSwitch: "CAMBIO PROFILO", confSwitch: "Sei sicuro di voler passare al", titleBoot: "RIAVVIO SISTEMA", confBoot: "Sei sicuro di voler RIAVVIARE il nodo " titleSwitch: "CAMBIO PROFILO", confSwitch: "Sei sicuro di voler passare al", titleBoot: "RIAVVIO SISTEMA", confBoot: "Sei sicuro di voler RIAVVIARE il nodo ",
ttReqCfg: "Richiedi aggiornamento dati", ttGlobal: "Forza cambio profilo globale", ttAdmin: "Gestione utenti e sistema", ttPass: "Cambia la tua password", ttLogout: "Disconnetti",
ttProfA: "Passa al Profilo A", ttProfB: "Passa al Profilo B", ttTgOn: "Abilita notifiche Telegram", ttTgOff: "Disabilita notifiche Telegram", ttSvc: "Gestisci demoni di sistema", ttFile: "Modifica file .ini da remoto", ttHat: "Reset fisico scheda modem", ttBoot: "Riavvia sistema operativo",
ttSwitchTo: "Passa al profilo: ", ttSvcStart: "Avvia servizio", ttSvcRestart: "Riavvia servizio", ttSvcEdit: "Modifica configurazione", ttSvcStop: "Ferma servizio", ttLang: "Cambia lingua", ttTheme: "Cambia tema visivo"
} }
}; };
let currentLang = localStorage.getItem('lang') || 'en'; let currentLang = localStorage.getItem('lang') || 'en';
function t(key) { return i18n[currentLang][key] || key; } function t(key) { return i18n[currentLang][key] || key; }
function toggleLang() { currentLang = currentLang === 'it' ? 'en' : 'it'; localStorage.setItem('lang', currentLang); location.reload(); } function toggleLang() { currentLang = currentLang === 'it' ? 'en' : 'it'; localStorage.setItem('lang', currentLang); location.reload(); }
function applyTranslations() { function applyTranslations() {
document.getElementById('lang-btn').innerText = currentLang === 'it' ? "🇬🇧 ENG" : "🇮🇹 ITA"; document.getElementById('lang-btn').innerText = currentLang === 'it' ? "🇬🇧 ENG" : "🇮🇹 ITA";
// Translate innerHTML
document.querySelectorAll('[data-i18n]').forEach(el => { document.querySelectorAll('[data-i18n]').forEach(el => {
const key = el.getAttribute('data-i18n'); const key = el.getAttribute('data-i18n');
if (i18n[currentLang][key]) el.innerHTML = i18n[currentLang][key]; if (i18n[currentLang][key]) el.innerHTML = i18n[currentLang][key];
}); });
// Translate tooltips (titles)
document.querySelectorAll('[data-i18n-title]').forEach(el => {
const key = el.getAttribute('data-i18n-title');
if (i18n[currentLang][key]) el.title = i18n[currentLang][key];
});
// Translate placeholders
const newPassInput = document.getElementById('new-pass'); const newPassInput = document.getElementById('new-pass');
if (newPassInput && editingUserId) newPassInput.placeholder = t('phNewPass'); if (newPassInput && editingUserId) newPassInput.placeholder = t('phNewPass');
else if (newPassInput) newPassInput.placeholder = t('phPass'); else if (newPassInput) newPassInput.placeholder = t('phPass');
@@ -515,14 +532,14 @@
if (isAuthenticated) { if (isAuthenticated) {
let adminBtn = role === 'admin' ? ` let adminBtn = role === 'admin' ? `
<button onclick="sendGlobalUpdate()" class="auth-btn" style="background:#f59e0b; color:white;">${t('btnReqCfg')}</button> <button onclick="sendGlobalUpdate()" class="auth-btn" style="background:#f59e0b; color:white;" data-i18n-title="ttReqCfg" title="${t('ttReqCfg')}">${t('btnReqCfg')}</button>
<button onclick="triggerGlobalEmergency()" class="auth-btn" style="background:#ef4444; color:white;">${t('btnGlobal')}</button> <button onclick="triggerGlobalEmergency()" class="auth-btn" style="background:#ef4444; color:white;" data-i18n-title="ttGlobal" title="${t('ttGlobal')}">${t('btnGlobal')}</button>
<button onclick="openAdmin()" class="auth-btn" style="background:var(--accent); color:white;">${t('btnAdmin')}</button>` : ''; <button onclick="openAdmin()" class="auth-btn" style="background:var(--accent); color:white;" data-i18n-title="ttAdmin" title="${t('ttAdmin')}">${t('btnAdmin')}</button>` : '';
authContainer.innerHTML = `${adminBtn} authContainer.innerHTML = `${adminBtn}
<span style="font-weight:800; font-size:0.9rem; margin: 0 10px;">👤 ${sessionStorage.getItem('user_name').toUpperCase()}</span> <span style="font-weight:800; font-size:0.9rem; margin: 0 10px;">👤 ${sessionStorage.getItem('user_name').toUpperCase()}</span>
<button onclick="changeMyPassword()" class="auth-btn" style="background:#64748b; color:white;">${t('btnPass')}</button> <button onclick="changeMyPassword()" class="auth-btn" style="background:#64748b; color:white;" data-i18n-title="ttPass" title="${t('ttPass')}">${t('btnPass')}</button>
<button onclick="logout()" class="auth-btn" style="background:var(--text-main); color:var(--card-bg);">${t('btnLogout')}</button>`; <button onclick="logout()" class="auth-btn" style="background:var(--text-main); color:var(--card-bg);" data-i18n-title="ttLogout" title="${t('ttLogout')}">${t('btnLogout')}</button>`;
} else { } else {
authContainer.innerHTML = `<button onclick="openLoginModal()" class="auth-btn" style="background:var(--primary); color:white; padding: 8px 25px;">LOGIN</button>`; authContainer.innerHTML = `<button onclick="openLoginModal()" class="auth-btn" style="background:var(--primary); color:white; padding: 8px 25px;">LOGIN</button>`;
} }
@@ -560,18 +577,18 @@
</div> </div>
<div class="actions" style="${(isAuthenticated && canControl) ? 'display:flex;' : 'display:none'}"> <div class="actions" style="${(isAuthenticated && canControl) ? 'display:flex;' : 'display:none'}">
<button id="btn-profA-${c.id}" class="btn-cmd" style="background: var(--accent);" onclick="confirmSwitch('${c.id}', 'A')">PROFILE A</button> <button id="btn-profA-${c.id}" class="btn-cmd" style="background: var(--accent);" title="${t('ttProfA')}" onclick="confirmSwitch('${c.id}', 'A')">PROFILE A</button>
<button id="btn-profB-${c.id}" class="btn-cmd" style="background: #eab308;" onclick="confirmSwitch('${c.id}', 'B')">PROFILE B</button> <button id="btn-profB-${c.id}" class="btn-cmd" style="background: #eab308;" title="${t('ttProfB')}" onclick="confirmSwitch('${c.id}', 'B')">PROFILE B</button>
<div style="width: 100%; display: flex; gap: 10px;"> <div style="width: 100%; display: flex; gap: 10px;">
<button class="btn-cmd" style="background: var(--success);" onclick="sendTgCommand('${c.id}', 'TG:ON')">🔔 Telegram ON</button> <button class="btn-cmd" style="background: var(--success);" title="${t('ttTgOn')}" onclick="sendTgCommand('${c.id}', 'TG:ON')">🔔 Telegram ON</button>
<button class="btn-cmd" style="background: var(--text-muted);" onclick="sendTgCommand('${c.id}', 'TG:OFF')">🔇 Telegram OFF</button> <button class="btn-cmd" style="background: var(--text-muted);" title="${t('ttTgOff')}" onclick="sendTgCommand('${c.id}', 'TG:OFF')">🔇 Telegram OFF</button>
</div> </div>
${showReboot ? ` ${showReboot ? `
<button id="btn-svc-${c.id}" class="btn-cmd" style="background: #334155;" onclick="openServicesModal('${c.id}')">${t('btnSvc')}</button> <button id="btn-svc-${c.id}" class="btn-cmd" style="background: #334155;" title="${t('ttSvc')}" onclick="openServicesModal('${c.id}')">${t('btnSvc')}</button>
<button class="btn-cmd" style="background: #8e44ad;" onclick="openConfigsModal('${c.id}')">${t('btnFile')}</button> <button class="btn-cmd" style="background: #8e44ad;" title="${t('ttFile')}" onclick="openConfigsModal('${c.id}')">${t('btnFile')}</button>
<button class="btn-cmd" style="background: #ea580c;" onclick="confirmHatReset('${c.id}')">${t('btnHat')}</button> <button class="btn-cmd" style="background: #ea580c;" title="${t('ttHat')}" onclick="confirmHatReset('${c.id}')">${t('btnHat')}</button>
<button class="btn-cmd btn-reboot" style="background: var(--danger);" onclick="confirmReboot('${c.id}')">${t('btnBoot')}</button> <button class="btn-cmd btn-reboot" style="background: var(--danger);" title="${t('ttBoot')}" onclick="confirmReboot('${c.id}')">${t('btnBoot')}</button>
` : ''} ` : ''}
</div> </div>
</div>`; </div>`;
@@ -678,12 +695,26 @@
if (healthObj && isOnline) { if (healthObj && isOnline) {
healthContainer.style.display = 'flex'; healthContainer.style.display = 'flex';
let cpu = healthObj.cpu; cpuSpan.innerText = cpu; cpuSpan.style.color = cpu < 50 ? 'var(--success)' : (cpu < 80 ? '#f59e0b' : 'var(--danger)'); let cpu = healthObj.cpu; cpuSpan.innerText = cpu; cpuSpan.style.color = cpu < 50 ? 'var(--success)' : (cpu < 80 ? '#f59e0b' : 'var(--danger)');
let t = healthObj.temp; tempSpan.innerText = t; tempSpan.style.color = t < 55 ? 'var(--success)' : (t < 70 ? '#f59e0b' : 'var(--danger)');
// FIXED TEMPERATURE VARIABLE NAME HERE
let tempVal = healthObj.temp;
tempSpan.innerText = tempVal;
tempSpan.style.color = tempVal < 55 ? 'var(--success)' : (tempVal < 70 ? '#f59e0b' : 'var(--danger)');
ramSpan.innerText = healthObj.ram; let d = healthObj.disk; diskSpan.innerText = d; diskSpan.style.color = d < 85 ? 'inherit' : (d < 95 ? '#f59e0b' : 'var(--danger)'); ramSpan.innerText = healthObj.ram; let d = healthObj.disk; diskSpan.innerText = d; diskSpan.style.color = d < 85 ? 'inherit' : (d < 95 ? '#f59e0b' : 'var(--danger)');
let profA = (healthObj.profiles && healthObj.profiles.A) ? healthObj.profiles.A : "PROFILE A"; let profB = (healthObj.profiles && healthObj.profiles.B) ? healthObj.profiles.B : "PROFILE B"; let profA = (healthObj.profiles && healthObj.profiles.A) ? healthObj.profiles.A : "PROFILE A"; let profB = (healthObj.profiles && healthObj.profiles.B) ? healthObj.profiles.B : "PROFILE B";
const btnA = document.getElementById(`btn-profA-${c.id}`); const btnB = document.getElementById(`btn-profB-${c.id}`); const btnA = document.getElementById(`btn-profA-${c.id}`); const btnB = document.getElementById(`btn-profB-${c.id}`);
if (btnA && btnA.innerText !== profA) btnA.innerText = profA; if (btnB && btnB.innerText !== profB) btnB.innerText = profB;
if (btnA) {
if (btnA.innerText !== profA) btnA.innerText = profA;
btnA.title = `${t('ttSwitchTo')}${profA}`;
}
if (btnB) {
if (btnB.innerText !== profB) btnB.innerText = profB;
btnB.title = `${t('ttSwitchTo')}${profB}`;
}
} else { if (healthContainer) healthContainer.style.display = 'none'; } } else { if (healthContainer) healthContainer.style.display = 'none'; }
globalHealthData[c.id.toLowerCase()] = healthObj; globalHealthData[c.id.toLowerCase()] = healthObj;
@@ -902,7 +933,7 @@
listDiv.innerHTML = listaFile.map(filename => ` listDiv.innerHTML = listaFile.map(filename => `
<div style="display:flex; justify-content:space-between; align-items:center; padding:12px; background:rgba(128,128,128,0.1); border-radius:12px; border:1px solid var(--border-color); margin-bottom:8px;"> <div style="display:flex; justify-content:space-between; align-items:center; padding:12px; background:rgba(128,128,128,0.1); border-radius:12px; border:1px solid var(--border-color); margin-bottom:8px;">
<span style="font-family:'JetBrains Mono',monospace; font-weight:bold;">${filename.toUpperCase()}.ini</span> <span style="font-family:'JetBrains Mono',monospace; font-weight:bold;">${filename.toUpperCase()}.ini</span>
<button onclick="closeConfigsModal(); openEditorModal('${clientId}', '${filename}')" class="btn-cmd" style="background:#8e44ad; max-width:120px;">${t('btnEdit')}</button> <button onclick="closeConfigsModal(); openEditorModal('${clientId}', '${filename}')" class="btn-cmd" style="background:#8e44ad; max-width:120px;" title="${t('ttFile')}">${t('btnEdit')}</button>
</div>`).join(''); </div>`).join('');
} }
document.getElementById('configs-modal').style.display = 'flex'; document.getElementById('configs-modal').style.display = 'flex';
@@ -924,10 +955,10 @@
<span style="color:${statusColor}; font-size:0.8rem; font-weight:800; ${statusAnim}">${status.toUpperCase()}</span> <span style="color:${statusColor}; font-size:0.8rem; font-weight:800; ${statusAnim}">${status.toUpperCase()}</span>
</div> </div>
<div style="display:flex; gap:8px;"> <div style="display:flex; gap:8px;">
${!isOnline ? `<button onclick="controlService('${clientId}', '${name}', 'restart')" class="btn-cmd" style="background:var(--success);">▶</button>` : ''} ${!isOnline ? `<button onclick="controlService('${clientId}', '${name}', 'start')" class="btn-cmd" style="background:var(--success);" title="${t('ttSvcStart')}">▶</button>` : ''}
<button onclick="controlService('${clientId}', '${name}', 'restart')" class="btn-cmd" style="background:#f59e0b;">🔄</button> <button onclick="controlService('${clientId}', '${name}', 'restart')" class="btn-cmd" style="background:#f59e0b;" title="${t('ttSvcRestart')}">🔄</button>
<button onclick="openEditorModal('${clientId}', '${name}')" class="btn-cmd" style="background:#8e44ad;">📝</button> <button onclick="openEditorModal('${clientId}', '${name}')" class="btn-cmd" style="background:#8e44ad;" title="${t('ttSvcEdit')}">📝</button>
${isOnline ? `<button onclick="controlService('${clientId}', '${name}', 'stop')" class="btn-cmd" style="background:var(--danger);">🛑</button>` : ''} ${isOnline ? `<button onclick="controlService('${clientId}', '${name}', 'stop')" class="btn-cmd" style="background:var(--danger);" title="${t('ttSvcStop')}">🛑</button>` : ''}
</div> </div>
</div>`; </div>`;
} }