Add upload overwrite dialog
This commit is contained in:
+80
-3
@@ -12,6 +12,7 @@ const state = {
|
||||
selectedEntry: null,
|
||||
contextMenu: null,
|
||||
permissionsDialog: null,
|
||||
uploadConflictDialog: null,
|
||||
draggedEntry: null,
|
||||
pointerDrag: null,
|
||||
suppressClickPath: null,
|
||||
@@ -197,6 +198,9 @@ function render() {
|
||||
if (state.permissionsDialog) {
|
||||
workspace.appendChild(renderPermissionsDialog());
|
||||
}
|
||||
if (state.uploadConflictDialog) {
|
||||
workspace.appendChild(renderUploadConflictDialog());
|
||||
}
|
||||
renderTransferPanel();
|
||||
renderSettingsPanel();
|
||||
}
|
||||
@@ -928,6 +932,7 @@ async function uploadFileList(win, files, targetPath) {
|
||||
if (!files.length) return;
|
||||
const uploadItems = normalizeUploadItems(files);
|
||||
const transfer = createUploadTransfer(targetPath, uploadItems);
|
||||
let overwriteAll = false;
|
||||
for (const [index, item] of uploadItems.entries()) {
|
||||
updateUploadTransfer(transfer, {
|
||||
status: 'running',
|
||||
@@ -955,11 +960,21 @@ async function uploadFileList(win, files, targetPath) {
|
||||
}, true);
|
||||
throw error;
|
||||
}
|
||||
const overwrite = window.confirm(`"${item.path}" existiert bereits.\n\nVorhandene Datei überschreiben?`);
|
||||
recordDebug('upload.overwrite.prompt', { path: item.path, overwrite });
|
||||
const conflictAction = overwriteAll ? 'overwrite' : await askUploadConflict({
|
||||
path: item.path,
|
||||
targetPath,
|
||||
index: index + 1,
|
||||
total: uploadItems.length
|
||||
});
|
||||
if (conflictAction === 'overwrite-all') {
|
||||
overwriteAll = true;
|
||||
}
|
||||
const overwrite = overwriteAll || conflictAction === 'overwrite';
|
||||
recordDebug('upload.overwrite.prompt', { path: item.path, action: conflictAction, overwrite });
|
||||
if (!overwrite) {
|
||||
updateUploadTransfer(transfer, {
|
||||
skippedFiles: transfer.skippedFiles + 1,
|
||||
skippedBytes: transfer.skippedBytes + Number(item.file.size || 0),
|
||||
currentFile: item.path,
|
||||
progress: uploadProgressPercent(transfer)
|
||||
});
|
||||
@@ -1051,6 +1066,7 @@ function createUploadTransfer(targetPath, uploadItems) {
|
||||
overwrittenFiles: 0,
|
||||
totalBytes: uploadItems.reduce((sum, item) => sum + Number(item.file?.size || 0), 0),
|
||||
uploadedBytes: 0,
|
||||
skippedBytes: 0,
|
||||
currentFile: '',
|
||||
currentIndex: 0,
|
||||
progress: 0,
|
||||
@@ -1084,7 +1100,7 @@ function addUploadProgress(transfer, bytes) {
|
||||
|
||||
function uploadProgressPercent(transfer) {
|
||||
if (transfer.totalBytes > 0) {
|
||||
return (transfer.uploadedBytes / transfer.totalBytes) * 100;
|
||||
return ((transfer.uploadedBytes + transfer.skippedBytes) / transfer.totalBytes) * 100;
|
||||
}
|
||||
if (transfer.totalFiles > 0) {
|
||||
return ((transfer.completedFiles + transfer.skippedFiles) / transfer.totalFiles) * 100;
|
||||
@@ -1424,6 +1440,67 @@ function renderPermissionsDialog() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function askUploadConflict(details) {
|
||||
return new Promise((resolve) => {
|
||||
state.uploadConflictDialog = { ...details, resolve };
|
||||
render();
|
||||
});
|
||||
}
|
||||
|
||||
function renderUploadConflictDialog() {
|
||||
const dialog = state.uploadConflictDialog;
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'modal-overlay';
|
||||
overlay.innerHTML = `
|
||||
<form class="permissions-modal conflict-modal" aria-label="Datei existiert bereits">
|
||||
<header>
|
||||
<strong>Datei existiert bereits</strong>
|
||||
<button type="button" class="icon" data-action="skip" title="Überspringen" aria-label="Überspringen">×</button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
<p>Im Zielordner existiert bereits eine Datei mit diesem Namen.</p>
|
||||
<dl class="conflict-details">
|
||||
<dt>Datei</dt>
|
||||
<dd>${escapeHtml(dialog.path)}</dd>
|
||||
<dt>Ziel</dt>
|
||||
<dd>${escapeHtml(dialog.targetPath)}</dd>
|
||||
<dt>Upload</dt>
|
||||
<dd>${escapeHtml(`${dialog.index}/${dialog.total}`)}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<footer>
|
||||
<button type="button" data-action="skip">Überspringen</button>
|
||||
<button type="button" data-action="overwrite">Überschreiben</button>
|
||||
<button type="submit" class="primary">Alle überschreiben</button>
|
||||
</footer>
|
||||
</form>
|
||||
`;
|
||||
|
||||
const form = overlay.querySelector('form');
|
||||
form.addEventListener('click', (event) => event.stopPropagation());
|
||||
overlay.addEventListener('click', () => closeUploadConflictDialog('skip'));
|
||||
overlay.querySelectorAll('[data-action="skip"]').forEach((button) => {
|
||||
button.addEventListener('click', () => closeUploadConflictDialog('skip'));
|
||||
});
|
||||
overlay.querySelector('[data-action="overwrite"]').addEventListener('click', () => closeUploadConflictDialog('overwrite'));
|
||||
form.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
closeUploadConflictDialog('overwrite-all');
|
||||
});
|
||||
setTimeout(() => {
|
||||
form.querySelector('.primary')?.focus();
|
||||
}, 0);
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function closeUploadConflictDialog(action) {
|
||||
const dialog = state.uploadConflictDialog;
|
||||
if (!dialog) return;
|
||||
state.uploadConflictDialog = null;
|
||||
dialog.resolve(action);
|
||||
render();
|
||||
}
|
||||
|
||||
function permissionMatrixMarkup(mode) {
|
||||
const digits = modeToDigits(mode);
|
||||
const rows = [
|
||||
|
||||
@@ -581,6 +581,31 @@
|
||||
opacity: 0.48;
|
||||
}
|
||||
|
||||
.u-nav .conflict-modal {
|
||||
width: 520px;
|
||||
}
|
||||
|
||||
.u-nav .conflict-details {
|
||||
background: var(--surface-2);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
display: grid;
|
||||
gap: 8px 12px;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.u-nav .conflict-details dt {
|
||||
color: var(--muted);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.u-nav .conflict-details dd {
|
||||
margin: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.u-nav .check-row {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user