From a3618246b7f7c5c9909155316de21d4e53c839b7 Mon Sep 17 00:00:00 2001 From: Miguel Date: Tue, 3 Jun 2025 11:35:37 +0200 Subject: [PATCH] Iniciando agregado de launcher de scripts con GUI --- adicion_launcher4GUI.md | 1055 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1055 insertions(+) create mode 100644 adicion_launcher4GUI.md diff --git a/adicion_launcher4GUI.md b/adicion_launcher4GUI.md new file mode 100644 index 0000000..42bdef6 --- /dev/null +++ b/adicion_launcher4GUI.md @@ -0,0 +1,1055 @@ +# 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 + +### 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 +