diff --git a/build-plugin.sh b/build-plugin.sh index db8b8d4..5861591 100755 --- a/build-plugin.sh +++ b/build-plugin.sh @@ -2,7 +2,7 @@ set -eu PLUGIN="u-navigator" -VERSION="2026.07.04.r005" +VERSION="2026.07.04.r006" PKG_DIR="packages" WORK_DIR=".plugin-build" PKG_NAME="${PLUGIN}-${VERSION}.tgz" diff --git a/packages/u-navigator-2026.07.04.r005.tgz b/packages/u-navigator-2026.07.04.r005.tgz deleted file mode 100644 index 1c09a81..0000000 Binary files a/packages/u-navigator-2026.07.04.r005.tgz and /dev/null differ diff --git a/packages/u-navigator-2026.07.04.r006.tgz b/packages/u-navigator-2026.07.04.r006.tgz new file mode 100644 index 0000000..beb91ce Binary files /dev/null and b/packages/u-navigator-2026.07.04.r006.tgz differ diff --git a/server/public/app.js b/server/public/app.js index 480e56b..55e6c68 100644 --- a/server/public/app.js +++ b/server/public/app.js @@ -13,6 +13,7 @@ const state = { contextMenu: null, permissionsDialog: null, uploadConflictDialog: null, + uiDialog: null, draggedEntry: null, pointerDrag: null, suppressClickPath: null, @@ -215,6 +216,9 @@ function render() { if (state.uploadConflictDialog) { workspace.appendChild(renderUploadConflictDialog()); } + if (state.uiDialog) { + workspace.appendChild(renderUiDialog()); + } renderTransferPanel(); renderSettingsPanel(); } @@ -1288,8 +1292,8 @@ async function readAllDirectoryEntries(reader) { function showError(error) { const debug = recordDebug('error.shown', serializeError(error)); const message = error?.message || String(error); - const detail = debug ? `\n\nDebug #${debug.id}: ${debug.label}` : ''; - alert(`${message}${detail}`); + const detail = debug ? `Debug #${debug.id}: ${debug.label}` : ''; + showMessageDialog('Fehler', message, detail).catch(() => {}); } function getDroppedFiles(event) { @@ -1330,7 +1334,7 @@ async function renameEntry(win, entry) { showError(new Error('Read-only mode ist aktiv.')); return; } - const nextName = prompt('Neuer Name', entry.name); + const nextName = await showPromptDialog('Umbenennen', 'Neuer Name', entry.name); if (!nextName || nextName === entry.name) { return; } @@ -1346,7 +1350,11 @@ async function promptTransfer(win, entry, type) { showError(new Error('Read-only mode ist aktiv.')); return; } - const targetDir = prompt(type === 'copy' ? 'Kopieren nach Ordner' : 'Verschieben nach Ordner', win.data.path); + const targetDir = await showPromptDialog( + type === 'copy' ? 'Kopieren' : 'Verschieben', + type === 'copy' ? 'Kopieren nach Ordner' : 'Verschieben nach Ordner', + win.data.path + ); if (!targetDir) { return; } @@ -1364,7 +1372,11 @@ async function deleteEntries(win, entry = null) { return; } const label = entries.length === 1 ? `"${entries[0].name}" wirklich löschen?` : `${entries.length} Objekte wirklich löschen?`; - if (!confirm(`${label}\n\nDieser Vorgang löscht direkt vom Dateisystem.`)) { + const confirmed = await showConfirmDialog('Löschen bestätigen', label, 'Dieser Vorgang löscht direkt vom Dateisystem.', { + confirmLabel: 'Löschen', + danger: true + }); + if (!confirmed) { return; } for (const item of entries) { @@ -1536,6 +1548,108 @@ function closeUploadConflictDialog(action) { render(); } +function showMessageDialog(title, message, detail = '') { + return showUiDialog({ + type: 'message', + title, + message, + detail, + confirmLabel: 'OK' + }); +} + +function showConfirmDialog(title, message, detail = '', options = {}) { + return showUiDialog({ + type: 'confirm', + title, + message, + detail, + confirmLabel: options.confirmLabel || 'OK', + cancelLabel: options.cancelLabel || 'Abbrechen', + danger: Boolean(options.danger) + }); +} + +function showPromptDialog(title, label, value = '') { + return showUiDialog({ + type: 'prompt', + title, + message: label, + value, + confirmLabel: 'OK', + cancelLabel: 'Abbrechen' + }); +} + +function showUiDialog(options) { + return new Promise((resolve) => { + state.uiDialog = { ...options, resolve }; + render(); + }); +} + +function renderUiDialog() { + const dialog = state.uiDialog; + const overlay = document.createElement('div'); + overlay.className = 'modal-overlay'; + const isPrompt = dialog.type === 'prompt'; + const isConfirm = dialog.type === 'confirm'; + overlay.innerHTML = ` +
+
+ ${escapeHtml(dialog.title)} + +
+ + +
+ `; + + const form = overlay.querySelector('form'); + form.addEventListener('click', (event) => event.stopPropagation()); + overlay.addEventListener('click', () => closeUiDialog(cancelDialogValue(dialog))); + overlay.querySelectorAll('[data-action="cancel"]').forEach((button) => { + button.addEventListener('click', () => closeUiDialog(cancelDialogValue(dialog))); + }); + form.addEventListener('submit', (event) => { + event.preventDefault(); + if (isPrompt) { + closeUiDialog(form.elements.value.value); + return; + } + closeUiDialog(isConfirm ? true : undefined); + }); + setTimeout(() => { + const focusTarget = isPrompt ? form.elements.value : form.querySelector('.primary'); + focusTarget?.focus(); + if (isPrompt) { + focusTarget.select(); + } + }, 0); + return overlay; +} + +function cancelDialogValue(dialog) { + if (dialog.type === 'confirm') return false; + if (dialog.type === 'prompt') return null; + return undefined; +} + +function closeUiDialog(value) { + const dialog = state.uiDialog; + if (!dialog) return; + state.uiDialog = null; + dialog.resolve(value); + render(); +} + function permissionMatrixMarkup(mode) { const digits = modeToDigits(mode); const rows = [ diff --git a/server/public/styles.css b/server/public/styles.css index 9a0696b..93755ba 100644 --- a/server/public/styles.css +++ b/server/public/styles.css @@ -624,6 +624,24 @@ width: 100%; } +.u-nav .ui-modal { + width: min(460px, calc(100vw - 28px)); +} + +.u-nav .ui-modal .modal-body p { + margin: 0; + overflow-wrap: anywhere; +} + +.u-nav .ui-modal footer { + gap: 8px; +} + +.u-nav .ui-modal .danger-action { + background: #c4382d; + border-color: #c4382d; +} + .u-nav .conflict-details { background: var(--surface-2); border: 1px solid var(--line); diff --git a/u-navigator.plg b/u-navigator.plg index 771f1df..6733b4f 100644 --- a/u-navigator.plg +++ b/u-navigator.plg @@ -1,7 +1,7 @@ - + @@ -24,7 +24,7 @@ https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package; -e990c21ddfd6cb6be0dd48f8b25bc3f8 +d7ee76b55ed3afd4dbef81ad29e7a17e