feat: v1.3.67 — UI table refactor: remove Env/Pkg columns, add Type icon + Info modal

This commit is contained in:
“Naeel”
2026-05-08 09:19:01 +04:00
parent f9bb898893
commit 8f4659d2ef
4 changed files with 86 additions and 12 deletions
+1 -1
View File
@@ -55,7 +55,7 @@ spec:
serviceAccountName: fission-console
containers:
- name: console
image: naeel/fission-console:v1.3.66
image: naeel/fission-console:v1.3.67
imagePullPolicy: Always
ports:
- containerPort: 8090
+15 -4
View File
@@ -102,7 +102,7 @@
<div class="nubes">NUBES</div>
<div class="product">FISSION CONSOLE</div>
</div>
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.66</div>
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.67</div>
</div>
<div class="row" style="margin:0;">
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
@@ -146,8 +146,7 @@
<thead>
<tr>
<th>Имя</th>
<th>Окружение</th>
<th>Пакет</th>
<th title="Тип источника функции">Тип</th>
<th>Создана</th>
<th>Изменена</th>
<th>Маршрут</th>
@@ -384,6 +383,18 @@
</div>
</div>
<div id="info-modal" class="modal">
<div class="panel" style="width:560px; max-width:95vw;">
<h3 id="info-title">Информация о функции</h3>
<table class="info-table">
<tbody id="info-rows"></tbody>
</table>
<div class="actions" style="margin-top:14px;">
<button class="btn ghost" onclick="closeInfo()">Закрыть</button>
</div>
</div>
</div>
<div id="logs-modal" class="modal">
<div class="panel" style="width:700px; max-width:95vw;">
<h3 id="logs-title">Логи функции</h3>
@@ -474,7 +485,7 @@
</div>
<div class="actions" style="justify-content:space-between; align-items:center;">
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.66</span>
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.67</span>
<button class="btn ghost" onclick="closeHelp()">Закрыть</button>
</div>
</div>
+17 -5
View File
@@ -5,7 +5,7 @@ async function reloadAll() {
// Показываем таблицу сразу с placeholder'ом
document.getElementById('fn-rows').innerHTML =
'<tr><td colspan="9" style="color:var(--text-secondary); font-style:italic;">⏳ Загружаем функции...</td></tr>';
'<tr><td colspan="8" style="color:var(--text-secondary); font-style:italic;">⏳ Загружаем функции...</td></tr>';
try {
const [envs, pkgs, fns, http, times] = await Promise.all([
@@ -35,6 +35,8 @@ async function reloadAll() {
const ann = meta.annotations || {};
const env = (spec.environment && spec.environment.name) || '-';
const pkg = (spec.package && spec.package.packageref && spec.package.packageref.name) || '-';
const entrypoint = (spec.package && spec.package.functionName) || '-';
const timeout = spec.functionTimeout || 60;
const name = (f.metadata && f.metadata.name) || '-';
const trig = httpTriggerByFn(name) || {};
const timeTrig = timeTriggerByFn(name) || {};
@@ -45,18 +47,28 @@ async function reloadAll() {
const cronCell = cron ? '<span class="chip">' + h(cron) + '</span>' : '<span class="mono" style="color:var(--text-secondary)">—</span>';
const createdAt = ann['fission-console/created-at'] || meta.creationTimestamp || '-';
const updatedAt = ann['fission-console/updated-at'] || createdAt;
const sourceType = ann['fission-console/source-type'] || 'code';
const sourceIcon = sourceType === 'archive'
? '<span title="Из архива (.zip)" style="font-size:1.1em; cursor:default;">📦</span>'
: '<span title="Из кода (редактор)" style="font-size:1.1em; cursor:default;">📝</span>';
var isGo = /go[-_]env/.test(env);
var isTf = /^tf-/.test(name);
var tfBadge = (isGo || isTf) ? '<span class="chip" style="background:#555;color:#ffa" title="Управляется Terraform. Изменения могут быть перезаписаны при terraform apply.">TF</span> ' : '';
// Сохраняем все данные в data-атрибуте для openInfo (избегаем повторного запроса)
var infoData = h(JSON.stringify({
name: name, env: env, pkg: pkg, entrypoint: entrypoint, timeout: timeout,
route: route, methods: methods, sourceType: sourceType,
createdAt: createdAt, updatedAt: updatedAt, cron: cron
}));
var actions = tfBadge +
'<button class="btn ghost" onclick="openInfo(\'' + h(name) + '\', this)" data-info="' + infoData + '">Info</button> ' +
'<button class="btn ghost" onclick="openEdit(\'' + h(name) + '\')">Ред.</button> ' +
'<button class="btn ghost" onclick="openInvoke(\'' + h(name) + '\')">Вызов</button> ' +
'<button class="btn ghost" onclick="openLogs(\'' + h(name) + '\')">Логи</button> ' +
'<button class="btn danger" onclick="removeFn(\'' + h(name) + '\')">Удалить</button>';
return '<tr>' +
'<td class="mono">' + h(name) + '</td>' +
'<td>' + h(env) + '</td>' +
'<td class="mono">' + h(pkg) + '</td>' +
'<td style="text-align:center;">' + sourceIcon + '</td>' +
'<td>' + timestampCell(createdAt) + '</td>' +
'<td>' + timestampCell(updatedAt) + '</td>' +
'<td class="mono">' + h(route) + '</td>' +
@@ -69,7 +81,7 @@ async function reloadAll() {
var fnList = fns || [];
if (fnList.length === 0) {
progress.stop('Загружено: нет функций', '');
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="9">Нет функций</td></tr>';
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="8">Нет функций</td></tr>';
} else {
// Рендерим первую строку сразу — убираем placeholder
var tbody = document.getElementById('fn-rows');
@@ -90,7 +102,7 @@ async function reloadAll() {
setTimeout(appendNext, 40);
}
} catch (e) {
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="9">Load error: ' + e.message + '</td></tr>';
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="8">Load error: ' + e.message + '</td></tr>';
progress.stop('Ошибка загрузки: ' + e.message, 'err');
}
}
+53 -2
View File
@@ -46,12 +46,12 @@ function makeDraggable(modalId) {
// Инициализация после загрузки DOM
document.addEventListener('DOMContentLoaded', function() {
['create-code-modal', 'create-archive-modal', 'edit-modal', 'help-modal', 'invoke-modal', 'logs-modal'].forEach(makeDraggable);
['create-code-modal', 'create-archive-modal', 'edit-modal', 'help-modal', 'invoke-modal', 'logs-modal', 'info-modal'].forEach(makeDraggable);
// ESC закрывает активное модальное окно
document.addEventListener('keydown', function(e) {
if (e.key !== 'Escape') return;
var modals = ['create-code-modal', 'create-archive-modal', 'edit-modal', 'help-modal', 'invoke-modal', 'logs-modal'];
var modals = ['create-code-modal', 'create-archive-modal', 'edit-modal', 'help-modal', 'invoke-modal', 'logs-modal', 'info-modal'];
for (var i = 0; i < modals.length; i++) {
var el = document.getElementById(modals[i]);
if (el && el.classList.contains('open')) {
@@ -179,3 +179,54 @@ async function _fetchLogs(name) {
out.value = 'Ошибка загрузки логов: ' + e.message;
}
}
// openInfo — открывает модалку с подробной информацией о функции.
// Данные берутся из data-атрибута кнопки (без дополнительного запроса к API).
function openInfo(name, btn) {
var raw = btn ? btn.getAttribute('data-info') : null;
var info = null;
try { info = raw ? JSON.parse(raw) : null; } catch(e) {}
if (!info) {
document.getElementById('info-rows').innerHTML = '<tr><td colspan="2">Нет данных</td></tr>';
document.getElementById('info-title').textContent = 'Информация: ' + name;
document.getElementById('info-modal').classList.add('open');
return;
}
function copyBtn(val) {
return val && val !== '-'
? ' <button class="btn ghost" style="padding:1px 6px; font-size:11px;" onclick="navigator.clipboard.writeText(\'' + val.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + '\')">📋</button>'
: '';
}
var rows = [
['Имя', info.name],
['Окружение', info.env],
['Пакет', info.pkg],
['Entrypoint', info.entrypoint],
['Таймаут', info.timeout ? info.timeout + ' сек' : '-'],
['Тип источника', info.sourceType === 'archive' ? '📦 archive' : '📝 code'],
['Маршрут', info.route],
['Методы', Array.isArray(info.methods) && info.methods.length ? info.methods.join(', ') : '-'],
['Cron', info.cron || '-'],
['Создана', info.createdAt],
['Изменена', info.updatedAt],
];
var html = rows.map(function(r) {
var val = r[1] || '-';
return '<tr>' +
'<td style="color:var(--text-secondary);padding:4px 10px 4px 0;white-space:nowrap;vertical-align:top;">' + h(r[0]) + '</td>' +
'<td class="mono" style="word-break:break-all;padding:4px 0;">' + h(val) + copyBtn(val) + '</td>' +
'</tr>';
}).join('');
document.getElementById('info-title').textContent = 'Информация: ' + name;
document.getElementById('info-rows').innerHTML = html;
document.getElementById('info-modal').classList.add('open');
}
// closeInfo — закрывает Info-модалку.
function closeInfo() {
document.getElementById('info-modal').classList.remove('open');
}