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,
"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.",
"permissions": [
"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`);
// 5. SÉQUENTIEL : xhr2 (lieu/contact de la bulle) EN PREMIER,
// puis fetches fiches (ref/statut/texte complet) APRÈS.
// Raison : le texte complet de la timeline (branche fiches) peut
// écraser bulleDescription/bulleContact/bulleLieu. Il ne faut pas
// que ça arrive AVANT que la bulle de base soit posée, sinon on se
// retrouve avec une popup vide ou incomplète pendant des secondes.
// 5. PARALLÈLE : xhr2 (lieu/contact) + fetches fiches (ref/statut)
// Avant v3.1.1 : séquentiel, on devait attendre les 34 xhr2 avant de
// lancer les 34 fiches. Résultat : première ref arrivait après ~1s.
// Maintenant : les deux démarrent en même temps, chacun met à jour
// la ligne correspondante via le rendu incrémental.
const bulleNeeded = [];
for (const tech of merged.techs) {
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()) {
const tBulles = performance.now();
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`);
if (!isRefreshAborted()) {
renderFromData({
@@ -490,24 +491,37 @@ async function loadForDate(isoDate, opts = {}) {
source: "fresh+bulles"
});
}
})
);
}
// Étape 5b : fiches APRÈS les xhr2 (ref/statut + texte complet de timeline)
if ((opts.doStatusRefresh || needFetch) && !isRefreshAborted()) {
const tFiches = performance.now();
const nFiches = merged.techs.flatMap(t=>t.interventions).filter(i=>i.type==="AL-Intervention").length;
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`);
})
);
}
// 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)
// Uniquement si on est allé au bout (pas d'annulation).
if (!isRefreshAborted()) {
if (raceResult === "done" && !isRefreshAborted()) {
await writeCache(isoDate, { techs: merged.techs });
}
if (!isRefreshAborted()) {
if (raceResult === "done" && !isRefreshAborted()) {
showRefreshDone();
console.log(`[load] TOTAL: ${Math.round(performance.now() - t0)} ms`);