Skip to content

BDD-151 — Corrections UI : bouton vider le canvas, verrouillage mapper et modale de modification

Contexte

Plusieurs anomalies visuelles et comportementales ont été identifiées dans l'éditeur de workflow :

  • Le bouton « Vider le canvas » apparaissait toujours surligné en gris, comme s'il était sélectionné en permanence.
  • Le type de traitement Mapper n'était jamais verrouillé après sauvegarde, contrairement à tous les autres types.
  • La modale de confirmation de changement de type affichait un libellé trop long (« Réinitialiser et modifier »).
  • Le renommage de colonnes dans le Mapper devenait impossible via la touche Suppr (l'ancien nom se restaurait à chaque suppression).
  • Lorsque le bloc amont du Mapper produisait 0 ligne, l'exécution échouait avec un message trompeur (« entrée amont indisponible »).
  • Les deux boutons d'export (Markdown / PDF) étaient dupliqués visuellement sans hiérarchie claire.

Critères d'acceptance

#CritèreCouvert par
1Le bouton « Vider le canvas » n'est plus sélectionné par défautCSS — background déplacé sur :hover
2Le type Mapper est verrouillé après la première sauvegarde, comme les autres typesSentinel _savedByUser + markActiveMapperAsSaved()
3La modale de modification affiche uniquement « Annuler » et « Oui »WorkflowNodeConfigModal — label remplacé

Corrections supplémentaires incluses

Alignement des éléments du menu débordement

Les trois éléments du menu « ··· » (Exporter la doc, Vider le canvas) n'étaient pas alignés : le bouton destructif utilisait un padding (10px 12px) et un min-width d'avatar (40px) différents des valeurs par défaut Quasar (8px 16px et 56px).

Correctif : alignement sur les valeurs Quasar par défaut dans .toolbar-overflow-destructive-tile.

Fusion des boutons d'export

Les boutons « Exporter la doc (Markdown) » et « Exporter la doc (PDF) » ont été fusionnés en un seul bouton « Exporter la doc ». Un clic ouvre une boîte de dialogue permettant de choisir le format. Les fonctions exportWorkflowDocumentationMarkdown() et exportWorkflowDocumentationPdf() sont inchangées.

Correction du renommage de colonnes dans le Mapper

Dans WorkflowMapperPanel, l'event @update:model-value utilisait $event || row.source : dès que l'utilisateur vidait le champ, la valeur revenait à l'ancien nom car une chaîne vide est falsy. L'utilisateur était bloqué dans une boucle infinie de suppression.

Correctif : @update:model-value passe $event directement (la chaîne vide est autorisée pendant la saisie). Un @blur restaure l'ancien nom uniquement si le champ est laissé vide à la perte de focus.

Correction — Mapper sur entrée amont à 0 ligne (staging)

Dans workflow-run-staging-execution.service.ts, la vérification d'accessibilité de l'entrée amont utilisait countRows(). countRows retourne 0 à la fois quand la table de staging n'existe pas et quand elle existe mais est vide. La condition !countRows() lançait donc une BadRequestException (« Bloc Traitement : entrée amont indisponible ») dès que le bloc amont produisait 0 ligne, même si la configuration était correcte.

Correctif : ajout de la méthode nodeTableExists(runUuid, nodeUuid) dans WorkflowRunStagingService (vérifie uniquement l'existence de la table, sans compter les lignes). La condition utilise désormais nodeTableExists : elle lève une erreur uniquement si la table est absente (bloc amont non exécuté ou en échec), et laisse passer le cas 0 ligne.

Architecture

Verrouillage du type Mapper après première sauvegarde

Le verrouillage des types de traitement repose sur le flag treatmentTypeSaved dans le state Vue Flow. Pour les types non-Mapper, ce flag est activé dès que config.type est non nul dans la réponse API — ce qui fonctionne car ces types n'ont pas de config par défaut avant que l'utilisateur sauvegarde.

Le Mapper génère systématiquement une config par défaut { type: 'mapper', columns: [] } dès la première persistance automatique (autosave canvas), ce qui rendait config.type non nul dès le début, avant toute action utilisateur. Il était donc impossible de détecter « l'utilisateur a sauvegardé » par ce seul flag.

Solution — sentinel _savedByUser

Un champ _savedByUser: true est injecté dans la config Mapper uniquement lors d'une sauvegarde explicite (clic sur « Sauvegarder » dans la modale), via la fonction markActiveMapperAsSaved() appelée dans handleModalSave.

Ce champ est persisté dans l'API avec le reste de la config JSONB, et ignoré par le backend à l'exécution. Lors du rechargement de la page ou de la re-synchronisation serveur, buildCanvasNodeFromApi et applyServerCanvasAfterSave vérifient config._savedByUser === true pour activer treatmentTypeSaved.

ScénarioRésultat
Nouveau nœud Mapper, autosave déclenché_savedByUser absent → non verrouillé
Utilisateur clique « Sauvegarder »_savedByUser: true injecté → verrouillé immédiatement
Rechargement page après sauvegardeAPI retourne _savedByUser: true → verrouillé
Utilisateur clique « Modifier le type »onResetTreatmentType remet config: null → sentinel effacé → déverrouillé

Fichiers modifiés

FichierModification
front/src/pages/admin/workflows/WorkflowEditorPage.vueCSS bouton destructif, fusion export, verrouillage Mapper (markActiveMapperAsSaved, _savedByUser), handleModalSave
front/src/pages/admin/workflows/workflow-canvas.model.jsbuildCanvasNodeFromApi — condition treatmentTypeSaved étendue au Mapper via _savedByUser
front/src/components/workflows/WorkflowNodeConfigModal.vueLabel « Oui » dans la modale de confirmation de changement de type
front/src/components/workflows/WorkflowMapperPanel.vueCorrectif @update:model-value / @blur pour le renommage de colonnes
back/src/api/workflows/staging/workflow-run-staging.service.tsAjout de nodeTableExists()
back/src/api/workflows/staging/workflow-run-staging-execution.service.tsRemplacement de countRows par nodeTableExists pour la vérification amont