feat(ui): vervang start/restart/stop knoppen door 3-dot dropdown in containers en pods

This commit is contained in:
kodi
2026-02-20 09:05:08 +01:00
parent d18d0c0f77
commit c1f8e8335b
+97 -12
View File
@@ -122,6 +122,19 @@
.btn.ok{border-color: rgba(45,212,191,.6)}
.btn.bad{border-color: rgba(251,113,133,.6)}
.btn.warn{border-color: rgba(251,191,36,.6)}
.btn.icon {
padding: 6px 7px;
min-width: 28px;
height: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 13px;
border-radius: 8px;
}
.btn.icon span {
pointer-events: none;
}
.pill{
display:inline-flex; align-items:center; gap:8px;
padding:6px 10px;
@@ -233,6 +246,45 @@
opacity: 0.65;
font-style: italic;
}
/* 3-dot dropdown actions */
.actions-menu { position: relative; display: inline-flex; }
.menuPanel{
position: absolute;
right: 0;
top: 34px;
min-width: 140px;
background: linear-gradient(180deg, rgba(17,26,46,.98), rgba(14,23,48,.98));
border: 1px solid rgba(36,52,95,.9);
border-radius: 12px;
box-shadow: var(--shadow);
padding: 6px;
display: none;
z-index: 50;
}
.menuPanel.open { display: block; }
.menuItem{
width: 100%;
text-align: left;
padding: 8px 10px;
border-radius: 10px;
border: 1px solid transparent;
background: transparent;
color: var(--text);
cursor: pointer;
font-size: 13px;
}
.menuItem:hover{
background: rgba(96,165,250,.10);
border-color: rgba(96,165,250,.25);
}
.menuItem.ok{ border-color: rgba(45,212,191,.35); }
.menuItem.warn{ border-color: rgba(251,191,36,.35); }
.menuItem.bad{ border-color: rgba(251,113,133,.35); }
</style>
</head>
@@ -516,6 +568,25 @@
function hideModal() { document.getElementById('modalBack').style.display = 'none'; }
function closeModal(e){ if(e.target.id === 'modalBack') hideModal(); }
function closeAllMenus() {
document.querySelectorAll('.menuPanel.open').forEach(p => p.classList.remove('open'));
}
function toggleMenu(menuId) {
const el = document.getElementById(menuId);
if (!el) return;
const willOpen = !el.classList.contains('open');
closeAllMenus();
if (willOpen) el.classList.add('open');
}
// klik buiten menu = sluiten
document.addEventListener('click', (e) => {
// als je op een menu knop klikt, laat toggleMenu het regelen
if (e.target.closest('.actions-menu')) return;
closeAllMenus();
});
// ---- Tabs ----
let currentTab = 'dashboard';
function setTab(tab) {
@@ -656,12 +727,28 @@
localStorage.setItem('pod_group_collapsed:' + pod, v ? '1' : '0');
}
function renderActionsDropdown(menuId, actionFn, targetEsc) {
// actionFn is string: "containerAction" of "podAction"
// targetEsc is al esc(...) dus veilig in onclick
return `
<span class="actions-menu">
<button class="btn icon" title="Acties" onclick="toggleMenu('${menuId}')">⋮</button>
<div class="menuPanel" id="${menuId}">
<button class="menuItem ok" onclick="${actionFn}('start','${targetEsc}'); closeAllMenus();">Start</button>
<button class="menuItem warn" onclick="${actionFn}('restart','${targetEsc}'); closeAllMenus();">Restart</button>
<button class="menuItem bad" onclick="${actionFn}('stop','${targetEsc}'); closeAllMenus();">Stop</button>
</div>
</span>
`;
}
function renderContainerRow(c) {
const name = (c.Names && c.Names[0]) ? c.Names[0] : (c.Names || c.Name || c.name || '');
const status = c.Status || c.State || c.state || '';
const podName = c.PodName || '-';
const image = c.Image || c.image || '';
const managed = c._dashboard_source || 'podman';
const menuId = `menu-${cssSafeId('c:' + normalizeContainerName(name))}`;
const inPod = !!(c.PodName && String(c.PodName).trim());
const ports = inPod
? '' // verberg bij pod-containers
@@ -680,11 +767,9 @@
<td>${ports || '-'}</td>
<td>
<div class="flex">
<button class="btn small" onclick="containerInspect('${esc(name)}')">Inspect</button>
<button class="btn small" onclick="containerLogs('${esc(name)}')">Logs</button>
<button class="btn small ok" onclick="containerAction('start','${esc(name)}')">Start</button>
<button class="btn small warn" onclick="containerAction('restart','${esc(name)}')">Restart</button>
<button class="btn small bad" onclick="containerAction('stop','${esc(name)}')">Stop</button>
<button class="btn icon" title="Inspect" onclick="containerInspect('${esc(name)}')">🔍</button>
<button class="btn icon" title="Logs" onclick="containerLogs('${esc(name)}')">📄</button>
${renderActionsDropdown(menuId, 'containerAction', esc(name))}
</div>
</td>
</tr>
@@ -727,6 +812,7 @@
const collapsed = _isCollapsed(pod);
const isRealPod = (pod !== '(geen pod)');
const total = items.length;
const podMenuId = `menu-${cssSafeId('p:' + pod)}`;
let podPortsText = "-";
if (isRealPod) {
@@ -779,14 +865,13 @@
<td class="mono">${esc(podPortsText)}</td>
<td>
${isRealPod ? `
<div class="flex">
<button class="btn small" disabled style="visibility:hidden;">Inspect</button>
<button class="btn small" disabled style="visibility:hidden;">Logs</button>
<div class="flex">
<!-- placeholders voor uitlijning -->
<button class="btn icon" disabled style="visibility:hidden;" aria-hidden="true" tabindex="-1">🔍</button>
<button class="btn icon" disabled style="visibility:hidden;" aria-hidden="true" tabindex="-1">📄</button>
<button class="btn small ok" onclick="podAction('start','${esc(pod)}')">Start</button>
<button class="btn small warn" onclick="podAction('restart','${esc(pod)}')">Restart</button>
<button class="btn small bad" onclick="podAction('stop','${esc(pod)}')">Stop</button>
</div>
${renderActionsDropdown(podMenuId, 'podAction', esc(pod))}
</div>
` : '<span class="muted">-</span>'}
</td>
</tr>