feat: add comprehensive error handling and logging for vault settings save operations with permission error detection and detailed error messages in UI toast notifications

This commit is contained in:
Bruno Charest 2026-03-26 16:00:27 -04:00
parent 2686cc5d11
commit 34f4e41419
4 changed files with 180 additions and 9 deletions

137
TROUBLESHOOTING.md Normal file
View File

@ -0,0 +1,137 @@
# Dépannage ObsiGate
## Problème : Interface gèle lors de la sauvegarde des paramètres de fichiers cachés
### Symptômes
- L'interface se fige quand vous cliquez sur "Sauvegarder" dans la section "Fichiers cachés"
- Le fichier `vault_settings.json` n'est pas créé dans `/DOCKER_CONFIG/ObsiGate/data`
- Aucun message d'erreur n'apparaît (ou message générique)
### Cause
Le conteneur Docker n'a pas les permissions nécessaires pour écrire dans le répertoire `/app/data` (monté depuis `/DOCKER_CONFIG/ObsiGate/data` sur l'hôte).
### Solution
#### 1. Vérifier que le répertoire existe sur l'hôte
```bash
# Créer le répertoire s'il n'existe pas
sudo mkdir -p /DOCKER_CONFIG/ObsiGate/data
# Vérifier qu'il existe
ls -la /DOCKER_CONFIG/ObsiGate/
```
#### 2. Corriger les permissions
Le conteneur s'exécute avec l'utilisateur `1000:1000` (voir `docker-compose.yml`). Le répertoire doit être accessible en écriture par cet utilisateur.
```bash
# Option A: Donner la propriété à l'utilisateur 1000
sudo chown -R 1000:1000 /DOCKER_CONFIG/ObsiGate/data
# Option B: Rendre le répertoire accessible en écriture pour tous (moins sécurisé)
sudo chmod -R 777 /DOCKER_CONFIG/ObsiGate/data
```
#### 3. Redémarrer le conteneur
```bash
cd /path/to/ObsiGate
docker-compose restart
```
#### 4. Vérifier les logs
Après le redémarrage, les logs backend afficheront des informations détaillées sur la sauvegarde :
```bash
docker-compose logs -f obsigate
```
Recherchez des lignes comme :
- `Attempting to save settings to /app/data/vault_settings.json`
- `Successfully saved settings for X vaults`
- Ou des erreurs : `Permission denied writing to...`
#### 5. Tester la sauvegarde
1. Ouvrez l'interface ObsiGate
2. Allez dans Configuration → Fichiers cachés
3. Modifiez un paramètre (cochez/décochez "Afficher tous les fichiers cachés")
4. Cliquez sur "💾 Sauvegarder"
5. Vous devriez voir un message de succès : "✓ Paramètres sauvegardés"
6. Si erreur, le message affichera maintenant le détail : "Erreur: Permission denied: Cannot write to settings file..."
#### 6. Vérifier que le fichier a été créé
```bash
ls -la /DOCKER_CONFIG/ObsiGate/data/vault_settings.json
cat /DOCKER_CONFIG/ObsiGate/data/vault_settings.json
```
Le fichier devrait contenir un JSON avec vos paramètres :
```json
{
"Workout": {
"includeHidden": true,
"hiddenWhitelist": []
},
"Bruno": {
"includeHidden": false,
"hiddenWhitelist": [".obsidian"]
}
}
```
### Vérification des permissions actuelles
```bash
# Voir les permissions du répertoire
ls -la /DOCKER_CONFIG/ObsiGate/
# Voir l'utilisateur qui exécute le conteneur
docker-compose exec obsigate id
# Devrait afficher : uid=1000 gid=1000
```
### Alternative : Changer l'utilisateur du conteneur
Si vous ne pouvez pas modifier les permissions de `/DOCKER_CONFIG/ObsiGate/data`, vous pouvez changer l'utilisateur du conteneur dans `docker-compose.yml` :
```yaml
services:
obsigate:
# Remplacer user: "1000:1000" par l'UID/GID du propriétaire du répertoire
user: "0:0" # root (non recommandé pour la sécurité)
# OU
user: "$(id -u):$(id -g)" # Votre utilisateur actuel
```
Puis redémarrez :
```bash
docker-compose down
docker-compose up -d
```
## Autres problèmes courants
### Les fichiers cachés ne s'affichent pas après sauvegarde
**Cause** : Les paramètres sont sauvegardés mais l'index n'a pas été reconstruit.
**Solution** : Après avoir cliqué sur "Sauvegarder", cliquez sur "🔄 Réindexer" pour reconstruire l'index avec les nouveaux paramètres.
### L'interface se fige lors de la réindexation
**Cause** : Vous essayez d'indexer un très gros répertoire caché (ex: `.git`, `.node_modules`).
**Solution** :
1. N'activez pas "Afficher tous les fichiers cachés" pour les vaults contenant de gros répertoires cachés
2. Utilisez plutôt la liste blanche pour ajouter uniquement les dossiers cachés spécifiques dont vous avez besoin (ex: `.obsidian`)
3. La réindexation sélective (uniquement les vaults modifiés) devrait être plus rapide
### Message "Permission denied" dans les logs
Voir la section principale ci-dessus pour corriger les permissions.

View File

@ -1477,7 +1477,20 @@ async def api_update_vault_settings(vault_name: str, body: dict = Body(...), cur
settings_to_update["hiddenWhitelist"] = body["hiddenWhitelist"] settings_to_update["hiddenWhitelist"] = body["hiddenWhitelist"]
# Update persisted settings # Update persisted settings
try:
updated = update_vault_setting(vault_name, settings_to_update) updated = update_vault_setting(vault_name, settings_to_update)
except PermissionError as e:
logger.error(f"Permission error saving settings for vault '{vault_name}': {e}")
raise HTTPException(
status_code=500,
detail=f"Permission denied: Cannot write to settings file. Check /app/data permissions."
)
except Exception as e:
logger.error(f"Error saving settings for vault '{vault_name}': {e}")
raise HTTPException(
status_code=500,
detail=f"Failed to save settings: {str(e)}"
)
# Update in-memory vault config # Update in-memory vault config
if vault_name in vault_config: if vault_name in vault_config:

View File

@ -46,14 +46,27 @@ def save_vault_settings() -> None:
"""Persist vault settings to disk.""" """Persist vault settings to disk."""
with _settings_lock: with _settings_lock:
try: try:
logger.info(f"Attempting to save settings to {_SETTINGS_PATH}")
logger.info(f"Parent directory: {_SETTINGS_PATH.parent}")
logger.info(f"Parent exists: {_SETTINGS_PATH.parent.exists()}")
_SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True) _SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
_SETTINGS_PATH.write_text( logger.info(f"Directory created/verified: {_SETTINGS_PATH.parent}")
json.dumps(_vault_settings, indent=2, ensure_ascii=False),
encoding="utf-8" content = json.dumps(_vault_settings, indent=2, ensure_ascii=False)
) logger.info(f"JSON content prepared ({len(content)} bytes)")
logger.info(f"Saved settings for {len(_vault_settings)} vaults")
_SETTINGS_PATH.write_text(content, encoding="utf-8")
logger.info(f"Successfully saved settings for {len(_vault_settings)} vaults to {_SETTINGS_PATH}")
except PermissionError as e:
logger.error(f"Permission denied writing to {_SETTINGS_PATH}: {e}")
logger.error(f"Check that user has write permissions to {_SETTINGS_PATH.parent}")
raise
except Exception as e: except Exception as e:
logger.error(f"Failed to save vault settings: {e}") logger.error(f"Failed to save vault settings to {_SETTINGS_PATH}: {e}")
logger.error(f"Error type: {type(e).__name__}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
raise raise

View File

@ -3456,6 +3456,12 @@
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(settings) body: JSON.stringify(settings)
}).then(async response => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({ detail: response.statusText }));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return response.json();
}) })
); );
}); });
@ -3466,7 +3472,8 @@
showToast("✓ Paramètres sauvegardés", "success"); showToast("✓ Paramètres sauvegardés", "success");
} catch (err) { } catch (err) {
console.error("Failed to save hidden files settings:", err); console.error("Failed to save hidden files settings:", err);
showToast("Erreur de sauvegarde", "error"); const errorMsg = err.message || "Erreur inconnue";
showToast(`Erreur: ${errorMsg}`, "error");
} finally { } finally {
if (btn) { btn.disabled = false; btn.textContent = "💾 Sauvegarder"; } if (btn) { btn.disabled = false; btn.textContent = "💾 Sauvegarder"; }
} }
@ -3501,7 +3508,8 @@
await Promise.all([loadVaults(), loadTags()]); await Promise.all([loadVaults(), loadTags()]);
} catch (err) { } catch (err) {
console.error("Reindex with hidden files error:", err); console.error("Reindex with hidden files error:", err);
showToast("Erreur de réindexation", "error"); const errorMsg = err.message || "Erreur inconnue";
showToast(`Erreur: ${errorMsg}`, "error");
} finally { } finally {
if (btn) { btn.disabled = false; btn.textContent = "🔄 Réindexer"; } if (btn) { btn.disabled = false; btn.textContent = "🔄 Réindexer"; }
} }