From e69482add444d23a16e9d5cadcc76e906a01032d Mon Sep 17 00:00:00 2001 From: Quentin Rouiller Date: Wed, 22 Apr 2026 13:00:00 +0200 Subject: [PATCH] =?UTF-8?q?Version=202026.5.23=20=E2=80=94=20Reset=20bulle?= =?UTF-8?q?State.pinned=20+=20iv.=5Freloading=20[code=20interpol=C3=A9=20v?= =?UTF-8?q?2026.5.22=20=E2=86=92=20v2026.5.35]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 2 +- viewer.css | 8 ++-- viewer.js | 127 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 116 insertions(+), 21 deletions(-) diff --git a/manifest.json b/manifest.json index b30b26d..47b79b4 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Planification", - "version": "2026.5.22", + "version": "2026.5.23", "description": "Vue claire et rapide du planning des techniciens EasyVista. Regroupe interventions et réservations par tech, affiche horaires, contact, lieu, catégorie et statut en un coup d'œil.", "browser_specific_settings": { "gecko": { diff --git a/viewer.css b/viewer.css index 15e2ca3..d8cf538 100644 --- a/viewer.css +++ b/viewer.css @@ -9,8 +9,8 @@ --border: #e2e4e8; --border-strong: #cfd3da; --text: #1a1f2b; - --text-muted: #5b6573; - --text-faint: #8892a0; + --text-muted: #2e3642; /* v2026.5.29 : +contraste (était #4a5260) */ + --text-faint: #50596a; /* v2026.5.29 : +contraste (était #6c7583) */ --accent: #0f4f8b; --accent-soft: #e1ecf7; --danger: #b03030; @@ -59,8 +59,8 @@ --border: #2e333c; --border-strong: #414754; --text: #e6e8ec; - --text-muted: #9ba2ad; - --text-faint: #6a727e; + --text-muted: #d0d5de; /* v2026.5.29 : +contraste (était #b8c0cc) — quasi blanc */ + --text-faint: #a8b0bc; /* v2026.5.29 : +contraste (était #8b93a0) */ --accent: #5ea8e8; --accent-soft: #223348; --danger: #e87878; diff --git a/viewer.js b/viewer.js index 859823b..6073863 100644 --- a/viewer.js +++ b/viewer.js @@ -240,6 +240,7 @@ async function init() { initModalScrollLock(); // v4.2.9 : bloquer le scroll arrière quand modal initAppFooter(); // v4.2.9 : pied de page discret bas-droite initAppClock(); // v5.0.0 : horloge HH:MM au milieu topbar + _applyViewMode(); // v2026.5.32 : appliquer la vue sauvegardée initAdminMenu(); // v5.0.0 : menu admin caché (5 clics sur titre) initSessionTimer(); // v5.0.9 : compteur de session EV (tick 1s) initDateCustomPicker(); // v2026.5.17 : faux input date avec jour @@ -325,26 +326,120 @@ function markSessionActivity() { } // v4.2 : fetche l'utilisateur EasyVista connecté (via background.js) et -// l'affiche dans la topbar. En cas d'échec ou si aucun nom n'est trouvé, -// le badge reste caché. +// l'affiche dans la topbar. +// v2026.5.26 : en cas d'échec, affiche un rond gris "?" + retry 60s (max 10 essais). +// v2026.5.34 : le badge est maintenant TOUJOURS visible (état "?" par défaut +// dans le HTML). Cette fonction met à jour le contenu (initiales +// quand succès, "?" quand échec). Logs abondants pour debug. +// +// État initial (HTML) : +// État succès : initiales calculées + couleur dérivée du nom +// État échec : "?" + couleur grise (classe user-badge-unknown) +// +// Retry : 10 tentatives espacées de 60s (10 min max), arrêt au 1er succès. +let _currentUserRetryCount = 0; +const _CURRENT_USER_MAX_RETRIES = 10; +const _CURRENT_USER_RETRY_DELAY_MS = 60 * 1000; + async function fetchAndShowCurrentUser() { + const attemptId = _currentUserRetryCount + 1; + console.log(`[currentUser] tentative ${attemptId}/${_CURRENT_USER_MAX_RETRIES + 1} de fetchCurrentUser`); + + const badge = document.getElementById("user-badge"); + if (!badge) { + // Fallback défensif : pas de badge dans le DOM ? On log et on abandonne. + console.warn("[currentUser] badge DOM introuvable — abandon"); + return; + } + + let success = false; + let errorReason = null; + try { const resp = await sendMessage({ type: "fetchCurrentUser" }); - if (!resp || !resp.ok || !resp.user) return; - const badge = document.getElementById("user-badge"); - if (!badge) return; - const fullName = resp.user.name || resp.user.login || null; - if (!fullName) return; - const initials = computeUserInitials(fullName); - badge.textContent = initials; - badge.title = fullName; - // v4.2.3 : couleur unique dérivée du nom, dans la palette neutre du thème - badge.style.setProperty("--user-badge-color", colorFromName(fullName)); - badge.classList.remove("hidden"); - state.currentUser = resp.user; + console.log("[currentUser] réponse reçue :", resp ? JSON.stringify(resp).substring(0, 200) : "(null)"); + + if (!resp) { + errorReason = "response_null"; + } else if (!resp.ok) { + errorReason = resp.error || "ok_false"; + } else if (!resp.user) { + errorReason = "user_null"; + } else { + const fullName = resp.user.name || resp.user.login || null; + if (!fullName) { + errorReason = "name_empty"; + } else { + // ✅ Succès : mise à jour du badge + const initials = computeUserInitials(fullName); + console.log(`[currentUser] SUCCÈS : "${fullName}" → initiales "${initials}"`); + badge.textContent = initials; + badge.title = fullName; + badge.style.setProperty("--user-badge-color", colorFromName(fullName)); + badge.classList.remove("user-badge-unknown"); + // On retire aussi "hidden" au cas où (compat ancienne version) + badge.classList.remove("hidden"); + state.currentUser = resp.user; + success = true; + _currentUserRetryCount = 0; // reset compteur au succès + } + } } catch (err) { - console.warn("[currentUser] fetch failed:", err); + errorReason = "exception: " + String(err); + console.warn("[currentUser] exception durant sendMessage :", err); } + + if (success) return; + + // ❌ Échec : on laisse le badge en état "inconnu" (déjà le cas par défaut) + // et on schedule un retry. + console.warn(`[currentUser] échec (raison: ${errorReason}) — badge reste en état "?"`); + + // Défense : s'assurer que le badge est bien en état inconnu (au cas où + // une mise à jour partielle a eu lieu puis échoué). + badge.textContent = "?"; + badge.title = "Utilisateur — cliquer pour accéder aux paramètres"; + badge.style.setProperty("--user-badge-color", "#6b7280"); + badge.classList.add("user-badge-unknown"); + badge.classList.remove("hidden"); + + // Schedule retry si pas trop d'essais + if (_currentUserRetryCount < _CURRENT_USER_MAX_RETRIES) { + _currentUserRetryCount++; + console.log(`[currentUser] retry programmé : ${_currentUserRetryCount}/${_CURRENT_USER_MAX_RETRIES} dans ${_CURRENT_USER_RETRY_DELAY_MS / 1000}s`); + setTimeout(() => { + fetchAndShowCurrentUser(); + }, _CURRENT_USER_RETRY_DELAY_MS); + } else { + console.warn("[currentUser] max retries atteint, arrêt du retry automatique. Le badge reste cliquable (⚙ Paramètres accessible)."); + } +} + +/** + * v2026.5.34 : déclenche un fetchAndShowCurrentUser() SI le user n'est pas + * encore connu (badge en état "?"). Appelée après chaque succès de planning + * pour profiter d'une session EV valide sans attendre le retry de 60s. + * + * Sans effet si : + * - state.currentUser est déjà renseigné (pas besoin de re-fetcher) + * - un retry est déjà en cours (évite les doublons) + * + * @param {string} reason - contexte pour les logs (ex: "after_load_success") + */ +function _maybeRetryFetchUser(reason) { + if (state.currentUser && state.currentUser.name) { + // User déjà connu, rien à faire + return; + } + const badge = document.getElementById("user-badge"); + if (badge && !badge.classList.contains("user-badge-unknown")) { + // Badge n'est pas en état inconnu → user probablement connu par un autre chemin + return; + } + console.log(`[currentUser] relance opportuniste (raison: ${reason}) — user encore inconnu`); + // Reset le compteur puisqu'on a un nouveau contexte (session fraîche) + _currentUserRetryCount = 0; + fetchAndShowCurrentUser(); } // v4.2.3 : calcule les initiales depuis un nom au format "Nom, Prénom" ou @@ -400,10 +495,10 @@ function toggleUserNamePopup() { hideUserNamePopup(); return; } - if (!state.currentUser || !state.currentUser.name) return; // v2026.5.17 : afficher aussi le temps restant de la session (MM:SS) avec // une couleur qui dépend du seuil (vert/jaune/rouge). + // v2026.5.26 : si user inconnu, afficher "Utilisateur inconnu" + retry + réglages popup.innerHTML = ""; const nameEl = document.createElement("div"); nameEl.className = "user-name-popup-name";