- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
647 lines
27 KiB
Python
Executable File
647 lines
27 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Script de Diagnostic - Propriétés d'Étapes Vides VWB
|
|
Auteur : Dom, Alice, Kiro - 12 janvier 2026
|
|
|
|
Ce script diagnostique le problème des propriétés d'étapes vides dans le Visual Workflow Builder
|
|
en analysant la configuration, les types d'étapes et les mappings.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any, Optional
|
|
import subprocess
|
|
import re
|
|
|
|
class VWBPropertiesDiagnostic:
|
|
"""Diagnostic complet du système de propriétés d'étapes VWB."""
|
|
|
|
def __init__(self):
|
|
"""Initialise le diagnostic."""
|
|
self.project_root = Path(__file__).parent.parent
|
|
self.frontend_path = self.project_root / "visual_workflow_builder" / "frontend"
|
|
self.backend_path = self.project_root / "visual_workflow_builder" / "backend"
|
|
|
|
self.results = {
|
|
"timestamp": "2026-01-12",
|
|
"diagnostic_version": "1.0.0",
|
|
"issues_found": [],
|
|
"recommendations": [],
|
|
"file_analysis": {},
|
|
"type_mappings": {},
|
|
"vwb_actions": {},
|
|
"configuration_status": {}
|
|
}
|
|
|
|
print("🔍 Diagnostic des Propriétés d'Étapes VWB - Démarrage")
|
|
print(f"📁 Racine du projet : {self.project_root}")
|
|
|
|
def run_full_diagnostic(self) -> Dict[str, Any]:
|
|
"""Exécute le diagnostic complet."""
|
|
try:
|
|
print("\n" + "="*60)
|
|
print("🔍 DIAGNOSTIC COMPLET DES PROPRIÉTÉS D'ÉTAPES")
|
|
print("="*60)
|
|
|
|
# 1. Analyser la configuration des paramètres
|
|
self._analyze_step_parameters_config()
|
|
|
|
# 2. Analyser les types d'étapes
|
|
self._analyze_step_types()
|
|
|
|
# 3. Analyser les actions VWB
|
|
self._analyze_vwb_actions()
|
|
|
|
# 4. Analyser les hooks d'intégration
|
|
self._analyze_integration_hooks()
|
|
|
|
# 5. Analyser le composant PropertiesPanel
|
|
self._analyze_properties_panel()
|
|
|
|
# 6. Vérifier la cohérence TypeScript
|
|
self._check_typescript_consistency()
|
|
|
|
# 7. Générer les recommandations
|
|
self._generate_recommendations()
|
|
|
|
# 8. Sauvegarder le rapport
|
|
self._save_diagnostic_report()
|
|
|
|
print(f"\n✅ Diagnostic terminé - {len(self.results['issues_found'])} problèmes identifiés")
|
|
return self.results
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur lors du diagnostic : {e}")
|
|
self.results["fatal_error"] = str(e)
|
|
return self.results
|
|
|
|
def _analyze_step_parameters_config(self):
|
|
"""Analyse la configuration stepParametersConfig."""
|
|
print("\n📋 Analyse de la configuration stepParametersConfig...")
|
|
|
|
properties_panel_path = self.frontend_path / "src" / "components" / "PropertiesPanel" / "index.tsx"
|
|
|
|
if not properties_panel_path.exists():
|
|
self._add_issue("CRITICAL", "Fichier PropertiesPanel/index.tsx introuvable", {
|
|
"expected_path": str(properties_panel_path)
|
|
})
|
|
return
|
|
|
|
try:
|
|
content = properties_panel_path.read_text(encoding='utf-8')
|
|
|
|
# Extraire la configuration stepParametersConfig
|
|
config_match = re.search(
|
|
r'const stepParametersConfig:\s*Record<StepType,\s*ParameterConfig\[\]>\s*=\s*{([^}]+)}',
|
|
content,
|
|
re.DOTALL
|
|
)
|
|
|
|
if config_match:
|
|
config_content = config_match.group(1)
|
|
|
|
# Extraire les types configurés
|
|
type_matches = re.findall(r'(\w+):\s*\[', config_content)
|
|
configured_types = set(type_matches)
|
|
|
|
self.results["configuration_status"]["stepParametersConfig"] = {
|
|
"found": True,
|
|
"configured_types": list(configured_types),
|
|
"type_count": len(configured_types)
|
|
}
|
|
|
|
print(f" ✅ Configuration trouvée avec {len(configured_types)} types :")
|
|
for step_type in sorted(configured_types):
|
|
print(f" - {step_type}")
|
|
|
|
# Analyser chaque type configuré
|
|
for step_type in configured_types:
|
|
self._analyze_step_type_config(content, step_type)
|
|
|
|
else:
|
|
self._add_issue("CRITICAL", "Configuration stepParametersConfig non trouvée", {
|
|
"file": str(properties_panel_path),
|
|
"search_pattern": "stepParametersConfig"
|
|
})
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur lecture PropertiesPanel : {e}", {
|
|
"file": str(properties_panel_path)
|
|
})
|
|
|
|
def _analyze_step_type_config(self, content: str, step_type: str):
|
|
"""Analyse la configuration d'un type d'étape spécifique."""
|
|
# Extraire la configuration pour ce type
|
|
pattern = rf'{step_type}:\s*\[(.*?)\]'
|
|
match = re.search(pattern, content, re.DOTALL)
|
|
|
|
if match:
|
|
config_content = match.group(1)
|
|
|
|
# Compter les paramètres
|
|
param_matches = re.findall(r'{\s*name:\s*[\'"](\w+)[\'"]', config_content)
|
|
|
|
self.results["type_mappings"][step_type] = {
|
|
"parameters": param_matches,
|
|
"parameter_count": len(param_matches),
|
|
"has_required_params": "required: true" in config_content,
|
|
"has_visual_params": "type: 'visual'" in config_content
|
|
}
|
|
|
|
print(f" 📝 {step_type}: {len(param_matches)} paramètres")
|
|
|
|
def _analyze_step_types(self):
|
|
"""Analyse les types d'étapes définis."""
|
|
print("\n🏷️ Analyse des types d'étapes...")
|
|
|
|
types_path = self.frontend_path / "src" / "types" / "index.ts"
|
|
|
|
if not types_path.exists():
|
|
self._add_issue("CRITICAL", "Fichier types/index.ts introuvable", {
|
|
"expected_path": str(types_path)
|
|
})
|
|
return
|
|
|
|
try:
|
|
content = types_path.read_text(encoding='utf-8')
|
|
|
|
# Chercher la définition de StepType
|
|
step_type_match = re.search(
|
|
r'export\s+type\s+StepType\s*=\s*([^;]+);',
|
|
content,
|
|
re.DOTALL
|
|
)
|
|
|
|
if step_type_match:
|
|
step_type_def = step_type_match.group(1)
|
|
|
|
# Extraire les types définis
|
|
type_matches = re.findall(r"['\"](\w+)['\"]", step_type_def)
|
|
defined_types = set(type_matches)
|
|
|
|
self.results["configuration_status"]["stepTypes"] = {
|
|
"found": True,
|
|
"defined_types": list(defined_types),
|
|
"type_count": len(defined_types)
|
|
}
|
|
|
|
print(f" ✅ Types StepType trouvés ({len(defined_types)}) :")
|
|
for step_type in sorted(defined_types):
|
|
print(f" - {step_type}")
|
|
|
|
# Comparer avec la configuration
|
|
configured_types = set(self.results["configuration_status"].get("stepParametersConfig", {}).get("configured_types", []))
|
|
|
|
missing_in_config = defined_types - configured_types
|
|
extra_in_config = configured_types - defined_types
|
|
|
|
if missing_in_config:
|
|
self._add_issue("WARNING", "Types définis mais non configurés", {
|
|
"missing_types": list(missing_in_config)
|
|
})
|
|
|
|
if extra_in_config:
|
|
self._add_issue("WARNING", "Types configurés mais non définis", {
|
|
"extra_types": list(extra_in_config)
|
|
})
|
|
|
|
else:
|
|
self._add_issue("CRITICAL", "Définition StepType non trouvée", {
|
|
"file": str(types_path)
|
|
})
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur lecture types : {e}", {
|
|
"file": str(types_path)
|
|
})
|
|
|
|
def _analyze_vwb_actions(self):
|
|
"""Analyse les actions VWB du catalogue."""
|
|
print("\n🎯 Analyse des actions VWB...")
|
|
|
|
# Analyser le catalogue statique
|
|
static_catalog_path = self.frontend_path / "src" / "data" / "staticCatalog.ts"
|
|
|
|
if static_catalog_path.exists():
|
|
try:
|
|
content = static_catalog_path.read_text(encoding='utf-8')
|
|
|
|
# Extraire les IDs d'actions
|
|
id_matches = re.findall(r"id:\s*['\"](\w+)['\"]", content)
|
|
vwb_action_ids = set(id_matches)
|
|
|
|
self.results["vwb_actions"]["static_catalog"] = {
|
|
"found": True,
|
|
"action_ids": list(vwb_action_ids),
|
|
"action_count": len(vwb_action_ids)
|
|
}
|
|
|
|
print(f" ✅ Catalogue statique trouvé avec {len(vwb_action_ids)} actions :")
|
|
for action_id in sorted(vwb_action_ids):
|
|
print(f" - {action_id}")
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur lecture catalogue statique : {e}", {
|
|
"file": str(static_catalog_path)
|
|
})
|
|
|
|
# Analyser le registry backend
|
|
registry_path = self.backend_path / "actions" / "registry.py"
|
|
|
|
if registry_path.exists():
|
|
try:
|
|
content = registry_path.read_text(encoding='utf-8')
|
|
|
|
# Vérifier la présence du registry
|
|
if "class VWBActionRegistry" in content:
|
|
self.results["vwb_actions"]["backend_registry"] = {
|
|
"found": True,
|
|
"has_auto_discovery": "auto_discover_actions" in content,
|
|
"has_global_instance": "get_global_registry" in content
|
|
}
|
|
print(" ✅ Registry backend trouvé et fonctionnel")
|
|
else:
|
|
self._add_issue("WARNING", "Registry backend incomplet", {
|
|
"file": str(registry_path)
|
|
})
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur lecture registry : {e}", {
|
|
"file": str(registry_path)
|
|
})
|
|
|
|
def _analyze_integration_hooks(self):
|
|
"""Analyse les hooks d'intégration VWB."""
|
|
print("\n🔗 Analyse des hooks d'intégration...")
|
|
|
|
hooks_path = self.frontend_path / "src" / "hooks" / "useVWBStepIntegration.ts"
|
|
|
|
if not hooks_path.exists():
|
|
self._add_issue("CRITICAL", "Hooks d'intégration VWB introuvables", {
|
|
"expected_path": str(hooks_path)
|
|
})
|
|
return
|
|
|
|
try:
|
|
content = hooks_path.read_text(encoding='utf-8')
|
|
|
|
# Vérifier les hooks principaux
|
|
hooks_found = {
|
|
"useVWBStepIntegration": "useVWBStepIntegration" in content,
|
|
"useIsVWBStep": "useIsVWBStep" in content,
|
|
"useVWBActionId": "useVWBActionId" in content
|
|
}
|
|
|
|
self.results["configuration_status"]["integration_hooks"] = hooks_found
|
|
|
|
print(" 🔍 Hooks d'intégration :")
|
|
for hook_name, found in hooks_found.items():
|
|
status = "✅" if found else "❌"
|
|
print(f" {status} {hook_name}")
|
|
|
|
if not found:
|
|
self._add_issue("CRITICAL", f"Hook {hook_name} manquant", {
|
|
"file": str(hooks_path)
|
|
})
|
|
|
|
# Analyser la logique de détection VWB
|
|
if "useIsVWBStep" in content:
|
|
# Chercher la logique de détection
|
|
detection_patterns = [
|
|
"isVWBCatalogAction",
|
|
"vwbActionId",
|
|
"startsWith('vwb_')",
|
|
"includes('catalog_')"
|
|
]
|
|
|
|
detection_logic = {}
|
|
for pattern in detection_patterns:
|
|
detection_logic[pattern] = pattern in content
|
|
|
|
self.results["configuration_status"]["vwb_detection_logic"] = detection_logic
|
|
|
|
print(" 🎯 Logique de détection VWB :")
|
|
for pattern, found in detection_logic.items():
|
|
status = "✅" if found else "❌"
|
|
print(f" {status} {pattern}")
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur lecture hooks : {e}", {
|
|
"file": str(hooks_path)
|
|
})
|
|
|
|
def _analyze_properties_panel(self):
|
|
"""Analyse le composant PropertiesPanel en détail."""
|
|
print("\n🎛️ Analyse détaillée du PropertiesPanel...")
|
|
|
|
properties_panel_path = self.frontend_path / "src" / "components" / "PropertiesPanel" / "index.tsx"
|
|
|
|
try:
|
|
content = properties_panel_path.read_text(encoding='utf-8')
|
|
|
|
# Analyser la fonction getParameterConfig
|
|
get_param_config_match = re.search(
|
|
r'const getParameterConfig = useCallback\(\(\):\s*ParameterConfig\[\]\s*=>\s*{([^}]+)}\s*,',
|
|
content,
|
|
re.DOTALL
|
|
)
|
|
|
|
if get_param_config_match:
|
|
function_body = get_param_config_match.group(1)
|
|
|
|
analysis = {
|
|
"function_found": True,
|
|
"has_null_check": "if (!selectedStep)" in function_body,
|
|
"uses_step_type": "selectedStep.type" in function_body,
|
|
"uses_config_lookup": "stepParametersConfig[" in function_body,
|
|
"has_fallback": "|| []" in function_body,
|
|
"function_body": function_body.strip()
|
|
}
|
|
|
|
self.results["configuration_status"]["getParameterConfig"] = analysis
|
|
|
|
print(" 🔍 Fonction getParameterConfig :")
|
|
for key, value in analysis.items():
|
|
if key != "function_body":
|
|
status = "✅" if value else "❌"
|
|
print(f" {status} {key}")
|
|
|
|
# Identifier le problème potentiel
|
|
if analysis["uses_step_type"] and analysis["uses_config_lookup"]:
|
|
print(" ⚠️ Problème potentiel identifié :")
|
|
print(" La fonction utilise selectedStep.type pour chercher dans stepParametersConfig")
|
|
print(" Mais il pourrait y avoir une incohérence entre les types d'étapes créées")
|
|
print(" et les clés de configuration disponibles.")
|
|
|
|
self._add_issue("CRITICAL", "Incohérence potentielle dans getParameterConfig", {
|
|
"description": "La fonction getParameterConfig utilise selectedStep.type mais pourrait ne pas trouver la configuration correspondante",
|
|
"function_body": function_body.strip()
|
|
})
|
|
|
|
else:
|
|
self._add_issue("CRITICAL", "Fonction getParameterConfig non trouvée", {
|
|
"file": str(properties_panel_path)
|
|
})
|
|
|
|
# Analyser la logique de rendu conditionnel
|
|
vwb_rendering_patterns = [
|
|
"isVWBCatalogAction",
|
|
"VWBActionProperties",
|
|
"vwbAction",
|
|
"parameterConfigs.length === 0"
|
|
]
|
|
|
|
rendering_analysis = {}
|
|
for pattern in vwb_rendering_patterns:
|
|
rendering_analysis[pattern] = pattern in content
|
|
|
|
self.results["configuration_status"]["rendering_logic"] = rendering_analysis
|
|
|
|
print(" 🎨 Logique de rendu :")
|
|
for pattern, found in rendering_analysis.items():
|
|
status = "✅" if found else "❌"
|
|
print(f" {status} {pattern}")
|
|
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur analyse PropertiesPanel : {e}", {
|
|
"file": str(properties_panel_path)
|
|
})
|
|
|
|
def _check_typescript_consistency(self):
|
|
"""Vérifie la cohérence TypeScript."""
|
|
print("\n🔧 Vérification de la cohérence TypeScript...")
|
|
|
|
try:
|
|
# Changer vers le répertoire frontend
|
|
frontend_dir = self.frontend_path
|
|
|
|
if not frontend_dir.exists():
|
|
self._add_issue("CRITICAL", "Répertoire frontend introuvable", {
|
|
"expected_path": str(frontend_dir)
|
|
})
|
|
return
|
|
|
|
# Exécuter la vérification TypeScript
|
|
result = subprocess.run(
|
|
["npx", "tsc", "--noEmit"],
|
|
cwd=frontend_dir,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60
|
|
)
|
|
|
|
typescript_status = {
|
|
"exit_code": result.returncode,
|
|
"has_errors": result.returncode != 0,
|
|
"stdout": result.stdout,
|
|
"stderr": result.stderr
|
|
}
|
|
|
|
self.results["configuration_status"]["typescript"] = typescript_status
|
|
|
|
if result.returncode == 0:
|
|
print(" ✅ Compilation TypeScript réussie")
|
|
else:
|
|
print(" ❌ Erreurs TypeScript détectées :")
|
|
if result.stderr:
|
|
for line in result.stderr.split('\n')[:10]: # Limiter à 10 lignes
|
|
if line.strip():
|
|
print(f" {line}")
|
|
|
|
self._add_issue("ERROR", "Erreurs de compilation TypeScript", {
|
|
"stderr": result.stderr,
|
|
"stdout": result.stdout
|
|
})
|
|
|
|
except subprocess.TimeoutExpired:
|
|
self._add_issue("ERROR", "Timeout lors de la vérification TypeScript", {})
|
|
except FileNotFoundError:
|
|
self._add_issue("WARNING", "npx/tsc non disponible pour la vérification", {})
|
|
except Exception as e:
|
|
self._add_issue("ERROR", f"Erreur vérification TypeScript : {e}", {})
|
|
|
|
def _generate_recommendations(self):
|
|
"""Génère les recommandations basées sur l'analyse."""
|
|
print("\n💡 Génération des recommandations...")
|
|
|
|
# Analyser les problèmes trouvés
|
|
critical_issues = [issue for issue in self.results["issues_found"] if issue["severity"] == "CRITICAL"]
|
|
|
|
if critical_issues:
|
|
self.results["recommendations"].append({
|
|
"priority": "URGENT",
|
|
"title": "Corriger les problèmes critiques identifiés",
|
|
"description": "Plusieurs problèmes critiques empêchent le bon fonctionnement des propriétés d'étapes",
|
|
"actions": [
|
|
"Vérifier la cohérence entre les types d'étapes et la configuration stepParametersConfig",
|
|
"Corriger la logique de détection des actions VWB",
|
|
"Ajouter des logs de débogage dans getParameterConfig()",
|
|
"Implémenter un système de fallback robuste"
|
|
]
|
|
})
|
|
|
|
# Recommandations spécifiques basées sur l'analyse
|
|
config_status = self.results["configuration_status"]
|
|
|
|
if config_status.get("stepParametersConfig", {}).get("found"):
|
|
configured_types = set(config_status["stepParametersConfig"]["configured_types"])
|
|
defined_types = set(config_status.get("stepTypes", {}).get("defined_types", []))
|
|
|
|
if configured_types != defined_types:
|
|
self.results["recommendations"].append({
|
|
"priority": "HIGH",
|
|
"title": "Synchroniser les types d'étapes et leur configuration",
|
|
"description": "Incohérence entre les types StepType définis et la configuration stepParametersConfig",
|
|
"actions": [
|
|
f"Ajouter la configuration pour : {list(defined_types - configured_types)}",
|
|
f"Supprimer ou corriger : {list(configured_types - defined_types)}",
|
|
"Créer un système de validation automatique"
|
|
]
|
|
})
|
|
|
|
if not config_status.get("integration_hooks", {}).get("useIsVWBStep", False):
|
|
self.results["recommendations"].append({
|
|
"priority": "HIGH",
|
|
"title": "Corriger les hooks d'intégration VWB",
|
|
"description": "Les hooks de détection des actions VWB sont manquants ou défaillants",
|
|
"actions": [
|
|
"Implémenter useIsVWBStep avec logique robuste",
|
|
"Corriger useVWBActionId pour la détection d'ID",
|
|
"Ajouter la gestion d'erreurs dans les hooks"
|
|
]
|
|
})
|
|
|
|
# Recommandation pour le système de diagnostic
|
|
self.results["recommendations"].append({
|
|
"priority": "MEDIUM",
|
|
"title": "Implémenter un système de diagnostic intégré",
|
|
"description": "Ajouter des outils de diagnostic dans l'interface pour faciliter le débogage",
|
|
"actions": [
|
|
"Créer un composant DebugPanel pour le mode développement",
|
|
"Ajouter des logs structurés dans les composants critiques",
|
|
"Implémenter des métriques de performance",
|
|
"Créer des tests automatisés pour la détection de régression"
|
|
]
|
|
})
|
|
|
|
print(f" ✅ {len(self.results['recommendations'])} recommandations générées")
|
|
|
|
def _add_issue(self, severity: str, description: str, details: Dict[str, Any]):
|
|
"""Ajoute un problème identifié."""
|
|
issue = {
|
|
"severity": severity,
|
|
"description": description,
|
|
"details": details,
|
|
"timestamp": "2026-01-12"
|
|
}
|
|
|
|
self.results["issues_found"].append(issue)
|
|
|
|
# Afficher immédiatement les problèmes critiques
|
|
if severity == "CRITICAL":
|
|
print(f" 🚨 CRITIQUE : {description}")
|
|
|
|
def _save_diagnostic_report(self):
|
|
"""Sauvegarde le rapport de diagnostic."""
|
|
report_path = self.project_root / "docs" / "DIAGNOSTIC_PROPRIETES_ETAPES_VIDES_12JAN2026.json"
|
|
|
|
try:
|
|
# Créer le répertoire docs s'il n'existe pas
|
|
report_path.parent.mkdir(exist_ok=True)
|
|
|
|
# Sauvegarder le rapport JSON
|
|
with open(report_path, 'w', encoding='utf-8') as f:
|
|
json.dump(self.results, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f"\n📄 Rapport sauvegardé : {report_path}")
|
|
|
|
# Créer aussi un résumé markdown
|
|
self._create_markdown_summary(report_path.with_suffix('.md'))
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur sauvegarde rapport : {e}")
|
|
|
|
def _create_markdown_summary(self, md_path: Path):
|
|
"""Crée un résumé markdown du diagnostic."""
|
|
try:
|
|
with open(md_path, 'w', encoding='utf-8') as f:
|
|
f.write("# Diagnostic des Propriétés d'Étapes Vides - Rapport\n\n")
|
|
f.write("**Auteur :** Dom, Alice, Kiro \n")
|
|
f.write("**Date :** 12 janvier 2026 \n")
|
|
f.write("**Version :** 1.0.0\n\n")
|
|
|
|
# Résumé exécutif
|
|
f.write("## Résumé Exécutif\n\n")
|
|
f.write(f"- **Problèmes identifiés :** {len(self.results['issues_found'])}\n")
|
|
f.write(f"- **Recommandations :** {len(self.results['recommendations'])}\n")
|
|
|
|
critical_count = len([i for i in self.results['issues_found'] if i['severity'] == 'CRITICAL'])
|
|
f.write(f"- **Problèmes critiques :** {critical_count}\n\n")
|
|
|
|
# Problèmes identifiés
|
|
if self.results['issues_found']:
|
|
f.write("## Problèmes Identifiés\n\n")
|
|
for issue in self.results['issues_found']:
|
|
f.write(f"### {issue['severity']} : {issue['description']}\n\n")
|
|
if issue['details']:
|
|
f.write("**Détails :**\n")
|
|
for key, value in issue['details'].items():
|
|
f.write(f"- **{key}** : {value}\n")
|
|
f.write("\n")
|
|
|
|
# Recommandations
|
|
if self.results['recommendations']:
|
|
f.write("## Recommandations\n\n")
|
|
for rec in self.results['recommendations']:
|
|
f.write(f"### {rec['priority']} : {rec['title']}\n\n")
|
|
f.write(f"{rec['description']}\n\n")
|
|
f.write("**Actions recommandées :**\n")
|
|
for action in rec['actions']:
|
|
f.write(f"- {action}\n")
|
|
f.write("\n")
|
|
|
|
# Configuration actuelle
|
|
f.write("## État de la Configuration\n\n")
|
|
for section, status in self.results['configuration_status'].items():
|
|
f.write(f"### {section}\n\n")
|
|
f.write(f"```json\n{json.dumps(status, indent=2)}\n```\n\n")
|
|
|
|
print(f"📄 Résumé markdown créé : {md_path}")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur création résumé markdown : {e}")
|
|
|
|
|
|
def main():
|
|
"""Fonction principale."""
|
|
print("🚀 Lancement du diagnostic des propriétés d'étapes VWB")
|
|
|
|
diagnostic = VWBPropertiesDiagnostic()
|
|
results = diagnostic.run_full_diagnostic()
|
|
|
|
# Afficher le résumé final
|
|
print("\n" + "="*60)
|
|
print("📊 RÉSUMÉ DU DIAGNOSTIC")
|
|
print("="*60)
|
|
|
|
print(f"✅ Diagnostic terminé avec succès")
|
|
print(f"🔍 Problèmes identifiés : {len(results['issues_found'])}")
|
|
print(f"💡 Recommandations : {len(results['recommendations'])}")
|
|
|
|
critical_issues = [i for i in results['issues_found'] if i['severity'] == 'CRITICAL']
|
|
if critical_issues:
|
|
print(f"🚨 Problèmes critiques : {len(critical_issues)}")
|
|
print("\nProblèmes critiques à traiter en priorité :")
|
|
for issue in critical_issues:
|
|
print(f" - {issue['description']}")
|
|
|
|
print(f"\n📄 Rapport complet disponible dans docs/")
|
|
print("🔧 Utilisez ce diagnostic pour implémenter les corrections nécessaires.")
|
|
|
|
return 0 if len(critical_issues) == 0 else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |