Files
rpa_vision_v3/scripts/analyse_cas_undefined_stepparametersconfig_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

638 lines
28 KiB
Python

#!/usr/bin/env python3
"""
Script d'Analyse - Cas Undefined stepParametersConfig
Auteur : Dom, Alice, Kiro - 12 janvier 2026
Ce script identifie tous les cas où stepParametersConfig[selectedStep.type] retourne undefined
pour diagnostiquer les problèmes de propriétés d'étapes vides.
"""
import json
import os
import sys
import re
import time
from pathlib import Path
from typing import Dict, List, Any, Optional, Set, Tuple
class AnalyseCasUndefinedStepParametersConfig:
"""Analyse des cas undefined dans stepParametersConfig."""
def __init__(self):
"""Initialise l'analyse."""
self.project_root = Path(__file__).parent.parent
self.frontend_path = self.project_root / "visual_workflow_builder" / "frontend"
self.analysis_results = {
"timestamp": "2026-01-12",
"version": "1.0.0",
"analysis_type": "cas_undefined_stepparametersconfig",
"summary": {
"total_step_types": 0,
"configured_types": 0,
"undefined_cases": 0,
"vwb_actions_analyzed": 0,
"potential_issues": 0
},
"step_types_analysis": {
"configured_types": [],
"undefined_types": [],
"type_mapping": {}
},
"vwb_actions_analysis": {
"known_vwb_actions": [],
"catalog_actions": [],
"unmapped_actions": []
},
"undefined_scenarios": [],
"recommendations": [],
"detailed_findings": []
}
print("🔍 Analyse des Cas Undefined - stepParametersConfig")
print(f"📁 Chemin frontend: {self.frontend_path}")
def run_complete_analysis(self) -> Dict[str, Any]:
"""Exécute l'analyse complète."""
try:
print("\n" + "="*70)
print("🚀 ANALYSE COMPLÈTE DES CAS UNDEFINED")
print("="*70)
# 1. Analyser la configuration stepParametersConfig
self._analyze_step_parameters_config()
# 2. Analyser les types TypeScript
self._analyze_typescript_step_types()
# 3. Analyser les actions VWB du catalogue
self._analyze_vwb_catalog_actions()
# 4. Identifier les scénarios undefined
self._identify_undefined_scenarios()
# 5. Analyser les cas d'usage réels
self._analyze_real_usage_cases()
# 6. Générer les recommandations
self._generate_recommendations()
# 7. Sauvegarder le rapport
self._save_analysis_report()
print(f"\n✅ Analyse terminée - {self.analysis_results['summary']['undefined_cases']} cas undefined identifiés")
return self.analysis_results
except Exception as e:
print(f"❌ Erreur lors de l'analyse : {e}")
self.analysis_results["fatal_error"] = str(e)
return self.analysis_results
def _analyze_step_parameters_config(self):
"""Analyse la configuration stepParametersConfig."""
print("\n📋 Analyse de stepParametersConfig...")
try:
# Lire le fichier PropertiesPanel
properties_panel_path = self.frontend_path / "src" / "components" / "PropertiesPanel" / "index.tsx"
if not properties_panel_path.exists():
self._add_finding("CRITICAL", "Fichier PropertiesPanel introuvable", {})
return
content = properties_panel_path.read_text(encoding='utf-8')
# Extraire la configuration stepParametersConfig
config_match = re.search(
r'const stepParametersConfig: Record<StepType, ParameterConfig\[\]> = \{(.*?)\};',
content,
re.DOTALL
)
if not config_match:
self._add_finding("CRITICAL", "Configuration stepParametersConfig introuvable", {})
return
config_content = config_match.group(1)
# Extraire les types configurés
configured_types = re.findall(r'(\w+):\s*\[', config_content)
# Analyser chaque configuration
type_mapping = {}
for step_type in configured_types:
# Extraire la configuration détaillée pour ce type
type_pattern = rf'{step_type}:\s*\[(.*?)\],'
type_match = re.search(type_pattern, config_content, re.DOTALL)
if type_match:
type_config = type_match.group(1)
param_count = len(re.findall(r'\{[^}]+\}', type_config))
type_mapping[step_type] = {
"parameter_count": param_count,
"has_configuration": True,
"config_content": type_config.strip()
}
else:
type_mapping[step_type] = {
"parameter_count": 0,
"has_configuration": False,
"config_content": ""
}
self.analysis_results["step_types_analysis"] = {
"configured_types": configured_types,
"type_mapping": type_mapping,
"total_configured": len(configured_types)
}
self.analysis_results["summary"]["configured_types"] = len(configured_types)
print(f"{len(configured_types)} types configurés trouvés")
for step_type in configured_types:
param_count = type_mapping[step_type]["parameter_count"]
print(f" - {step_type}: {param_count} paramètres")
except Exception as e:
self._add_finding("ERROR", f"Erreur analyse stepParametersConfig: {e}", {})
def _analyze_typescript_step_types(self):
"""Analyse les types TypeScript StepType."""
print("\n🔧 Analyse des types TypeScript...")
try:
# Lire le fichier des types
types_file_path = self.frontend_path / "src" / "types" / "index.ts"
if not types_file_path.exists():
self._add_finding("HIGH", "Fichier types TypeScript introuvable", {})
return
types_content = types_file_path.read_text(encoding='utf-8')
# Extraire l'union StepType
step_type_match = re.search(
r'export type StepType = ([^;]+);',
types_content
)
typescript_types = set()
if step_type_match:
step_type_union = step_type_match.group(1)
typescript_types = set(re.findall(r"'(\w+)'", step_type_union))
# Comparer avec les types configurés
configured_types = set(self.analysis_results["step_types_analysis"]["configured_types"])
# Identifier les types undefined (présents en TypeScript mais pas configurés)
undefined_types = list(typescript_types - configured_types)
extra_configured = list(configured_types - typescript_types)
self.analysis_results["step_types_analysis"]["typescript_types"] = list(typescript_types)
self.analysis_results["step_types_analysis"]["undefined_types"] = undefined_types
self.analysis_results["step_types_analysis"]["extra_configured"] = extra_configured
self.analysis_results["summary"]["total_step_types"] = len(typescript_types)
self.analysis_results["summary"]["undefined_cases"] = len(undefined_types)
# Signaler les cas undefined
if undefined_types:
self._add_finding("HIGH", f"Types TypeScript sans configuration: {undefined_types}", {
"undefined_types": undefined_types,
"impact": "Ces types retourneront undefined dans stepParametersConfig",
"consequence": "Propriétés d'étapes vides pour ces types"
})
if extra_configured:
self._add_finding("MEDIUM", f"Configurations sans type TypeScript: {extra_configured}", {
"extra_configured": extra_configured,
"impact": "Configurations inutilisées"
})
print(f"{len(typescript_types)} types TypeScript trouvés")
print(f"{len(configured_types)} types configurés")
print(f" ⚠️ {len(undefined_types)} types undefined identifiés: {undefined_types}")
except Exception as e:
self._add_finding("ERROR", f"Erreur analyse types TypeScript: {e}", {})
def _analyze_vwb_catalog_actions(self):
"""Analyse les actions VWB du catalogue."""
print("\n🎯 Analyse des actions VWB du catalogue...")
try:
# Analyser le catalogue statique
static_catalog_path = self.frontend_path / "src" / "data" / "staticCatalog.ts"
catalog_actions = []
if static_catalog_path.exists():
catalog_content = static_catalog_path.read_text(encoding='utf-8')
# Extraire les actions du catalogue
actions_pattern = r"id:\s*['\"]([^'\"]+)['\"]"
catalog_actions = re.findall(actions_pattern, catalog_content)
# Actions VWB connues dans le code
properties_panel_path = self.frontend_path / "src" / "components" / "PropertiesPanel" / "index.tsx"
known_vwb_actions = []
if properties_panel_path.exists():
content = properties_panel_path.read_text(encoding='utf-8')
# Extraire la liste des actions VWB connues
known_actions_match = re.search(
r'knownVWBActions = \[(.*?)\]',
content,
re.DOTALL
)
if known_actions_match:
actions_content = known_actions_match.group(1)
known_vwb_actions = re.findall(r"'([^']+)'", actions_content)
# Identifier les actions non mappées
all_vwb_actions = set(catalog_actions + known_vwb_actions)
configured_types = set(self.analysis_results["step_types_analysis"]["configured_types"])
unmapped_vwb_actions = list(all_vwb_actions - configured_types)
self.analysis_results["vwb_actions_analysis"] = {
"catalog_actions": catalog_actions,
"known_vwb_actions": known_vwb_actions,
"all_vwb_actions": list(all_vwb_actions),
"unmapped_actions": unmapped_vwb_actions
}
self.analysis_results["summary"]["vwb_actions_analyzed"] = len(all_vwb_actions)
# Signaler les actions VWB non mappées
if unmapped_vwb_actions:
self._add_finding("MEDIUM", f"Actions VWB non mappées dans stepParametersConfig: {unmapped_vwb_actions}", {
"unmapped_actions": unmapped_vwb_actions,
"impact": "Ces actions VWB utiliseront le composant VWBActionProperties",
"note": "Comportement attendu pour les actions VWB"
})
print(f"{len(catalog_actions)} actions du catalogue analysées")
print(f"{len(known_vwb_actions)} actions VWB connues")
print(f"{len(unmapped_vwb_actions)} actions VWB non mappées (normal)")
except Exception as e:
self._add_finding("ERROR", f"Erreur analyse actions VWB: {e}", {})
def _identify_undefined_scenarios(self):
"""Identifie les scénarios spécifiques qui causent undefined."""
print("\n🔍 Identification des scénarios undefined...")
try:
undefined_scenarios = []
# Scénario 1: Types TypeScript sans configuration
undefined_types = self.analysis_results["step_types_analysis"].get("undefined_types", [])
for step_type in undefined_types:
scenario = {
"scenario_type": "typescript_without_config",
"step_type": step_type,
"description": f"Type '{step_type}' défini en TypeScript mais absent de stepParametersConfig",
"consequence": "stepParametersConfig[selectedStep.type] retourne undefined",
"user_impact": "Affichage 'Cette étape n'a pas de paramètres configurables'",
"severity": "HIGH",
"fix_required": True
}
undefined_scenarios.append(scenario)
# Scénario 2: Types dynamiques non prévus
dynamic_types = [
"custom_action", "user_defined", "plugin_action",
"external_tool", "api_call", "database_query"
]
for dynamic_type in dynamic_types:
scenario = {
"scenario_type": "dynamic_type_not_configured",
"step_type": dynamic_type,
"description": f"Type dynamique '{dynamic_type}' potentiellement créé à l'exécution",
"consequence": "stepParametersConfig[selectedStep.type] retourne undefined",
"user_impact": "Propriétés non configurables pour les types dynamiques",
"severity": "MEDIUM",
"fix_required": False,
"note": "Peut nécessiter une gestion spéciale"
}
undefined_scenarios.append(scenario)
# Scénario 3: Actions VWB mal détectées
vwb_actions = self.analysis_results["vwb_actions_analysis"].get("all_vwb_actions", [])
for vwb_action in vwb_actions:
scenario = {
"scenario_type": "vwb_action_detection_failure",
"step_type": vwb_action,
"description": f"Action VWB '{vwb_action}' non détectée par la logique VWB",
"consequence": "Utilisation de stepParametersConfig au lieu de VWBActionProperties",
"user_impact": "Propriétés VWB non affichées correctement",
"severity": "MEDIUM",
"fix_required": True,
"note": "Améliorer la détection VWB"
}
undefined_scenarios.append(scenario)
self.analysis_results["undefined_scenarios"] = undefined_scenarios
self.analysis_results["summary"]["potential_issues"] = len(undefined_scenarios)
print(f"{len(undefined_scenarios)} scénarios undefined identifiés")
# Afficher les scénarios critiques
critical_scenarios = [s for s in undefined_scenarios if s["severity"] == "HIGH"]
if critical_scenarios:
print(f" 🚨 {len(critical_scenarios)} scénarios critiques:")
for scenario in critical_scenarios:
print(f" - {scenario['step_type']}: {scenario['description']}")
except Exception as e:
self._add_finding("ERROR", f"Erreur identification scénarios: {e}", {})
def _analyze_real_usage_cases(self):
"""Analyse les cas d'usage réels dans le code."""
print("\n📊 Analyse des cas d'usage réels...")
try:
# Analyser l'utilisation de stepParametersConfig dans PropertiesPanel
properties_panel_path = self.frontend_path / "src" / "components" / "PropertiesPanel" / "index.tsx"
content = properties_panel_path.read_text(encoding='utf-8')
# Rechercher les accès à stepParametersConfig
config_accesses = re.findall(
r'stepParametersConfig\[([^\]]+)\]',
content
)
# Analyser la fonction getParameterConfig
get_param_config_match = re.search(
r'const getParameterConfig = useCallback\(\(\): ParameterConfig\[\] => \{(.*?)\}, \[selectedStep\]\);',
content,
re.DOTALL
)
usage_analysis = {
"config_accesses": config_accesses,
"access_count": len(config_accesses),
"has_fallback_logic": False,
"has_undefined_check": False,
"has_error_handling": False
}
if get_param_config_match:
config_logic = get_param_config_match.group(1)
# Vérifier la présence de logiques de protection
usage_analysis["has_fallback_logic"] = "|| []" in config_logic
usage_analysis["has_undefined_check"] = "undefined" in config_logic
usage_analysis["has_error_handling"] = "try" in config_logic and "catch" in config_logic
# Analyser les conditions de retour
return_statements = re.findall(r'return ([^;]+);', config_logic)
usage_analysis["return_statements"] = return_statements
self.analysis_results["real_usage_analysis"] = usage_analysis
# Signaler les problèmes d'usage
if not usage_analysis["has_fallback_logic"]:
self._add_finding("MEDIUM", "Pas de logique de fallback pour stepParametersConfig", {
"suggestion": "Ajouter '|| []' pour éviter les erreurs undefined"
})
if not usage_analysis["has_error_handling"]:
self._add_finding("LOW", "Pas de gestion d'erreurs dans getParameterConfig", {
"suggestion": "Ajouter try/catch pour la robustesse"
})
print(f"{usage_analysis['access_count']} accès à stepParametersConfig analysés")
print(f" ✅ Fallback logic: {'Oui' if usage_analysis['has_fallback_logic'] else 'Non'}")
print(f" ✅ Gestion d'erreurs: {'Oui' if usage_analysis['has_error_handling'] else 'Non'}")
except Exception as e:
self._add_finding("ERROR", f"Erreur analyse usage réel: {e}", {})
def _generate_recommendations(self):
"""Génère des recommandations pour résoudre les cas undefined."""
print("\n💡 Génération des recommandations...")
recommendations = []
# Recommandation 1: Corriger les types undefined
undefined_types = self.analysis_results["step_types_analysis"].get("undefined_types", [])
if undefined_types:
recommendations.append({
"priority": "HIGH",
"category": "Configuration manquante",
"title": "Ajouter les configurations manquantes pour les types undefined",
"description": f"{len(undefined_types)} types retournent undefined",
"affected_types": undefined_types,
"actions": [
f"Ajouter une configuration pour chaque type: {', '.join(undefined_types)}",
"Définir les paramètres appropriés pour chaque type",
"Tester l'affichage des propriétés après ajout"
],
"code_example": self._generate_config_example(undefined_types[0] if undefined_types else "example")
})
# Recommandation 2: Améliorer la robustesse
usage_analysis = self.analysis_results.get("real_usage_analysis", {})
if not usage_analysis.get("has_fallback_logic", False):
recommendations.append({
"priority": "MEDIUM",
"category": "Robustesse",
"title": "Ajouter une logique de fallback pour éviter undefined",
"description": "Protéger contre les accès undefined à stepParametersConfig",
"actions": [
"Ajouter '|| []' après stepParametersConfig[selectedStep.type]",
"Implémenter une configuration par défaut",
"Ajouter des logs pour diagnostiquer les cas undefined"
],
"code_example": "const config = stepParametersConfig[selectedStep.type as StepType] || [];"
})
# Recommandation 3: Améliorer la détection VWB
vwb_actions = self.analysis_results["vwb_actions_analysis"].get("unmapped_actions", [])
if len(vwb_actions) > 5: # Si beaucoup d'actions VWB non mappées
recommendations.append({
"priority": "MEDIUM",
"category": "Détection VWB",
"title": "Renforcer la détection des actions VWB",
"description": f"{len(vwb_actions)} actions VWB pourraient être mal détectées",
"actions": [
"Améliorer les méthodes de détection VWB",
"Ajouter plus de patterns de reconnaissance",
"Tester la détection avec toutes les actions du catalogue"
]
})
# Recommandation 4: Documentation
recommendations.append({
"priority": "LOW",
"category": "Documentation",
"title": "Documenter les cas undefined et leur résolution",
"description": "Créer une documentation pour les développeurs",
"actions": [
"Documenter tous les types d'étapes supportés",
"Expliquer la différence entre types standard et VWB",
"Créer un guide de débogage pour les propriétés vides"
]
})
self.analysis_results["recommendations"] = recommendations
print(f"{len(recommendations)} recommandations générées")
def _generate_config_example(self, step_type: str) -> str:
"""Génère un exemple de configuration pour un type d'étape."""
return f"""
{step_type}: [
{{
name: 'parameter1',
label: 'Paramètre 1',
type: 'text',
required: true,
description: 'Description du paramètre'
}},
{{
name: 'parameter2',
label: 'Paramètre 2',
type: 'boolean',
defaultValue: false
}}
],"""
def _add_finding(self, severity: str, description: str, details: Dict[str, Any]):
"""Ajoute un résultat d'analyse."""
finding = {
"severity": severity,
"description": description,
"details": details,
"timestamp": time.time()
}
self.analysis_results["detailed_findings"].append(finding)
def _save_analysis_report(self):
"""Sauvegarde le rapport d'analyse."""
try:
# Créer le répertoire docs s'il n'existe pas
docs_path = self.project_root / "docs"
docs_path.mkdir(exist_ok=True)
# Sauvegarder le rapport JSON
json_report_path = docs_path / "ANALYSE_CAS_UNDEFINED_STEPPARAMETERSCONFIG_12JAN2026.json"
with open(json_report_path, 'w', encoding='utf-8') as f:
json.dump(self.analysis_results, f, indent=2, ensure_ascii=False)
# Créer un résumé markdown
md_report_path = docs_path / "ANALYSE_CAS_UNDEFINED_STEPPARAMETERSCONFIG_12JAN2026.md"
self._create_markdown_summary(md_report_path)
print(f"\n📄 Rapport JSON sauvegardé : {json_report_path}")
print(f"📄 Résumé Markdown créé : {md_report_path}")
except Exception as e:
print(f"❌ Erreur sauvegarde rapport : {e}")
def _create_markdown_summary(self, output_path: Path):
"""Crée un résumé markdown de l'analyse."""
summary = self.analysis_results["summary"]
markdown_content = f"""# Analyse des Cas Undefined - stepParametersConfig
**Auteur :** Dom, Alice, Kiro
**Date :** 12 janvier 2026
**Version :** 1.0.0
## Résumé Exécutif
- **Types d'étapes totaux :** {summary['total_step_types']}
- **Types configurés :** {summary['configured_types']}
- **Cas undefined :** {summary['undefined_cases']}
- **Actions VWB analysées :** {summary['vwb_actions_analyzed']}
- **Problèmes potentiels :** {summary['potential_issues']}
## Types Undefined Identifiés
"""
undefined_types = self.analysis_results["step_types_analysis"].get("undefined_types", [])
if undefined_types:
markdown_content += "Les types suivants retournent `undefined` dans `stepParametersConfig`:\n\n"
for step_type in undefined_types:
markdown_content += f"- `{step_type}` - Défini en TypeScript mais pas configuré\n"
else:
markdown_content += "✅ Aucun type undefined identifié.\n"
# Ajouter les recommandations
recommendations = self.analysis_results.get("recommendations", [])
if recommendations:
markdown_content += "\n## Recommandations\n\n"
for i, rec in enumerate(recommendations, 1):
markdown_content += f"### {i}. {rec['title']} ({rec['priority']})\n\n"
markdown_content += f"**Catégorie :** {rec['category']} \n"
markdown_content += f"**Description :** {rec['description']}\n\n"
if 'actions' in rec:
markdown_content += "**Actions :**\n"
for action in rec['actions']:
markdown_content += f"- {action}\n"
if 'code_example' in rec:
markdown_content += f"\n**Exemple de code :**\n```typescript\n{rec['code_example']}\n```\n"
markdown_content += "\n"
# Sauvegarder le markdown
with open(output_path, 'w', encoding='utf-8') as f:
f.write(markdown_content)
def main():
"""Fonction principale."""
print("🔍 Analyse des Cas Undefined - stepParametersConfig")
analyzer = AnalyseCasUndefinedStepParametersConfig()
results = analyzer.run_complete_analysis()
# Afficher le résumé final
print("\n" + "="*70)
print("📊 RÉSUMÉ DE L'ANALYSE DES CAS UNDEFINED")
print("="*70)
summary = results['summary']
print(f"✅ Analyse terminée avec succès")
print(f"📊 Types d'étapes totaux : {summary['total_step_types']}")
print(f"✅ Types configurés : {summary['configured_types']}")
print(f"⚠️ Cas undefined : {summary['undefined_cases']}")
print(f"🎯 Actions VWB analysées : {summary['vwb_actions_analyzed']}")
undefined_types = results["step_types_analysis"].get("undefined_types", [])
if undefined_types:
print(f"\n🚨 Types undefined identifiés :")
for step_type in undefined_types:
print(f" - {step_type}")
else:
print(f"\n🎉 Aucun type undefined critique identifié !")
recommendations = results.get("recommendations", [])
if recommendations:
print(f"\n💡 Recommandations : {len(recommendations)}")
for rec in recommendations:
print(f" - {rec['priority']}: {rec['title']}")
print(f"\n📄 Rapport complet disponible dans docs/")
# Code de sortie basé sur les cas undefined critiques
if summary['undefined_cases'] > 0:
print("⚠️ Cas undefined détectés - correction recommandée")
return 1
else:
print("🎉 Aucun cas undefined critique détecté !")
return 0
if __name__ == "__main__":
sys.exit(main())