217 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # 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** :
 | |
| ```typescript
 | |
| ngAfterViewInit(): void {
 | |
|   this.bindEditorHostListeners(); // ❌ Trop tôt
 | |
|   setTimeout(() => this.bindEditorHostListeners(), 0);
 | |
| }
 | |
| ```
 | |
| 
 | |
| **Après** :
 | |
| ```typescript
 | |
| 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** :
 | |
| ```typescript
 | |
| 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  
 |