v0.5.107: inline-редактирование в таблице, редирект / → /v2/app

This commit is contained in:
2026-06-15 13:57:48 +04:00
parent eb3c17cd68
commit ebcdb1ccb1
4 changed files with 53 additions and 14 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ipwhitelist", "name": "ipwhitelist",
"version": "0.5.106", "version": "0.5.107",
"description": "IP WhiteList microservice for cloud provider", "description": "IP WhiteList microservice for cloud provider",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
+2
View File
@@ -136,6 +136,8 @@ async function start() {
// ── UI-слой: SSR через EJS, данные из /api/v1/* ─────────────────────────── // ── UI-слой: SSR через EJS, данные из /api/v1/* ───────────────────────────
// Монтируется ПОСЛЕ /api/v1/ — не перехватывает API-запросы. // Монтируется ПОСЛЕ /api/v1/ — не перехватывает API-запросы.
// ── V2 — тестовый роутер (Keycloak → IAM → вывод) ───────────────── // ── V2 — тестовый роутер (Keycloak → IAM → вывод) ─────────────────
// Редирект корня на V2
app.get('/', (req, res) => res.redirect('/v2/app'));
const { createV2Router } = require('./v2/server'); const { createV2Router } = require('./v2/server');
app.use('/v2', createV2Router()); app.use('/v2', createV2Router());
// Хранит Bearer token в сессии, рендерит те же views/*.ejs. // Хранит Bearer token в сессии, рендерит те же views/*.ejs.
+1 -1
View File
@@ -9,7 +9,7 @@
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════
module.exports = { module.exports = {
version: '0.5.103', version: '0.5.104',
// ── IAM ────────────────────────────────────────────────────────────────── // ── IAM ──────────────────────────────────────────────────────────────────
iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user', iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user',
+49 -12
View File
@@ -215,26 +215,34 @@
<th>Комментарий</th> <th>Комментарий</th>
<th>Добавил</th> <th>Добавил</th>
<th>Добавлена</th> <th>Добавлена</th>
<th style="text-align:center;">Действия</th> <th style="text-align:center;width:80px;">Действия</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% entries.forEach(function(e) { %> <% entries.forEach(function(e) { %>
<tr style="<%= e.deleted_at ? 'opacity:.5;text-decoration:line-through;' : '' %>"> <tr id="row-<%= e.id %>" style="<%= e.deleted_at ? 'opacity:.5;text-decoration:line-through;' : '' %>">
<td><code><%= e.value_cidr %></code><% if (e.deleted_at) { %> <span style="font-size:.7rem;color:var(--red);">удалена</span><% } %></td> <td>
<td><%= e.comment || '—' %></td> <span class="view"><code><%= e.value_cidr %></code><% if (e.deleted_at) { %> <span style="font-size:.7rem;color:var(--red);">удалена</span><% } %></span>
<input class="edit" type="text" name="cidr" value="<%= e.value_cidr %>" size="18" style="display:none;padding:.3rem .5rem;border:1px solid var(--blue);border-radius:4px;font-size:.82rem;">
</td>
<td>
<span class="view"><%= e.comment || '—' %></span>
<input class="edit" type="text" name="comment" value="<%= e.comment || '' %>" size="20" style="display:none;padding:.3rem .5rem;border:1px solid var(--blue);border-radius:4px;font-size:.82rem;">
</td>
<td><%= e.created_by %></td> <td><%= e.created_by %></td>
<td><%= new Date(e.created_at).toLocaleString('ru') %></td> <td><%= new Date(e.created_at).toLocaleString('ru') %></td>
<td style="text-align:center;white-space:nowrap;"> <td style="text-align:center;white-space:nowrap;">
<% if (!e.deleted_at) { %> <% if (!e.deleted_at) { %>
<form method="POST" action="/v2/app/edit/<%= e.id %>" style="display:inline;"> <span class="view">
<input name="cidr" value="<%= e.value_cidr %>" size="18" style="padding:.3rem .5rem;border:1px solid var(--border);border-radius:4px;font-size:.82rem;"> <button class="btn btn-sm" onclick="editRow(<%= e.id %>)" title="Редактировать">✏️</button>
<input name="comment" value="<%= e.comment || '' %>" size="18" style="padding:.3rem .5rem;border:1px solid var(--border);border-radius:4px;font-size:.82rem;"> <form method="POST" action="/v2/app/delete/<%= e.id %>" style="display:inline;">
<button class="btn btn-sm">изменить</button> <button class="btn btn-sm btn-danger" onclick="return confirm('Удалить?')" title="Удалить">🗑️</button>
</form> </form>
<form method="POST" action="/v2/app/delete/<%= e.id %>" style="display:inline;"> </span>
<button class="btn btn-sm btn-danger" onclick="return confirm('Удалить?')">удалить</button> <span class="edit" style="display:none;">
</form> <button class="btn btn-sm btn-primary" onclick="saveRow(<%= e.id %>)" title="Сохранить">✓</button>
<button class="btn btn-sm" onclick="cancelEdit(<%= e.id %>)" title="Отмена">✕</button>
</span>
<% } %> <% } %>
</td> </td>
</tr> </tr>
@@ -247,6 +255,35 @@
</div> </div>
<script>
function editRow(id) {
var row = document.getElementById('row-' + id);
row.querySelectorAll('.view').forEach(function(el) { el.style.display = 'none'; });
row.querySelectorAll('.edit').forEach(function(el) { el.style.display = ''; });
row.querySelector('input[name="cidr"]').focus();
}
function cancelEdit(id) {
var row = document.getElementById('row-' + id);
row.querySelectorAll('.view').forEach(function(el) { el.style.display = ''; });
row.querySelectorAll('.edit').forEach(function(el) { el.style.display = 'none'; });
}
function saveRow(id) {
var row = document.getElementById('row-' + id);
var cidr = row.querySelector('input[name="cidr"]').value;
var comment = row.querySelector('input[name="comment"]').value;
var form = document.createElement('form');
form.method = 'POST';
form.action = '/v2/app/edit/' + id;
form.style.display = 'none';
var c = document.createElement('input'); c.name = 'cidr'; c.value = cidr; form.appendChild(c);
var m = document.createElement('input'); m.name = 'comment'; m.value = comment; form.appendChild(m);
document.body.appendChild(form);
form.submit();
}
</script>
<footer style="text-align:right;padding:.5rem 1.5rem;font-size:.72rem;color:var(--muted);">v<%= version %></footer> <footer style="text-align:right;padding:.5rem 1.5rem;font-size:.72rem;color:var(--muted);">v<%= version %></footer>
</body> </body>
</html> </html>