Compare commits

...

2 commits

Author SHA1 Message Date
1cb0da05e2 Merge pull request 'feat(ui): bouton « Tout réessayer »' (#17) from feat/retry-all into main
All checks were successful
Publier l'image Docker / test (push) Successful in 18s
Publier l'image Docker / publish (push) Successful in 13s
2026-10-14 08:55:04 +02:00
01fa3a9efe feat(ui): bouton « Tout réessayer »
Relance en une fois tous les fichiers en échec ; la barre de file reste
visible tant qu'il y en a et indique leur nombre.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 08:54:22 +02:00
2 changed files with 26 additions and 9 deletions

View file

@ -272,6 +272,7 @@
<div id="queueRow" class="card" hidden>
<span id="queueInfo" class="muted"></span>
<span class="queue-actions">
<button id="queueRetry" type="button" class="btn secondary" hidden>Tout réessayer</button>
<button id="queuePause" type="button" class="btn secondary">Tout mettre en pause</button>
<button id="queueCancel" type="button" class="btn secondary">Tout annuler</button>
</span>
@ -287,6 +288,7 @@
const queueInfo = document.getElementById('queueInfo');
const queueCancel = document.getElementById('queueCancel');
const queuePause = document.getElementById('queuePause');
const queueRetry = document.getElementById('queueRetry');
const list = document.getElementById('list');
const MAX_PARALLEL = 3; // dépôts directs (petits fichiers) simultanés
@ -376,6 +378,8 @@
job.state = state;
if (state === 'done' || state === 'failed' || state === 'cancelled') jobs.delete(job);
else jobs.add(job);
if (state === 'failed') failedJobs.add(job);
else failedJobs.delete(job);
updateQueueRow();
const { pauseBtn, retryBtn, cancelBtn } = job.ui;
pauseBtn.hidden = state !== 'running' && state !== 'paused';
@ -393,6 +397,7 @@
const active = new Set();
const jobs = new Set(); // jobs non terminés (en attente, en cours ou en pause)
const failedJobs = new Set(); // jobs en échec, relançables (« Réessayer » / « Tout réessayer »)
let allPaused = false; // « Tout mettre en pause » actif : la file ne démarre plus rien
function updateQueueRow() {
@ -404,18 +409,24 @@
else if (job.state === 'paused') paused += 1;
else waiting += 1;
}
if (jobs.size === 0) {
queueRow.hidden = true;
const failed = failedJobs.size;
const hasJobs = jobs.size > 0;
if (!hasJobs) {
allPaused = false;
queuePause.textContent = 'Tout mettre en pause';
return;
}
queueRow.hidden = false;
queueInfo.textContent =
running +
' en cours' +
(paused ? ' · ' + paused + ' en pause' : '') +
(waiting ? ' · ' + waiting + ' en attente' : '');
queueRow.hidden = !hasJobs && failed === 0;
queuePause.hidden = !hasJobs;
queueCancel.hidden = !hasJobs;
queueRetry.hidden = failed === 0;
queueInfo.textContent = [
hasJobs ? running + ' en cours' : '',
paused ? paused + ' en pause' : '',
waiting ? waiting + ' en attente' : '',
failed ? failed + ' en échec' : '',
]
.filter(Boolean)
.join(' · ');
}
function pump() {
@ -908,7 +919,12 @@
pump();
}
function retryAll() {
for (const job of Array.from(failedJobs)) retryJob(job);
}
queuePause.addEventListener('click', toggleAllPaused);
queueRetry.addEventListener('click', retryAll);
queueCancel.addEventListener('click', cancelAll);
// items : tableau de { file, path } — path '' = fichier simple, sinon dépôt de dossier.

View file

@ -95,6 +95,7 @@ describe('GET /', () => {
});
expect(res.body).toContain('id="zones"');
expect(res.body).toContain('id="queuePause"');
expect(res.body).toContain('id="queueRetry"');
expect(res.body).not.toContain('targetSelect');
expect(res.body).not.toContain('dirPicker');
});