Upload folder via GUI - renderer
This commit is contained in:
@@ -488,11 +488,16 @@
|
|||||||
<option value="warning">Warn</option>
|
<option value="warning">Warn</option>
|
||||||
<option value="error">Error</option>
|
<option value="error">Error</option>
|
||||||
</select>
|
</select>
|
||||||
|
<select id="activityFilterFix">
|
||||||
|
<option value="all">Alle Einträge</option>
|
||||||
|
<option value="fixable">Nur mit Fix</option>
|
||||||
|
</select>
|
||||||
<button id="btnRetryQueueRefresh" class="secondary">🔁 Queue jetzt retry</button>
|
<button id="btnRetryQueueRefresh" class="secondary">🔁 Queue jetzt retry</button>
|
||||||
<button id="btnClearActivityLog" class="secondary">🧹 Log leeren</button>
|
<button id="btnClearActivityLog" class="secondary">🧹 Log leeren</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="activityQueueInfo" class="activity-queue-info">Retry-Queue: 0</div>
|
<div id="activityQueueInfo" class="activity-queue-info">Retry-Queue: 0</div>
|
||||||
|
<div id="activitySummaryInfo" class="activity-summary-info">Fehler mit Fix: 0</div>
|
||||||
<div id="activityLogList" class="activity-log-list"></div>
|
<div id="activityLogList" class="activity-log-list"></div>
|
||||||
|
|
||||||
<div class="modal-buttons">
|
<div class="modal-buttons">
|
||||||
|
|||||||
@@ -1281,17 +1281,150 @@ function getActiveHeatmapMonths() {
|
|||||||
return activityHeatmapRangeMonths;
|
return activityHeatmapRangeMonths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function logActivity(level, message) {
|
function classifyActivityEntry(level, message, meta = null) {
|
||||||
|
const text = String(message || '').trim();
|
||||||
|
const raw = text.toLowerCase();
|
||||||
|
const safeMeta = meta && typeof meta === 'object' ? meta : null;
|
||||||
|
|
||||||
|
let category = 'Allgemein';
|
||||||
|
let fixAction = null;
|
||||||
|
|
||||||
|
const useRetryFix = () => ({
|
||||||
|
type: 'retry-queue-now',
|
||||||
|
label: '🩹 Queue jetzt retry',
|
||||||
|
title: 'Versucht fehlgeschlagene Netzwerk-Aktionen erneut'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (raw.includes('authentifizierung fehlgeschlagen') || raw.includes('unauthorized') || raw.includes('401') || raw.includes('token')) {
|
||||||
|
category = 'Authentifizierung';
|
||||||
|
fixAction = {
|
||||||
|
type: 'open-settings-token',
|
||||||
|
label: '🩹 Token prüfen',
|
||||||
|
title: 'Öffnet Einstellungen und fokussiert den Token'
|
||||||
|
};
|
||||||
|
} else if (raw.includes('zugriff verweigert') || raw.includes('forbidden') || raw.includes('403')) {
|
||||||
|
category = 'Berechtigungen';
|
||||||
|
fixAction = {
|
||||||
|
type: 'open-settings-token',
|
||||||
|
label: '🩹 Rechte prüfen',
|
||||||
|
title: 'Öffnet Einstellungen zur Scope-Prüfung'
|
||||||
|
};
|
||||||
|
} else if (raw.includes('ungültige url') || raw.includes('ungueltige url') || raw.includes('server nicht erreichbar') || raw.includes('dns') || raw.includes('econnrefused') || raw.includes('enotfound') || raw.includes('eai_again') || raw.includes('zeitüberschreitung') || raw.includes('timeout')) {
|
||||||
|
category = 'Verbindung';
|
||||||
|
fixAction = {
|
||||||
|
type: 'open-settings-url',
|
||||||
|
label: '🩹 URL prüfen',
|
||||||
|
title: 'Öffnet Einstellungen und fokussiert die Gitea-URL'
|
||||||
|
};
|
||||||
|
} else if (raw.includes('retry-queue') || raw.includes('queue-r') || raw.includes('queue:') || raw.includes('netzwerkproblem erkannt')) {
|
||||||
|
category = 'Retry-Queue';
|
||||||
|
fixAction = useRetryFix();
|
||||||
|
} else if (raw.startsWith('batch ') || raw.includes('batch beendet')) {
|
||||||
|
category = 'Batch';
|
||||||
|
if (String(level || '').toLowerCase() === 'error' || raw.includes('fehlgeschlagen')) {
|
||||||
|
fixAction = {
|
||||||
|
type: 'open-batch-modal',
|
||||||
|
label: '🩹 Batch erneut starten',
|
||||||
|
title: 'Öffnet den Batch-Dialog'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fixAction && safeMeta && safeMeta.suggestRetryQueue) {
|
||||||
|
category = safeMeta.category || category;
|
||||||
|
fixAction = useRetryFix();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fixAction && safeMeta && safeMeta.fixAction && typeof safeMeta.fixAction === 'object') {
|
||||||
|
fixAction = safeMeta.fixAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
category,
|
||||||
|
fixAction,
|
||||||
|
meta: safeMeta
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runActivityFixAction(entry) {
|
||||||
|
const action = entry?.fixAction;
|
||||||
|
if (!action || !action.type) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (action.type === 'retry-queue-now') {
|
||||||
|
const res = await window.electronAPI.processRetryQueueNow();
|
||||||
|
if (res?.ok) {
|
||||||
|
showSuccess(`Queue verarbeitet: ${res.succeeded || 0} erfolgreich, ${res.failed || 0} verworfen.`);
|
||||||
|
} else {
|
||||||
|
showWarning(res?.error || 'Queue konnte nicht verarbeitet werden');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === 'open-settings-token') {
|
||||||
|
openSettingsForFix(currentPlatformKey() === 'github' ? 'githubToken' : 'giteaToken');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === 'open-settings-url') {
|
||||||
|
openSettingsForFix('giteaURL');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === 'open-batch-modal') {
|
||||||
|
$('batchActionModal')?.classList.remove('hidden');
|
||||||
|
updateBatchActionFields();
|
||||||
|
scheduleBatchCloneValidation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError(error && error.message ? error.message : String(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSettingsForFix(focusId = null) {
|
||||||
|
const modal = $('settingsModal');
|
||||||
|
if (!modal) return;
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
$('settingsWatermarkCard')?.classList.add('hidden');
|
||||||
|
renderSettingsHealth();
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
syncSettingsPanelHeights();
|
||||||
|
if (focusId && $(focusId)) {
|
||||||
|
$(focusId).focus();
|
||||||
|
try { $(focusId).select?.(); } catch (_) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function countFixableErrors(entries) {
|
||||||
|
return (Array.isArray(entries) ? entries : []).filter((e) => e.level === 'error' && !!e.fixAction).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateActivitySummary() {
|
||||||
|
const summaryEl = $('activitySummaryInfo');
|
||||||
|
if (summaryEl) {
|
||||||
|
const fixableErrors = countFixableErrors(activityEntries);
|
||||||
|
summaryEl.textContent = `Fehler mit Fix: ${fixableErrors}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function logActivity(level, message, meta = null) {
|
||||||
|
const classification = classifyActivityEntry(level, message, meta);
|
||||||
const entry = {
|
const entry = {
|
||||||
id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
||||||
level: level || 'info',
|
level: level || 'info',
|
||||||
message: String(message || ''),
|
message: String(message || ''),
|
||||||
ts: new Date().toISOString()
|
ts: new Date().toISOString(),
|
||||||
|
category: classification.category,
|
||||||
|
fixAction: classification.fixAction,
|
||||||
|
meta: classification.meta
|
||||||
};
|
};
|
||||||
activityEntries.unshift(entry);
|
activityEntries.unshift(entry);
|
||||||
if (activityEntries.length > MAX_ACTIVITY_ITEMS) {
|
if (activityEntries.length > MAX_ACTIVITY_ITEMS) {
|
||||||
activityEntries = activityEntries.slice(0, MAX_ACTIVITY_ITEMS);
|
activityEntries = activityEntries.slice(0, MAX_ACTIVITY_ITEMS);
|
||||||
}
|
}
|
||||||
|
updateActivitySummary();
|
||||||
renderActivityLog();
|
renderActivityLog();
|
||||||
refreshActivityHeatmapIfVisible();
|
refreshActivityHeatmapIfVisible();
|
||||||
}
|
}
|
||||||
@@ -1682,7 +1815,12 @@ function renderActivityLog() {
|
|||||||
if (!list) return;
|
if (!list) return;
|
||||||
|
|
||||||
const filter = ($('activityFilterLevel') && $('activityFilterLevel').value) || 'all';
|
const filter = ($('activityFilterLevel') && $('activityFilterLevel').value) || 'all';
|
||||||
const visible = activityEntries.filter(e => filter === 'all' || e.level === filter);
|
const filterFix = ($('activityFilterFix') && $('activityFilterFix').value) || 'all';
|
||||||
|
const visible = activityEntries.filter(e => {
|
||||||
|
const levelMatches = filter === 'all' || e.level === filter;
|
||||||
|
const fixMatches = filterFix === 'all' || !!e.fixAction;
|
||||||
|
return levelMatches && fixMatches;
|
||||||
|
});
|
||||||
|
|
||||||
if (visible.length === 0) {
|
if (visible.length === 0) {
|
||||||
list.innerHTML = '';
|
list.innerHTML = '';
|
||||||
@@ -1701,6 +1839,9 @@ function renderActivityLog() {
|
|||||||
const row = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
row.className = `activity-log-item ${e.level || 'info'}`;
|
row.className = `activity-log-item ${e.level || 'info'}`;
|
||||||
|
|
||||||
|
const header = document.createElement('div');
|
||||||
|
header.className = 'activity-log-row-header';
|
||||||
|
|
||||||
const time = document.createElement('span');
|
const time = document.createElement('span');
|
||||||
time.className = 'activity-log-time';
|
time.className = 'activity-log-time';
|
||||||
time.textContent = formatActivityTimestamp(e.ts);
|
time.textContent = formatActivityTimestamp(e.ts);
|
||||||
@@ -1709,13 +1850,36 @@ function renderActivityLog() {
|
|||||||
level.className = 'activity-log-level';
|
level.className = 'activity-log-level';
|
||||||
level.textContent = (e.level || 'info').toUpperCase();
|
level.textContent = (e.level || 'info').toUpperCase();
|
||||||
|
|
||||||
|
const category = document.createElement('span');
|
||||||
|
category.className = 'activity-log-category';
|
||||||
|
category.textContent = e.category || 'Allgemein';
|
||||||
|
|
||||||
|
header.appendChild(time);
|
||||||
|
header.appendChild(level);
|
||||||
|
header.appendChild(category);
|
||||||
|
|
||||||
const msg = document.createElement('span');
|
const msg = document.createElement('span');
|
||||||
msg.className = 'activity-log-message';
|
msg.className = 'activity-log-message';
|
||||||
msg.textContent = String(e.message || '');
|
msg.textContent = String(e.message || '');
|
||||||
|
|
||||||
row.appendChild(time);
|
row.appendChild(header);
|
||||||
row.appendChild(level);
|
|
||||||
row.appendChild(msg);
|
row.appendChild(msg);
|
||||||
|
|
||||||
|
if (e.fixAction) {
|
||||||
|
const actions = document.createElement('div');
|
||||||
|
actions.className = 'activity-log-actions';
|
||||||
|
|
||||||
|
const fixBtn = document.createElement('button');
|
||||||
|
fixBtn.className = 'activity-log-fix-btn';
|
||||||
|
fixBtn.type = 'button';
|
||||||
|
fixBtn.textContent = e.fixAction.label || '🩹 Fix ausführen';
|
||||||
|
fixBtn.title = e.fixAction.title || 'Empfohlenen Fix ausführen';
|
||||||
|
fixBtn.onclick = () => runActivityFixAction(e);
|
||||||
|
|
||||||
|
actions.appendChild(fixBtn);
|
||||||
|
row.appendChild(actions);
|
||||||
|
}
|
||||||
|
|
||||||
list.appendChild(row);
|
list.appendChild(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1726,6 +1890,7 @@ function updateRetryQueueBadge(count) {
|
|||||||
if (btn) btn.textContent = `🔁 Queue (${retryQueueCount})`;
|
if (btn) btn.textContent = `🔁 Queue (${retryQueueCount})`;
|
||||||
const info = $('activityQueueInfo');
|
const info = $('activityQueueInfo');
|
||||||
if (info) info.textContent = `Retry-Queue: ${retryQueueCount}`;
|
if (info) info.textContent = `Retry-Queue: ${retryQueueCount}`;
|
||||||
|
updateActivitySummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseBatchRepoInput(raw) {
|
function parseBatchRepoInput(raw) {
|
||||||
@@ -3777,10 +3942,12 @@ async function loadRepoContents(owner, repo, path) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Wenn zur Übersicht gewechselt wird, Gravur zurücksetzen
|
// Wenn zur Übersicht gewechselt wird, Gravur zurücksetzen
|
||||||
function resetProjectGravurTitle() {
|
window.resetProjectGravurTitle = function() {
|
||||||
const gravurTitle = document.getElementById('project-gravur-title');
|
const gravurTitle = document.getElementById('project-gravur-title');
|
||||||
if (gravurTitle) gravurTitle.textContent = '';
|
if (gravurTitle) gravurTitle.textContent = '';
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// ...existing code...
|
||||||
|
|
||||||
// Nach dem Laden der Repo-Liste oder beim Klick auf "Zurück" rufe resetProjectGravurTitle() auf
|
// Nach dem Laden der Repo-Liste oder beim Klick auf "Zurück" rufe resetProjectGravurTitle() auf
|
||||||
const origLoadRepos = loadRepos;
|
const origLoadRepos = loadRepos;
|
||||||
@@ -5617,7 +5784,10 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
// Event Handlers
|
// Event Handlers
|
||||||
if ($('btnLoadGiteaRepos')) {
|
if ($('btnLoadGiteaRepos')) {
|
||||||
$('btnLoadGiteaRepos').onclick = loadRepos;
|
$('btnLoadGiteaRepos').onclick = () => {
|
||||||
|
window.resetProjectGravurTitle();
|
||||||
|
loadRepos();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($('btnSelectFolder')) {
|
if ($('btnSelectFolder')) {
|
||||||
@@ -5636,6 +5806,7 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
$('btnBack').onclick = () => {
|
$('btnBack').onclick = () => {
|
||||||
if (currentState.view === 'gitea-repo') {
|
if (currentState.view === 'gitea-repo') {
|
||||||
if (currentState.path === '' || currentState.path === '/') {
|
if (currentState.path === '' || currentState.path === '/') {
|
||||||
|
window.resetProjectGravurTitle(); // Projektname ausblenden
|
||||||
loadGiteaRepos();
|
loadGiteaRepos();
|
||||||
} else {
|
} else {
|
||||||
const parts = currentState.path.split('/').filter(p => p);
|
const parts = currentState.path.split('/').filter(p => p);
|
||||||
@@ -5693,6 +5864,7 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
if ($('btnOpenActivityLog')) {
|
if ($('btnOpenActivityLog')) {
|
||||||
$('btnOpenActivityLog').onclick = () => {
|
$('btnOpenActivityLog').onclick = () => {
|
||||||
$('activityLogModal')?.classList.remove('hidden');
|
$('activityLogModal')?.classList.remove('hidden');
|
||||||
|
updateActivitySummary();
|
||||||
renderActivityLog();
|
renderActivityLog();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -5705,9 +5877,14 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
$('activityFilterLevel').addEventListener('change', renderActivityLog);
|
$('activityFilterLevel').addEventListener('change', renderActivityLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($('activityFilterFix')) {
|
||||||
|
$('activityFilterFix').addEventListener('change', renderActivityLog);
|
||||||
|
}
|
||||||
|
|
||||||
if ($('btnClearActivityLog')) {
|
if ($('btnClearActivityLog')) {
|
||||||
$('btnClearActivityLog').onclick = () => {
|
$('btnClearActivityLog').onclick = () => {
|
||||||
activityEntries = [];
|
activityEntries = [];
|
||||||
|
updateActivitySummary();
|
||||||
renderActivityLog();
|
renderActivityLog();
|
||||||
refreshActivityHeatmapIfVisible();
|
refreshActivityHeatmapIfVisible();
|
||||||
};
|
};
|
||||||
@@ -6358,7 +6535,11 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
updateRetryQueueBadge(size);
|
updateRetryQueueBadge(size);
|
||||||
if (payload && payload.event === 'queued' && payload.item) {
|
if (payload && payload.event === 'queued' && payload.item) {
|
||||||
const p = payload.item.payload || {};
|
const p = payload.item.payload || {};
|
||||||
logActivity('warning', `Queue: ${p.owner}/${p.repo}/${p.path} wurde eingeplant`);
|
logActivity('warning', `Queue: ${p.owner}/${p.repo}/${p.path} wurde eingeplant`, {
|
||||||
|
category: 'Retry-Queue',
|
||||||
|
suggestRetryQueue: true,
|
||||||
|
queueId: payload.item.id || null
|
||||||
|
});
|
||||||
} else if (payload && payload.event === 'processed') {
|
} else if (payload && payload.event === 'processed') {
|
||||||
logActivity('info', `Queue-Retry: ${payload.succeeded || 0} erfolgreich, ${payload.failed || 0} verworfen`);
|
logActivity('info', `Queue-Retry: ${payload.succeeded || 0} erfolgreich, ${payload.failed || 0} verworfen`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1994,6 +1994,12 @@ input[type="checkbox"] {
|
|||||||
.activity-queue-info {
|
.activity-queue-info {
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-summary-info {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 12px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2014,6 +2020,9 @@ input[type="checkbox"] {
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border-left: 3px solid rgba(255, 255, 255, 0.2);
|
border-left: 3px solid rgba(255, 255, 255, 0.2);
|
||||||
background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02));
|
background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.02));
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-log-item.info {
|
.activity-log-item.info {
|
||||||
@@ -2031,14 +2040,34 @@ input[type="checkbox"] {
|
|||||||
.activity-log-time {
|
.activity-log-time {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-right: 6px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-log-level {
|
.activity-log-level {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.4px;
|
letter-spacing: 0.4px;
|
||||||
margin-right: 6px;
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-log-row-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-log-category {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.35px;
|
||||||
|
color: #cfe8ff;
|
||||||
|
border: 1px solid rgba(140, 190, 255, 0.35);
|
||||||
|
background: rgba(58, 120, 200, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-log-message {
|
.activity-log-message {
|
||||||
@@ -2046,6 +2075,30 @@ input[type="checkbox"] {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activity-log-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-log-fix-btn {
|
||||||
|
height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid rgba(92, 210, 255, 0.5);
|
||||||
|
background: rgba(17, 92, 132, 0.28);
|
||||||
|
color: #d9f4ff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, transform 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-log-fix-btn:hover {
|
||||||
|
background: rgba(23, 122, 173, 0.35);
|
||||||
|
border-color: rgba(122, 227, 255, 0.75);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================
|
/* ===========================
|
||||||
CONTEXT MENU
|
CONTEXT MENU
|
||||||
=========================== */
|
=========================== */
|
||||||
|
|||||||
Reference in New Issue
Block a user