#!/usr/bin/env python3 """ Script de Vérification Complète des Propriétés d'Étapes VWB Auteur : Dom, Alice, Kiro - 12 janvier 2026 Ce script vérifie que toutes les actions du catalogue VWB ont leurs propriétés correctement définies et implémentées dans le système de propriétés. """ import json import sys import os from pathlib import Path from typing import Dict, List, Any, Set from datetime import datetime # Ajouter le répertoire racine au path sys.path.insert(0, str(Path(__file__).parent.parent)) def analyser_catalogue_statique() -> Dict[str, Any]: """ Analyse le catalogue statique pour extraire toutes les actions et leurs paramètres. Returns: Dictionnaire avec les actions et leurs configurations """ print("📋 Analyse du catalogue statique...") # Lire le fichier TypeScript du catalogue statique catalogue_path = Path("visual_workflow_builder/frontend/src/data/staticCatalog.ts") if not catalogue_path.exists(): print(f"❌ Fichier catalogue non trouvé : {catalogue_path}") return {} try: with open(catalogue_path, 'r', encoding='utf-8') as f: contenu = f.read() # Extraire les actions (analyse simple du contenu) actions_trouvees = {} # Rechercher les définitions d'actions import re # Pattern pour extraire les IDs d'actions pattern_id = r"id:\s*['\"]([^'\"]+)['\"]" ids = re.findall(pattern_id, contenu) # Pattern pour extraire les noms d'actions pattern_name = r"name:\s*['\"]([^'\"]+)['\"]" names = re.findall(pattern_name, contenu) # Pattern pour extraire les catégories pattern_category = r"category:\s*['\"]([^'\"]+)['\"]" categories = re.findall(pattern_category, contenu) # Combiner les informations for i, action_id in enumerate(ids): actions_trouvees[action_id] = { 'id': action_id, 'name': names[i] if i < len(names) else action_id, 'category': categories[i] if i < len(categories) else 'unknown', 'parameters_found': True, # Présumé vrai pour le catalogue statique } print(f"✅ {len(actions_trouvees)} actions trouvées dans le catalogue statique") return actions_trouvees except Exception as e: print(f"❌ Erreur lors de l'analyse du catalogue : {e}") return {} def analyser_backend_registry() -> Dict[str, Any]: """ Analyse le registry backend pour vérifier les actions disponibles. Returns: Dictionnaire avec les actions du backend """ print("🔧 Analyse du registry backend...") try: # Importer le registry from visual_workflow_builder.backend.actions.registry import get_global_registry registry = get_global_registry() # Obtenir les informations du registry info = registry.get_registry_stats() actions = registry.list_actions() actions_backend = {} for action_id in actions: metadata = registry.get_action_metadata(action_id) actions_backend[action_id] = { 'id': action_id, 'metadata': metadata, 'class_available': registry.get_action_class(action_id) is not None, } print(f"✅ {len(actions_backend)} actions trouvées dans le registry backend") return { 'stats': info, 'actions': actions_backend, } except Exception as e: print(f"❌ Erreur lors de l'analyse du registry backend : {e}") return {} def analyser_composants_frontend() -> Dict[str, Any]: """ Analyse les composants frontend pour vérifier l'implémentation des propriétés. Returns: Dictionnaire avec l'état des composants frontend """ print("🎨 Analyse des composants frontend...") composants_analyses = {} # Analyser PropertiesPanel principal properties_panel_path = Path("visual_workflow_builder/frontend/src/components/PropertiesPanel/index.tsx") if properties_panel_path.exists(): try: with open(properties_panel_path, 'r', encoding='utf-8') as f: contenu = f.read() composants_analyses['PropertiesPanel'] = { 'exists': True, 'has_step_parameters_config': 'stepParametersConfig' in contenu, 'has_vwb_integration': 'useVWBStepIntegration' in contenu, 'has_visual_selector': 'VisualSelector' in contenu, 'has_variable_autocomplete': 'VariableAutocomplete' in contenu, 'file_size': len(contenu), } except Exception as e: composants_analyses['PropertiesPanel'] = {'exists': True, 'error': str(e)} else: composants_analyses['PropertiesPanel'] = {'exists': False} # Analyser VWBActionProperties vwb_properties_path = Path("visual_workflow_builder/frontend/src/components/PropertiesPanel/VWBActionProperties.tsx") if vwb_properties_path.exists(): try: with open(vwb_properties_path, 'r', encoding='utf-8') as f: contenu = f.read() composants_analyses['VWBActionProperties'] = { 'exists': True, 'has_visual_anchor_editor': 'VisualAnchorEditor' in contenu, 'has_parameter_validation': 'validateParameters' in contenu, 'has_real_time_validation': 'validation' in contenu, 'has_examples_display': 'examples' in contenu, 'file_size': len(contenu), } except Exception as e: composants_analyses['VWBActionProperties'] = {'exists': True, 'error': str(e)} else: composants_analyses['VWBActionProperties'] = {'exists': False} # Analyser useVWBStepIntegration hook hook_path = Path("visual_workflow_builder/frontend/src/hooks/useVWBStepIntegration.ts") if hook_path.exists(): try: with open(hook_path, 'r', encoding='utf-8') as f: contenu = f.read() composants_analyses['useVWBStepIntegration'] = { 'exists': True, 'has_create_vwb_step': 'createVWBStep' in contenu, 'has_validation': 'validateVWBStep' in contenu, 'has_drag_drop_support': 'convertDragDataToVWBStep' in contenu, 'file_size': len(contenu), } except Exception as e: composants_analyses['useVWBStepIntegration'] = {'exists': True, 'error': str(e)} else: composants_analyses['useVWBStepIntegration'] = {'exists': False} print(f"✅ {len(composants_analyses)} composants analysés") return composants_analyses def verifier_coherence_types() -> Dict[str, Any]: """ Vérifie la cohérence des types TypeScript entre les différents fichiers. Returns: Résultats de la vérification de cohérence """ print("🔍 Vérification de la cohérence des types...") coherence = { 'catalog_types_exists': False, 'main_types_exists': False, 'types_coherent': False, 'issues': [], } # Vérifier catalog.ts catalog_types_path = Path("visual_workflow_builder/frontend/src/types/catalog.ts") if catalog_types_path.exists(): coherence['catalog_types_exists'] = True try: with open(catalog_types_path, 'r', encoding='utf-8') as f: contenu = f.read() # Vérifier la présence des types essentiels types_essentiels = [ 'VWBCatalogAction', 'VWBActionParameter', 'VWBVisualAnchor', 'VWBActionValidationResult', ] for type_name in types_essentiels: if type_name not in contenu: coherence['issues'].append(f"Type manquant : {type_name}") except Exception as e: coherence['issues'].append(f"Erreur lecture catalog.ts : {e}") else: coherence['issues'].append("Fichier catalog.ts manquant") # Vérifier index.ts principal main_types_path = Path("visual_workflow_builder/frontend/src/types/index.ts") if main_types_path.exists(): coherence['main_types_exists'] = True else: coherence['issues'].append("Fichier types/index.ts manquant") coherence['types_coherent'] = len(coherence['issues']) == 0 print(f"✅ Vérification de cohérence terminée - {len(coherence['issues'])} problèmes trouvés") return coherence def generer_rapport_complet() -> Dict[str, Any]: """ Génère un rapport complet de l'état des propriétés d'étapes. Returns: Rapport complet """ print("📊 Génération du rapport complet...") rapport = { 'timestamp': datetime.now().isoformat(), 'version': '1.0.0', 'auteur': 'Dom, Alice, Kiro', 'catalogue_statique': analyser_catalogue_statique(), 'backend_registry': analyser_backend_registry(), 'composants_frontend': analyser_composants_frontend(), 'coherence_types': verifier_coherence_types(), } # Calculer des métriques globales catalogue_actions = rapport['catalogue_statique'] backend_actions = rapport['backend_registry'].get('actions', {}) rapport['metriques'] = { 'total_actions_catalogue': len(catalogue_actions), 'total_actions_backend': len(backend_actions), 'actions_communes': len(set(catalogue_actions.keys()) & set(backend_actions.keys())), 'actions_catalogue_seulement': list(set(catalogue_actions.keys()) - set(backend_actions.keys())), 'actions_backend_seulement': list(set(backend_actions.keys()) - set(catalogue_actions.keys())), } # Évaluer l'état global composants = rapport['composants_frontend'] coherence = rapport['coherence_types'] rapport['etat_global'] = { 'properties_panel_ok': composants.get('PropertiesPanel', {}).get('exists', False), 'vwb_properties_ok': composants.get('VWBActionProperties', {}).get('exists', False), 'integration_hook_ok': composants.get('useVWBStepIntegration', {}).get('exists', False), 'types_coherents': coherence.get('types_coherent', False), 'pret_pour_production': False, # Sera calculé } # Calculer si prêt pour production etat = rapport['etat_global'] etat['pret_pour_production'] = all([ etat['properties_panel_ok'], etat['vwb_properties_ok'], etat['integration_hook_ok'], etat['types_coherents'], rapport['metriques']['total_actions_catalogue'] > 0, ]) return rapport def sauvegarder_rapport(rapport: Dict[str, Any]) -> str: """ Sauvegarde le rapport dans un fichier JSON. Args: rapport: Rapport à sauvegarder Returns: Chemin du fichier sauvegardé """ # Créer le répertoire docs s'il n'existe pas docs_dir = Path("docs") docs_dir.mkdir(exist_ok=True) # Nom du fichier avec timestamp timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") fichier_rapport = docs_dir / f"rapport_verification_proprietes_etapes_{timestamp}.json" try: with open(fichier_rapport, 'w', encoding='utf-8') as f: json.dump(rapport, f, indent=2, ensure_ascii=False) print(f"✅ Rapport sauvegardé : {fichier_rapport}") return str(fichier_rapport) except Exception as e: print(f"❌ Erreur sauvegarde rapport : {e}") return "" def afficher_resume(rapport: Dict[str, Any]): """ Affiche un résumé du rapport. Args: rapport: Rapport à résumer """ print("\n" + "="*60) print("📋 RÉSUMÉ DE LA VÉRIFICATION DES PROPRIÉTÉS D'ÉTAPES") print("="*60) metriques = rapport['metriques'] etat = rapport['etat_global'] print(f"📊 Actions catalogue : {metriques['total_actions_catalogue']}") print(f"🔧 Actions backend : {metriques['total_actions_backend']}") print(f"🤝 Actions communes : {metriques['actions_communes']}") print(f"\n🎨 Composants Frontend :") print(f" - PropertiesPanel : {'✅' if etat['properties_panel_ok'] else '❌'}") print(f" - VWBActionProperties : {'✅' if etat['vwb_properties_ok'] else '❌'}") print(f" - useVWBStepIntegration : {'✅' if etat['integration_hook_ok'] else '❌'}") print(f"\n🔍 Types TypeScript : {'✅' if etat['types_coherents'] else '❌'}") print(f"\n🚀 Prêt pour production : {'✅' if etat['pret_pour_production'] else '❌'}") # Afficher les problèmes s'il y en a coherence = rapport['coherence_types'] if coherence.get('issues'): print(f"\n⚠️ Problèmes détectés :") for issue in coherence['issues']: print(f" - {issue}") # Afficher les actions manquantes if metriques['actions_catalogue_seulement']: print(f"\n📋 Actions catalogue non implémentées backend :") for action in metriques['actions_catalogue_seulement']: print(f" - {action}") if metriques['actions_backend_seulement']: print(f"\n🔧 Actions backend non référencées catalogue :") for action in metriques['actions_backend_seulement']: print(f" - {action}") def main(): """Fonction principale du script.""" print("🔍 Vérification Complète des Propriétés d'Étapes VWB") print("Auteur : Dom, Alice, Kiro - 12 janvier 2026") print("-" * 60) try: # Générer le rapport complet rapport = generer_rapport_complet() # Sauvegarder le rapport fichier_rapport = sauvegarder_rapport(rapport) # Afficher le résumé afficher_resume(rapport) # Déterminer le code de sortie if rapport['etat_global']['pret_pour_production']: print(f"\n✅ Système prêt - Toutes les propriétés d'étapes sont correctement implémentées") return 0 else: print(f"\n⚠️ Système nécessite des améliorations - Voir le rapport : {fichier_rapport}") return 1 except Exception as e: print(f"❌ Erreur lors de la vérification : {e}") import traceback traceback.print_exc() return 2 if __name__ == "__main__": exit_code = main() sys.exit(exit_code)