# Guía de Desarrollo: Launcher para Scripts GUI La aplicación original @app.py busca y ejecuta scripts Python sin GUI. Deseo agregar una nueva funcionalidad para scripts con GUI que no necesiten el sistema de datos grupal o directorio de trabajo con eschema de datos. La página principal @index.html se dividirá en dos pestañas: una sin cambios y otra para un launcher de scripts Python con GUI. Esta nueva pagina de launcher usará una lista manual de directorios almacenada en un archivo launcher_scripts.json. Necesitamos la opcion de poder agregar, eliminar o modificar estos directorios de grupos de scripts. La lista se mostrará en un combo box, similar a la aplicación actual, describiendo cada grupo de scripts. Al seleccionar un grupo, se buscarán los scripts en el directorio root correspondiente. El sistema de configuración no se usará, solo el directorio de trabajo para indicar desde donde se ejecuta el script, por defecto el directorio root del script. El sistema de logging se mantendrá. Además, si hay un archivo icon.ico en un directorio de scripts, se mostrará como referencia gráfica del grupo en la página. De ser posible quisiera que el icono del grupo se muestre en la combo de seleccion de grupos. ## Resumen del Proyecto Esta guía detalla la implementación de un nuevo launcher para scripts Python con interfaz gráfica (GUI), que coexistirá con el sistema actual de scripts de configuración. El nuevo sistema incluirá funcionalidades avanzadas como categorización, favoritos, historial y argumentos simples. ## Índice 1. [Arquitectura General](#arquitectura-general) 2. [Estructura de Archivos](#estructura-de-archivos) 3. [Fase 1: Estructura Básica](#fase-1-estructura-básica) 4. [Fase 2: Funcionalidad Core](#fase-2-funcionalidad-core) 5. [Fase 3: Mejoras Avanzadas](#fase-3-mejoras-avanzadas) 6. [Fase 4: Sistema de Iconos](#fase-4-sistema-de-iconos) 7. [APIs Requeridas](#apis-requeridas) 8. [Estructura de Datos](#estructura-de-datos) 9. [Componentes UI](#componentes-ui) 10. [Testing y Validación](#testing-y-validación) --- ## Arquitectura General ### Principios de Diseño - **Coexistencia**: El nuevo launcher coexistirá con el sistema actual sin interferir - **Reutilización**: Aprovechar componentes existentes (logging, UI base, etc.) - **Modularidad**: Código separado y mantenible - **Flexibilidad**: Configuración manual de directorios y categorías - Mecanismo para seleccionar el entorno miniconda a utlizar para cada grupo de scripts. ### Diferencias con Sistema Actual | Aspecto | Sistema Actual | Nuevo Launcher GUI | |---------|---------------|-------------------| | Fuente de grupos | Directorios automáticos | `launcher_scripts.json` manual | | Configuración | 3 niveles de schemas | Sin configuración compleja | | Directorio trabajo | Configurable avanzado | Por defecto directorio del script | | Metadatos | Archivos separados | Centralizados en JSON | | Categorización | No disponible | ✅ Por categorías | | Favoritos | No disponible | ✅ Sistema de favoritos | | Historial | No disponible | ✅ Historial de ejecución | | Argumentos | Vía configuración | ✅ Argumentos simples | --- ## Estructura de Archivos ### Archivos Nuevos a Crear ParamManagerScripts/ ├── data/ │ ├── launcher_scripts.json # Configuración principal del launcher │ ├── launcher_favorites.json # Scripts marcados como favoritos │ └── launcher_history.json # Historial de ejecución ├── lib/ │ └── launcher_manager.py # Gestor principal del launcher ├── static/ │ ├── css/ │ │ └── launcher.css # Estilos específicos │ └── js/ │ └── launcher.js # Lógica JavaScript ├── templates/ │ └── components/ │ ├── launcher_tab.html # Tab del launcher │ ├── launcher_editor.html # Editor de grupos │ ├── script_args_modal.html # Modal para argumentos │ └── favorites_panel.html # Panel de favoritos └── adicion_launcher4GUI.md # Esta guía ### Archivos a Modificar ParamManagerScripts/ ├── app.py # Agregar rutas del launcher ├── templates/ │ └── index.html # Implementar sistema de tabs └── static/ ├── css/ │ └── styles.css # Estilos para tabs y iconos └── js/ └── scripts.js # Lógica de tabs --- ## Fase 1: Estructura Básica ### 1.1 Crear launcher_manager.py ```python # lib/launcher_manager.py import os import json from typing import Dict, Any, List, Optional from datetime import datetime class LauncherManager: def __init__(self, data_path: str): self.data_path = data_path self.launcher_config_path = os.path.join(data_path, "launcher_scripts.json") self.favorites_path = os.path.join(data_path, "launcher_favorites.json") self.history_path = os.path.join(data_path, "launcher_history.json") # Inicializar archivos si no existen self._initialize_files() def _initialize_files(self): """Crear archivos de configuración por defecto si no existen""" # Implementar inicialización pass def get_launcher_groups(self) -> List[Dict[str, Any]]: """Obtener todos los grupos de scripts GUI""" pass def add_launcher_group(self, group_data: Dict[str, Any]) -> Dict[str, str]: """Agregar nuevo grupo de scripts GUI""" pass def update_launcher_group(self, group_id: str, group_data: Dict[str, Any]) -> Dict[str, str]: """Actualizar grupo existente""" pass def delete_launcher_group(self, group_id: str) -> Dict[str, str]: """Eliminar grupo de scripts GUI""" pass def get_group_scripts(self, group_id: str) -> List[Dict[str, Any]]: """Obtener scripts de un grupo específico""" pass ``` ### 1.2 Implementar Sistema de Tabs en index.html ```html
``` ### 1.3 CSS para Tabs ```css /* static/css/styles.css - Agregar al final */ /* Tab Styles */ .tab-button { color: #6B7280; border-color: transparent; transition: all 0.2s ease; } .tab-button:hover { color: #374151; border-color: #D1D5DB; } .tab-button.active { color: #3B82F6; border-color: #3B82F6; } .tab-content { display: block; } .tab-content.hidden { display: none; } /* Icon Styles */ .group-icon { width: 48px; height: 48px; border-radius: 8px; object-fit: cover; border: 2px solid #E5E7EB; } .group-icon.default { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; } /* Category Badge */ .category-badge { display: inline-block; padding: 0.25rem 0.5rem; background: #EFF6FF; color: #1D4ED8; border-radius: 9999px; font-size: 0.75rem; font-weight: 500; } /* Favorite Star */ .favorite-star { cursor: pointer; transition: all 0.2s ease; } .favorite-star:hover { transform: scale(1.1); } .favorite-star.active { color: #F59E0B; } ``` --- ## Fase 2: Funcionalidad Core ### 2.1 APIs del Launcher ```python # Agregar a app.py from lib.launcher_manager import LauncherManager # Inicializar launcher manager launcher_manager = LauncherManager(os.path.join(config_manager.data_path)) @app.route("/api/launcher-groups", methods=["GET", "POST"]) def handle_launcher_groups(): """Gestionar grupos de launcher (GET: obtener, POST: crear)""" if request.method == "GET": try: groups = launcher_manager.get_launcher_groups() return jsonify(groups) except Exception as e: return jsonify({"error": str(e)}), 500 else: # POST try: data = request.json result = launcher_manager.add_launcher_group(data) return jsonify(result) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route("/api/launcher-groups/", methods=["GET", "PUT", "DELETE"]) def handle_launcher_group(group_id): """Gestionar grupo específico (GET: obtener, PUT: actualizar, DELETE: eliminar)""" if request.method == "GET": try: group = launcher_manager.get_launcher_group(group_id) return jsonify(group) except Exception as e: return jsonify({"error": str(e)}), 500 elif request.method == "PUT": try: data = request.json result = launcher_manager.update_launcher_group(group_id, data) return jsonify(result) except Exception as e: return jsonify({"error": str(e)}), 500 else: # DELETE try: result = launcher_manager.delete_launcher_group(group_id) return jsonify(result) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route("/api/launcher-scripts/") def get_launcher_scripts(group_id): """Obtener scripts de un grupo del launcher""" try: scripts = launcher_manager.get_group_scripts(group_id) return jsonify(scripts) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route("/api/execute-gui-script", methods=["POST"]) def execute_gui_script(): """Ejecutar script GUI con argumentos opcionales""" try: data = request.json group_id = data["group_id"] script_name = data["script_name"] script_args = data.get("args", []) result = launcher_manager.execute_gui_script( group_id, script_name, script_args, broadcast_message ) return jsonify(result) except Exception as e: error_msg = f"Error ejecutando script GUI: {str(e)}" broadcast_message(error_msg) return jsonify({"error": error_msg}), 500 ``` ### 2.2 JavaScript del Launcher ```javascript // static/js/launcher.js class LauncherManager { constructor() { this.currentGroup = null; this.groups = []; this.scripts = []; this.favorites = new Set(); this.history = []; this.categories = [ 'Herramientas', 'Análisis', 'Utilidades', 'Desarrollo', 'Visualización', 'Otros' ]; } async init() { await this.loadGroups(); await this.loadFavorites(); await this.loadHistory(); this.setupEventListeners(); this.renderInterface(); } async loadGroups() { try { const response = await fetch('/api/launcher-groups'); this.groups = await response.json(); } catch (error) { console.error('Error loading launcher groups:', error); } } async loadFavorites() { try { const response = await fetch('/api/launcher-favorites'); const data = await response.json(); this.favorites = new Set(data.favorites || []); } catch (error) { console.error('Error loading favorites:', error); } } async loadHistory() { try { const response = await fetch('/api/launcher-history'); const data = await response.json(); this.history = data.history || []; } catch (error) { console.error('Error loading history:', error); } } setupEventListeners() { // Event listeners para la interfaz } renderInterface() { this.renderGroupSelector(); this.renderCategoryFilter(); this.renderFavoritesPanel(); this.renderHistoryPanel(); } // Métodos adicionales... } // Inicialización global window.launcherManager = new LauncherManager(); ``` --- ## Fase 3: Mejoras Avanzadas ### 3.1 Sistema de Categorías #### Estructura de Datos ```json { "groups": [ { "id": "data_tools", "name": "Herramientas de Datos", "description": "Scripts para análisis y manipulación de datos", "directory": "D:/Scripts/DataTools", "category": "Análisis", "subcategory": "Datos", "version": "1.0", "author": "DataTeam", "icon": "icon.ico", "tags": ["excel", "csv", "análisis"] } ], "categories": { "Herramientas": { "color": "#3B82F6", "icon": "🔧", "subcategories": ["Generales", "Desarrollo", "Sistema"] }, "Análisis": { "color": "#10B981", "icon": "📊", "subcategories": ["Datos", "Estadísticas", "Visualización"] } } } ``` #### Componente de Filtro por Categorías ```html

Filtrar por Categoría

``` ### 3.2 Sistema de Favoritos #### Estructura de Datos ```json { "favorites": [ { "group_id": "data_tools", "script_name": "excel_analyzer.py", "added_date": "2024-01-15T10:30:00Z", "execution_count": 15, "last_executed": "2024-01-20T14:45:00Z" } ] } ``` #### Panel de Favoritos ```html

⭐ Scripts Favoritos

0 favoritos
``` ### 3.3 Historial de Ejecución #### Estructura de Datos ```json { "history": [ { "group_id": "data_tools", "script_name": "excel_analyzer.py", "executed_date": "2024-01-20T14:45:00Z", "execution_time": 2.5, "arguments": ["--input", "data.xlsx"], "status": "success", "output_summary": "Procesados 1,500 registros exitosamente" } ], "settings": { "max_history_entries": 100, "auto_cleanup_days": 30 } } ``` #### Panel de Historial ```html

📝 Historial Reciente

excel_analyzer.py Herramientas de Datos
hace 2 horas
✅ Éxito - 2.5s - Procesados 1,500 registros
``` ### 3.4 Sistema de Argumentos Simples #### Modal de Argumentos ```html ``` --- ## Fase 4: Sistema de Iconos ### 4.1 API para Iconos ```python # Agregar a app.py @app.route("/api/group-icon//") def get_group_icon(launcher_type, group_id): """Obtener icono de un grupo (config o launcher)""" try: if launcher_type == "launcher": group = launcher_manager.get_launcher_group(group_id) if not group: return jsonify({"error": "Group not found"}), 404 icon_path = os.path.join(group["directory"], "icon.ico") if os.path.exists(icon_path): return send_file(icon_path, mimetype='image/x-icon') elif launcher_type == "config": group_path = os.path.join(config_manager.script_groups_path, group_id) icon_path = os.path.join(group_path, "icon.ico") if os.path.exists(icon_path): return send_file(icon_path, mimetype='image/x-icon') # Icono por defecto default_icon_path = os.path.join(app.static_folder, 'icons', 'default-group.png') if os.path.exists(default_icon_path): return send_file(default_icon_path) else: # SVG por defecto como fallback return jsonify({"type": "default", "icon": "📁"}) except Exception as e: return jsonify({"error": str(e)}), 500 ``` ### 4.2 Componente de Icono ```javascript // static/js/launcher.js - Agregar método class LauncherManager { renderGroupIcon(group) { const iconContainer = document.createElement('div'); iconContainer.className = 'group-icon-container relative'; // Intentar cargar icono personalizado const img = document.createElement('img'); img.className = 'group-icon'; img.src = `/api/group-icon/launcher/${group.id}`; img.alt = group.name; img.onerror = () => { // Fallback a icono por defecto iconContainer.innerHTML = `
${this.getDefaultIconForCategory(group.category)}
`; }; iconContainer.appendChild(img); return iconContainer; } getDefaultIconForCategory(category) { const icons = { 'Herramientas': '🔧', 'Análisis': '📊', 'Utilidades': '⚙️', 'Desarrollo': '💻', 'Visualización': '📈', 'Otros': '📁' }; return icons[category] || '📁'; } } ``` --- ## APIs Requeridas ### Resumen de Endpoints | Método | Endpoint | Descripción | |--------|----------|-------------| | GET | `/api/launcher-groups` | Obtener todos los grupos | | POST | `/api/launcher-groups` | Crear nuevo grupo | | GET | `/api/launcher-groups/` | Obtener grupo específico | | PUT | `/api/launcher-groups/` | Actualizar grupo | | DELETE | `/api/launcher-groups/` | Eliminar grupo | | GET | `/api/launcher-scripts/` | Obtener scripts de grupo | | POST | `/api/execute-gui-script` | Ejecutar script GUI | | GET | `/api/launcher-favorites` | Obtener favoritos | | POST | `/api/launcher-favorites` | Agregar/quitar favorito | | GET | `/api/launcher-history` | Obtener historial | | DELETE | `/api/launcher-history` | Limpiar historial | | GET | `/api/group-icon//` | Obtener icono de grupo | --- ## Estructura de Datos ### launcher_scripts.json ```json { "version": "1.0", "groups": [ { "id": "data_analysis", "name": "Análisis de Datos", "description": "Scripts para análisis y visualización de datos", "directory": "D:/Scripts/DataAnalysis", "category": "Análisis", "subcategory": "Datos", "version": "2.1", "author": "DataTeam", "icon": "icon.ico", "tags": ["excel", "csv", "análisis", "visualización"], "created_date": "2024-01-01T00:00:00Z", "updated_date": "2024-01-15T10:30:00Z" } ], "categories": { "Análisis": { "color": "#10B981", "icon": "📊", "subcategories": ["Datos", "Estadísticas", "Visualización"] }, "Herramientas": { "color": "#3B82F6", "icon": "🔧", "subcategories": ["Generales", "Desarrollo", "Sistema"] } }, "settings": { "default_execution_directory": "script_directory", "enable_argument_validation": true, "max_history_entries": 100, "auto_cleanup_days": 30 } } ``` ### launcher_favorites.json ```json { "favorites": [ { "id": "data_analysis_excel_analyzer", "group_id": "data_analysis", "script_name": "excel_analyzer.py", "added_date": "2024-01-15T10:30:00Z", "execution_count": 15, "last_executed": "2024-01-20T14:45:00Z", "custom_name": "Analizador Excel Principal" } ] } ``` ### launcher_history.json ```json { "history": [ { "id": "exec_20240120_144500", "group_id": "data_analysis", "script_name": "excel_analyzer.py", "executed_date": "2024-01-20T14:45:00Z", "execution_time": 2.5, "arguments": ["--input", "data.xlsx", "--output", "results.csv"], "working_directory": "D:/Projects/DataAnalysis", "status": "success", "exit_code": 0, "output_summary": "Procesados 1,500 registros exitosamente", "error_message": null } ], "settings": { "max_entries": 100, "auto_cleanup_days": 30, "track_execution_time": true, "track_arguments": true } } ``` --- ## Componentes UI ### Selector de Grupos con Iconos ```html
``` ### Lista de Scripts con Favoritos ```html

excel_analyzer.py

Analiza archivos Excel y genera reportes

Análisis
``` ### Editor de Grupos ```html ``` --- ## Testing y Validación ### Plan de Testing #### 1. Testing Unitario - **LauncherManager**: Todas las operaciones CRUD - **Validación**: Rutas de directorios, estructura JSON - **Ejecución**: Scripts con diferentes argumentos #### 2. Testing de Integración - **APIs**: Todos los endpoints del launcher - **Persistencia**: Guardado y carga de configuraciones - **Logging**: Integración con sistema de logs existente #### 3. Testing de UI - **Navegación**: Cambio entre tabs - **Responsividad**: Funcionalidad en diferentes tamaños de pantalla - **Interactividad**: Favoritos, filtros, argumentos #### 4. Testing de Sistema - **Coexistencia**: No interferencia con sistema actual - **Rendimiento**: Carga de grupos grandes - **Seguridad**: Validación de rutas y argumentos ### Casos de Prueba #### Funcionalidad Básica ```javascript // Ejemplo de test para favoritos describe('Favorites System', () => { test('should add script to favorites', async () => { const result = await launcherManager.addToFavorites('group1', 'script1.py'); expect(result.status).toBe('success'); expect(launcherManager.favorites.has('group1_script1.py')).toBe(true); }); test('should remove script from favorites', async () => { await launcherManager.removeFromFavorites('group1', 'script1.py'); expect(launcherManager.favorites.has('group1_script1.py')).toBe(false); }); }); ``` #### Validación de Datos ```python # Ejemplo de validación de grupo def test_group_validation(): invalid_group = { "name": "", # Nombre vacío "directory": "/path/that/does/not/exist" # Directorio inexistente } result = launcher_manager.add_launcher_group(invalid_group) assert result["status"] == "error" assert "validation" in result["message"] ``` --- ## Cronograma de Desarrollo ### Semana 1: Estructura Básica - [ ] Crear `launcher_manager.py` con funciones básicas - [ ] Implementar sistema de tabs en `index.html` - [ ] Configurar rutas básicas en `app.py` - [ ] CSS base para tabs y componentes ### Semana 2: Funcionalidad Core - [ ] APIs completas para gestión de grupos - [ ] Editor de grupos funcional - [ ] Carga y listado de scripts - [ ] Ejecución básica de scripts ### Semana 3: Mejoras Avanzadas - [ ] Sistema de categorías - [ ] Funcionalidad de favoritos - [ ] Historial de ejecución - [ ] Modal de argumentos ### Semana 4: Sistema de Iconos y Pulimiento - [ ] API de iconos - [ ] Iconos por defecto - [ ] Refinamiento de UI - [ ] Testing y correcciones ### Semana 5: Testing y Documentación - [ ] Testing completo - [ ] Documentación de usuario - [ ] Optimizaciones de rendimiento - [ ] Deployment y validación final --- ## Notas de Implementación ### Consideraciones de Seguridad 1. **Validación de Rutas**: Verificar que los directorios especificados existen y son accesibles 2. **Sanitización de Argumentos**: Limpiar argumentos de línea de comandos para prevenir inyección 3. **Permisos**: Verificar permisos de ejecución en scripts 4. **Logging de Seguridad**: Registrar intentos de acceso a rutas no autorizadas ### Optimizaciones de Rendimiento 1. **Caché de Scripts**: Cachear lista de scripts por directorio 2. **Lazy Loading**: Cargar scripts solo cuando se selecciona un grupo 3. **Debouncing**: Evitar búsquedas/filtros excesivos 4. **Paginación**: Para directorios con muchos scripts ### Compatibilidad 1. **Paths Multiplataforma**: Usar `os.path` para compatibilidad Windows/Linux 2. **Encoding**: UTF-8 para todos los archivos JSON 3. **Fallbacks**: Manejar casos donde faltan dependencias o archivos ### Extensibilidad Futura 1. **Plugins**: Sistema para agregar nuevos tipos de launcher 2. **Temas**: Personalización visual 3. **Integración**: APIs para herramientas externas 4. **Sincronización**: Posible sincronización entre múltiples instancias --- ## Recursos de Referencia ### Documentación Relevante - [Flask Documentation](https://flask.palletsprojects.com/) - [Tailwind CSS](https://tailwindcss.com/docs) - [JavaScript ES6+](https://developer.mozilla.org/en-US/docs/Web/JavaScript) ### Archivos de Referencia del Proyecto - `lib/config_manager.py` - Patrón de gestión existente - `static/js/scripts.js` - Implementación JavaScript actual - `templates/index.html` - Estructura HTML base --- **Autor**: Sistema de Desarrollo ParamManagerScripts **Fecha**: Enero 2024 **Versión**: 1.0