From 10a1aef4c71698ac55c3527574465a965fdb66fc Mon Sep 17 00:00:00 2001 From: Quentin Rouiller Date: Thu, 23 Apr 2026 16:00:38 +0200 Subject: [PATCH] =?UTF-8?q?v2026.5.25=20=E2=80=94=20Bouton=20=E2=9A=99=20P?= =?UTF-8?q?aram=C3=A8tres=20dans=20popup=20user-badge=20(remplace=205=20cl?= =?UTF-8?q?ics=20secrets=20sur=20le=20titre)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 2 +- viewer.css | 87 +++++++++++++++++++++++++++++++++ viewer.js | 131 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 196 insertions(+), 24 deletions(-) diff --git a/manifest.json b/manifest.json index a6f0872..9563de0 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Planification", - "version": "2026.5.24", + "version": "2026.5.25", "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.", "permissions": ["activeTab", "scripting", "storage", "tabs", "alarms"], "host_permissions": [ diff --git a/viewer.css b/viewer.css index 12ace06..a3dd8dd 100644 --- a/viewer.css +++ b/viewer.css @@ -3002,3 +3002,90 @@ body.popup-dragging .pinned-popup { from { transform: scale(1); } to { transform: scale(1.05); } } + +/* ========================================================================== + v2026.5.25 : pastille dock enrichie (lieu + service + date) + + bouton Paramètres dans popup user-badge + + ref dans mini-menu pill + ========================================================================== */ + +/* Pastille dock : 3 lignes */ +.pinned-popup-dock-pill { + flex-direction: column !important; + align-items: flex-start !important; + padding: 6px 14px !important; + gap: 2px !important; + line-height: 1.2 !important; + text-align: left; + min-width: 200px; + max-width: 300px; +} +.pinned-popup-dock-pill-lieu { + display: block; + font-size: 13px; + font-weight: 700; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pinned-popup-dock-pill-service { + display: block; + font-size: 11px; + font-weight: 500; + opacity: 0.85; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.pinned-popup-dock-pill-date { + display: block; + font-size: 10px; + font-weight: 500; + opacity: 0.75; + font-family: var(--mono, monospace); +} + +/* Ref dans le mini-menu hover de la pastille */ +.pill-hover-menu-ref { + padding: 6px 12px; + text-align: center; + font-family: var(--mono, monospace); + font-size: 13px; + font-weight: 700; + color: var(--text); + border-bottom: 1px solid var(--border); + margin-bottom: 4px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Bouton Paramètres dans popup user-badge */ +.user-name-popup-settings { + display: flex; + align-items: center; + gap: 8px; + margin-top: 8px; + padding: 6px 10px; + background: var(--bg-muted); + color: var(--text); + border: 1px solid var(--border); + border-radius: 6px; + font-family: inherit; + font-size: 13px; + font-weight: 500; + cursor: pointer; + width: 100%; + justify-content: center; + transition: background 0.12s, color 0.12s, border-color 0.12s; +} +.user-name-popup-settings:hover { + background: var(--accent, #3b82f6); + color: white; + border-color: var(--accent, #3b82f6); +} +.user-name-popup-settings .settings-ico { + font-size: 15px; +} diff --git a/viewer.js b/viewer.js index 86f447e..a3fc558 100644 --- a/viewer.js +++ b/viewer.js @@ -416,6 +416,21 @@ function toggleUserNamePopup() { _renderUserPopupSessionLine(sessEl); popup.appendChild(sessEl); + // v2026.5.25 : bouton Paramètres (remplace les 5 clics sur le titre) + const settingsBtn = document.createElement("button"); + settingsBtn.type = "button"; + settingsBtn.className = "user-name-popup-settings"; + settingsBtn.innerHTML = ' Paramètres'; + settingsBtn.title = "Ouvrir les paramètres d'administration"; + settingsBtn.addEventListener("click", (e) => { + e.stopPropagation(); + hideUserNamePopup(); + if (typeof showAdminPanel === "function") { + showAdminPanel(); + } + }); + popup.appendChild(settingsBtn); + popup.classList.remove("hidden"); badge.classList.add("open"); // Positionne juste en dessous de la pastille @@ -1002,25 +1017,14 @@ function updateNowLine() { }); } -// v5.0.0 : menu admin caché. 5 clics consécutifs sur le titre "Planification" -// (avec max 2 secondes entre chaque clic) ouvrent le panneau admin. +// v5.0.0 : menu admin caché via 5 clics sur le titre "Planification". +// v2026.5.25 : SUPPRIMÉ — l'accès au panneau admin se fait désormais via le +// bouton "⚙ Paramètres" du popup user-badge (clic sur les initiales). function initAdminMenu() { const title = document.getElementById("app-title"); if (!title) return; - let clicks = 0; - let resetTimer = null; - title.addEventListener("click", () => { - clicks++; - if (resetTimer) clearTimeout(resetTimer); - resetTimer = setTimeout(() => { clicks = 0; }, 2000); - if (clicks >= 5) { - clicks = 0; - clearTimeout(resetTimer); - showAdminPanel(); - } - }); - // Cursor pointer pour indiquer (discrètement) qu'il est cliquable title.style.cursor = "default"; + // Plus de handler de clic : les 5 clics n'ouvrent plus rien. } // ============================================================================ @@ -5623,6 +5627,21 @@ function extractContacts(raw) { */ function splitOneContact(raw) { if (!raw) return { name: null, phone: null }; + + // v2026.5.25 : avant d'extraire les numéros, on REMPLACE les séquences qui + // sont des identifiants de matériel (LETTRES_CHIFFRES) par des espaces. + // Exemples : XXXX_NNNNNNNNNNN, XNNNNNN, XNNNNNN, XNNNNNN. + // Sans ça, XXXX_NNNNNNNNNNN laisse des "NNNN NNN NN NN" qui se font prendre + // pour un numéro de téléphone par le regex qui greedy sur [0-9\s.\-]. + // On remplace par des espaces de même longueur pour préserver les offsets + // (important pour le calcul de position du nom avant le 1er numéro). + raw = String(raw); + raw = raw.replace(/\b[A-Z]{1,6}_\d+/g, (m) => " ".repeat(m.length)); + // Idem pour les identifiants sans underscore style XNNNNNN, XNNNNNN, XNNNNNN + // (1-2 lettres majuscules suivies de 5+ chiffres collés). On garde assez + // permissif pour matcher les variantes sans enlever des vrais mots. + raw = raw.replace(/\b[A-Z]{1,3}\d{5,}\b/g, (m) => " ".repeat(m.length)); + // v4.1.20 : regex plus permissives pour tolérer les erreurs humaines : // - pas d'espace après le numéro (ex: "021555555Textecoller") // - pas d'espace/parenthèse avant un court numéro @@ -6606,6 +6625,35 @@ function pinTooltip() { // v2026.5.19 : mémoriser aussi la date pour l'afficher sur la pastille dock popup.dataset.originDate = state.currentDate || ""; + // v2026.5.25 : mémoriser aussi lieu + service pour la pastille enrichie + try { + const info = iv.infobulle || {}; + const lieuRaw = info.lieu || iv.bulleLieu || ""; + // Format pour pastille : "VILLE, Adresse" (on extrait les 2 premières parties) + const { ville, adresse } = (typeof splitLieu === "function") + ? splitLieu(lieuRaw) + : { ville: null, adresse: null }; + let lieuFmt = ""; + if (ville && adresse) lieuFmt = ville.toUpperCase() + ", " + adresse; + else if (adresse) lieuFmt = adresse; + else if (ville) lieuFmt = ville.toUpperCase(); + popup.dataset.lieu = lieuFmt; + + // Service : prendre les 2 dernières parties séparées par "/" + // Ex: "AdmCV/DJES/SSCM/SSCM - Admin/TEO - OS" → "SSCM - Admin/TEO - OS" + // "AdmCV/OJV/JPX/JPX Lavaux-Oron" → "JPX/JPX Lavaux-Oron" + const serviceRaw = (info.service) || iv.categoryLine || ""; + if (serviceRaw) { + const parts = serviceRaw.split("/").map(s => s.trim()).filter(Boolean); + const last2 = parts.slice(-2).join("/"); + popup.dataset.service = last2; + } else { + popup.dataset.service = ""; + } + } catch (err) { + console.warn("[pin] lieu/service build failed", err); + } + // v2026.5.17 : masquer l'icône 📌 du contenu cloné (redondante car le // popup a sa propre topbar avec le bouton "désépingler" 📍 explicite) const oldPin = popup.querySelector('.tooltip-pinbtn[data-action="pin"]'); @@ -6985,24 +7033,34 @@ function _reducePinnedPopup(popup) { // Créer la pastille dock // v2026.5.18 : le fond de la pastille prend la couleur de catégorie - // (via la classe color-XXX déjà utilisée ailleurs dans le CSS) - // v2026.5.19 : pastille à 2 lignes — ref (gras) + date origine (petit) + // v2026.5.25 : pastille à 3 lignes — lieu (fort), service (petit), date (petit) + // La référence est affichée dans le mini-menu au survol. const pill = document.createElement("button"); pill.type = "button"; pill.className = "pinned-popup-dock-pill color-" + colorKey; pill.title = "Cliquer pour agrandir"; - const pillRef = document.createElement("span"); - pillRef.className = "pinned-popup-dock-pill-ref"; - pillRef.textContent = label; - pill.appendChild(pillRef); + // Ligne 1 : lieu (ou ref si pas de lieu) + const pillLieu = document.createElement("span"); + pillLieu.className = "pinned-popup-dock-pill-lieu"; + pillLieu.textContent = popup.dataset.lieu || label || "—"; + pill.appendChild(pillLieu); - // Date d'origine (ex: "21.04") + // Ligne 2 : service (2 dernières parties) + const serviceTxt = popup.dataset.service || ""; + if (serviceTxt) { + const pillService = document.createElement("span"); + pillService.className = "pinned-popup-dock-pill-service"; + pillService.textContent = serviceTxt; + pill.appendChild(pillService); + } + + // Ligne 3 : date "Mardi 22.04" const originDate = popup.dataset.originDate || ""; if (originDate) { const pillDate = document.createElement("span"); pillDate.className = "pinned-popup-dock-pill-date"; - pillDate.textContent = _formatDateShort(originDate); + pillDate.textContent = _formatDateForPill(originDate); pill.appendChild(pillDate); } @@ -7078,6 +7136,15 @@ function _showPillHoverMenu(pill, popup) { menu._linkedPill = pill; menu._linkedPopup = popup; + // v2026.5.25 : REF en haut du menu (info seulement, centrée) + const refText = popup.dataset.ref || ""; + if (refText) { + const refLabel = document.createElement("div"); + refLabel.className = "pill-hover-menu-ref"; + refLabel.textContent = refText; + menu.appendChild(refLabel); + } + const restoreBtn = document.createElement("button"); restoreBtn.type = "button"; restoreBtn.className = "pill-hover-menu-btn"; @@ -7419,6 +7486,24 @@ function _formatDateShort(iso) { return `${m[3]}.${m[2]}`; } +/** + * v2026.5.25 : formatte une date ISO en "Mardi 22.04" pour la pastille dock. + */ +function _formatDateForPill(iso) { + if (!iso) return ""; + const m = String(iso).match(/^(\d{4})-(\d{2})-(\d{2})$/); + if (!m) return iso; + try { + const d = new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])); + const dayName = (typeof DAY_NAMES_FULL !== "undefined" && DAY_NAMES_FULL[d.getDay()]) + ? DAY_NAMES_FULL[d.getDay()] + : ""; + return (dayName ? dayName + " " : "") + m[3] + "." + m[2]; + } catch (e) { + return m[3] + "." + m[2]; + } +} + /** * v2026.5.18 : ajoute (ou met à jour) le bouton "Fermer tous" dans le dock * quand au moins 2 popups épinglés existent (réduits OU affichés).