NathMen12 commited on
Commit
e29f91d
·
verified ·
1 Parent(s): af47e71

Update public/admin.html

Browse files
Files changed (1) hide show
  1. public/admin.html +32 -101
public/admin.html CHANGED
@@ -5,7 +5,6 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Admin Panel - Translator API</title>
7
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
8
- <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
9
  <style>
10
  * { box-sizing: border-box; margin: 0; padding: 0; }
11
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; min-height: 100vh; }
@@ -46,6 +45,7 @@
46
  .auth-box button { width: 100%; padding: 12px; background: #1a73e8; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; }
47
  .auth-box button:hover { background: #1557b0; }
48
  .error-msg { color: #dc3545; margin-bottom: 15px; display: none; }
 
49
  </style>
50
  </head>
51
  <body>
@@ -129,10 +129,7 @@
129
  let charts = {};
130
  let refreshInterval;
131
 
132
- // Fenêtre d'affichage fixe : 120 secondes
133
- const WINDOW_MS = 120_000;
134
- const MAX_POINTS = 120; // 1 point/seconde
135
-
136
  window.onload = () => {
137
  const savedCode = sessionStorage.getItem('adminCode');
138
  if (savedCode) {
@@ -171,8 +168,6 @@
171
  sessionStorage.removeItem('adminCode');
172
  document.getElementById('authModal').classList.remove('hidden');
173
  if (refreshInterval) clearInterval(refreshInterval);
174
- Object.values(charts).forEach(c => c.destroy());
175
- charts = {};
176
  }
177
 
178
  function apiCall(endpoint) {
@@ -184,59 +179,41 @@
184
  function initDashboard() {
185
  createCharts();
186
  loadData();
187
- // Rafraîchissement toutes les 1 seconde
188
- refreshInterval = setInterval(loadData, 1000);
189
  }
190
 
191
  function createCharts() {
192
- const now = Date.now();
193
- // Labels fixes : 120 points, 1 par seconde, du plus ancien au plus récent
194
- const initialLabels = Array.from({ length: MAX_POINTS }, (_, i) => now - WINDOW_MS + i * 1000);
195
- const emptyData = Array(MAX_POINTS).fill(null);
196
-
197
  const commonOptions = {
198
  responsive: true,
199
  maintainAspectRatio: false,
200
- animation: { duration: 0 }, // Pas d'animation = pas de "saut"
201
- interaction: { mode: 'index', intersect: false },
202
  scales: {
203
- x: {
204
- type: 'time',
205
- time: {
206
- unit: 'second',
207
- displayFormats: { second: 'HH:mm:ss' },
208
- min: now - WINDOW_MS,
209
- max: now
210
- },
211
- title: { display: true, text: 'Temps' },
212
- ticks: { maxTicksLimit: 10, source: 'auto' }
213
- },
214
- y: { beginAtZero: true }
215
  },
216
- plugins: { legend: { display: false } },
217
- elements: { point: { radius: 0 } }
218
  };
219
 
220
  charts.cpu = new Chart(document.getElementById('cpuChart'), {
221
  type: 'line',
222
- data: { labels: initialLabels, datasets: [{ label: 'CPU %', data: emptyData, borderColor: '#1a73e8', backgroundColor: 'rgba(26,115,232,0.1)', fill: true, tension: 0.3 }] },
223
- options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, min: 0, max: 100, title: { display: true, text: '% CPU' } } } }
224
  });
225
 
226
  charts.ram = new Chart(document.getElementById('ramChart'), {
227
  type: 'line',
228
- data: { labels: initialLabels, datasets: [{ label: 'RAM (MB)', data: emptyData, borderColor: '#34a853', backgroundColor: 'rgba(52,168,83,0.1)', fill: true, tension: 0.3 }] },
229
- options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, title: { display: true, text: 'MB' } } } }
230
  });
231
 
232
  charts.requests = new Chart(document.getElementById('requestsChart'), {
233
- type: 'bar', // Barres = plus lisible pour req/min
234
- data: { labels: initialLabels, datasets: [{ label: 'Req/min', data: emptyData, backgroundColor: 'rgba(234,67,53,0.6)', borderColor: '#ea4335', borderWidth: 1 }] },
235
  options: {
236
  ...commonOptions,
237
  scales: {
238
- x: { ...commonOptions.scales.x, title: { display: true, text: 'Temps' } },
239
- y: { ...commonOptions.scales.y, beginAtZero: true, title: { display: true, text: 'Requêtes/min' } }
240
  }
241
  }
242
  });
@@ -254,47 +231,17 @@
254
  }
255
 
256
  function updateMachinesTab(data) {
257
- const now = Date.now();
258
- const windowStart = now - WINDOW_MS;
259
-
260
- // --- CPU : fusionner l'historique + point actuel, garder fenêtre 120s ---
261
- const cpuMap = new Map();
262
- data.cpuHistory.forEach(m => cpuMap.set(m.timestamp, m.cpu));
263
- // Ajouter le point actuel (currentCpu) si dispo
264
- if (data.currentCpu !== undefined) cpuMap.set(now, data.currentCpu);
265
-
266
- const cpuLabels = [];
267
- const cpuValues = [];
268
- for (let t = windowStart; t <= now; t += 1000) {
269
- cpuLabels.push(t);
270
- cpuValues.push(cpuMap.has(t) ? cpuMap.get(t) : null); // null = gap dans la courbe
271
- }
272
-
273
- charts.cpu.data.labels = cpuLabels;
274
- charts.cpu.data.datasets[0].data = cpuValues;
275
- charts.cpu.options.scales.x.min = windowStart;
276
- charts.cpu.options.scales.x.max = now;
277
  charts.cpu.update('none');
278
 
279
- // --- RAM : même logique ---
280
- const ramMap = new Map();
281
- data.ramHistory.forEach(m => ramMap.set(m.timestamp, (m.used / 1024 / 1024).toFixed(1)));
282
- if (data.currentRam !== undefined) ramMap.set(now, (data.currentRam / 1024 / 1024).toFixed(1));
283
-
284
- const ramLabels = [];
285
- const ramValues = [];
286
- for (let t = windowStart; t <= now; t += 1000) {
287
- ramLabels.push(t);
288
- ramValues.push(ramMap.has(t) ? ramMap.get(t) : null);
289
- }
290
-
291
- charts.ram.data.labels = ramLabels;
292
- charts.ram.data.datasets[0].data = ramValues;
293
- charts.ram.options.scales.x.min = windowStart;
294
- charts.ram.options.scales.x.max = now;
295
  charts.ram.update('none');
296
 
297
- // --- Workers ---
298
  const workersList = document.getElementById('workersList');
299
  if (data.workers.length === 0) {
300
  workersList.innerHTML = '<div class="loading">Aucun worker connecté</div>';
@@ -312,34 +259,18 @@
312
  }
313
 
314
  function updateRequestsTab(data) {
 
315
  const now = Date.now();
316
- const windowStart = now - WINDOW_MS;
317
-
318
- // Compter requêtes par seconde (fenêtre glissante 60s pour req/min)
319
- const reqPerSec = new Map();
320
- data.requests.forEach(r => {
321
- if (r.timestamp >= windowStart) {
322
- const sec = Math.floor(r.timestamp / 1000) * 1000;
323
- reqPerSec.set(sec, (reqPerSec.get(sec) || 0) + 1);
324
- }
325
- });
326
-
327
- // Calculer req/min = somme des 60 dernières secondes pour chaque seconde
328
- const labels = [];
329
- const values = [];
330
- for (let t = windowStart; t <= now; t += 1000) {
331
- labels.push(t);
332
- let sum = 0;
333
- for (let i = 0; i < 60; i++) {
334
- sum += reqPerSec.get(t - i * 1000) || 0;
335
- }
336
- values.push(sum);
337
  }
338
 
339
- charts.requests.data.labels = labels;
340
- charts.requests.data.datasets[0].data = values;
341
- charts.requests.options.scales.x.min = windowStart;
342
- charts.requests.options.scales.x.max = now;
343
  charts.requests.update('none');
344
 
345
  // Stats
@@ -350,7 +281,7 @@
350
  <div class="metric"><span class="metric-label">Total requêtes (2 min)</span><span class="metric-value">${totalLast2min}</span></div>
351
  <div class="metric"><span class="metric-label">Durée moyenne</span><span class="metric-value">${avgDuration} ms</span></div>
352
  <div class="metric"><span class="metric-label">Workers actifs</span><span class="metric-value">${data.workers.filter(w => w.jobsActive > 0).length}</span></div>
353
- <div class="metric"><span class="metric-label">Taux actuel</span><span class="metric-value">${values[values.length-1] || 0} req/min</span></div>
354
  `;
355
  }
356
 
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Admin Panel - Translator API</title>
7
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
 
8
  <style>
9
  * { box-sizing: border-box; margin: 0; padding: 0; }
10
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; min-height: 100vh; }
 
45
  .auth-box button { width: 100%; padding: 12px; background: #1a73e8; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; }
46
  .auth-box button:hover { background: #1557b0; }
47
  .error-msg { color: #dc3545; margin-bottom: 15px; display: none; }
48
+ .refresh-info { font-size: 12px; color: #999; margin-left: 10px; }
49
  </style>
50
  </head>
51
  <body>
 
129
  let charts = {};
130
  let refreshInterval;
131
 
132
+ // Check auth on load
 
 
 
133
  window.onload = () => {
134
  const savedCode = sessionStorage.getItem('adminCode');
135
  if (savedCode) {
 
168
  sessionStorage.removeItem('adminCode');
169
  document.getElementById('authModal').classList.remove('hidden');
170
  if (refreshInterval) clearInterval(refreshInterval);
 
 
171
  }
172
 
173
  function apiCall(endpoint) {
 
179
  function initDashboard() {
180
  createCharts();
181
  loadData();
182
+ refreshInterval = setInterval(loadData, 5000);
 
183
  }
184
 
185
  function createCharts() {
 
 
 
 
 
186
  const commonOptions = {
187
  responsive: true,
188
  maintainAspectRatio: false,
189
+ animation: { duration: 300 },
 
190
  scales: {
191
+ x: { type: 'time', time: { unit: 'second', displayFormats: { second: 'HH:mm:ss' } }, title: { display: true, text: 'Temps' } },
192
+ y: { beginAtZero: true, title: { display: true } }
 
 
 
 
 
 
 
 
 
 
193
  },
194
+ plugins: { legend: { display: false } }
 
195
  };
196
 
197
  charts.cpu = new Chart(document.getElementById('cpuChart'), {
198
  type: 'line',
199
+ data: { datasets: [{ label: 'CPU %', data: [], borderColor: '#1a73e8', backgroundColor: 'rgba(26,115,232,0.1)', fill: true, tension: 0.3 }] },
200
+ options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, max: 100, title: { display: true, text: '% CPU' } } } }
201
  });
202
 
203
  charts.ram = new Chart(document.getElementById('ramChart'), {
204
  type: 'line',
205
+ data: { datasets: [{ label: 'RAM Used (GB)', data: [], borderColor: '#34a853', backgroundColor: 'rgba(52,168,83,0.1)', fill: true, tension: 0.3 }] },
206
+ options: { ...commonOptions, scales: { ...commonOptions.scales, y: { ...commonOptions.scales.y, title: { display: true, text: 'GB' } } } }
207
  });
208
 
209
  charts.requests = new Chart(document.getElementById('requestsChart'), {
210
+ type: 'bar',
211
+ data: { labels: [], datasets: [{ label: 'Req/min', data: [], backgroundColor: '#ea4335' }] },
212
  options: {
213
  ...commonOptions,
214
  scales: {
215
+ x: { type: 'time', time: { unit: 'second', displayFormats: { second: 'HH:mm:ss' } }, title: { display: true, text: 'Temps' } },
216
+ y: { beginAtZero: true, title: { display: true, text: 'Requêtes/min' } }
217
  }
218
  }
219
  });
 
231
  }
232
 
233
  function updateMachinesTab(data) {
234
+ // Update CPU chart
235
+ const cpuData = data.cpuHistory.map(m => ({ x: new Date(m.timestamp), y: (m.cpu / 1000000).toFixed(1) })).slice(-60);
236
+ charts.cpu.data.datasets[0].data = cpuData;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  charts.cpu.update('none');
238
 
239
+ // Update RAM chart
240
+ const ramData = data.ramHistory.map(m => ({ x: new Date(m.timestamp), y: (m.used / 1024 / 1024 / 1024).toFixed(2) })).slice(-60);
241
+ charts.ram.data.datasets[0].data = ramData;
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  charts.ram.update('none');
243
 
244
+ // Update workers list
245
  const workersList = document.getElementById('workersList');
246
  if (data.workers.length === 0) {
247
  workersList.innerHTML = '<div class="loading">Aucun worker connecté</div>';
 
259
  }
260
 
261
  function updateRequestsTab(data) {
262
+ // Group requests by 10-second intervals
263
  const now = Date.now();
264
+ const intervals = [];
265
+ for (let i = 11; i >= 0; i--) {
266
+ const start = now - (i + 1) * 10000;
267
+ const end = now - i * 10000;
268
+ const count = data.requests.filter(r => r.timestamp >= start && r.timestamp < end).length * 6; // project to per minute
269
+ intervals.push({ time: new Date(start), count });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
271
 
272
+ charts.requests.data.labels = intervals.map(i => i.time);
273
+ charts.requests.data.datasets[0].data = intervals.map(i => i.count);
 
 
274
  charts.requests.update('none');
275
 
276
  // Stats
 
281
  <div class="metric"><span class="metric-label">Total requêtes (2 min)</span><span class="metric-value">${totalLast2min}</span></div>
282
  <div class="metric"><span class="metric-label">Durée moyenne</span><span class="metric-value">${avgDuration} ms</span></div>
283
  <div class="metric"><span class="metric-label">Workers actifs</span><span class="metric-value">${data.workers.filter(w => w.jobsActive > 0).length}</span></div>
284
+ <div class="metric"><span class="metric-label">Taux actuel</span><span class="metric-value">${data.requestRate} req/min</span></div>
285
  `;
286
  }
287