-
- [d.high, d.low]);
+ const minV = Math.min(...allVals) * 0.8;
+ const maxV = Math.max(...allVals) * 1.2 || 100;
+ const range = maxV - minV;
+
+ const step = w / this.data.length;
+ const candleW = Math.max(2, step * 0.7);
+
+ this.data.forEach((d, i) => {
+ const x = i * step + (step/2);
+ const color = d.ok ? '#00ff88' : '#ff3366';
+
+ const yO = h - ((d.open - minV) / range * h);
+ const yC = h - ((d.close - minV) / range * h);
+ const yH = h - ((d.high - minV) / range * h);
+ const yL = h - ((d.low - minV) / range * h);
+
+ this.ctx.beginPath();
+ this.ctx.strokeStyle = color;
+ this.ctx.lineWidth = 1;
+ this.ctx.moveTo(x, yH);
+ this.ctx.lineTo(x, yL);
+ this.ctx.stroke();
+
+ const bY = Math.min(yO, yC);
+ const bH = Math.max(1, Math.abs(yO - yC));
+
+ this.ctx.fillStyle = color;
+ this.ctx.fillRect(x - candleW/2, bY, candleW, bH);
+ });
}
}
@@ -419,6 +364,8 @@ declare(strict_types=1);
function enterMobileMonitor() {
document.getElementById('mobile-monitor').style.display = 'flex';
+ // Force refresh sparklines
+ Object.values(sparklines).forEach(s => s.resize());
refreshData();
}
@@ -428,7 +375,7 @@ declare(strict_types=1);
}
async function init() {
- const resp = await fetch('api/uptime.php?action=settings');
+ const resp = await fetch('api/uptime.php?action=settings&v=');
const data = await resp.json();
isMonitoring = data.monitoring_enabled;
updateStatusUI();
@@ -484,9 +431,9 @@ declare(strict_types=1);
}
async function refreshData() {
- const statResp = await fetch('api/uptime.php?action=stats');
+ const statResp = await fetch('api/uptime.php?action=stats&v=');
const stats = await statResp.json();
- document.getElementById('stat-total').innerText = stats.total;
+ document.getElementById('stat-total').innerText = stats.total + ' Assets';
document.getElementById('stat-latency').innerText = Math.round(stats.avg_latency) + 'ms';
const health = stats.total > 0 ? ((stats.up / stats.total) * 100).toFixed(1) : 100;
document.getElementById('stat-health').innerText = health + '%';
@@ -499,42 +446,25 @@ declare(strict_types=1);
mainChart.update('none');
}
- const listResp = await fetch('api/uptime.php?action=list');
+ const listResp = await fetch('api/uptime.php?action=list&v=');
const assets = await listResp.json();
const inventory = document.getElementById('inventory-list');
- const batteryRows = document.getElementById('battery-rows');
const mmCryptoGrid = document.getElementById('mm-crypto-grid');
inventory.innerHTML = '';
- batteryRows.innerHTML = '';
assets.forEach(u => {
const isOk = u.last_status === 'ok';
inventory.innerHTML += `${u.url} ${u.last_status} ${u.last_latency}ms `;
- // Dashboard Battery Rows
- const brow = document.createElement('div');
- brow.style.marginBottom = '10px';
- brow.innerHTML = `
- [NETWORK HEALTH: 100%] [NODES ACTIVE: 12]
+
-
-
+
+
-
+
+
+
+
-
+ [NET: 100%]
+
-
- 00:00:00
+
+
+ 00:00:00
-
@@ -306,17 +225,19 @@ declare(strict_types=1);
- Total Assets
- 0
+
-
+ Click for Candle View
+ 0 Assets
Avg Latency
@@ -279,14 +203,9 @@ declare(strict_types=1);
-
-
Asset Status (Battery View)
- -Latency Graph
- +Team Management
Manage your monitoring teams here.
API Keys
Generate keys for external integrations.
Team Management
Manage monitoring teams.
API Keys
External integrations.
🕯️
+
- REALTIME MONITOR
+ REALTIME CANDLES
@@ -324,9 +245,9 @@ declare(strict_types=1);
-
@@ -336,17 +257,32 @@ declare(strict_types=1);
const sparklines = {};
class CryptoSparkline {
- constructor(canvasId, initialData = []) {
+ constructor(canvasId) {
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
- this.data = initialData.length ? initialData : Array(30).fill(0);
- this.color = '#00ff88';
+ this.data = [];
+ this.lastVal = Math.random() * 50 + 20;
+ // Pre-fill dummy data
+ for(let i=0; i<45; i++) {
+ this.addCandle(this.lastVal + (Math.random()*10-5), 'ok');
+ }
this.resize();
window.addEventListener('resize', () => this.resize());
}
+ addCandle(val, status) {
+ const open = this.lastVal;
+ const close = val;
+ const high = Math.max(open, close) + Math.random() * 4;
+ const low = Math.max(0, Math.min(open, close) - Math.random() * 4);
+ this.data.push({ open, close, high, low, ok: status === 'ok' });
+ this.lastVal = val;
+ if (this.data.length > 55) this.data.shift();
+ }
+
resize() {
const rect = this.canvas.parentElement.getBoundingClientRect();
+ if (!rect.width) return;
this.canvas.width = rect.width * window.devicePixelRatio;
this.canvas.height = rect.height * window.devicePixelRatio;
this.ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
@@ -354,9 +290,7 @@ declare(strict_types=1);
}
update(val, status) {
- this.data.push(val);
- if (this.data.length > 50) this.data.shift();
- this.color = status === 'ok' ? '#00ff88' : '#ff3366';
+ this.addCandle(val, status);
this.draw();
}
@@ -365,36 +299,47 @@ declare(strict_types=1);
const h = this.canvas.height / window.devicePixelRatio;
this.ctx.clearRect(0, 0, w, h);
- if (this.data.length < 2) return;
-
- const min = Math.min(...this.data) * 0.8;
- const max = Math.max(...this.data) * 1.2 || 100;
- const range = max - min;
-
- this.ctx.beginPath();
- this.ctx.strokeStyle = this.color;
- this.ctx.lineWidth = 2;
- this.ctx.lineJoin = 'round';
- this.ctx.lineCap = 'round';
-
- const step = w / (this.data.length - 1);
-
- for (let i = 0; i < this.data.length; i++) {
- const x = i * step;
- const y = h - ((this.data[i] - min) / range * h);
- if (i === 0) this.ctx.moveTo(x, y);
- else this.ctx.lineTo(x, y);
+ this.ctx.strokeStyle = '#111';
+ this.ctx.lineWidth = 0.5;
+ for(let i=0; i00:00:00
- 100% HEALTH
+
+
00:00:00
+ 100% HEALTH
${u.url}${u.last_latency}ms
`;
- const bcont = document.createElement('div');
- bcont.className = 'battery-container';
- for(let i=0; i<24; i++) {
- const b = document.createElement('div');
- b.className = 'battery-bar' + (isOk ? ' ok' : ' err');
- bcont.appendChild(b);
- }
- brow.appendChild(bcont);
- batteryRows.appendChild(brow);
-
- // Mobile Crypto Grid
if (!document.getElementById(`mm-row-${u.id}`)) {
const mrow = document.createElement('div');
mrow.id = `mm-row-${u.id}`;
mrow.className = 'mm-row';
mrow.innerHTML = `
- ${u.url.split('//')[1]}
+ ${u.url.replace('https://','').replace('http://','')}
${u.last_latency}ms