v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution

- 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>
This commit is contained in:
Dom
2026-01-29 11:23:51 +01:00
parent 21bfa3b337
commit a27b74cf22
1595 changed files with 412691 additions and 400 deletions

View File

@@ -0,0 +1,434 @@
#!/usr/bin/env python3
"""
Script de validation - Intégration complète de l'interface des propriétés
Auteur : Dom, Alice, Kiro - 12 janvier 2026
Ce script valide l'intégration complète de tous les composants de l'interface
des propriétés d'étapes après la Tâche 5 (intégration dans PropertiesPanel).
Composants validés :
- ParameterFieldRenderer (Tâche 1)
- StandardParametersEditor (Tâche 2)
- VWBActionProperties amélioré (Tâche 3)
- EmptyStateMessage et LoadingState (Tâche 4)
- Intégration complète dans PropertiesPanel (Tâche 5)
"""
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"
HOOKS_PATH = FRONTEND_PATH / "src" / "hooks"
TESTS_PATH = PROJECT_ROOT / "tests" / "property"
class IntegrationValidator:
"""Validateur pour l'intégration complète de l'interface des propriétés"""
def __init__(self):
self.results: List[Dict[str, Any]] = []
def validate_complete_file_structure(self) -> Dict[str, Any]:
"""Valide la structure complète des fichiers après intégration"""
result = {
'name': 'Structure complète des fichiers',
'success': False,
'errors': [],
'warnings': [],
'details': {}
}
# Tous les fichiers requis après Tâche 5
required_files = [
# Composants principaux
COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
COMPONENTS_PATH / "StandardParametersEditor.tsx",
COMPONENTS_PATH / "VWBActionProperties.tsx",
COMPONENTS_PATH / "EmptyStateMessage.tsx",
COMPONENTS_PATH / "LoadingState.tsx",
COMPONENTS_PATH / "index.tsx", # PropertiesPanel intégré
# Hooks
HOOKS_PATH / "useAutoSave.ts",
# Tests de propriétés
TESTS_PATH / "test_parameter_field_renderer_properties_12jan2026.py",
TESTS_PATH / "test_standard_parameters_editor_properties_12jan2026.py",
TESTS_PATH / "test_auto_save_properties_12jan2026.py",
TESTS_PATH / "test_vwb_action_properties_12jan2026.py",
TESTS_PATH / "test_empty_state_message_properties_12jan2026.py",
TESTS_PATH / "test_loading_state_properties_12jan2026.py",
]
for file_path in required_files:
if not file_path.exists():
result['errors'].append(f"Fichier manquant: {file_path.relative_to(PROJECT_ROOT)}")
else:
# Vérifier la taille du fichier
file_size = file_path.stat().st_size
if file_size < 1024: # Moins de 1KB
result['warnings'].append(f"Fichier très petit: {file_path.name} ({file_size} bytes)")
result['details'][f"size_{file_path.name}"] = file_size
result['success'] = len(result['errors']) == 0
return result
def validate_properties_panel_integration(self) -> Dict[str, Any]:
"""Valide l'intégration dans PropertiesPanel"""
result = {
'name': 'Intégration PropertiesPanel',
'success': False,
'errors': [],
'warnings': [],
'details': {}
}
properties_panel_path = COMPONENTS_PATH / "index.tsx"
if not properties_panel_path.exists():
result['errors'].append("PropertiesPanel principal manquant")
return result
try:
content = properties_panel_path.read_text(encoding='utf-8')
# Vérifier les imports des nouveaux composants
required_imports = [
'StandardParametersEditor',
'EmptyStateMessage',
'LoadingState',
'StepResolutionLoading',
'VWBActionLoading',
'useStepParametersAutoSave'
]
for import_name in required_imports:
if import_name in content:
result['details'][f"import_{import_name}"] = True
else:
result['errors'].append(f"Import manquant: {import_name}")
# Vérifier la logique de rendu conditionnel
conditional_logic_checks = [
'getDisplayState',
'displayState.type',
'case \'loading\'',
'case \'empty\'',
'case \'vwb-properties\'',
'case \'standard-parameters\''
]
for check in conditional_logic_checks:
if check in content:
result['details'][f"logic_{check.replace(' ', '_').replace('\'', '')}"] = True
else:
result['warnings'].append(f"Logique conditionnelle manquante: {check}")
# Vérifier l'intégration de l'auto-sauvegarde
autosave_checks = [
'autoSave.triggerSave',
'autoSave.saveState',
'handleValidationChange'
]
for check in autosave_checks:
if check in content:
result['details'][f"autosave_{check.replace('.', '_')}"] = True
else:
result['warnings'].append(f"Intégration auto-sauvegarde manquante: {check}")
# Vérifier la suppression de l'ancien code
deprecated_elements = [
'renderParameterField',
'TextField',
'FormControl',
'Switch'
]
for element in deprecated_elements:
if element in content:
result['warnings'].append(f"Élément obsolète encore présent: {element}")
result['success'] = len(result['errors']) == 0
except Exception as e:
result['errors'].append(f"Erreur lecture PropertiesPanel: {str(e)}")
result['success'] = False
return result
def validate_component_exports(self) -> Dict[str, Any]:
"""Valide les exports de tous les composants"""
result = {
'name': 'Exports des composants',
'success': False,
'errors': [],
'warnings': [],
'details': {}
}
# Vérifications des exports par composant
component_exports = [
{
'file': COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
'exports': ['ParameterFieldRenderer', 'fieldRendererRegistry', 'FieldRendererType'],
'default_export': 'ParameterFieldRenderer'
},
{
'file': COMPONENTS_PATH / "StandardParametersEditor.tsx",
'exports': ['StandardParametersEditor', 'StandardParametersEditorProps'],
'default_export': 'StandardParametersEditor'
},
{
'file': COMPONENTS_PATH / "EmptyStateMessage.tsx",
'exports': ['EmptyStateMessage', 'EmptyStateReason', 'SmartEmptyStateMessage'],
'default_export': 'EmptyStateMessage'
},
{
'file': COMPONENTS_PATH / "LoadingState.tsx",
'exports': ['LoadingState', 'LoadingType', 'StepResolutionLoading', 'VWBActionLoading'],
'default_export': 'LoadingState'
},
{
'file': HOOKS_PATH / "useAutoSave.ts",
'exports': ['useAutoSave', 'useStepParametersAutoSave', 'useSyncedAutoSave'],
'default_export': 'useAutoSave'
}
]
for component in component_exports:
file_path = component['file']
if not file_path.exists():
result['errors'].append(f"Fichier manquant: {file_path.name}")
continue
try:
content = file_path.read_text(encoding='utf-8')
# Vérifier les exports nommés
for export_name in component['exports']:
if f"export" in content and export_name in content:
result['details'][f"export_{file_path.name}_{export_name}"] = True
else:
result['warnings'].append(f"Export manquant dans {file_path.name}: {export_name}")
# Vérifier l'export par défaut
default_export = component['default_export']
if f"export default" in content:
result['details'][f"default_export_{file_path.name}"] = True
else:
result['errors'].append(f"Export par défaut manquant dans {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 validate_typescript_compilation_complete(self) -> Dict[str, Any]:
"""Valide la compilation TypeScript complète"""
result = {
'name': 'Compilation TypeScript complète',
'success': False,
'errors': [],
'warnings': [],
'details': {}
}
try:
# Compilation globale du projet
compile_result = subprocess.run(
["npx", "tsc", "--noEmit", "--project", "."],
cwd=FRONTEND_PATH,
capture_output=True,
text=True,
timeout=60
)
result['details']['compilation_exit_code'] = compile_result.returncode
result['details']['compilation_stdout'] = compile_result.stdout[:500] # Limiter la sortie
result['details']['compilation_stderr'] = compile_result.stderr[:500]
if compile_result.returncode == 0:
result['success'] = True
result['details']['compilation_status'] = 'success'
else:
result['errors'].append(f"Erreurs de compilation TypeScript: {compile_result.stderr}")
result['details']['compilation_status'] = 'failed'
except subprocess.TimeoutExpired:
result['errors'].append("Timeout lors de la compilation TypeScript")
result['details']['compilation_status'] = 'timeout'
except Exception as e:
result['errors'].append(f"Erreur lors de la compilation: {str(e)}")
result['details']['compilation_status'] = 'error'
return result
def validate_property_tests_execution(self) -> Dict[str, Any]:
"""Valide l'exécution des tests de propriétés"""
result = {
'name': 'Exécution des tests de propriétés',
'success': False,
'errors': [],
'warnings': [],
'details': {}
}
# Tests de propriétés à exécuter
property_test_files = [
"test_parameter_field_renderer_properties_12jan2026.py",
"test_standard_parameters_editor_properties_12jan2026.py",
"test_auto_save_properties_12jan2026.py",
"test_vwb_action_properties_12jan2026.py",
"test_empty_state_message_properties_12jan2026.py",
"test_loading_state_properties_12jan2026.py"
]
successful_tests = 0
for test_file in property_test_files:
test_path = TESTS_PATH / test_file
if not test_path.exists():
result['errors'].append(f"Test manquant: {test_file}")
continue
try:
# Exécuter le test avec pytest
test_result = subprocess.run(
["python", "-m", "pytest", str(test_path), "-v", "--tb=short"],
cwd=PROJECT_ROOT,
capture_output=True,
text=True,
timeout=30
)
result['details'][f"test_{test_file}_exit_code"] = test_result.returncode
if test_result.returncode == 0:
successful_tests += 1
result['details'][f"test_{test_file}_status"] = 'passed'
else:
result['warnings'].append(f"Test échoué: {test_file}")
result['details'][f"test_{test_file}_status"] = 'failed'
result['details'][f"test_{test_file}_stderr"] = test_result.stderr[:200]
except subprocess.TimeoutExpired:
result['warnings'].append(f"Timeout test: {test_file}")
result['details'][f"test_{test_file}_status"] = 'timeout'
except Exception as e:
result['warnings'].append(f"Erreur test {test_file}: {str(e)}")
result['details'][f"test_{test_file}_status"] = 'error'
result['details']['successful_tests'] = successful_tests
result['details']['total_tests'] = len(property_test_files)
# Succès si au moins 80% des tests passent
success_rate = successful_tests / len(property_test_files)
result['success'] = success_rate >= 0.8
result['details']['success_rate'] = f"{success_rate * 100:.1f}%"
return result
def run_complete_validation(self) -> Dict[str, Any]:
"""Exécute la validation complète de l'intégration"""
print("🔍 Validation complète de l'intégration - Interface Propriétés d'Étapes")
print("=" * 80)
# Exécuter toutes les validations
validations = [
self.validate_complete_file_structure,
self.validate_properties_panel_integration,
self.validate_component_exports,
self.validate_typescript_compilation_complete,
self.validate_property_tests_execution,
]
for validation_func in validations:
print(f"\n📋 {validation_func.__name__.replace('validate_', '').replace('_', ' ').title()}...")
result = validation_func()
self.results.append(result)
if result['success']:
print(f"{result['name']} - Succès")
else:
print(f"{result['name']} - Échec")
# Afficher les erreurs
for error in result['errors']:
print(f" 🔴 {error}")
# Afficher les avertissements
for warning in result['warnings']:
print(f" 🟡 {warning}")
# Résumé global
print("\n" + "=" * 80)
print("📊 RÉSUMÉ DE VALIDATION COMPLÈTE")
print("=" * 80)
total_validations = len(self.results)
successful_validations = sum(1 for r in self.results if r['success'])
total_errors = sum(len(r['errors']) for r in self.results)
total_warnings = sum(len(r['warnings']) for r in self.results)
print(f"Validations réussies: {successful_validations}/{total_validations}")
print(f"Erreurs totales: {total_errors}")
print(f"Avertissements totaux: {total_warnings}")
# Statut global
global_success = successful_validations == total_validations and total_errors == 0
if global_success:
print("\n🎉 INTÉGRATION COMPLÈTE RÉUSSIE")
print("✅ Tous les composants sont intégrés et fonctionnels")
print("🚀 Prêt pour les fonctionnalités avancées (Tâches 7-13)")
else:
print("\n⚠️ INTÉGRATION PARTIELLEMENT RÉUSSIE")
print("🔧 Corrections mineures recommandées")
if successful_validations >= total_validations * 0.8:
print("📈 Intégration majoritairement fonctionnelle")
# Prochaines étapes
print("\n📋 PROCHAINES ÉTAPES RECOMMANDÉES:")
print("1. Implémenter les fonctionnalités avancées de validation (Tâche 7)")
print("2. Optimiser les performances et l'accessibilité (Tâche 8)")
print("3. Assurer la cohérence visuelle et le design system (Tâche 9)")
print("4. Vérifier la compatibilité et l'intégration système (Tâche 10)")
return {
"global_success": global_success,
"successful_validations": successful_validations,
"total_validations": total_validations,
"total_errors": total_errors,
"total_warnings": total_warnings,
"integration_ready": successful_validations >= total_validations * 0.8,
"results": self.results
}
def main():
"""Fonction principale"""
validator = IntegrationValidator()
results = validator.run_complete_validation()
# Sauvegarder les résultats
results_file = PROJECT_ROOT / "validation_integration_complete_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 dans: {results_file}")
# Code de sortie
sys.exit(0 if results["integration_ready"] else 1)
if __name__ == "__main__":
main()