ObsiViewer/docs/EXCALIDRAW_SAVE_FIX.md

6.4 KiB

Fix de la Sauvegarde Excalidraw - Diagnostic et Solution

Problème Initial

  1. Bouton Sauvegarde ne déclenchait aucune requête réseau
  2. Boutons Export PNG/SVG désactivés en permanence

Cause Racine

Le problème était dans la séquence de binding des listeners :

Séquence défaillante :

  1. ngAfterViewInit() s'exécute
  2. Tente de binder les listeners sur <excalidraw-editor>
  3. Mais l'élément n'existe pas encore car il est derrière *ngIf="!isLoading()"
  4. Les listeners ne sont jamais attachés
  5. L'événement scene-change n'est jamais capturé
  6. excalidrawReady reste false
  7. Les exports restent désactivés

Solution Implémentée

1. Binding au bon moment

Avant :

ngAfterViewInit(): void {
  this.bindEditorHostListeners(); // ❌ Trop tôt
  setTimeout(() => this.bindEditorHostListeners(), 0);
}

Après :

onExcalidrawReady() {
  this.excalidrawReady = true;
  this.bindEditorHostListeners(); // ✅ Après le (ready) event
}

ngAfterViewInit(): void {
  // L'élément sera bindé via (ready)="onExcalidrawReady()"
}

Le template a déjà (ready)="onExcalidrawReady()" qui se déclenche quand l'API Excalidraw est disponible.

2. Indicateur Visuel de Sauvegarde

Remplacement du bouton texte par un indicateur visuel avec icône de disquette :

États :

  • 🔴 Rouge + "Non sauvegardé" : modifications non enregistrées
  • Gris + "Sauvegardé" : tout est sauvegardé
  • 🟡 Jaune + "Sauvegarde..." + animation pulse : sauvegarde en cours

Comportement :

  • Cliquable : force une sauvegarde immédiate
  • Tooltip : indique l'état et suggère Ctrl+S
  • Toast : notification "Sauvegarde réussie" ou "Erreur de sauvegarde"

3. Sauvegarde Automatique

Pipeline RxJS :

fromEvent<CustomEvent>(host, 'scene-change')
  .pipe(
    debounceTime(2000),           // Attend 2s après le dernier changement
    distinctUntilChanged(),       // Ignore si identique au dernier hash
    switchMap(() => save()),      // Sauvegarde
  )

4. Logs de Diagnostic

Ajout de logs console pour tracer le flux :

  • 🎨 Excalidraw Ready - Binding listeners
  • 🔗 Binding Excalidraw host listeners
  • 📝 Scene changed
  • 💾 Autosaving...
  • ✅ Autosave successful
  • 💾 Manual save triggered
  • 📤 Sending save request...
  • ✅ Manual save successful

Fichiers Modifiés

src/app/features/drawings/drawings-editor.component.ts

  • Déplacement du binding dans onExcalidrawReady()
  • Ajout de logs pour diagnostic
  • Toast sur sauvegarde manuelle
  • Debounce augmenté à 2s pour l'autosave

src/app/features/drawings/drawings-editor.component.html

  • Remplacement du bouton "💾 Sauvegarder" par indicateur visuel
  • Icône SVG de disquette avec états de couleur
  • Suppression des indicateurs redondants ("Modifications non enregistrées")
  • Conservation uniquement des erreurs et conflits

Comment Tester

1. Ouvrir un fichier

1. Ouvrir tests.excalidraw.md
2. Vérifier dans la console : "🎨 Excalidraw Ready"
3. Vérifier : "🔗 Binding Excalidraw host listeners"

2. Test Sauvegarde Automatique

1. Ajouter un élément au dessin
2. Vérifier console : "📝 Scene changed"
3. Attendre 2 secondes
4. Vérifier console : "💾 Autosaving..."
5. Vérifier console : "✅ Autosave successful"
6. Vérifier requête réseau : PUT /api/files?path=...
7. Vérifier indicateur : 🔴 Rouge → ⚫ Gris

3. Test Sauvegarde Manuelle

1. Ajouter un élément au dessin
2. Cliquer sur l'indicateur (disquette rouge)
3. Vérifier console : "💾 Manual save triggered"
4. Vérifier console : "📤 Sending save request..."
5. Vérifier console : "✅ Manual save successful"
6. Vérifier toast : "Sauvegarde réussie"
7. Vérifier requête réseau : PUT /api/files?path=...
8. Vérifier indicateur : 🔴 → ⚫

4. Test Export PNG/SVG

1. S'assurer que le fichier est chargé
2. Vérifier que les boutons Export sont activés
3. Cliquer "🖼️ Export PNG"
4. Vérifier requête réseau : PUT /api/files/blob?path=...png
5. Vérifier toast si erreur

5. Test Ctrl+S

1. Modifier le dessin
2. Appuyer Ctrl+S (ou Cmd+S sur Mac)
3. Vérifier console : "💾 Manual save triggered"
4. Vérifier toast : "Sauvegarde réussie"

Comportement Attendu

Au Chargement

  1. Spinner de chargement
  2. GET /api/files?path=tests.excalidraw.md
  3. 🎨 Excalidraw Ready - Binding listeners
  4. 🔗 Binding Excalidraw host listeners
  5. Indicateur : Gris "Sauvegardé"
  6. Exports : activés

Pendant l'Édition

  1. Ajout d'un élément
  2. 📝 Scene changed
  3. Indicateur : 🔴 Rouge "Non sauvegardé"
  4. Attente de 2 secondes
  5. 💾 Autosaving...
  6. PUT /api/files?path=...
  7. ✅ Autosave successful
  8. Indicateur : Gris "Sauvegardé"

Après Clic Sauvegarde

  1. 💾 Manual save triggered
  2. 📤 Sending save request...
  3. PUT /api/files?path=...
  4. ✅ Manual save successful
  5. Toast : "Sauvegarde réussie"
  6. Indicateur : Gris "Sauvegardé"

Troubleshooting

Pas de logs dans la console

→ Le composant ne charge pas, vérifier ngOnInit()

"⚠️ Cannot bind listeners - host element not found"

→ L'élément web component n'est pas créé, vérifier le template *ngIf

" No host element" lors du clic Sauvegarde

@ViewChild ne trouve pas l'élément, vérifier #editorEl

" No scene data"

getScene() retourne null, vérifier que l'API Excalidraw est initialisée

Pas de requête réseau

→ Vérifier dans la console les logs "💾" et "📤" → Si absents, le binding n'a pas eu lieu

Export désactivés

→ Vérifier excalidrawReady dans le composant → Doit être true après onExcalidrawReady()

Prochaines Étapes

Une fois le problème résolu (les logs apparaissent et les requêtes passent) :

  1. Retirer les logs de debug dans drawings-editor.component.ts
  2. Tester la sauvegarde intensive (ajouter/supprimer rapidement des éléments)
  3. Tester les conflits (modifier le fichier externellement)
  4. Vérifier la performance (fichiers avec 100+ éléments)
  5. Tester sur mobile (responsive + touch)

Résumé

Binding des listeners au bon moment (après ready)
Indicateur visuel clair (disquette colorée)
Sauvegarde automatique (2s debounce)
Sauvegarde manuelle (clic ou Ctrl+S)
Toast notifications
Logs de diagnostic
Export PNG/SVG fonctionnels