Remplace la modale liste+menus deroulants du Scenario par un vrai graphe visuel
Build and deploy / test-python (push) Successful in 7m32s
Build and deploy / test-js (push) Successful in 49s
Build and deploy / lint-python (push) Successful in 5m21s
Build and deploy / lint-js (push) Failing after 1m12s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 3m53s

Retour utilisateur : "passons a un veritable graphe visuel". Chaque
nœud gagne une position x/y (document_engine/labels/scenario_config.py
: un x/y manquant/invalide retombe sur un quadrillage en cascade derive
de l'index du nœud, jamais (0, 0) pour tous les nœuds qui les
empilerait au meme endroit).

Cote editeur (static/document/js/document-editor.js) : les nœuds sont
des cartes deplacables a la souris sur un canevas (glisser-deposer reel,
meme principe que le glisser des formes libres), les choix relies a une
cible sont dessines comme des fleches SVG etiquetees par leur texte
(jamais un menu deroulant). Editer le texte/les choix d'un nœud se fait
dans un panneau inspecteur (colonne de droite) pour le nœud
selectionne ; relier un choix se fait en cliquant "Relier" puis le nœud
cible sur le graphe (mode connexion, Echap annule sans fermer la
modale). La modale generique (.docModal*) est agrandie specifiquement
pour ce graphe (jusqu'a 1180px) sans toucher sa taille par defaut.

Verifie via simulation DOM reelle (jsdom) : rendu des nœuds/positions,
glisser-deposer avec persistance au relachement, traces des fleches SVG
+ etiquettes, workflow complet du mode connexion, suppression d'un nœud
avec reparation des references pendantes, et les 3 façons de fermer la
modale (bouton/fond/Echap) y compris l'annulation du mode connexion
sans fermer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-21 09:03:47 +02:00
co-authored by Claude Sonnet 5
parent 7e504b7865
commit d92f75a803
6 changed files with 777 additions and 159 deletions
+214
View File
@@ -1469,6 +1469,220 @@ img.docImage {
justify-content: center;
}
/* ---- Scénario : éditeur d'arbre en GRAPHE VISUEL (retour utilisateur
du 21/09/2026 : "passons à un véritable graphe visuel", remplace la
première version en liste de nœuds + menus déroulants). Dialogue bien
plus grand que la modale générique par défaut : un graphe a besoin de
place pour être lisible. ---- */
#docScenarioTreeModal .docModalDialog {
width: min(1180px, 95vw);
max-height: min(88vh, 820px);
}
#docScenarioTreeModal .docModalBody {
padding: 0;
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 0;
}
.docScenarioGraphTitleRow {
padding: 16px 20px;
border-bottom: 1px solid var(--doc-border);
}
.docScenarioGraphTitleRow input {
width: 100%;
border: 1px solid var(--doc-border);
border-radius: 8px;
padding: 8px 10px;
font-size: 14px;
font-weight: 700;
color: var(--doc-text);
background: var(--doc-bg-2);
}
.docScenarioGraphToolbar {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px;
border-bottom: 1px solid var(--doc-border);
}
.docScenarioGraphHint {
font-size: 12.5px;
color: var(--doc-muted);
}
.docScenarioGraphHint.is-connecting {
color: var(--doc-accent);
font-weight: 600;
}
.docScenarioGraphSplit {
flex: 1 1 auto;
min-height: 0;
display: flex;
}
.docScenarioGraphCanvas {
position: relative;
flex: 1 1 auto;
min-width: 0;
overflow: auto;
background:
radial-gradient(circle, var(--doc-border) 1px, transparent 1px) 0 0 / 24px 24px,
var(--doc-bg-2);
cursor: default;
}
.docScenarioGraphCanvas.is-connecting {
cursor: crosshair;
}
.docScenarioGraphCanvas.is-connecting .docScenarioGraphNode {
cursor: crosshair;
}
.docScenarioGraphInner {
position: relative;
width: 2200px;
height: 1600px;
}
.docScenarioGraphSvg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.docScenarioGraphEdge {
fill: none;
stroke: var(--doc-muted);
stroke-width: 2;
}
.docScenarioGraphEdgeLabel {
position: absolute;
transform: translate(-50%, -50%);
background: var(--doc-bg-2);
border: 1px solid var(--doc-border);
border-radius: 6px;
padding: 2px 7px;
font-size: 11px;
font-weight: 600;
color: var(--doc-muted);
white-space: nowrap;
max-width: 140px;
overflow: hidden;
text-overflow: ellipsis;
}
.docScenarioGraphNode {
position: absolute;
width: 180px;
border: 1px solid var(--doc-border);
border-radius: 10px;
background: var(--doc-card);
padding: 10px 12px;
cursor: grab;
user-select: none;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
.docScenarioGraphNode:active {
cursor: grabbing;
}
.docScenarioGraphNode.is-root {
border-color: var(--doc-accent);
}
.docScenarioGraphNode.is-selected {
border-color: var(--doc-accent);
box-shadow: 0 0 0 2px var(--doc-accent);
}
.docScenarioGraphNode.is-connect-target:hover {
border-color: var(--doc-quiz-success-border);
box-shadow: 0 0 0 2px var(--doc-quiz-success-border);
}
.docScenarioGraphNodeLabel {
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
color: var(--doc-accent);
margin-bottom: 4px;
}
.docScenarioGraphNodeText {
font-size: 12.5px;
line-height: 1.35;
color: var(--doc-text);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
.docScenarioGraphInspector {
flex: 0 0 300px;
border-left: 1px solid var(--doc-border);
padding: 16px;
overflow-y: auto;
}
.docScenarioGraphInspectorEmpty {
font-size: 13px;
color: var(--doc-muted);
text-align: center;
padding: 30px 10px;
}
.docScenarioChoiceTargetRow {
display: flex;
align-items: center;
gap: 6px;
margin-top: 4px;
}
.docScenarioChoiceTargetLabel {
flex: 1;
min-width: 0;
font-size: 12px;
color: var(--doc-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.docScenarioChoiceLinkBtn {
border: 1px solid var(--doc-border);
background: transparent;
color: var(--doc-text);
border-radius: 6px;
padding: 3px 8px;
font-size: 11.5px;
cursor: pointer;
white-space: nowrap;
}
.docScenarioChoiceLinkBtn:hover {
border-color: var(--doc-accent);
}
.docScenarioChoiceLinkBtn.is-active {
border-color: var(--doc-accent);
background: var(--doc-accent);
color: #14100c;
}
/* ===== RESPONSIVE (chrome de l'éditeur lui-même, <900px) ===== */
@media (width <= 900px) {
.docCrumbDim {