/** * javascript/containers.js * * Containers panel: table of all containers with lifecycle actions * (start/stop/restart/remove), backed entirely by ajax/containers.php. */ (function () { 'use strict'; const P = window.Podman; let allContainers = []; let filter = 'all'; let searchTerm = ''; function iconLabel(name) { return P.escapeHtml(name.slice(0, 2).toUpperCase()); } function rowHtml(c) { const cpuMem = c.state === 'running' ? 'running' : ''; return '' + '' + '' + P.escapeHtml(c.health || c.state) + '' + '
' + iconLabel(c.name) + '' + P.escapeHtml(c.name) + '
' + '' + P.escapeHtml(c.image) + '' + '' + cpuMem + '' + '' + P.escapeHtml(c.ports.join(', ') || '—') + '' + '' + P.formatDuration(c.uptimeSeconds) + '' + '' + actionButtons(c) + '' + ''; } function actionButtons(c) { if (c.state === 'running') { return '' + '' + '' + ''; } return '' + '' + ''; } function applyFilters() { return allContainers.filter(function (c) { if (filter === 'running' && c.state !== 'running') return false; if (filter === 'stopped' && c.state === 'running') return false; if (searchTerm && c.name.toLowerCase().indexOf(searchTerm) === -1 && c.image.toLowerCase().indexOf(searchTerm) === -1) return false; return true; }); } function renderTable() { const tbody = P.el('containers-tbody'); const visible = applyFilters(); tbody.innerHTML = visible.length ? visible.map(rowHtml).join('') : 'No containers match.'; } function renderCounts() { const running = allContainers.filter(function (c) { return c.state === 'running'; }).length; P.el('containers-count-all').textContent = 'All ' + allContainers.length; P.el('containers-count-running').textContent = 'Running ' + running; P.el('containers-count-stopped').textContent = 'Stopped ' + (allContainers.length - running); } function load() { const tbody = P.el('containers-tbody'); tbody.innerHTML = P.loadingRow(7); return P.get('containers', 'list').then(function (data) { allContainers = data; renderCounts(); renderTable(); }).catch(function (err) { tbody.innerHTML = P.errorRow(7, err.message); }); } function handleAction(id, action, btn) { const doIt = function (extra) { btn.disabled = true; return P.post('containers', action, Object.assign({ id: id }, extra)).then(load).catch(function (err) { alert('Action failed: ' + err.message); btn.disabled = false; }); }; if (action === 'remove') { if (!confirm('Remove this container? This does not remove its volumes.')) return; doIt({ force: true }); } else { doIt({}); } } function init() { P.el('containers-search').addEventListener('input', function (e) { searchTerm = e.target.value.trim().toLowerCase(); renderTable(); }); document.querySelectorAll('#containers-filterset button').forEach(function (btn) { btn.addEventListener('click', function () { document.querySelectorAll('#containers-filterset button').forEach(function (b) { b.classList.remove('active'); }); btn.classList.add('active'); filter = btn.dataset.filter; renderTable(); }); }); P.el('containers-tbody').addEventListener('click', function (e) { const btn = e.target.closest('button[data-action]'); if (!btn || btn.disabled) return; const row = btn.closest('tr'); handleAction(row.dataset.id, btn.dataset.action, btn); }); return load(); } P.registerPanel('containers', { init: init, refresh: load }); })();