feat: outils gestion fichiers dans le VWB (📁 Fichiers)

- 5 actions : lister, créer dossier, déplacer, copier, classer par extension
- Exécution sur Windows via agent port 5006
- Sécurité chemins (bloque C:\Windows, /etc, etc.)
- Propriétés panel + preview canvas pour chaque action

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-18 16:05:36 +01:00
parent 97d708c6f5
commit 40e5fba86c
10 changed files with 898 additions and 9 deletions

View File

@@ -77,6 +77,12 @@ _CONDITION_ACTION_TYPES = {"visual_condition"}
# Actions VWB de type data loop
_DATA_LOOP_ACTION_TYPES = {"import_excel", "db_foreach"}
# Actions VWB de gestion de fichiers
_FILE_ACTION_TYPES = {
"file_list_dir", "file_create_dir", "file_move",
"file_copy", "file_sort_by_ext",
}
def _classify_step_type(action_type: str) -> StepType:
"""Détermine le StepType DAG à partir du action_type VWB."""
@@ -982,6 +988,43 @@ def execute_windows():
if vwb_type in ('keyboard_shortcut', 'hotkey') and 'keys' in params:
action['keys'] = params['keys']
# ---------------------------------------------------------------
# Actions fichiers → proxy vers /file-action de l'agent (port 5006)
# ---------------------------------------------------------------
if 'actions' in data:
file_actions = [a for a in data['actions'] if a.get('type', '') in _FILE_ACTION_TYPES]
if file_actions:
# Exécuter les actions fichiers via l'agent Windows
file_results = []
for fa in file_actions:
try:
fa_resp = req.post(
'http://192.168.1.11:5006/file-action',
json={
'action': fa['type'],
'params': fa.get('parameters', {}),
},
timeout=30,
)
file_results.append(fa_resp.json())
except req.ConnectionError:
file_results.append({
'error': "Agent Windows (port 5006) non disponible pour l'action fichier"
})
except Exception as e:
file_results.append({'error': str(e)})
# Si TOUTES les actions sont des actions fichiers, retourner directement
non_file_actions = [a for a in data['actions'] if a.get('type', '') not in _FILE_ACTION_TYPES]
if not non_file_actions:
return jsonify({
'success': all('error' not in r for r in file_results),
'file_results': file_results,
})
# Sinon, retirer les actions fichiers du flux principal
data['actions'] = non_file_actions
# Injecter le machine_id pour le ciblage multi-machine
# Chercher la première machine Windows connectée si pas spécifié
if 'machine_id' not in data or not data.get('machine_id'):