v5.0.10 — Stabilité session EV

This commit is contained in:
Quentin Rouiller
2026-04-21 15:32:44 +02:00
parent e17f604d9e
commit 7ba28d3bac
3 changed files with 51 additions and 27 deletions
+3 -1
View File
@@ -1004,7 +1004,9 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === "openEasyVistaLogin") { if (msg.type === "openEasyVistaLogin") {
// v5.0.9 : ouvre EasyVista dans un nouvel onglet pour provoquer // v5.0.9 : ouvre EasyVista dans un nouvel onglet pour provoquer
// le SSO Windows automatique (reconnexion transparente). // le SSO Windows automatique (reconnexion transparente).
const origin = msg.origin || "https://itsma.etat-de-vaud.ch"; // v5.0.10 : fallback sur itsma.vd.ch (externe, accessible de partout)
// au lieu de .etat-de-vaud.ch (inaccessible en télétravail).
const origin = msg.origin || "https://itsma.vd.ch";
try { try {
const tab = await chrome.tabs.create({ const tab = await chrome.tabs.create({
url: `${origin}/index.php?eventName=HelpDesk_PlanningItem`, url: `${origin}/index.php?eventName=HelpDesk_PlanningItem`,
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Planification", "name": "Planification",
"version": "5.0.9", "version": "5.0.10",
"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.", "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"], "permissions": ["activeTab", "scripting", "storage", "tabs", "alarms"],
"host_permissions": [ "host_permissions": [
+47 -25
View File
@@ -152,16 +152,18 @@ let state = {
currentData: null, // résultat parsé (techs, stats, ...) currentData: null, // résultat parsé (techs, stats, ...)
loading: false, loading: false,
// v5.0.9 : timestamp (ms) auquel la session EV va expirer. // v5.0.9 : timestamp (ms) auquel la session EV va expirer.
// On suppose une durée de 30 min à chaque requête EV réussie.
// null = inconnu (pas encore récupéré).
sessionExpireAt: null, sessionExpireAt: null,
// v5.0.9 : true pendant une reconnexion en cours (après clic sur "Me // v5.0.9 : true pendant une reconnexion en cours
// reconnecter" tant que la nouvelle session n'est pas détectée)
reconnecting: false, reconnecting: false,
// v5.0.9 : true si la session est expirée (bannière rouge affichée) // v5.0.9 : true si la session est expirée (bannière rouge affichée)
sessionExpired: false, sessionExpired: false,
// v5.0.9 : true si on a déjà fait le ping de confirmation < 5 min // v5.0.9 : true si on a déjà fait le ping de confirmation < 5 min
sessionPingDone: false sessionPingDone: false,
// v5.0.10 : dernière origine EV connue comme fonctionnelle (itsma.vd.ch
// ou itsma.etat-de-vaud.ch selon qu'on est en externe ou interne).
// Conservée même quand state.session est null, pour savoir où rediriger
// lors de la reconnexion.
lastKnownOrigin: null
}; };
// v5.0.9 : constantes session // v5.0.9 : constantes session
@@ -263,6 +265,10 @@ async function refreshSessionAndLoad() {
return; return;
} }
state.session = resp.session; state.session = resp.session;
// v5.0.10 : mémoriser l'origine courante pour la reconnexion si besoin
if (resp.session && resp.session.origin) {
state.lastKnownOrigin = resp.session.origin;
}
hideSessionNeeded(); hideSessionNeeded();
hideEvUnreachable(); hideEvUnreachable();
hideSessionExpiredBanner(); hideSessionExpiredBanner();
@@ -496,7 +502,12 @@ function bindTopbar() {
} }
}); });
document.getElementById("open-ev-btn").addEventListener("click", openEasyVista); // v5.0.10 : clic "Ouvrir EasyVista" sur l'écran plein → déclenche la
// reconnexion SSO + l'auto-reload du viewer dès que la nouvelle session
// est détectée (au lieu d'ouvrir juste un onglet).
document.getElementById("open-ev-btn").addEventListener("click", () => {
triggerReconnect();
});
// v4.2 : écran "EasyVista inaccessible" // v4.2 : écran "EasyVista inaccessible"
const openEvBtn2 = document.getElementById("open-ev-btn-2"); const openEvBtn2 = document.getElementById("open-ev-btn-2");
@@ -527,11 +538,16 @@ function bindTopbar() {
} }
async function openEasyVista() { async function openEasyVista() {
// Ouvrir sur le domaine externe (accessible depuis l'extérieur). // v5.0.10 : ouvrir sur le domaine le plus approprié :
// Le domaine interne (itsma.etat-de-vaud.ch) n'est accessible que depuis le réseau VD. // - lastKnownOrigin si on a déjà eu une session fonctionnelle (respecte
// Une fois connecté, l'extension détectera automatiquement le PHPSESSID quel que // interne vs externe selon le réseau)
// soit le domaine où tu es connecté. // - session.origin si on a encore la session
await chrome.tabs.create({ url: "https://itsma.vd.ch/" }); // - itsma.vd.ch en fallback (domaine externe accessible de partout,
// même depuis le réseau VD il redirige vers l'interne transparent)
const origin = state.lastKnownOrigin
|| (state.session && state.session.origin)
|| "https://itsma.vd.ch";
await chrome.tabs.create({ url: origin + "/" });
} }
// Navigation ±1 jour en sautant les week-ends // Navigation ±1 jour en sautant les week-ends
@@ -1001,13 +1017,20 @@ function showSessionCriticalModal() {
* Appelé au clic "Me reconnecter" dans la bannière. Ouvre EasyVista dans un * Appelé au clic "Me reconnecter" dans la bannière. Ouvre EasyVista dans un
* nouvel onglet (déclenche Windows SSO Kerberos automatique). Le polling * nouvel onglet (déclenche Windows SSO Kerberos automatique). Le polling
* dans initSessionTimer détectera la nouvelle session et rechargera le viewer. * dans initSessionTimer détectera la nouvelle session et rechargera le viewer.
*
* v5.0.10 : utilise l'origine dynamique (interne ou externe selon le réseau).
* Priorité : lastKnownOrigin (mémorisée quand ça marchait) > session.origin >
* itsma.vd.ch (externe, accessible de partout) en fallback.
*/ */
async function triggerReconnect() { async function triggerReconnect() {
state.reconnecting = true; state.reconnecting = true;
hideSessionExpiredBanner(); hideSessionExpiredBanner();
showReconnectingBanner(); showReconnectingBanner();
try { try {
const origin = (state.session && state.session.origin) || "https://itsma.etat-de-vaud.ch"; const origin = state.lastKnownOrigin
|| (state.session && state.session.origin)
|| "https://itsma.vd.ch";
console.log("[session] triggerReconnect → ouverture de", origin);
await sendMessage({ type: "openEasyVistaLogin", origin }); await sendMessage({ type: "openEasyVistaLogin", origin });
} catch (err) { } catch (err) {
console.warn("[session] openEasyVistaLogin failed:", err); console.warn("[session] openEasyVistaLogin failed:", err);
@@ -6773,18 +6796,19 @@ function showSessionExpiredBanner() {
const b = document.getElementById("session-expired-banner"); const b = document.getElementById("session-expired-banner");
if (b) { if (b) {
b.classList.remove("hidden"); b.classList.remove("hidden");
// v5.0.9 : s'assurer que la bannière contient le bouton "Me reconnecter" // v5.0.10 : rebrancher le bouton "Ouvrir EasyVista" natif pour qu'il
// et qu'il appelle triggerReconnect (SSO Windows transparent). // appelle triggerReconnect() au lieu de juste ouvrir un onglet. Ça
if (!b.querySelector(".session-expired-reconnect-btn")) { // déclenche la reconnexion SSO ET l'auto-reload du viewer quand la
// Chercher le premier .banner-content ou injecter du contenu si vide // nouvelle session est détectée.
let content = b.querySelector(".banner-content") || b; // On renomme aussi le bouton pour être explicite.
// Si déjà du contenu natif, on ajoute juste le bouton à la fin const btn = b.querySelector("#session-banner-reconnect");
const btn = document.createElement("button"); if (btn && !btn.dataset.boundReconnect) {
btn.type = "button"; btn.dataset.boundReconnect = "1";
btn.className = "session-expired-reconnect-btn";
btn.textContent = "🔄 Me reconnecter"; btn.textContent = "🔄 Me reconnecter";
btn.addEventListener("click", () => triggerReconnect()); // Retirer d'éventuels anciens listeners en clonant le bouton
content.appendChild(btn); const clone = btn.cloneNode(true);
btn.parentNode.replaceChild(clone, btn);
clone.addEventListener("click", () => triggerReconnect());
} }
} }
hideEvUnreachableBanner(); hideEvUnreachableBanner();
@@ -6800,7 +6824,6 @@ function hideSessionExpiredBanner() {
function showReconnectingBanner() { function showReconnectingBanner() {
let b = document.getElementById("session-reconnecting-banner"); let b = document.getElementById("session-reconnecting-banner");
if (!b) { if (!b) {
// Créer la bannière si elle n'existe pas (dans le topbar)
b = document.createElement("div"); b = document.createElement("div");
b.id = "session-reconnecting-banner"; b.id = "session-reconnecting-banner";
b.className = "banner-reconnecting"; b.className = "banner-reconnecting";
@@ -6808,7 +6831,6 @@ function showReconnectingBanner() {
<span class="banner-spinner"></span> <span class="banner-spinner"></span>
<span class="banner-text">Reconnexion à EasyVista en cours Connectez-vous dans l'onglet qui vient de s'ouvrir.</span> <span class="banner-text">Reconnexion à EasyVista en cours Connectez-vous dans l'onglet qui vient de s'ouvrir.</span>
`; `;
// L'insérer juste après la topbar
const topbar = document.querySelector(".topbar") || document.querySelector("header") || document.body; const topbar = document.querySelector(".topbar") || document.querySelector("header") || document.body;
if (topbar.nextSibling) { if (topbar.nextSibling) {
topbar.parentNode.insertBefore(b, topbar.nextSibling); topbar.parentNode.insertBefore(b, topbar.nextSibling);