sinhronizacija
This commit is contained in:
222
webroot/index.html
Normal file
222
webroot/index.html
Normal file
@@ -0,0 +1,222 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>System Monitor</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background: #f4f4f4; margin: 0; padding: 0; }
|
||||
.container { max-width: 600px; margin: 40px auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);}
|
||||
h1 { text-align: center; }
|
||||
.stat { display: flex; justify-content: space-between; margin: 16px 0; font-size: 1.2em; }
|
||||
.label { color: #555; }
|
||||
.value { font-weight: bold; }
|
||||
.refresh-btn { display: block; margin: 24px auto 0; padding: 8px 24px; font-size: 1em; border: none; border-radius: 4px; background: #0078d4; color: #fff; cursor: pointer; }
|
||||
.refresh-btn:hover { background: #005fa3; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>NUIKS SysMonitor</h1>
|
||||
<div class="stat"><span class="label">CPU Usage:</span> <span class="value" id="cpu">--</span></div>
|
||||
<div class="stat"><span class="label">RAM Usage:</span> <span class="value" id="ram">--</span></div>
|
||||
<div class="stat"><span class="label">SSD Usage:</span> <span class="value" id="disk">--</span></div>
|
||||
<div class="stat"><span class="label">Uptime:</span> <span class="value" id="uptime">--</span></div>
|
||||
</div>
|
||||
|
||||
<div class="container" style="margin-top:24px;">
|
||||
<h1>Limit overages</h1>
|
||||
<form id="addMessageForm" style="margin-bottom:16px;">
|
||||
<input type="text" id="newMessage" placeholder="Type a message..." style="width:70%;padding:8px;" required>
|
||||
<button type="submit" class="refresh-btn" style="display:inline-block;margin:0;">Add</button>
|
||||
</form>
|
||||
<ul id="messages" style="list-style:none;padding:0;"></ul>
|
||||
</div>
|
||||
|
||||
<div class="container" style="margin-top:24px;">
|
||||
<h1>Resource Limits</h1>
|
||||
<div class="stat">
|
||||
<span class="label">CPU Limit:</span>
|
||||
<input type="range" id="cpuLimit" min="1" max="100" value="50" style="flex:1;margin:0 12px;">
|
||||
<span class="value" id="cpuLimitValue">50%</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="label">RAM Limit:</span>
|
||||
<input type="range" id="ramLimit" min="1" max="100" value="50" style="flex:1;margin:0 12px;">
|
||||
<span class="value" id="ramLimitValue">50%</span>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="label">SSD Limit:</span>
|
||||
<input type="range" id="diskLimit" min="1" max="100" value="50" style="flex:1;margin:0 12px;">
|
||||
<span class="value" id="diskLimitValue">50%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function fetchStats() {
|
||||
try {
|
||||
const [cpu, ram, disk, uptime] = await Promise.all([
|
||||
fetch('/cpu').then(res => res.json()),
|
||||
fetch('/ram').then(res => res.json()),
|
||||
fetch('/disk').then(res => res.json()),
|
||||
fetch('/uptime').then(res => res.json())
|
||||
]);
|
||||
document.getElementById('cpu').textContent = cpu.cpu_percent + '%';
|
||||
document.getElementById('ram').textContent = ram.percent + '%';
|
||||
document.getElementById('disk').textContent = disk.percent + '%';
|
||||
document.getElementById('uptime').textContent = uptime.uptime_seconds + ' s';
|
||||
} catch (e) {
|
||||
document.getElementById('cpu').textContent = 'Error';
|
||||
document.getElementById('ram').textContent = 'Error';
|
||||
document.getElementById('disk').textContent = 'Error';
|
||||
document.getElementById('uptime').textContent = 'Error';
|
||||
}
|
||||
}
|
||||
function formatTimestamp(ts) {
|
||||
// Try to parse as ISO string, fallback to Date.parse
|
||||
let date = new Date(ts);
|
||||
if (isNaN(date.getTime())) {
|
||||
// If ts is seconds since epoch
|
||||
date = new Date(Number(ts) * 1000);
|
||||
}
|
||||
return date.toLocaleString();
|
||||
}
|
||||
// Wall Messages CRUD
|
||||
async function fetchMessages() {
|
||||
const res = await fetch('/wall');
|
||||
const messages = await res.json();
|
||||
const ul = document.getElementById('messages');
|
||||
ul.innerHTML = '';
|
||||
messages.forEach(msg => {
|
||||
const li = document.createElement('li');
|
||||
li.style.display = 'flex';
|
||||
li.style.justifyContent = 'space-between';
|
||||
li.style.alignItems = 'center';
|
||||
li.style.padding = '8px 0';
|
||||
|
||||
const span = document.createElement('span');
|
||||
span.textContent = formatTimestamp(msg.timestamp) + " " + msg.text;
|
||||
|
||||
const editBtn = document.createElement('button');
|
||||
editBtn.textContent = 'Edit';
|
||||
editBtn.className = 'refresh-btn';
|
||||
editBtn.style.background = '#ffa500';
|
||||
editBtn.style.marginRight = '8px';
|
||||
editBtn.onclick = () => editMessage(msg);
|
||||
|
||||
const delBtn = document.createElement('button');
|
||||
delBtn.textContent = 'Delete';
|
||||
delBtn.className = 'refresh-btn';
|
||||
delBtn.style.background = '#d40000';
|
||||
delBtn.onclick = () => deleteMessage(msg.id);
|
||||
|
||||
const btns = document.createElement('span');
|
||||
btns.appendChild(editBtn);
|
||||
btns.appendChild(delBtn);
|
||||
|
||||
li.appendChild(span);
|
||||
li.appendChild(btns);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
async function addMessage(text) {
|
||||
await fetch('/wall', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({text})
|
||||
});
|
||||
fetchMessages();
|
||||
}
|
||||
|
||||
async function deleteMessage(id) {
|
||||
await fetch(`/wall/${id}`, { method: 'DELETE' });
|
||||
fetchMessages();
|
||||
}
|
||||
|
||||
function editMessage(msg) {
|
||||
const newText = prompt('Edit message:', msg.text);
|
||||
if (newText !== null && newText.trim() !== '') {
|
||||
updateMessage(msg.id, newText.trim());
|
||||
}
|
||||
}
|
||||
|
||||
async function updateMessage(id, text) {
|
||||
await fetch(`/wall/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({text})
|
||||
});
|
||||
fetchMessages();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// --- Resource Limits Sliders ---
|
||||
async function fetchLimits() {
|
||||
try {
|
||||
const res = await fetch('/limits');
|
||||
const limits = await res.json();
|
||||
document.getElementById('cpuLimit').value = limits.cpu;
|
||||
document.getElementById('ramLimit').value = limits.ram;
|
||||
document.getElementById('diskLimit').value = limits.disk;
|
||||
document.getElementById('cpuLimitValue').textContent = limits.cpu + '%';
|
||||
document.getElementById('ramLimitValue').textContent = limits.ram + '%';
|
||||
document.getElementById('diskLimitValue').textContent = limits.disk + '%';
|
||||
} catch (e) {
|
||||
// fallback: set to 50 if error
|
||||
document.getElementById('cpuLimit').value = 50;
|
||||
document.getElementById('ramLimit').value = 50;
|
||||
document.getElementById('diskLimit').value = 50;
|
||||
document.getElementById('cpuLimitValue').textContent = '50%';
|
||||
document.getElementById('ramLimitValue').textContent = '50%';
|
||||
document.getElementById('diskLimitValue').textContent = '50%';
|
||||
}
|
||||
}
|
||||
|
||||
async function updateLimits() {
|
||||
const cpu = parseInt(document.getElementById('cpuLimit').value, 10);
|
||||
const ram = parseInt(document.getElementById('ramLimit').value, 10);
|
||||
const disk = parseInt(document.getElementById('diskLimit').value, 10);
|
||||
await fetch('/limits', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ cpu, ram, disk })
|
||||
});
|
||||
}
|
||||
|
||||
function setupLimitSliders() {
|
||||
['cpu', 'ram', 'disk'].forEach(resource => {
|
||||
const slider = document.getElementById(resource + 'Limit');
|
||||
const valueSpan = document.getElementById(resource + 'LimitValue');
|
||||
slider.oninput = function() {
|
||||
valueSpan.textContent = slider.value + '%';
|
||||
};
|
||||
slider.onchange = function() {
|
||||
updateLimits();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('addMessageForm').onsubmit = function(e) {
|
||||
e.preventDefault();
|
||||
const input = document.getElementById('newMessage');
|
||||
const text = input.value.trim();
|
||||
if (text) {
|
||||
addMessage(text);
|
||||
input.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
fetchStats();
|
||||
setInterval(fetchStats, 5000); // Fetch every 5 seconds
|
||||
fetchMessages();
|
||||
setInterval(fetchMessages, 5000); // Fetch messages every 5 seconds
|
||||
fetchLimits();
|
||||
setupLimitSliders();
|
||||
setInterval(fetchLimits, 5000); // Fetch limits every 5 seconds
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user