ui: restore ⟳/✕ actions in edit mode only; shrink toggles; uniform 22px rows

The camera table actions column is back as the 9th column but stays empty in
the normal view — restart (⟳) and delete (✕) buttons render only on existing
cameras while bulk-editing. Restart in bulk mode no longer reloads the table
(keeps pending edits); delete reloads as before.

Row height is now truly uniform: cams-fixed cells use line-height:1 with
vertically-centred controls, the Вкл/Запись toggles shrink to 30×16, and
selects/inputs/action buttons cap at 20px so filled rows match empty slots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 21:25:33 +05:00
parent a519b78eb2
commit b29b808c6d
4 changed files with 38 additions and 9 deletions
+18 -5
View File
@@ -1257,6 +1257,12 @@ const CamSettings = {
`<td class="cell-dual">` +
`<input class="cell-in" type="text" data-f="user" value="${user}" title="Логин">` +
`<input class="cell-in" type="password" data-f="password" value="${password}" title="Пароль" placeholder="пароль">` +
`</td>` +
`<td class="actions">` +
(cam
? `<button data-act="restart" data-id="${cam.id}" title="Перезапустить камеру">⟳</button> ` +
`<button data-act="delete" data-id="${cam.id}" title="Удалить камеру (записи архива сохранятся)">✕</button>`
: "") +
`</td>`
);
},
@@ -1328,7 +1334,7 @@ const CamSettings = {
const v = (x) => this.esc(x);
const isEdit = !!cam;
return (
`<td colspan="8" class="cam-edit">` +
`<td colspan="9" class="cam-edit">` +
`<div class="cam-edit-grid">` +
`<label>ID<input type="text" id="e-id" value="${cam ? v(cam.id) : ""}" ${isEdit ? "disabled" : ""} placeholder="cam${slotNo}"></label>` +
`<label>Имя<input type="text" id="e-name" value="${cam ? v(cam.name) : ""}" placeholder="Камера ${slotNo}"></label>` +
@@ -1444,7 +1450,8 @@ const CamSettings = {
`<td><input type="checkbox" class="en-toggle" data-id="${c.id}" title="Камера включена (выкл — не работает совсем)" ${c.enabled ? "checked" : ""}></td>` +
`<td><input type="checkbox" class="rec-toggle" data-id="${c.id}" title="Запись на диск (выкл — только просмотр)" ${c.record ? "checked" : ""} ${c.enabled ? "" : "disabled"}></td>` +
`<td><select class="stor-sel" data-id="${c.id}" title="В какое хранилище писать">${this.storageOptions(c.storage_id)}</select></td>` +
`<td>${statusCell}</td>`;
`<td>${statusCell}</td>` +
`<td class="actions"></td>`;
tb.appendChild(tr);
} else {
tr.className = "slot-empty";
@@ -1452,7 +1459,8 @@ const CamSettings = {
tr.innerHTML =
`<td class="muted">${i + 1}</td>` +
`<td class="muted">—</td><td class="muted">—</td><td class="muted">—</td><td class="muted">—</td><td class="muted">—</td><td class="muted">—</td>` +
`<td class="muted">пусто</td>`;
`<td class="muted">пусто</td>` +
`<td></td>`;
tb.appendChild(tr);
}
}
@@ -1473,9 +1481,14 @@ const CamSettings = {
} else if (act === "delete") {
this.remove(id, this.byId[id] ? this.byId[id].name : id);
} else if (act === "restart") {
btn.disabled = true; btn.textContent = "…";
const prev = btn.textContent; btn.disabled = true; btn.textContent = "…";
await post(`/api/cameras/${id}/restart`);
setTimeout(() => this.load(), 1500);
if (this.bulk) { // в массовом режиме строки не перерисовываем (правки не теряем)
btn.textContent = "✓";
setTimeout(() => { btn.textContent = prev; btn.disabled = false; }, 1500);
} else {
setTimeout(() => this.load(), 1500);
}
} else if (act === "log") {
const box = document.getElementById("log-" + id);
if (!box.hidden) { box.hidden = true; return; }