Files
rpa_vision_v3/scripts/validation_interface_proprietes_etapes_checkpoint_12jan2026.py
Dom a27b74cf22 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>
2026-01-29 11:23:51 +01:00

397 lines
15 KiB
Python

#!/usr/bin/env python3
"""
Script de validation - Checkpoint Interface Propriétés d'Étapes
Auteur : Dom, Alice, Kiro - 12 janvier 2026
Ce script valide l'implémentation des composants de base de l'interface
des propriétés d'étapes selon les spécifications définies.
Composants validés :
- ParameterFieldRenderer (Tâche 1)
- StandardParametersEditor (Tâche 2)
- VWBActionProperties amélioré (Tâche 3)
"""
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 ValidationResult:
"""Résultat de validation"""
def __init__(self, name: str):
self.name = name
self.success = False
self.errors: List[str] = []
self.warnings: List[str] = []
self.details: Dict[str, Any] = {}
def add_error(self, message: str):
self.errors.append(message)
def add_warning(self, message: str):
self.warnings.append(message)
def set_success(self, success: bool):
self.success = success
def add_detail(self, key: str, value: Any):
self.details[key] = value
class InterfacePropertiesValidator:
"""Validateur pour l'interface des propriétés d'étapes"""
def __init__(self):
self.results: List[ValidationResult] = []
def validate_file_structure(self) -> ValidationResult:
"""Valide la structure des fichiers créés"""
result = ValidationResult("Structure des fichiers")
# Fichiers requis
required_files = [
COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
COMPONENTS_PATH / "StandardParametersEditor.tsx",
COMPONENTS_PATH / "VWBActionProperties.tsx",
HOOKS_PATH / "useAutoSave.ts",
]
# Tests de propriétés requis
required_tests = [
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",
]
all_files = required_files + required_tests
for file_path in all_files:
if not file_path.exists():
result.add_error(f"Fichier manquant: {file_path.relative_to(PROJECT_ROOT)}")
else:
# Vérifier la taille du fichier (doit être > 1KB)
file_size = file_path.stat().st_size
if file_size < 1024:
result.add_warning(f"Fichier très petit: {file_path.name} ({file_size} bytes)")
result.add_detail(f"size_{file_path.name}", file_size)
result.set_success(len(result.errors) == 0)
return result
def validate_typescript_compilation(self) -> ValidationResult:
"""Valide la compilation TypeScript des composants"""
result = ValidationResult("Compilation TypeScript")
try:
# Vérifier si TypeScript est disponible
ts_check = subprocess.run(
["npx", "tsc", "--version"],
cwd=FRONTEND_PATH,
capture_output=True,
text=True,
timeout=10
)
if ts_check.returncode != 0:
result.add_error("TypeScript non disponible")
result.set_success(False)
return result
result.add_detail("typescript_version", ts_check.stdout.strip())
# Compilation des fichiers TypeScript
ts_files = [
"src/components/PropertiesPanel/ParameterFieldRenderer.tsx",
"src/components/PropertiesPanel/StandardParametersEditor.tsx",
"src/hooks/useAutoSave.ts"
]
for ts_file in ts_files:
compile_result = subprocess.run(
["npx", "tsc", "--noEmit", "--project", "."],
cwd=FRONTEND_PATH,
capture_output=True,
text=True,
timeout=30
)
if compile_result.returncode != 0:
result.add_error(f"Erreur compilation globale: {compile_result.stderr}")
break
else:
result.add_detail(f"compiled_{Path(ts_file).name}", True)
result.set_success(len(result.errors) == 0)
except subprocess.TimeoutExpired:
result.add_error("Timeout lors de la compilation TypeScript")
result.set_success(False)
except Exception as e:
result.add_error(f"Erreur lors de la validation TypeScript: {str(e)}")
result.set_success(False)
return result
def validate_component_interfaces(self) -> ValidationResult:
"""Valide les interfaces des composants"""
result = ValidationResult("Interfaces des composants")
# Vérifier les exports et interfaces dans les fichiers
component_checks = [
{
"file": COMPONENTS_PATH / "ParameterFieldRenderer.tsx",
"exports": ["ParameterFieldRenderer", "fieldRendererRegistry", "FieldRendererType"],
"interfaces": ["ParameterFieldRendererProps", "CustomFieldRenderer"]
},
{
"file": COMPONENTS_PATH / "StandardParametersEditor.tsx",
"exports": ["StandardParametersEditor"],
"interfaces": ["StandardParametersEditorProps"]
},
{
"file": HOOKS_PATH / "useAutoSave.ts",
"exports": ["useAutoSave", "useStepParametersAutoSave", "useSyncedAutoSave"],
"interfaces": ["AutoSaveOptions", "SaveState", "UseAutoSaveResult"]
}
]
for check in component_checks:
file_path = check["file"]
if not file_path.exists():
result.add_error(f"Fichier manquant: {file_path.name}")
continue
try:
content = file_path.read_text(encoding='utf-8')
# Vérifier les exports
for export_name in check["exports"]:
if f"export" in content and export_name in content:
result.add_detail(f"export_{export_name}", True)
else:
result.add_warning(f"Export manquant dans {file_path.name}: {export_name}")
# Vérifier les interfaces
for interface_name in check["interfaces"]:
if f"interface {interface_name}" in content:
result.add_detail(f"interface_{interface_name}", True)
else:
result.add_warning(f"Interface manquante dans {file_path.name}: {interface_name}")
# Vérifier les commentaires français
if "Auteur : Dom, Alice, Kiro" not in content:
result.add_warning(f"Attribution d'auteur manquante dans {file_path.name}")
if "12 janvier 2026" not in content:
result.add_warning(f"Date manquante dans {file_path.name}")
except Exception as e:
result.add_error(f"Erreur lecture {file_path.name}: {str(e)}")
result.set_success(len(result.errors) == 0)
return result
def validate_property_tests(self) -> ValidationResult:
"""Valide les tests de propriétés"""
result = ValidationResult("Tests de propriétés")
test_files = [
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",
]
for test_file in test_files:
if not test_file.exists():
result.add_error(f"Test manquant: {test_file.name}")
continue
try:
content = test_file.read_text(encoding='utf-8')
# Vérifier la structure des tests de propriétés
required_elements = [
"from hypothesis import given",
"PROPERTY_TEST_SETTINGS",
"Feature: interface-proprietes-etapes-complete",
"Property",
"Validates: Requirements"
]
for element in required_elements:
if element in content:
result.add_detail(f"has_{element.replace(' ', '_').replace(':', '')}", True)
else:
result.add_warning(f"Élément manquant dans {test_file.name}: {element}")
# Compter les tests de propriétés
property_count = content.count("def test_property_")
result.add_detail(f"property_tests_{test_file.name}", property_count)
if property_count == 0:
result.add_error(f"Aucun test de propriété dans {test_file.name}")
except Exception as e:
result.add_error(f"Erreur lecture test {test_file.name}: {str(e)}")
result.set_success(len(result.errors) == 0)
return result
def validate_integration_readiness(self) -> ValidationResult:
"""Valide la préparation à l'intégration"""
result = ValidationResult("Préparation à l'intégration")
# Vérifier que PropertiesPanel existe et peut être modifié
properties_panel_path = COMPONENTS_PATH / "index.tsx"
if not properties_panel_path.exists():
result.add_error("PropertiesPanel principal manquant")
result.set_success(False)
return result
try:
content = properties_panel_path.read_text(encoding='utf-8')
# Vérifier les imports nécessaires
required_imports = [
"ParameterFieldRenderer",
"useStepTypeResolver",
"VWBActionProperties"
]
for import_name in required_imports:
if import_name in content:
result.add_detail(f"import_{import_name}", True)
else:
result.add_warning(f"Import manquant: {import_name}")
# Vérifier la structure du composant
if "const PropertiesPanel" in content:
result.add_detail("component_structure", True)
else:
result.add_error("Structure de composant invalide")
# Vérifier la mémorisation
if "memo(PropertiesPanel" in content:
result.add_detail("memoization", True)
else:
result.add_warning("Mémorisation manquante")
result.set_success(len(result.errors) == 0)
except Exception as e:
result.add_error(f"Erreur validation PropertiesPanel: {str(e)}")
result.set_success(False)
return result
def run_validation(self) -> Dict[str, Any]:
"""Exécute toutes les validations"""
print("🔍 Validation de l'interface des propriétés d'étapes - Checkpoint")
print("=" * 70)
# Exécuter toutes les validations
validations = [
self.validate_file_structure,
self.validate_typescript_compilation,
self.validate_component_interfaces,
self.validate_property_tests,
self.validate_integration_readiness,
]
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" + "=" * 70)
print("📊 RÉSUMÉ DE VALIDATION")
print("=" * 70)
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🎉 VALIDATION GLOBALE RÉUSSIE")
print("✅ Tous les composants sont prêts pour l'intégration")
else:
print("\n⚠️ VALIDATION GLOBALE PARTIELLE")
print("🔧 Corrections nécessaires avant l'intégration")
# Prochaines étapes
print("\n📋 PROCHAINES ÉTAPES:")
print("1. Créer les composants d'état (EmptyStateMessage, LoadingState)")
print("2. Intégrer tous les composants dans PropertiesPanel")
print("3. Implémenter les fonctionnalités avancées de validation")
print("4. Optimiser les performances et l'accessibilité")
return {
"global_success": global_success,
"successful_validations": successful_validations,
"total_validations": total_validations,
"total_errors": total_errors,
"total_warnings": total_warnings,
"results": [
{
"name": r.name,
"success": r.success,
"errors": r.errors,
"warnings": r.warnings,
"details": r.details
}
for r in self.results
]
}
def main():
"""Fonction principale"""
validator = InterfacePropertiesValidator()
results = validator.run_validation()
# Sauvegarder les résultats
results_file = PROJECT_ROOT / "validation_checkpoint_interface_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["global_success"] else 1)
if __name__ == "__main__":
main()