diff --git a/modules/pi_control/assets/commands.js b/modules/pi_control/assets/commands.js index 48c5cb0..67f4ebc 100644 --- a/modules/pi_control/assets/commands.js +++ b/modules/pi_control/assets/commands.js @@ -10,6 +10,14 @@ const adminInput = form.querySelector('input[name="admin_only"]'); const submitBtn = form.querySelector('[data-command-submit]'); const cancelBtn = form.querySelector('[data-command-cancel]'); + const modal = document.querySelector('[data-command-modal]'); + const modalTitle = document.querySelector('[data-command-modal-title]'); + const closeBtn = document.querySelector('[data-command-close]'); + const newBtn = document.querySelector('[data-command-new]'); + const unsavedBar = document.querySelector('[data-command-unsaved]'); + const discardBtn = document.querySelector('[data-command-discard]'); + + let initialSnapshot = ''; const resetForm = () => { if (idInput) idInput.value = ''; @@ -18,6 +26,37 @@ if (timeoutInput) timeoutInput.value = ''; if (adminInput) adminInput.checked = false; if (submitBtn) submitBtn.textContent = 'Speichern'; + if (unsavedBar) unsavedBar.style.display = 'none'; + }; + + const snapshot = () => { + return JSON.stringify({ + id: idInput ? idInput.value : '', + label: labelInput ? labelInput.value : '', + command: commandInput ? commandInput.value : '', + timeout: timeoutInput ? timeoutInput.value : '', + admin: adminInput ? adminInput.checked : false, + }); + }; + + const isDirty = () => snapshot() !== initialSnapshot; + + const openModal = () => { + if (!modal) return; + modal.classList.add('is-open'); + modal.setAttribute('aria-hidden', 'false'); + initialSnapshot = snapshot(); + }; + + const closeModal = (force = false) => { + if (!modal) return; + if (!force && isDirty()) { + if (unsavedBar) unsavedBar.style.display = 'flex'; + return; + } + modal.classList.remove('is-open'); + modal.setAttribute('aria-hidden', 'true'); + if (unsavedBar) unsavedBar.style.display = 'none'; }; document.querySelectorAll('[data-command-edit]').forEach((btn) => { @@ -30,9 +69,10 @@ if (timeoutInput) timeoutInput.value = item.dataset.timeout || ''; if (adminInput) adminInput.checked = item.dataset.admin === '1'; if (submitBtn) submitBtn.textContent = 'Aktualisieren'; + if (modalTitle) modalTitle.textContent = 'Befehl bearbeiten'; const details = btn.closest('details'); if (details) details.removeAttribute('open'); - form.scrollIntoView({ behavior: 'smooth', block: 'start' }); + openModal(); }); }); @@ -43,6 +83,31 @@ }); } + if (newBtn) { + newBtn.addEventListener('click', () => { + resetForm(); + if (modalTitle) modalTitle.textContent = 'Neuer Befehl'; + openModal(); + }); + } + + if (closeBtn) { + closeBtn.addEventListener('click', () => closeModal(false)); + } + + if (discardBtn) { + discardBtn.addEventListener('click', () => { + resetForm(); + closeModal(true); + }); + } + + form.addEventListener('input', () => { + if (unsavedBar && isDirty()) { + unsavedBar.style.display = 'flex'; + } + }); + if (!list) return; let dragging = null; diff --git a/modules/pi_control/assets/pi_control.css b/modules/pi_control/assets/pi_control.css index bfe6d53..82bd75c 100644 --- a/modules/pi_control/assets/pi_control.css +++ b/modules/pi_control/assets/pi_control.css @@ -86,6 +86,8 @@ display: grid; grid-template-rows: 120px 1fr; box-shadow: var(--shadow); + position: relative; + z-index: 1; } .host-card-image { background: linear-gradient(135deg, #2b3a67 0%, #3b2f5c 45%, #1c2b3f 100%); @@ -150,7 +152,7 @@ min-width: 160px; display: grid; gap: 4px; - z-index: 30; + z-index: 200; box-shadow: var(--shadow); } .action-menu-panel form { margin: 0; } diff --git a/modules/pi_control/pages/commands.php b/modules/pi_control/pages/commands.php index 7400df2..937eacb 100644 --- a/modules/pi_control/pages/commands.php +++ b/modules/pi_control/pages/commands.php @@ -81,7 +81,10 @@ $commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALE ?>
Verwalte vordefinierte SSH-Befehle.
@@ -95,24 +98,6 @@ $commands = $pdo->query('SELECT * FROM ' . $table('commands') . ' ORDER BY COALE