v3.0.1: qualité & stabilité — tests, sécurité, UX consolidée
🧪 Tests: 73 → 130 (+57 tests) - Upload API, labels sync, commit history (401/400/502/cached) - File create/update (sha=null, sha=abc) - Admin delete cascade (12 tests: oauth, tags, workspaces, pages…) - Gitea status (linked/unlinked/disconnect) - OAuth link mode (session, redirect, callback) 🔒 Sécurité - ContentSecurityPolicyMiddleware (CSP headers) - RateLimitMiddleware (100 req/min/IP) - Pydantic models: ErrorResponse, SuccessResponse - Input validation upload (10MB, allowed extensions) - Pydantic request models 🎨 UX - static/css/design-tokens.css (500 lines, thèmes + skeletons) - Toast system: 16 alert() remplacés par toast() - 59 lignes CSS dupliquées retirées (6 templates) - Skeletons cohérents sur toutes les vues ⚡ Performance - Cache TTL sur get_file_commits (consistant avec les autres méthodes)
This commit is contained in:
@@ -42,17 +42,6 @@
|
||||
.gw-commit-bar{display:flex;align-items:center;gap:8px;padding:12px 24px;background:var(--bg-secondary);border-top:1px solid var(--border);flex-wrap:wrap;}
|
||||
.gw-commit-bar input{flex:1;min-width:180px;padding:8px 12px;background:var(--bg-tertiary);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:13px;outline:none;}
|
||||
.gw-commit-bar input:focus{border-color:var(--accent);}
|
||||
.btn-primary{padding:8px 16px;border-radius:8px;font-size:13px;cursor:pointer;border:none;font-weight:500;background:var(--accent);color:#fff;}
|
||||
.btn-primary:hover{background:var(--accent-hover);}
|
||||
.btn-danger{background:rgba(255,80,80,.15);color:var(--danger);border:none;padding:8px 16px;border-radius:8px;font-size:13px;cursor:pointer;font-weight:500;}
|
||||
.btn-danger:hover{background:rgba(255,80,80,.25);}
|
||||
.btn{border:none;padding:8px 16px;border-radius:8px;font-size:13px;cursor:pointer;font-weight:500;border:1px solid var(--border);background:transparent;color:var(--text-dim);}
|
||||
.btn:hover{background:var(--bg-tertiary);color:var(--text);}
|
||||
|
||||
/* ── Skeleton loading animation ── */
|
||||
.skeleton{background:var(--bg-tertiary);animation:pulse 1.5s ease-in-out infinite;border-radius:4px;}
|
||||
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
||||
.file-skeleton{padding:16px;border:1px solid var(--border);border-radius:8px;background:var(--bg-secondary);max-height:70vh;overflow:hidden;}
|
||||
|
||||
/* Prism theme tweaks for dark UI */
|
||||
.gw-content pre[class*="language-"]{background:var(--bg-tertiary)!important;border:1px solid var(--border)!important;border-radius:8px!important;padding:16px!important;}
|
||||
@@ -70,7 +59,7 @@
|
||||
</div>
|
||||
<div class="gw-content">
|
||||
<!-- Skeleton loading -->
|
||||
<div x-show="fileLoading" class="file-skeleton">
|
||||
<div x-show="fileLoading" class="skeleton-file">
|
||||
<div class="skeleton" style="height:15px;width:60%;margin-bottom:12px;"></div>
|
||||
<div class="skeleton" style="height:15px;width:80%;margin-bottom:12px;"></div>
|
||||
<div class="skeleton" style="height:15px;width:40%;margin-bottom:12px;"></div>
|
||||
@@ -450,9 +439,9 @@ function giteaWorkspace() {
|
||||
}
|
||||
} else {
|
||||
var d = await r.json();
|
||||
alert('Failed to save: ' + (d.error || 'Unknown error'));
|
||||
window.showToast('Failed to save: ' + (d.error || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch(e) { alert('Network error'); }
|
||||
} catch(e) { window.showToast('Network error', 'error'); }
|
||||
},
|
||||
|
||||
async deleteCurrentFile() {
|
||||
@@ -551,9 +540,9 @@ function giteaWorkspace() {
|
||||
await this.loadSidebarTree();
|
||||
} else {
|
||||
var d = await r.json();
|
||||
alert('Failed: ' + (d.error || d.detail || 'Unknown error'));
|
||||
window.showToast('Failed: ' + (d.error || d.detail || 'Unknown error'), 'error');
|
||||
}
|
||||
} catch(e) { alert('Error: ' + e.message); }
|
||||
} catch(e) { window.showToast('Error: ' + e.message, 'error'); }
|
||||
},
|
||||
|
||||
// Upload files
|
||||
@@ -720,7 +709,7 @@ function giteaWorkspace() {
|
||||
span.className = 'page-name';
|
||||
span.textContent = originalName;
|
||||
input.replaceWith(span);
|
||||
alert('Rename failed');
|
||||
window.showToast('Rename failed', 'error');
|
||||
}
|
||||
}).catch(function() {
|
||||
var span = document.createElement('span');
|
||||
|
||||
Reference in New Issue
Block a user