Upload via GUI (31 Dateien)

This commit is contained in:
Git Manager GUI
2026-07-16 08:01:04 +02:00
parent 3ed561fe78
commit 565835418e
7 changed files with 373 additions and 116 deletions
+64 -87
View File
@@ -360,6 +360,23 @@ function loadRepos() {
}
}
// Gravur-/Projekttitel zurücksetzen, wenn zur Übersicht gewechselt wird.
// Einmalig auf Modulebene definiert, damit die Funktion sofort ab Programmstart
// verfügbar ist (früher versehentlich in loadRepoContents definiert -> beim
// Klick vor dem ersten Repo-Laden "resetProjectGravurTitle is not a function").
window.resetProjectGravurTitle = function() {
const gravurTitle = document.getElementById('project-gravur-title');
if (gravurTitle) gravurTitle.textContent = '';
};
// loadRepos EINMAL umhüllen, sodass beim Laden der Repo-Liste der Projekttitel
// zurückgesetzt wird (früher wurde bei jedem Repo-Aufruf neu umhüllt).
const origLoadRepos = loadRepos;
loadRepos = function(...args) {
window.resetProjectGravurTitle();
return origLoadRepos.apply(this, args);
};
/** Load repositories from GitHub and render the grid using loadGiteaRepos's renderer */
async function loadGithubRepos(requestId = null) {
const activeRequestId = requestId || ++repoLoadRequestId;
@@ -831,10 +848,6 @@ async function uploadDroppedPaths({ paths, owner, repo, destPath = '', cloneUrl
return { ok: false, error: 'Drag-and-Drop Upload ist aktuell nur für Gitea aktiv.' };
}
let successCount = 0;
let failedCount = 0;
const errors = [];
const withTimeout = (promise, ms, label) => {
return Promise.race([
promise,
@@ -842,79 +855,57 @@ async function uploadDroppedPaths({ paths, owner, repo, destPath = '', cloneUrl
]);
};
for (let i = 0; i < safePaths.length; i++) {
const p = safePaths[i];
const baseName = p.split(/[\\/]/).pop() || p;
showProgress(Math.round(((i + 1) / safePaths.length) * 100), `Upload ${i + 1}/${safePaths.length}: ${baseName}`);
try {
let res = null;
// Der KOMPLETTE Drop (alle Dateien UND Ordner zusammen) wird in EINEM
// Aufruf hochgeladen: ein Repo-Clone, ein Commit, ein Push egal wie
// viele Objekte gedroppt wurden. Das war die Ursache für die langen
// Wartezeiten und Zeitüberschreitungen (vorher: ein kompletter Clone+Push
// pro einzelner Datei bzw. pro Ordner).
showProgress(15, `Bereite Upload von ${safePaths.length} Objekt(en) vor ...`);
try {
const res = await withTimeout(window.electronAPI.uploadPathsToGitea({
paths: safePaths,
owner,
repo,
destPath,
branch,
messagePrefix: 'Upload via GUI'
}), 900000, 'upload-paths-to-gitea'); // 15 Min Sicherheits-Timeout
showProgress(100, 'Upload abgeschlossen');
console.log('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:result', res);
try { window.electronAPI.debugToMain('log', 'uploadDroppedPaths:result', { count: safePaths.length, ok: res?.ok, failedCount: res?.failedCount }); } catch (_) {}
const pathType = await withTimeout(window.electronAPI.getPathType(p), 5000, 'get-path-type');
console.log('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:pathType', { path: p, pathType });
try { window.electronAPI.debugToMain('log', 'uploadDroppedPaths:pathType', { path: p, pathType }); } catch (_) {}
if (!pathType?.ok) {
throw new Error(pathType?.error || 'path-type-failed');
}
if (pathType.type === 'file') {
res = await withTimeout(window.electronAPI.uploadGiteaFile({
owner,
repo,
localPath: [p],
destPath,
branch,
platform: currentState.platform
}), 15000, 'upload-gitea-file');
} else if (pathType.type === 'dir') {
res = await withTimeout(window.electronAPI.uploadLocalFolderToGitea({
localFolder: p,
owner,
repo,
destPath,
branch,
messagePrefix: 'Upload folder via GUI'
}), 600000, 'upload-local-folder-to-gitea');
} else {
throw new Error(`Nicht unterstuetzter Pfadtyp: ${pathType.type || 'unknown'}`);
}
console.log('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:itemResult', { path: p, res });
try { window.electronAPI.debugToMain('log', 'uploadDroppedPaths:itemResult', { path: p, res }); } catch (_) {}
if (!res?.ok) {
failedCount++;
const detailedFailure = Array.isArray(res?.failedFiles) && res.failedFiles.length > 0
? `${baseName}: ${res.failedFiles[0].targetPath} - ${res.failedFiles[0].error || 'Unbekannter Fehler'}`
: `${baseName}: ${res?.error || 'Unbekannter Fehler'}`;
errors.push(detailedFailure);
continue;
}
const failedEntries = Array.isArray(res.results) ? res.results.filter(r => !r.ok) : [];
if (failedEntries.length > 0) {
failedCount++;
errors.push(`${baseName}: ${failedEntries[0]?.error || 'Teilweise fehlgeschlagen'}`);
} else {
successCount++;
}
} catch (err) {
failedCount++;
const errMsg = String(err && err.message ? err.message : err);
errors.push(`${baseName}: ${errMsg}`);
console.error('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:itemError', { path: p, err: errMsg });
try { window.electronAPI.debugToMain('error', 'uploadDroppedPaths:itemError', { path: p, err: errMsg }); } catch (_) {}
if (!res?.ok) {
return {
ok: false,
error: res?.error || 'Upload fehlgeschlagen',
failedFiles: Array.isArray(res?.results) ? res.results.filter(r => !r.ok) : [],
successCount: 0,
failedCount: safePaths.length
};
}
}
if (failedCount > 0) {
return { ok: false, error: errors[0] || `${failedCount} Upload(s) fehlgeschlagen`, successCount, failedCount };
}
const failedEntries = Array.isArray(res.results) ? res.results.filter(r => !r.ok) : [];
const uploaded = (Array.isArray(res.results) ? res.results.length : 0) - failedEntries.length;
if (failedEntries.length > 0) {
return {
ok: false,
error: failedEntries[0]?.error || 'Teilweise fehlgeschlagen',
failedFiles: failedEntries,
successCount: uploaded,
failedCount: failedEntries.length
};
}
const result = { ok: true, uploadedFiles: successCount, uploadedDirs: 0 };
try { window.electronAPI.debugToMain('log', 'uploadDroppedPaths:done', result); } catch (_) {}
console.log('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:done', result);
return result;
const result = { ok: true, uploadedFiles: uploaded, uploadedDirs: 0 };
try { window.electronAPI.debugToMain('log', 'uploadDroppedPaths:done', result); } catch (_) {}
console.log('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:done', result);
return result;
} catch (err) {
const errMsg = String(err && err.message ? err.message : err);
console.error('[UPLOAD_DEBUG][renderer] uploadDroppedPaths:error', { err: errMsg });
try { window.electronAPI.debugToMain('error', 'uploadDroppedPaths:error', { err: errMsg }); } catch (_) {}
return { ok: false, error: errMsg, successCount: 0, failedCount: safePaths.length };
}
}
function extractDroppedPaths(files) {
@@ -3941,20 +3932,6 @@ async function loadRepoContents(owner, repo, path) {
showError('Error: ' + (res.error || 'Unknown error'));
return;
}
// Wenn zur Übersicht gewechselt wird, Gravur zurücksetzen
window.resetProjectGravurTitle = function() {
const gravurTitle = document.getElementById('project-gravur-title');
if (gravurTitle) gravurTitle.textContent = '';
};
// ...existing code...
// Nach dem Laden der Repo-Liste oder beim Klick auf "Zurück" rufe resetProjectGravurTitle() auf
const origLoadRepos = loadRepos;
loadRepos = function(...args) {
resetProjectGravurTitle();
return origLoadRepos.apply(this, args);
};
const grid = $('explorerGrid');
if (!grid) return;