From 506374f35b2b3054763cb834765cb15a9fa0859d Mon Sep 17 00:00:00 2001 From: Jens Reinemann Date: Mon, 18 May 2026 23:22:05 +0200 Subject: [PATCH] =?UTF-8?q?fix(admin-ui):=20improve=20D&D=20confirm=20UX?= =?UTF-8?q?=20=E2=80=93=20spinner,=20success/error=20feedback,=20auto-rese?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/static/admin/index.html | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/server/src/main/resources/static/admin/index.html b/server/src/main/resources/static/admin/index.html index 89469b1..e05a1b9 100644 --- a/server/src/main/resources/static/admin/index.html +++ b/server/src/main/resources/static/admin/index.html @@ -890,8 +890,9 @@ card.innerHTML = `
${item.fileFormat.toUpperCase()} – ${formatBytes(item.fileSize)} - +
+
@@ -943,6 +944,15 @@ const card = cards[idx]; if (!card) return; + const btn = card.querySelector('.rv-confirm-btn'); + const statusEl = card.querySelector('.rv-status'); + + // Show spinner + btn.disabled = true; + btn.textContent = '⏳ Wird gespeichert…'; + statusEl.innerHTML = ''; + statusEl.style.display = 'none'; + const item = JSON.parse(card.dataset.item); const payload = { filename: item.filename, @@ -965,28 +975,50 @@ body: JSON.stringify(payload) }); if (res.ok) { - card.style.opacity = '0.4'; - card.querySelector('button').disabled = true; - card.querySelector('button').textContent = '✓ Gespeichert'; + const created = await res.json(); + card.style.opacity = '0.5'; + btn.textContent = '✓ Gespeichert'; + statusEl.style.display = 'block'; + statusEl.style.color = '#7CBA3C'; + statusEl.innerHTML = `✓ Ressource angelegt:
${escHtml(created.title)}
${escHtml(created.guid)}`; + // Refresh list + reset D&D after 2s + resourcesLoaded = false; + loadResources(); + cachedTags = null; // refresh tags + setTimeout(() => resetDndZone(), 2000); } else { const body = await res.json().catch(() => ({})); - alert('Fehler: ' + (body.message || res.status)); + btn.textContent = '✓ Übernehmen'; + btn.disabled = false; + statusEl.style.display = 'block'; + statusEl.style.color = '#D95A20'; + statusEl.innerHTML = `Fehler: ${escHtml(body.message || 'HTTP ' + res.status)}
`; } } catch (e) { - alert('Verbindungsfehler: ' + e.message); + btn.textContent = '✓ Übernehmen'; + btn.disabled = false; + statusEl.style.display = 'block'; + statusEl.style.color = '#D95A20'; + statusEl.innerHTML = `Verbindungsfehler: ${escHtml(e.message)}
`; } } + function resetDndZone() { + const review = document.getElementById('dnd-review'); + review.style.display = 'none'; + review.innerHTML = ''; + document.getElementById('dnd-area').style.display = 'block'; + document.getElementById('dnd-zone').style.display = 'block'; + } + async function confirmAllAnalyzed() { const review = document.getElementById('dnd-review'); const cards = review.querySelectorAll('[data-item]'); for (let i = 0; i < cards.length; i++) { - if (cards[i].style.opacity !== '0.4') { + if (cards[i].style.opacity !== '0.5') { await confirmAnalyzedResource(i); } } - resourcesLoaded = false; - loadResources(); } function escHtml(str) {