feat(cron): Russian UI, table pagination 10 rows/page, bump to v1.3.11

This commit is contained in:
Naeel
2026-04-29 09:49:25 +03:00
parent 6816c038b4
commit abcd6bad36
2 changed files with 94 additions and 46 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ spec:
serviceAccountName: fission-console
containers:
- name: console
image: naeel/fission-console:v1.3.10
image: naeel/fission-console:v1.3.11
ports:
- containerPort: 8090
env:
+93 -45
View File
@@ -119,6 +119,19 @@
.status-warn { color: var(--warn); }
.status-bad { color: var(--bad); }
.empty { color: var(--text-secondary); padding: 24px 12px; text-align: center; }
.pagination {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
padding: 12px 16px; border-top: 1px solid var(--border);
}
.page-btn {
min-width: 32px; height: 28px; padding: 0 8px; border-radius: 6px;
background: #0c2b49; border: 1px solid #1d486d; color: #d7e7f7;
font-size: 12px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.page-btn:hover { background: #153d68; }
.page-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.page-btn:disabled { opacity: .35; cursor: default; }
.page-info { color: var(--text-secondary); font-size: 12px; margin-left: 6px; }
.footer {
padding-top: 12px; color: var(--text-secondary); font-size: 12px; line-height: 1.5;
}
@@ -137,12 +150,12 @@
<div class="brand-mark">N</div>
<div class="brand-text">
<div class="nubes">NUBES</div>
<div class="product">CRON METRICS</div>
<div class="product">МЕТРИКИ CRON</div>
</div>
</div>
<div class="actions">
<button class="btn ghost" id="btn-refresh">Refresh</button>
<a class="btn ghost" href="/console/">Console</a>
<button class="btn ghost" id="btn-refresh">Обновить</button>
<a class="btn ghost" href="/console/">Консоль</a>
</div>
</div>
@@ -176,7 +189,7 @@
<section class="panel">
<div class="panel-head">
<div>
<h2>History</h2>
<h2>История</h2>
<div class="meta" id="last-updated">Ожидание первых данных…</div>
</div>
<div class="meta mono" id="latest-source"></div>
@@ -185,19 +198,19 @@
<table>
<thead>
<tr>
<th>Time</th>
<th>Source</th>
<th>Host</th>
<th>Free mem</th>
<th>Avail mem</th>
<th>Used mem</th>
<th>Mem %</th>
<th>CPU 1m</th>
<th>CPU 5m</th>
<th>CPU 15m</th>
<th>Disk free</th>
<th>Uptime</th>
<th>Status</th>
<th>Время</th>
<th>Источник</th>
<th>Хост</th>
<th>Своб. МБ</th>
<th>Дост. МБ</th>
<th>Исп. МБ</th>
<th>Память %</th>
<th>ЦП 1м</th>
<th>ЦП 5м</th>
<th>ЦП 15м</th>
<th>Диск своб.</th>
<th>Аптайм</th>
<th>Статус</th>
</tr>
</thead>
<tbody id="history-body">
@@ -205,6 +218,7 @@
</tbody>
</table>
</div>
<div id="pagination" class="pagination"></div>
</section>
<div class="footer">
@@ -261,9 +275,9 @@
const days = Math.floor(sec / 86400);
const hours = Math.floor((sec % 86400) / 3600);
const mins = Math.floor((sec % 3600) / 60);
if (days > 0) return `${days}d ${hours}h ${mins}m`;
if (hours > 0) return `${hours}h ${mins}m`;
return `${Math.floor(sec)}s`;
if (days > 0) return `${days}д ${hours}ч ${mins}м`;
if (hours > 0) return `${hours}ч ${mins}м`;
return `${Math.floor(sec)}с`;
}
function cls(status) {
@@ -286,35 +300,48 @@
function renderSummary(latest, count) {
if (!latest) {
summaryEl.innerHTML = [
card('Snapshots', '0', 'Waiting for cron POSTs'),
card('Free memory', '—', 'MB'),
card('Available memory', '—', 'MB'),
card('Used memory', '—', 'MB'),
card('CPU load', '—', '1m / 5m / 15m'),
card('Disk free', '—', 'GB')
card('Снимки', '0', 'Ожидание cron-запросов'),
card('Своб. память', '—', 'МБ'),
card('Дост. память', '—', 'МБ'),
card('Исп. память', '—', 'МБ'),
card('Нагрузка ЦП', '—', '1м / 5м / 15м'),
card('Диск своб.', '—', 'ГБ')
].join('');
pointsBadge.textContent = '0 points';
pointsBadge.textContent = '0 снимков';
return;
}
summaryEl.innerHTML = [
card('Snapshots', String(count), `Source: ${latest.source || 'cron'}`),
card('Free memory', fmtNum(latest.memory_free_mb, 1, ' MB'), latest.hostname || '—'),
card('Available memory', fmtNum(latest.memory_available_mb, 1, ' MB'), 'Current available RAM'),
card('Used memory', fmtNum(latest.memory_used_mb, 1, ' MB'), `Mem ${fmtNum(latest.memory_percent, 1, '%')}`),
card('CPU load', [fmtNum(latest.cpu_load_1m, 2), fmtNum(latest.cpu_load_5m, 2), fmtNum(latest.cpu_load_15m, 2)].join(' / '), '1m / 5m / 15m'),
card('Disk free', fmtNum(latest.disk_free_gb, 1, ' GB'), `Uptime ${fmtUptime(latest.uptime_sec)}`)
card('Снимки', String(count), `Источник: ${latest.source || 'cron'}`),
card('Своб. память', fmtNum(latest.memory_free_mb, 1, ' МБ'), latest.hostname || '—'),
card('Дост. память', fmtNum(latest.memory_available_mb, 1, ' МБ'), 'Доступная RAM'),
card('Исп. память', fmtNum(latest.memory_used_mb, 1, ' МБ'), `Память ${fmtNum(latest.memory_percent, 1, '%')}`),
card('Нагрузка ЦП', [fmtNum(latest.cpu_load_1m, 2), fmtNum(latest.cpu_load_5m, 2), fmtNum(latest.cpu_load_15m, 2)].join(' / '), '1м / 5м / 15м'),
card('Диск своб.', fmtNum(latest.disk_free_gb, 1, ' ГБ'), `Аптайм ${fmtUptime(latest.uptime_sec)}`)
].join('');
pointsBadge.textContent = `${count} point(s)`;
pointsBadge.textContent = `${count} снимк${count === 1 ? '' : 'ов'}`;
}
function renderTable(history) {
if (!history.length) {
const PAGE_SIZE = 10;
let allHistory = [];
let currentPage = 1;
function renderPage(page) {
const total = allHistory.length;
const pages = Math.max(1, Math.ceil(total / PAGE_SIZE));
currentPage = Math.min(Math.max(1, page), pages);
const pg = document.getElementById('pagination');
if (!total) {
historyBody.innerHTML = '<tr><td class="empty" colspan="13">Данных пока нет</td></tr>';
pg.innerHTML = '';
return;
}
historyBody.innerHTML = history.slice().reverse().map(function (item) {
const start = (currentPage - 1) * PAGE_SIZE;
const slice = allHistory.slice(start, start + PAGE_SIZE);
historyBody.innerHTML = slice.map(function (item) {
return `
<tr>
<td class="mono">${fmtTime(item.timestamp)}</td>
@@ -327,12 +354,33 @@
<td class="mono">${fmtNum(item.cpu_load_1m, 2)}</td>
<td class="mono">${fmtNum(item.cpu_load_5m, 2)}</td>
<td class="mono">${fmtNum(item.cpu_load_15m, 2)}</td>
<td class="mono">${fmtNum(item.disk_free_gb, 1, ' GB')}</td>
<td class="mono">${fmtNum(item.disk_free_gb, 1, ' ГБ')}</td>
<td class="mono">${fmtUptime(item.uptime_sec)}</td>
<td class="${cls(item.status)}">${item.status || 'ok'}</td>
</tr>
`;
}).join('');
if (pages <= 1) { pg.innerHTML = ''; return; }
let btns = `<button class="page-btn" id="pg-prev" ${currentPage === 1 ? 'disabled' : ''}>←</button>`;
for (let i = 1; i <= pages; i++) {
btns += `<button class="page-btn ${i === currentPage ? 'active' : ''}" data-page="${i}">${i}</button>`;
}
btns += `<button class="page-btn" id="pg-next" ${currentPage === pages ? 'disabled' : ''}>→</button>`;
btns += `<span class="page-info">стр. ${currentPage} из ${pages} · всего ${total}</span>`;
pg.innerHTML = btns;
pg.querySelector('#pg-prev').addEventListener('click', function () { renderPage(currentPage - 1); });
pg.querySelector('#pg-next').addEventListener('click', function () { renderPage(currentPage + 1); });
pg.querySelectorAll('[data-page]').forEach(function (btn) {
btn.addEventListener('click', function () { renderPage(Number(btn.dataset.page)); });
});
}
function renderTable(history) {
allHistory = history.slice().reverse();
renderPage(1);
}
function updateMeta(history) {
@@ -358,17 +406,17 @@
updateMeta(history);
} catch (err) {
summaryEl.innerHTML = [
card('Snapshots', '—', 'Load error'),
card('Free memory', '—', err.message),
card('Available memory', '—', 'Check backend'),
card('Used memory', '—', 'Check cron function'),
card('CPU load', '—', 'Check backend'),
card('Disk free', '—', 'Check ingest')
card('Снимки', '—', 'Ошибка загрузки'),
card('Своб. память', '—', err.message),
card('Дост. память', '—', 'Проверить backend'),
card('Исп. память', '—', 'Проверить cron-функцию'),
card('Нагрузка ЦП', '—', 'Проверить backend'),
card('Диск своб.', '—', 'Проверить приём данных')
].join('');
historyBody.innerHTML = `<tr><td class="empty" colspan="13">Ошибка загрузки: ${err.message}</td></tr>`;
lastUpdatedEl.textContent = 'Ошибка обновления';
latestSourceEl.textContent = '';
pointsBadge.textContent = '0 points';
pointsBadge.textContent = '0 снимков';
}
}