fix: multi-sessions + système de toasts pour erreurs visibles

Sessions:
- Cookie pxp_refresh path: /api/auth/refresh → /api/auth/ pour être envoyé au logout
- Logout supprime uniquement le token de la session courante (via cookie hash)
  si pas de cookie = fallback suppression globale (rétro-compat)

Toasts:
- Store Alpine.store('toasts') avec error/success/warn/info + auto-dismiss
- Conteneur #pxp-toasts injecté dans <body>, persiste à travers les navigations Swup
- fetchMe(): HTTP non-401 → toast explicite (ex: HTTP 404 backend down)
- tryRefresh(): session expirée → sessionStorage → toast orange sur la page login
- logout(): message "Déconnexion réussie" sur la page login
- proxmoxPage.action(): toast succès/erreur pour start/stop LXC
- profilePage.revokeSession(): toast confirmation révocation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
enzo 2026-03-22 01:04:37 +01:00
parent 21e1e0ed1e
commit dc0c67b89c
3 changed files with 151 additions and 11 deletions

View file

@ -763,6 +763,57 @@
.history-status.success { color: var(--neu-success); }
.history-status.error { color: var(--neu-danger); }
/* ── Toasts ──────────────────────────────────────────────────────────────────── */
#pxp-toasts {
position: fixed;
bottom: 1.25rem;
right: 1.25rem;
z-index: 9999;
display: flex;
flex-direction: column;
gap: .5rem;
pointer-events: none;
max-width: 24rem;
}
.toast {
display: flex;
align-items: flex-start;
gap: .6rem;
padding: .75rem 1rem;
border-radius: var(--neu-radius);
background: var(--neu-surface);
box-shadow: 0 4px 16px rgba(0,0,0,.35);
border-left: 3px solid transparent;
font-size: .875rem;
pointer-events: all;
animation: toast-in .2s ease;
}
@keyframes toast-in {
from { opacity: 0; transform: translateX(1rem); }
to { opacity: 1; transform: translateX(0); }
}
.toast > i:first-child { margin-top: .05rem; flex-shrink: 0; font-size: 1rem; }
.toast-msg { flex: 1; color: var(--neu-text); line-height: 1.4; }
.toast-close {
background: none;
border: none;
cursor: pointer;
padding: 0;
color: var(--neu-text-muted);
line-height: 1;
flex-shrink: 0;
margin-top: .05rem;
}
.toast-close:hover { color: var(--neu-text); }
.toast--error { border-left-color: var(--neu-danger); }
.toast--error > i:first-child { color: var(--neu-danger); }
.toast--success { border-left-color: var(--neu-success); }
.toast--success > i:first-child { color: var(--neu-success); }
.toast--warn { border-left-color: var(--neu-warning); }
.toast--warn > i:first-child { color: var(--neu-warning); }
.toast--info { border-left-color: var(--neu-info); }
.toast--info > i:first-child { color: var(--neu-info); }
/* ── Éditeur de raccourcis ───────────────────────────────────────────────────── */
.shortcuts-editor { display: flex; flex-direction: column; gap: .5rem; }
.shortcut-row {