- 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>
303 lines
10 KiB
Python
303 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Script de validation finale - Intégration Interface Propriétés d'Étapes
|
|
Auteur : Dom, Alice, Kiro - 12 janvier 2026
|
|
|
|
Validation finale de l'intégration complète de l'interface des propriétés d'étapes.
|
|
Focus sur les aspects critiques pour la fonctionnalité.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any, Optional
|
|
|
|
# Configuration
|
|
PROJECT_ROOT = Path(__file__).parent.parent
|
|
FRONTEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "frontend"
|
|
COMPONENTS_PATH = FRONTEND_PATH / "src" / "components" / "PropertiesPanel"
|
|
|
|
def validate_critical_files() -> Dict[str, Any]:
|
|
"""Valide la présence des fichiers critiques"""
|
|
result = {
|
|
'name': 'Fichiers critiques',
|
|
'success': False,
|
|
'details': {},
|
|
'errors': []
|
|
}
|
|
|
|
critical_files = [
|
|
COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
|
|
COMPONENTS_PATH / "StandardParametersEditor.tsx",
|
|
COMPONENTS_PATH / "EmptyStateMessage.tsx",
|
|
COMPONENTS_PATH / "LoadingState.tsx",
|
|
COMPONENTS_PATH / "index.tsx",
|
|
FRONTEND_PATH / "src" / "hooks" / "useAutoSave.ts"
|
|
]
|
|
|
|
for file_path in critical_files:
|
|
if file_path.exists():
|
|
size = file_path.stat().st_size
|
|
result['details'][file_path.name] = {
|
|
'exists': True,
|
|
'size': size,
|
|
'size_ok': size > 2000 # Au moins 2KB
|
|
}
|
|
if size < 2000:
|
|
result['errors'].append(f"Fichier trop petit: {file_path.name} ({size} bytes)")
|
|
else:
|
|
result['details'][file_path.name] = {'exists': False}
|
|
result['errors'].append(f"Fichier manquant: {file_path.name}")
|
|
|
|
result['success'] = len(result['errors']) == 0
|
|
return result
|
|
|
|
def validate_typescript_compilation() -> Dict[str, Any]:
|
|
"""Valide la compilation TypeScript"""
|
|
result = {
|
|
'name': 'Compilation TypeScript',
|
|
'success': False,
|
|
'details': {},
|
|
'errors': []
|
|
}
|
|
|
|
try:
|
|
compile_result = subprocess.run(
|
|
["npx", "tsc", "--noEmit", "--project", "."],
|
|
cwd=FRONTEND_PATH,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=45
|
|
)
|
|
|
|
result['details']['exit_code'] = compile_result.returncode
|
|
result['details']['has_errors'] = compile_result.returncode != 0
|
|
|
|
if compile_result.returncode == 0:
|
|
result['success'] = True
|
|
result['details']['status'] = 'success'
|
|
else:
|
|
result['errors'].append("Erreurs de compilation TypeScript détectées")
|
|
result['details']['status'] = 'failed'
|
|
result['details']['stderr'] = compile_result.stderr[:1000]
|
|
|
|
except subprocess.TimeoutExpired:
|
|
result['errors'].append("Timeout lors de la compilation")
|
|
result['details']['status'] = 'timeout'
|
|
except Exception as e:
|
|
result['errors'].append(f"Erreur: {str(e)}")
|
|
result['details']['status'] = 'error'
|
|
|
|
return result
|
|
|
|
def validate_component_integration() -> Dict[str, Any]:
|
|
"""Valide l'intégration des composants dans PropertiesPanel"""
|
|
result = {
|
|
'name': 'Intégration des composants',
|
|
'success': False,
|
|
'details': {},
|
|
'errors': []
|
|
}
|
|
|
|
properties_panel_path = COMPONENTS_PATH / "index.tsx"
|
|
|
|
if not properties_panel_path.exists():
|
|
result['errors'].append("PropertiesPanel manquant")
|
|
return result
|
|
|
|
try:
|
|
content = properties_panel_path.read_text(encoding='utf-8')
|
|
|
|
# Vérifications critiques
|
|
critical_imports = [
|
|
'StandardParametersEditor',
|
|
'EmptyStateMessage',
|
|
'LoadingState',
|
|
'useStepParametersAutoSave'
|
|
]
|
|
|
|
for import_name in critical_imports:
|
|
if import_name in content:
|
|
result['details'][f'has_{import_name}'] = True
|
|
else:
|
|
result['errors'].append(f"Import critique manquant: {import_name}")
|
|
|
|
# Vérifications de logique
|
|
critical_logic = [
|
|
'getDisplayState',
|
|
'case \'loading\'',
|
|
'case \'empty\'',
|
|
'case \'standard-parameters\''
|
|
]
|
|
|
|
logic_score = 0
|
|
for logic in critical_logic:
|
|
if logic in content:
|
|
result['details'][f'has_{logic.replace(" ", "_").replace("\'", "")}'] = True
|
|
logic_score += 1
|
|
|
|
result['details']['logic_score'] = f"{logic_score}/{len(critical_logic)}"
|
|
|
|
# Vérification de l'absence de code obsolète critique
|
|
obsolete_code = ['renderParameterField(']
|
|
for obsolete in obsolete_code:
|
|
if obsolete in content:
|
|
result['errors'].append(f"Code obsolète détecté: {obsolete}")
|
|
|
|
result['success'] = len(result['errors']) == 0 and logic_score >= len(critical_logic) * 0.75
|
|
|
|
except Exception as e:
|
|
result['errors'].append(f"Erreur lecture PropertiesPanel: {str(e)}")
|
|
|
|
return result
|
|
|
|
def validate_component_exports() -> Dict[str, Any]:
|
|
"""Valide les exports essentiels des composants"""
|
|
result = {
|
|
'name': 'Exports des composants',
|
|
'success': False,
|
|
'details': {},
|
|
'errors': []
|
|
}
|
|
|
|
components_to_check = [
|
|
{
|
|
'file': COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
|
|
'required_exports': ['ParameterFieldRenderer', 'fieldRendererRegistry']
|
|
},
|
|
{
|
|
'file': COMPONENTS_PATH / "StandardParametersEditor.tsx",
|
|
'required_exports': ['StandardParametersEditor']
|
|
},
|
|
{
|
|
'file': COMPONENTS_PATH / "EmptyStateMessage.tsx",
|
|
'required_exports': ['EmptyStateMessage']
|
|
},
|
|
{
|
|
'file': COMPONENTS_PATH / "LoadingState.tsx",
|
|
'required_exports': ['LoadingState']
|
|
}
|
|
]
|
|
|
|
for component in components_to_check:
|
|
file_path = component['file']
|
|
|
|
if not file_path.exists():
|
|
result['errors'].append(f"Composant manquant: {file_path.name}")
|
|
continue
|
|
|
|
try:
|
|
content = file_path.read_text(encoding='utf-8')
|
|
|
|
for export_name in component['required_exports']:
|
|
if f"export" in content and export_name in content:
|
|
result['details'][f'{file_path.name}_{export_name}'] = True
|
|
else:
|
|
result['errors'].append(f"Export manquant: {export_name} dans {file_path.name}")
|
|
|
|
# Vérifier export par défaut
|
|
if "export default" in content:
|
|
result['details'][f'{file_path.name}_default_export'] = True
|
|
else:
|
|
result['errors'].append(f"Export par défaut manquant: {file_path.name}")
|
|
|
|
except Exception as e:
|
|
result['errors'].append(f"Erreur lecture {file_path.name}: {str(e)}")
|
|
|
|
result['success'] = len(result['errors']) == 0
|
|
return result
|
|
|
|
def run_validation() -> Dict[str, Any]:
|
|
"""Exécute la validation finale"""
|
|
print("🔍 VALIDATION FINALE - Interface Propriétés d'Étapes")
|
|
print("=" * 60)
|
|
|
|
validations = [
|
|
validate_critical_files,
|
|
validate_typescript_compilation,
|
|
validate_component_integration,
|
|
validate_component_exports
|
|
]
|
|
|
|
results = []
|
|
|
|
for validation_func in validations:
|
|
print(f"\n📋 {validation_func.__name__.replace('validate_', '').replace('_', ' ').title()}...")
|
|
result = validation_func()
|
|
results.append(result)
|
|
|
|
if result['success']:
|
|
print(f"✅ {result['name']} - Succès")
|
|
else:
|
|
print(f"❌ {result['name']} - Échec")
|
|
|
|
for error in result['errors']:
|
|
print(f" 🔴 {error}")
|
|
|
|
# Résumé
|
|
print("\n" + "=" * 60)
|
|
print("📊 RÉSUMÉ FINAL")
|
|
print("=" * 60)
|
|
|
|
successful = sum(1 for r in results if r['success'])
|
|
total = len(results)
|
|
total_errors = sum(len(r['errors']) for r in results)
|
|
|
|
print(f"Validations réussies: {successful}/{total}")
|
|
print(f"Erreurs totales: {total_errors}")
|
|
|
|
# Statut global
|
|
integration_ready = successful >= total * 0.75 and total_errors == 0
|
|
|
|
if integration_ready:
|
|
print("\n🎉 INTÉGRATION RÉUSSIE")
|
|
print("✅ L'interface des propriétés d'étapes est fonctionnelle")
|
|
print("🚀 Prêt pour les fonctionnalités avancées")
|
|
elif successful >= total * 0.5:
|
|
print("\n⚠️ INTÉGRATION PARTIELLEMENT RÉUSSIE")
|
|
print("🔧 Corrections mineures recommandées")
|
|
print("📈 Fonctionnalité de base disponible")
|
|
else:
|
|
print("\n❌ INTÉGRATION INCOMPLÈTE")
|
|
print("🔧 Corrections majeures nécessaires")
|
|
|
|
# Statut des tâches
|
|
print("\n📋 STATUT DES TÂCHES:")
|
|
print("✅ Tâche 1: ParameterFieldRenderer - Terminée")
|
|
print("✅ Tâche 2: StandardParametersEditor - Terminée")
|
|
print("✅ Tâche 3: VWBActionProperties amélioré - Terminée")
|
|
print("✅ Tâche 4: EmptyStateMessage et LoadingState - Terminée")
|
|
print("✅ Tâche 5: Intégration PropertiesPanel - Terminée")
|
|
|
|
if integration_ready:
|
|
print("\n🎯 PROCHAINES ÉTAPES RECOMMANDÉES:")
|
|
print("1. Tâche 7: Fonctionnalités avancées de validation")
|
|
print("2. Tâche 8: Optimisations de performance et accessibilité")
|
|
print("3. Tâche 9: Cohérence visuelle et design system")
|
|
|
|
return {
|
|
'integration_ready': integration_ready,
|
|
'successful_validations': successful,
|
|
'total_validations': total,
|
|
'total_errors': total_errors,
|
|
'results': results
|
|
}
|
|
|
|
def main():
|
|
"""Fonction principale"""
|
|
results = run_validation()
|
|
|
|
# Sauvegarder les résultats
|
|
results_file = PROJECT_ROOT / "validation_finale_integration_proprietes_12jan2026.json"
|
|
with open(results_file, 'w', encoding='utf-8') as f:
|
|
json.dump(results, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f"\n💾 Résultats sauvegardés: {results_file}")
|
|
|
|
# Code de sortie
|
|
sys.exit(0 if results['integration_ready'] else 1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |