Repousser un projet en bloc, sauf ce dont on ne décide pas
Glisser la barre résumé décale toutes les phases du même nombre de jours, écarts conservés : un projet engagé glisse souvent, et le faire phase par phase les déformait. Restent en place ce qui est terminé — on ne réécrit pas le passé — et les phases à date imposée, nouveau booléen `fixed` pour ce qui est délégué ou tenu du dehors. D'où le format en version 6 : sans l'incrément, un binaire antérieur effacerait ces dates imposées à la première sauvegarde. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
32
js/app.js
32
js/app.js
@@ -22,12 +22,14 @@ import {
|
||||
STATUTS,
|
||||
ajouterJours,
|
||||
ajouterPhase,
|
||||
ancreDecalage,
|
||||
aujourdhui,
|
||||
bornesPlanning,
|
||||
cleTag,
|
||||
clotureEcraseDesStatuts,
|
||||
creerPhase,
|
||||
creerProjet,
|
||||
decalerProjet,
|
||||
ecarterProjet,
|
||||
etatProjet,
|
||||
figerReference,
|
||||
@@ -869,6 +871,17 @@ installerGlisser(refs.couloirs, {
|
||||
}
|
||||
majPlanning(remplacerProjet(planning, idProjet, (projet) => ({ ...projet, horizon })));
|
||||
},
|
||||
surDecalageProjet(idProjet, jours) {
|
||||
// Même convention que pour une phase : null veut dire « geste annulé ou sans
|
||||
// effet », on redessine sans rien sauvegarder.
|
||||
if (!jours) {
|
||||
dessiner();
|
||||
return;
|
||||
}
|
||||
majPlanning(
|
||||
remplacerProjet(planning, idProjet, (projet) => decalerProjet(projet, jours))
|
||||
);
|
||||
},
|
||||
surClicProjet(idProjet) {
|
||||
const projet = planning.projects.find((p) => p.id === idProjet);
|
||||
if (projet) ouvrirProjet(projet);
|
||||
@@ -1315,16 +1328,29 @@ refs.frise.addEventListener(
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
// Flèches : ajustement fin de la phase du curseur, au jour près.
|
||||
// Flèches : ajustement fin, au jour près, de ce que porte le curseur.
|
||||
document.addEventListener('keydown', (evenement) => {
|
||||
// Une ligne de projet n'a pas de dates : les flèches n'y ont rien à décaler.
|
||||
if (!curseur?.phase) return;
|
||||
if (!curseur) return;
|
||||
// Pas d'interception pendant une saisie dans le panneau ou un dialogue.
|
||||
if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName)) return;
|
||||
|
||||
const pas = evenement.key === 'ArrowLeft' ? -1 : evenement.key === 'ArrowRight' ? 1 : 0;
|
||||
if (pas === 0) return;
|
||||
|
||||
// Sur la ligne d'un projet, les flèches repoussent le projet entier — le même
|
||||
// geste que le glisser de sa barre cumulative, au jour près. Maj n'y ajoute
|
||||
// rien : un projet ne s'étire pas (docs/decisions.md, section 8).
|
||||
if (!curseur.phase) {
|
||||
const projet = planning.projects.find((p) => p.id === curseur.projet);
|
||||
if (!projet || !ancreDecalage(projet)) return;
|
||||
|
||||
evenement.preventDefault();
|
||||
majPlanning(
|
||||
remplacerProjet(planning, curseur.projet, (aDecaler) => decalerProjet(aDecaler, pas))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
evenement.preventDefault();
|
||||
const trouve = localiser(curseur.projet, curseur.phase);
|
||||
if (!trouve) return;
|
||||
|
||||
Reference in New Issue
Block a user