// ========== CONTAINER SNAPSHOT / CHECKPOINT ========== (function() { // Inject modal HTML injectModal('snapshot-modal', `

💾 Container Snapshots

`); const modal = document.getElementById('snapshot-modal'); const openBtn = document.getElementById('snapshot-btn'); const closeBtn = document.getElementById('snapshot-close'); const containerSelect = document.getElementById('snapshot-container-select'); const detailsDiv = document.getElementById('snapshot-details'); const createBtn = document.getElementById('snapshot-create-btn'); const createStatus = document.getElementById('snapshot-create-status'); let currentContainerId = null; async function loadContainers() { try { const res = await fetch('/api/v1/containers'); const data = await res.json(); if (!data.success || !data.containers) return; containerSelect.innerHTML = ''; for (const c of data.containers) { const opt = document.createElement('option'); opt.value = c.id; opt.textContent = `${c.name || c.id} (${c.image || 'unknown'})`; opt.dataset.name = c.name; opt.dataset.image = c.image; opt.dataset.status = c.status; opt.dataset.created = c.created; containerSelect.appendChild(opt); } } catch (e) { console.error('Failed to load containers:', e); } } function showContainerDetails(opt) { if (!opt || !opt.value) { detailsDiv.style.display = 'none'; currentContainerId = null; return; } currentContainerId = opt.value; document.getElementById('snapshot-image').textContent = opt.dataset.image || '-'; document.getElementById('snapshot-status').textContent = opt.dataset.status || '-'; document.getElementById('snapshot-created').textContent = opt.dataset.created ? new Date(opt.dataset.created * 1000).toLocaleString() : '-'; document.getElementById('snapshot-id').textContent = opt.value.substring(0, 12); detailsDiv.style.display = ''; } async function createSnapshot() { if (!currentContainerId) { createStatus.textContent = 'Please select a container first'; createStatus.style.color = 'var(--bad-fg)'; return; } const name = document.getElementById('snapshot-name').value.trim(); if (!name) { createStatus.textContent = 'Please enter a snapshot name'; createStatus.style.color = 'var(--bad-fg)'; return; } const leaveRunning = document.getElementById('snapshot-leave-running').checked; createBtn.disabled = true; createBtn.textContent = 'Creating...'; createStatus.textContent = ''; try { const res = await fetch(`/api/v1/containers/${encodeURIComponent(currentContainerId)}/checkpoint`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, leaveRunning }) }); const data = await res.json(); if (data.success) { createStatus.textContent = `✓ Snapshot "${name}" created successfully`; createStatus.style.color = 'var(--ok-fg)'; document.getElementById('snapshot-name').value = ''; } else { createStatus.textContent = `✗ Failed: ${data.error || 'Unknown error'}`; createStatus.style.color = 'var(--bad-fg)'; } } catch (e) { createStatus.textContent = `✗ Error: ${e.message}`; createStatus.style.color = 'var(--bad-fg)'; } finally { createBtn.disabled = false; createBtn.textContent = '💾 Create Snapshot'; } } function openModal() { modal.classList.add('show'); loadContainers(); } function closeModal() { modal.classList.remove('show'); detailsDiv.style.display = 'none'; currentContainerId = null; containerSelect.selectedIndex = 0; } openBtn?.addEventListener('click', openModal); closeBtn?.addEventListener('click', closeModal); wireModal(modal, closeBtn); containerSelect?.addEventListener('change', (e) => { const opt = containerSelect.options[containerSelect.selectedIndex]; showContainerDetails(opt); }); createBtn?.addEventListener('click', createSnapshot); // Tab switching modal?.querySelectorAll('.panel-tab').forEach(tab => { tab.addEventListener('click', () => { modal.querySelectorAll('.panel-tab').forEach(t => t.classList.remove('active')); modal.querySelectorAll('.panel-section').forEach(s => s.classList.remove('active')); tab.classList.add('active'); modal.querySelector(`#${tab.dataset.panel}`).classList.add('active'); }); }); })();