Ne plus réadopter les runs de génération vidés au rechargement de la page
- Le bouton « Vider » ne retirait que les tâches du côté client : au rechargement, la « dernière génération » du serveur (.generation.job.json) était réadoptée et les tâches finies réappaissaient. - Les runs retirés sont mémorisés par horodatage serveur (sessionStorage) ; l'adoption au chargement les ignore désormais. - Les tâches lancées immédiatement (sans passer par la file) captent l'horodatage de leur run à la fin, pour être retirables sans réadoption.
This commit is contained in:
@ -3533,6 +3533,17 @@ function saveGenTasks() {
|
|||||||
try { sessionStorage.setItem(GEN_QKEY, JSON.stringify(genTasks)); } catch (e) { /* privé */ }
|
try { sessionStorage.setItem(GEN_QKEY, JSON.stringify(genTasks)); } catch (e) { /* privé */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs dont l'utilisateur a retiré la tâche « finie » de la liste : on les
|
||||||
|
// mémorise (par horodatage serveur `started`) pour que le rechargement de la
|
||||||
|
// page — qui réadopte la « dernière génération » depuis .generation.job.json
|
||||||
|
// — ne les re-crée pas à chaque rafraîchissement.
|
||||||
|
const GEN_DKEY = 'lidarGenDismissed';
|
||||||
|
let dismissedRuns = new Set();
|
||||||
|
try { dismissedRuns = new Set(JSON.parse(sessionStorage.getItem(GEN_DKEY) || '[]')); } catch (e) { dismissedRuns = new Set(); }
|
||||||
|
function saveDismissed() {
|
||||||
|
try { sessionStorage.setItem(GEN_DKEY, JSON.stringify([...dismissedRuns])); } catch (e) { /* privé */ }
|
||||||
|
}
|
||||||
|
|
||||||
function genStepEl(s) {
|
function genStepEl(s) {
|
||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
el.className = 'gen-step ' + s.state;
|
el.className = 'gen-step ' + s.state;
|
||||||
@ -3658,6 +3669,10 @@ function finishRunningTasks(d) {
|
|||||||
t.state = d.returncode === 0 ? 'done'
|
t.state = d.returncode === 0 ? 'done'
|
||||||
: (d.returncode === null || d.returncode < 0) ? 'stopped' : 'failed';
|
: (d.returncode === null || d.returncode < 0) ? 'stopped' : 'failed';
|
||||||
t.returncode = d.returncode;
|
t.returncode = d.returncode;
|
||||||
|
// Sans identité de run capturée (tâche lancée immédiatement, jamais en
|
||||||
|
// file) : on mémorise l'horodatage du run pour pouvoir la retirer sans
|
||||||
|
// qu'elle soit réadoptée au rechargement de la page.
|
||||||
|
if (t.started === undefined) t.started = d.started;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (changed) saveGenTasks();
|
if (changed) saveGenTasks();
|
||||||
@ -3844,8 +3859,15 @@ function syncThenReload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
genQueueClear.addEventListener('click', () => {
|
genQueueClear.addEventListener('click', () => {
|
||||||
|
// Les tâches retirées (finies, interrompues, échecs) sont mémorisées : sans
|
||||||
|
// cela le rechargement réadopterait la « dernière génération » du serveur
|
||||||
|
// (.generation.job.json) et les ferait réapparaître.
|
||||||
|
for (const t of genTasks) {
|
||||||
|
if (t.state === 'running' || t.state === 'queued') continue;
|
||||||
|
if (t.started !== undefined) dismissedRuns.add(t.started);
|
||||||
|
}
|
||||||
genTasks = genTasks.filter(t => t.state === 'running' || t.state === 'queued');
|
genTasks = genTasks.filter(t => t.state === 'running' || t.state === 'queued');
|
||||||
saveGenTasks(); renderGenQueue();
|
saveGenTasks(); saveDismissed(); renderGenQueue();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Arrêt de la génération en cours : SIGTERM au pipeline côté serveur, qui
|
// Arrêt de la génération en cours : SIGTERM au pipeline côté serveur, qui
|
||||||
@ -3887,6 +3909,8 @@ renderGenQueue();
|
|||||||
if (genTasks.some(t => t.state === 'running' || t.state === 'queued')) pollGenStatus();
|
if (genTasks.some(t => t.state === 'running' || t.state === 'queued')) pollGenStatus();
|
||||||
else fetch('/api/status').then(r => r.ok ? r.json() : null).then(s => {
|
else fetch('/api/status').then(r => r.ok ? r.json() : null).then(s => {
|
||||||
if (!s || genTasks.some(t => t.started === s.started)) return;
|
if (!s || genTasks.some(t => t.started === s.started)) return;
|
||||||
|
// Déjà retirée manuellement de la liste : ne pas réadopter ce run.
|
||||||
|
if (s.started != null && dismissedRuns.has(s.started)) return;
|
||||||
// Déjà suivie par une tâche (en cours ou en file côté serveur) : pas
|
// Déjà suivie par une tâche (en cours ou en file côté serveur) : pas
|
||||||
// d'adoption en doublon d'un run lancé depuis cet onglet.
|
// d'adoption en doublon d'un run lancé depuis cet onglet.
|
||||||
const trackedQids = new Set(genTasks.filter(t => t.qid !== undefined).map(t => t.qid));
|
const trackedQids = new Set(genTasks.filter(t => t.qid !== undefined).map(t => t.qid));
|
||||||
|
|||||||
@ -255,6 +255,11 @@ def test_build_index_generates_html(tmp_path):
|
|||||||
# un run terminé réapparaît dans la file avec ses tuiles, sans doublon.
|
# un run terminé réapparaît dans la file avec ses tuiles, sans doublon.
|
||||||
assert "Dernière génération" in app_js
|
assert "Dernière génération" in app_js
|
||||||
assert "t.started === s.started" in app_js
|
assert "t.started === s.started" in app_js
|
||||||
|
# Vidage de la file : les runs retirés sont mémorisés (par horodatage
|
||||||
|
# serveur) pour que le rechargement ne réadopte pas la « dernière
|
||||||
|
# génération » du serveur et ne refasse pas réapparaître les tâches finies.
|
||||||
|
assert "dismissedRuns" in app_js
|
||||||
|
assert "saveDismissed()" in app_js
|
||||||
# Bouton « Compléter » : visualisations manquantes des dalles présentes
|
# Bouton « Compléter » : visualisations manquantes des dalles présentes
|
||||||
# dans input/ (scope all_missing envoyé au preview et au generate).
|
# dans input/ (scope all_missing envoyé au preview et au generate).
|
||||||
# « + Zone » et « Compléter » ne vivent que dans l'onglet Génération,
|
# « + Zone » et « Compléter » ne vivent que dans l'onglet Génération,
|
||||||
|
|||||||
Reference in New Issue
Block a user