Compare commits

..

1 Commits

Author SHA1 Message Date
FroSteel edd6ffc1c3 Version 3.3.0 — Corrections + raffinements
(manifest.json corrigé : était resté à 3.2.0 par oubli)
2026-04-17 18:00:00 +02:00
2 changed files with 37 additions and 23 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Planning Techniciens — Vue claire", "name": "Planning Techniciens — Vue claire",
"version": "3.2.0", "version": "3.3.0",
"description": "Vue claire du planning EasyVista (itsma.etat-de-vaud.ch et itsma.vd.ch) avec navigation par date, détection automatique des interventions closes et cache 7 jours.", "description": "Vue claire du planning EasyVista (itsma.etat-de-vaud.ch et itsma.vd.ch) avec navigation par date, détection automatique des interventions closes et cache 7 jours.",
"permissions": [ "permissions": [
"activeTab", "activeTab",
+26 -12
View File
@@ -450,12 +450,11 @@ async function loadForDate(isoDate, opts = {}) {
}); });
console.log(`[load] 1er rendu (sans refs) à ${Math.round(performance.now() - t0)} ms`); console.log(`[load] 1er rendu (sans refs) à ${Math.round(performance.now() - t0)} ms`);
// 5. SÉQUENTIEL : xhr2 (lieu/contact de la bulle) EN PREMIER, // 5. PARALLÈLE : xhr2 (lieu/contact) + fetches fiches (ref/statut)
// puis fetches fiches (ref/statut/texte complet) APRÈS. // Avant v3.1.1 : séquentiel, on devait attendre les 34 xhr2 avant de
// Raison : le texte complet de la timeline (branche fiches) peut // lancer les 34 fiches. Résultat : première ref arrivait après ~1s.
// écraser bulleDescription/bulleContact/bulleLieu. Il ne faut pas // Maintenant : les deux démarrent en même temps, chacun met à jour
// que ça arrive AVANT que la bulle de base soit posée, sinon on se // la ligne correspondante via le rendu incrémental.
// retrouve avec une popup vide ou incomplète pendant des secondes.
const bulleNeeded = []; const bulleNeeded = [];
for (const tech of merged.techs) { for (const tech of merged.techs) {
for (const iv of tech.interventions) { for (const iv of tech.interventions) {
@@ -476,11 +475,13 @@ async function loadForDate(isoDate, opts = {}) {
) )
); );
// Étape 5a : xhr2 d'abord (bulle de base : lieu/contact/texte court) const promises = [];
if (bulleNeeded.length > 0 && !isRefreshAborted()) { if (bulleNeeded.length > 0 && !isRefreshAborted()) {
const tBulles = performance.now(); const tBulles = performance.now();
console.log(`[load] fetch xhr2 pour ${bulleNeeded.length} interventions…`); console.log(`[load] fetch xhr2 pour ${bulleNeeded.length} interventions…`);
await fetchBullesForInterventions(bulleNeeded); promises.push(
fetchBullesForInterventions(bulleNeeded).then(() => {
console.log(`[load] xhr2 finis en ${Math.round(performance.now() - tBulles)} ms`); console.log(`[load] xhr2 finis en ${Math.round(performance.now() - tBulles)} ms`);
if (!isRefreshAborted()) { if (!isRefreshAborted()) {
renderFromData({ renderFromData({
@@ -490,24 +491,37 @@ async function loadForDate(isoDate, opts = {}) {
source: "fresh+bulles" source: "fresh+bulles"
}); });
} }
})
);
} }
// Étape 5b : fiches APRÈS les xhr2 (ref/statut + texte complet de timeline)
if ((opts.doStatusRefresh || needFetch) && !isRefreshAborted()) { if ((opts.doStatusRefresh || needFetch) && !isRefreshAborted()) {
const tFiches = performance.now(); const tFiches = performance.now();
const nFiches = merged.techs.flatMap(t=>t.interventions).filter(i=>i.type==="AL-Intervention").length; const nFiches = merged.techs.flatMap(t=>t.interventions).filter(i=>i.type==="AL-Intervention").length;
console.log(`[load] début fetch des ${nFiches} fiches…`); console.log(`[load] début fetch des ${nFiches} fiches…`);
await refreshStatuses(merged.techs, isoDate); promises.push(
refreshStatuses(merged.techs, isoDate).then(() => {
console.log(`[load] fiches finies en ${Math.round(performance.now() - tFiches)} ms`); console.log(`[load] fiches finies en ${Math.round(performance.now() - tFiches)} ms`);
})
);
} }
// Race du Promise.all avec le signal d'annulation : dès que l'user clique
// Arrêter, loadForDate sort immédiatement (masque le bouton, fait un toast)
// sans attendre que les 15 workers en cours finissent leurs fetches.
// Les fetches continuent en arrière-plan mais le token a changé donc ils
// ne peuvent plus écrire le cache ni rafraîchir le DOM.
const abortPromise = makeAbortPromise(myToken);
const allDone = Promise.all(promises).then(() => "done");
const raceResult = await Promise.race([allDone, abortPromise]);
// 6. Sauvegarder dans le cache (une seule fois, après que tout soit enrichi) // 6. Sauvegarder dans le cache (une seule fois, après que tout soit enrichi)
// Uniquement si on est allé au bout (pas d'annulation). // Uniquement si on est allé au bout (pas d'annulation).
if (!isRefreshAborted()) { if (raceResult === "done" && !isRefreshAborted()) {
await writeCache(isoDate, { techs: merged.techs }); await writeCache(isoDate, { techs: merged.techs });
} }
if (!isRefreshAborted()) { if (raceResult === "done" && !isRefreshAborted()) {
showRefreshDone(); showRefreshDone();
console.log(`[load] TOTAL: ${Math.round(performance.now() - t0)} ms`); console.log(`[load] TOTAL: ${Math.round(performance.now() - t0)} ms`);