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
|