/** * javascript/settings.js * * Settings panel: reads/writes unraid-podman's own configuration via * ajax/settings.php (podman.cfg + the autostart list) — not a * PodmanClient/libpod concern, see that file's header comment. */ (function () { 'use strict'; const P = window.Podman; let autostartNames = []; function renderAutostart() { const tbody = P.el('autostart-tbody'); tbody.innerHTML = autostartNames.length ? autostartNames.map(function (name, i) { return '' + '' + (i + 1) + '' + '' + P.escapeHtml(name) + '' + '
' + '' + '' + '' + '
'; }).join('') : 'No containers in the autostart chain.'; } function saveAutostart() { return P.post('settings', 'autostart_save', { names: autostartNames }).catch(function (err) { alert('Could not save autostart order: ' + err.message); }); } function fillForm(settings) { P.el('settings-storage-path').value = settings.storagePath; P.el('settings-storage-size').value = settings.storageImageSizeGb; P.el('settings-enabled').checked = settings.enabled; P.el('settings-stop-timeout').value = settings.stopTimeoutSeconds; autostartNames = settings.autostart.slice(); renderAutostart(); const versions = settings.packageVersions || {}; const order = ['PODMAN', 'CONMON', 'CRUN', 'NETAVARK', 'AARDVARK_DNS', 'PASST', 'FUSE_OVERLAYFS']; const chipsHtml = order.map(function (k) { const name = k.toLowerCase().replace(/_/g, '-'); const version = versions[k + '_INSTALLED_VERSION']; return '' + P.escapeHtml(name) + ' ' + P.escapeHtml(version || '?') + ''; }).join(''); P.el('settings-package-versions').innerHTML = chipsHtml || 'No version manifest found.'; } function load() { return P.get('settings', 'get').then(fillForm).catch(function (err) { alert('Could not load settings: ' + err.message); }); } // --- Podman service status/start/restart ---------------------------------- function renderServiceResult(data) { const chip = P.el('settings-service-chip'); chip.className = 'podman-chip ' + (data.running ? 'podman-chip-good' : 'podman-chip-bad'); chip.innerHTML = '' + (data.running ? 'Running' : 'Not running'); const log = P.el('settings-service-log'); if (data.output) { log.style.display = ''; log.textContent = data.output; log.scrollTop = log.scrollHeight; } } function refreshServiceStatus() { const buttons = [P.el('settings-service-status-btn'), P.el('settings-service-start-btn'), P.el('settings-service-restart-btn')]; buttons.forEach(function (b) { b.disabled = true; }); return P.get('settings', 'service_status').then(renderServiceResult).catch(function (err) { P.el('settings-service-chip').className = 'podman-chip podman-chip-bad'; P.el('settings-service-chip').innerHTML = 'Unknown'; P.el('settings-service-log').style.display = ''; P.el('settings-service-log').textContent = err.message; }).finally(function () { buttons.forEach(function (b) { b.disabled = false; }); }); } function runServiceAction(action) { const buttons = [P.el('settings-service-status-btn'), P.el('settings-service-start-btn'), P.el('settings-service-restart-btn')]; buttons.forEach(function (b) { b.disabled = true; }); P.el('settings-service-log').style.display = ''; P.el('settings-service-log').textContent = 'Working…'; return P.post('settings', action, {}).then(renderServiceResult).catch(function (err) { P.el('settings-service-log').style.display = ''; P.el('settings-service-log').textContent = err.message; }).finally(function () { buttons.forEach(function (b) { b.disabled = false; }); }); } // --- Format a disk for podman storage -------------------------------------- function openFormatDiskModal() { const backdrop = document.createElement('div'); backdrop.className = 'podman-modal-backdrop'; backdrop.innerHTML = '' + ''; (document.querySelector('.podman-plugin') || document.body).appendChild(backdrop); const select = backdrop.querySelector('#fd-device'); const warning = backdrop.querySelector('#fd-warning'); const confirmBox = backdrop.querySelector('#fd-confirm'); const submitBtn = backdrop.querySelector('[data-role="submit"]'); function updateSubmitEnabled() { submitBtn.disabled = !(select.value && confirmBox.checked); } P.get('disks', 'list_candidates').then(function (list) { select.innerHTML = list.length ? list.map(function (d) { return ''; }).join('') : ''; updateSubmitEnabled(); }).catch(function (err) { select.innerHTML = ''; warning.textContent = err.message; }); select.addEventListener('change', updateSubmitEnabled); confirmBox.addEventListener('change', updateSubmitEnabled); function close() { backdrop.remove(); } submitBtn.addEventListener('click', function () { if (!select.value || !confirmBox.checked) return; if (!confirm('Format ' + select.value + '? This cannot be undone.')) return; submitBtn.disabled = true; submitBtn.textContent = 'Formatting…'; P.post('disks', 'format', { device: select.value }).then(function (data) { close(); P.el('settings-storage-path').value = data.mountPath; alert('Formatted and mounted at ' + data.mountPath + '. Storage path has been filled in below — click "Save Settings" to use it, then Restart Podman.'); }).catch(function (err) { submitBtn.disabled = false; submitBtn.textContent = 'Format Disk'; alert('Format failed: ' + err.message); }); }); backdrop.querySelector('[data-role="cancel"]').addEventListener('click', close); backdrop.addEventListener('click', function (e) { if (e.target === backdrop) close(); }); } function save() { const body = { storagePath: P.el('settings-storage-path').value.trim(), storageImageSizeGb: parseInt(P.el('settings-storage-size').value, 10) || 20, enabled: P.el('settings-enabled').checked, stopTimeoutSeconds: parseInt(P.el('settings-stop-timeout').value, 10) || 10, }; return P.post('settings', 'save', body).then(function () { alert('Saved. Restart podman (rc.podman restart) to apply storage/enabled changes.'); }).catch(function (err) { alert('Save failed: ' + err.message); }); } function init() { P.el('settings-save-btn').addEventListener('click', save); P.el('autostart-tbody').addEventListener('click', function (e) { const btn = e.target.closest('button[data-action]'); if (!btn) return; const i = parseInt(btn.closest('tr').dataset.index, 10); const action = btn.dataset.action; if (action === 'remove') { autostartNames.splice(i, 1); } else if (action === 'up' && i > 0) { [autostartNames[i - 1], autostartNames[i]] = [autostartNames[i], autostartNames[i - 1]]; } else if (action === 'down' && i < autostartNames.length - 1) { [autostartNames[i + 1], autostartNames[i]] = [autostartNames[i], autostartNames[i + 1]]; } renderAutostart(); saveAutostart(); }); P.el('settings-service-status-btn').addEventListener('click', refreshServiceStatus); P.el('settings-service-start-btn').addEventListener('click', function () { runServiceAction('service_start'); }); P.el('settings-service-restart-btn').addEventListener('click', function () { runServiceAction('service_restart'); }); P.el('settings-format-disk-btn').addEventListener('click', openFormatDiskModal); refreshServiceStatus(); return load(); } P.registerPanel('settings', { init: init, refresh: load }); })();