diff --git a/modules/pi_control/assets/hosts.js b/modules/pi_control/assets/hosts.js index 94313f7..bcc5602 100644 --- a/modules/pi_control/assets/hosts.js +++ b/modules/pi_control/assets/hosts.js @@ -13,6 +13,14 @@ const imageInput = form.querySelector('input[name="image_url"]'); const submitBtn = form.querySelector('[data-host-submit]'); const cancelBtn = form.querySelector('[data-host-cancel]'); + const modal = document.querySelector('[data-host-modal]'); + const modalTitle = document.querySelector('[data-host-modal-title]'); + const closeBtn = document.querySelector('[data-host-close]'); + const newBtn = document.querySelector('[data-host-new]'); + const unsavedBar = document.querySelector('[data-host-unsaved]'); + const discardBtn = document.querySelector('[data-host-discard]'); + + let initialSnapshot = ''; const resetForm = () => { if (idInput) idInput.value = ''; @@ -25,6 +33,41 @@ if (passInput) passInput.value = ''; if (imageInput) imageInput.value = ''; if (submitBtn) submitBtn.textContent = 'Speichern'; + if (unsavedBar) unsavedBar.style.display = 'none'; + }; + + const snapshot = () => { + return JSON.stringify({ + id: idInput ? idInput.value : '', + name: nameInput ? nameInput.value : '', + host: hostInput ? hostInput.value : '', + port: portInput ? portInput.value : '', + user: userInput ? userInput.value : '', + auth: authSelect ? authSelect.value : '', + key: keyInput ? keyInput.value : '', + pass: passInput ? passInput.value : '', + image: imageInput ? imageInput.value : '', + }); + }; + + 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-host-edit]').forEach((btn) => { @@ -41,9 +84,10 @@ if (passInput) passInput.value = ''; if (imageInput) imageInput.value = card.dataset.imageUrl || ''; if (submitBtn) submitBtn.textContent = 'Aktualisieren'; + if (modalTitle) modalTitle.textContent = 'Host bearbeiten'; const details = btn.closest('details'); if (details) details.removeAttribute('open'); - form.scrollIntoView({ behavior: 'smooth', block: 'start' }); + openModal(); }); }); @@ -54,6 +98,31 @@ }); } + if (newBtn) { + newBtn.addEventListener('click', () => { + resetForm(); + if (modalTitle) modalTitle.textContent = 'Neuer Host'; + 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'; + } + }); + const updateStatus = (card, status) => { const dot = card.querySelector('[data-host-status]'); if (!dot) return; diff --git a/modules/pi_control/assets/pi_control.css b/modules/pi_control/assets/pi_control.css index e2a1fc7..bfe6d53 100644 --- a/modules/pi_control/assets/pi_control.css +++ b/modules/pi_control/assets/pi_control.css @@ -155,6 +155,18 @@ } .action-menu-panel form { margin: 0; } +.host-unsaved { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 10px 12px; + border: 1px solid #f3c3b8; + background: #fff5f3; + color: #7a2114; + border-radius: 12px; +} + .command-list { list-style: none; padding: 0; diff --git a/modules/pi_control/pages/hosts.php b/modules/pi_control/pages/hosts.php index 58d61f8..663b280 100644 --- a/modules/pi_control/pages/hosts.php +++ b/modules/pi_control/pages/hosts.php @@ -177,7 +177,10 @@ function hostAuthOk(array $host, bool $strictHostKey): bool ?>
Verwalte die Raspberry Pis, die du steuern möchtest.
@@ -191,52 +194,6 @@ function hostAuthOk(array $host, bool $strictHostKey): bool