925 lines
33 KiB
JavaScript
925 lines
33 KiB
JavaScript
// launcher.js - Funcionalidad del Launcher GUI
|
|
|
|
class LauncherManager {
|
|
constructor() {
|
|
this.currentGroup = null;
|
|
this.groups = [];
|
|
this.scripts = [];
|
|
this.favorites = new Set();
|
|
this.history = [];
|
|
this.categories = {};
|
|
this.currentFilter = 'all';
|
|
this.currentEditingGroup = null;
|
|
this.pythonEnvs = [];
|
|
}
|
|
|
|
async init() {
|
|
console.log('Inicializando Launcher GUI...');
|
|
await this.loadCategories();
|
|
await this.loadPythonEnvironments();
|
|
await this.loadGroups();
|
|
await this.loadFavorites();
|
|
await this.loadHistory();
|
|
this.setupEventListeners();
|
|
this.renderInterface();
|
|
}
|
|
|
|
async loadCategories() {
|
|
try {
|
|
const response = await fetch('/api/launcher-categories');
|
|
this.categories = await response.json();
|
|
} catch (error) {
|
|
console.error('Error loading launcher categories:', error);
|
|
}
|
|
}
|
|
|
|
async loadPythonEnvironments() {
|
|
try {
|
|
const response = await fetch('/api/python-environments');
|
|
this.pythonEnvs = await response.json();
|
|
this.renderPythonEnvSelector();
|
|
} catch (error) {
|
|
console.error('Error loading Python environments:', error);
|
|
}
|
|
}
|
|
|
|
renderPythonEnvSelector() {
|
|
const selector = document.getElementById('group-python-env');
|
|
if (!selector) return;
|
|
|
|
selector.innerHTML = '';
|
|
this.pythonEnvs.forEach(env => {
|
|
const option = document.createElement('option');
|
|
option.value = env.name;
|
|
option.textContent = env.display_name;
|
|
selector.appendChild(option);
|
|
});
|
|
}
|
|
|
|
async loadGroups() {
|
|
try {
|
|
const response = await fetch('/api/launcher-groups');
|
|
this.groups = await response.json();
|
|
this.renderGroupSelector();
|
|
} 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.map(f => `${f.group_id}_${f.script_name}`));
|
|
this.renderFavorites(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 || [];
|
|
this.renderHistory();
|
|
} catch (error) {
|
|
console.error('Error loading history:', error);
|
|
}
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Event listener para el formulario de grupos
|
|
const groupForm = document.getElementById('group-form');
|
|
if (groupForm) {
|
|
groupForm.addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
this.saveGroup();
|
|
});
|
|
}
|
|
|
|
// Event listener para el formulario de metadatos de scripts
|
|
const scriptMetadataForm = document.getElementById('script-metadata-form');
|
|
if (scriptMetadataForm) {
|
|
scriptMetadataForm.addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
this.saveScriptMetadata();
|
|
});
|
|
}
|
|
}
|
|
|
|
renderInterface() {
|
|
this.renderGroupSelector();
|
|
this.renderCategoryFilter();
|
|
this.updateFavoritesCount();
|
|
}
|
|
|
|
renderGroupSelector() {
|
|
const selector = document.getElementById('launcher-group-select');
|
|
if (!selector) return;
|
|
|
|
selector.innerHTML = '<option value="">-- Seleccionar Grupo --</option>';
|
|
|
|
this.groups.forEach(group => {
|
|
const option = document.createElement('option');
|
|
option.value = group.id;
|
|
option.textContent = group.name;
|
|
option.dataset.category = group.category;
|
|
option.dataset.description = group.description;
|
|
selector.appendChild(option);
|
|
});
|
|
}
|
|
|
|
renderCategoryFilter() {
|
|
const filterContainer = document.querySelector('.category-filter .flex');
|
|
if (!filterContainer) return;
|
|
|
|
// Limpiar botones existentes excepto "Todas"
|
|
const buttons = filterContainer.querySelectorAll('.category-btn:not([data-category="all"])');
|
|
buttons.forEach(btn => btn.remove());
|
|
|
|
// Agregar botones por categoría
|
|
Object.keys(this.categories).forEach(category => {
|
|
const categoryData = this.categories[category];
|
|
const button = document.createElement('button');
|
|
button.className = 'category-btn px-3 py-1 rounded-full text-sm border';
|
|
button.dataset.category = category;
|
|
button.innerHTML = `${categoryData.icon} ${category}`;
|
|
button.onclick = () => this.filterByCategory(category);
|
|
filterContainer.appendChild(button);
|
|
});
|
|
}
|
|
|
|
async loadLauncherScripts() {
|
|
const groupId = document.getElementById('launcher-group-select').value;
|
|
if (!groupId) {
|
|
this.scripts = [];
|
|
this.renderScripts();
|
|
this.updateManageScriptsButton(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/launcher-scripts/${groupId}`);
|
|
this.scripts = await response.json();
|
|
this.currentGroup = this.groups.find(g => g.id === groupId);
|
|
this.updateGroupIcon();
|
|
this.renderScripts();
|
|
this.updateManageScriptsButton(true);
|
|
} catch (error) {
|
|
console.error('Error loading launcher scripts:', error);
|
|
this.scripts = [];
|
|
this.renderScripts();
|
|
this.updateManageScriptsButton(false);
|
|
}
|
|
}
|
|
|
|
updateManageScriptsButton(show) {
|
|
const button = document.getElementById('manage-scripts-btn');
|
|
if (button) {
|
|
button.style.display = show ? 'block' : 'none';
|
|
}
|
|
}
|
|
|
|
updateGroupIcon() {
|
|
const iconElement = document.getElementById('selected-group-icon');
|
|
if (!iconElement || !this.currentGroup) return;
|
|
|
|
// Intentar cargar icono personalizado
|
|
const img = document.createElement('img');
|
|
img.src = `/api/group-icon/launcher/${this.currentGroup.id}`;
|
|
img.className = 'w-6 h-6 rounded';
|
|
img.onerror = () => {
|
|
// Fallback a icono por defecto
|
|
iconElement.innerHTML = this.getDefaultIconForCategory(this.currentGroup.category);
|
|
};
|
|
img.onload = () => {
|
|
iconElement.innerHTML = '';
|
|
iconElement.appendChild(img);
|
|
};
|
|
}
|
|
|
|
getDefaultIconForCategory(category) {
|
|
const icons = {
|
|
'Herramientas': '🔧',
|
|
'Análisis': '📊',
|
|
'Utilidades': '⚙️',
|
|
'Desarrollo': '💻',
|
|
'Visualización': '📈',
|
|
'Otros': '📁'
|
|
};
|
|
return icons[category] || '📁';
|
|
}
|
|
|
|
renderScripts() {
|
|
const grid = document.getElementById('launcher-scripts-grid');
|
|
if (!grid) return;
|
|
|
|
if (this.scripts.length === 0) {
|
|
grid.innerHTML = `
|
|
<div class="col-span-full empty-state">
|
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
|
</svg>
|
|
<p class="text-lg font-medium">No hay scripts disponibles</p>
|
|
<p class="text-sm">Selecciona un grupo o verifica que el directorio contenga archivos .py</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
let filteredScripts = this.scripts;
|
|
if (this.currentFilter !== 'all' && this.currentGroup) {
|
|
if (this.currentGroup.category !== this.currentFilter) {
|
|
filteredScripts = [];
|
|
}
|
|
}
|
|
|
|
grid.innerHTML = '';
|
|
filteredScripts.forEach(script => {
|
|
const favoriteId = `${this.currentGroup.id}_${script.name}`;
|
|
const isFavorite = this.favorites.has(favoriteId);
|
|
|
|
const card = document.createElement('div');
|
|
card.className = `script-card ${isFavorite ? 'favorited' : ''}`;
|
|
card.innerHTML = `
|
|
<div class="flex justify-between items-start mb-2">
|
|
<h4 class="font-medium text-gray-900">${script.display_name}</h4>
|
|
<button class="favorite-star ${isFavorite ? 'active' : ''}"
|
|
onclick="launcherManager.toggleFavorite('${this.currentGroup.id}', '${script.name}')">
|
|
⭐
|
|
</button>
|
|
</div>
|
|
<p class="text-sm text-gray-600 mb-3 line-clamp-2">${script.description || 'Script: ' + script.name}</p>
|
|
<div class="flex justify-between items-center">
|
|
<span class="category-badge">${this.currentGroup.category}</span>
|
|
<div class="space-x-2">
|
|
<button class="text-blue-500 hover:underline text-sm"
|
|
onclick="launcherManager.showArgsModal('${script.name}', '${script.display_name}')">
|
|
Con Argumentos
|
|
</button>
|
|
<button class="bg-blue-500 text-white px-3 py-1 rounded text-sm hover:bg-blue-600"
|
|
onclick="launcherManager.executeScript('${script.name}')">
|
|
Ejecutar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
grid.appendChild(card);
|
|
});
|
|
}
|
|
|
|
// === GESTIÓN DE SCRIPTS INDIVIDUALES ===
|
|
|
|
async openScriptManager() {
|
|
if (!this.currentGroup) {
|
|
alert('Selecciona un grupo primero');
|
|
return;
|
|
}
|
|
|
|
const modal = document.getElementById('script-manager-modal');
|
|
const groupInfo = document.getElementById('script-manager-group-info');
|
|
|
|
if (modal && groupInfo) {
|
|
groupInfo.textContent = `Grupo: ${this.currentGroup.name} (${this.currentGroup.category})`;
|
|
await this.loadAllScriptsForManagement();
|
|
modal.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
closeScriptManager() {
|
|
const modal = document.getElementById('script-manager-modal');
|
|
if (modal) {
|
|
modal.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
async loadAllScriptsForManagement() {
|
|
if (!this.currentGroup) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/launcher-scripts-all/${this.currentGroup.id}`);
|
|
const allScripts = await response.json();
|
|
this.renderScriptManagerList(allScripts);
|
|
} catch (error) {
|
|
console.error('Error loading all scripts for management:', error);
|
|
}
|
|
}
|
|
|
|
renderScriptManagerList(scripts) {
|
|
const list = document.getElementById('script-manager-list');
|
|
if (!list) return;
|
|
|
|
if (scripts.length === 0) {
|
|
list.innerHTML = `
|
|
<div class="text-center text-gray-500 py-8">
|
|
<p>No hay scripts Python en este directorio</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
list.innerHTML = '';
|
|
scripts.forEach(script => {
|
|
const item = document.createElement('div');
|
|
item.className = `border rounded-lg p-4 ${script.hidden ? 'bg-gray-50 border-gray-300' : 'bg-white border-gray-200'}`;
|
|
item.innerHTML = `
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex-1">
|
|
<div class="flex items-center gap-2 mb-1">
|
|
<h4 class="font-medium ${script.hidden ? 'text-gray-500' : 'text-gray-900'}">${script.display_name}</h4>
|
|
${script.hidden ? '<span class="text-xs bg-gray-200 text-gray-600 px-2 py-1 rounded">Oculto</span>' : ''}
|
|
</div>
|
|
<p class="text-sm text-gray-600 mb-2">${script.description || 'Sin descripción'}</p>
|
|
<p class="text-xs text-gray-500">Archivo: ${script.name}</p>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button onclick="launcherManager.editScriptMetadata('${script.name}')"
|
|
class="text-blue-500 hover:underline text-sm">
|
|
Editar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
list.appendChild(item);
|
|
});
|
|
}
|
|
|
|
async editScriptMetadata(scriptName) {
|
|
if (!this.currentGroup) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/launcher-script-metadata/${this.currentGroup.id}/${scriptName}`);
|
|
const metadata = await response.json();
|
|
|
|
// Poblar el formulario
|
|
document.getElementById('edit-meta-group-id').value = this.currentGroup.id;
|
|
document.getElementById('edit-meta-script-name').value = scriptName;
|
|
document.getElementById('edit-meta-filename-display').textContent = scriptName;
|
|
document.getElementById('edit-meta-display-name').value = metadata.display_name || scriptName.replace('.py', '');
|
|
document.getElementById('edit-meta-description').value = metadata.description || '';
|
|
document.getElementById('edit-meta-long-description').value = metadata.long_description || '';
|
|
document.getElementById('edit-meta-hidden').checked = metadata.hidden || false;
|
|
|
|
// Mostrar modal
|
|
document.getElementById('script-metadata-editor-modal').classList.remove('hidden');
|
|
} catch (error) {
|
|
console.error('Error loading script metadata:', error);
|
|
alert('Error cargando metadatos del script');
|
|
}
|
|
}
|
|
|
|
closeScriptMetadataEditor() {
|
|
document.getElementById('script-metadata-editor-modal').classList.add('hidden');
|
|
}
|
|
|
|
async saveScriptMetadata() {
|
|
const groupId = document.getElementById('edit-meta-group-id').value;
|
|
const scriptName = document.getElementById('edit-meta-script-name').value;
|
|
const metadata = {
|
|
display_name: document.getElementById('edit-meta-display-name').value,
|
|
description: document.getElementById('edit-meta-description').value,
|
|
long_description: document.getElementById('edit-meta-long-description').value,
|
|
hidden: document.getElementById('edit-meta-hidden').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(`/api/launcher-script-metadata/${groupId}/${scriptName}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(metadata)
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
this.closeScriptMetadataEditor();
|
|
// Recargar datos
|
|
await this.loadAllScriptsForManagement();
|
|
await this.loadLauncherScripts(); // Actualizar la vista principal también
|
|
} else {
|
|
alert(`Error: ${result.message}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving script metadata:', error);
|
|
alert('Error guardando metadatos del script');
|
|
}
|
|
}
|
|
|
|
// === GESTIÓN DE GRUPOS (actualizada) ===
|
|
|
|
populateGroupForm(group) {
|
|
document.getElementById('group-id').value = group.id;
|
|
document.getElementById('group-name').value = group.name;
|
|
document.getElementById('group-description').value = group.description || '';
|
|
document.getElementById('group-category').value = group.category;
|
|
document.getElementById('group-version').value = group.version || '1.0';
|
|
document.getElementById('group-python-env').value = group.python_env || 'base';
|
|
document.getElementById('group-directory').value = group.directory;
|
|
}
|
|
|
|
clearGroupForm() {
|
|
document.getElementById('group-id').value = '';
|
|
document.getElementById('group-name').value = '';
|
|
document.getElementById('group-description').value = '';
|
|
document.getElementById('group-category').value = 'Otros';
|
|
document.getElementById('group-version').value = '1.0';
|
|
document.getElementById('group-python-env').value = 'base';
|
|
document.getElementById('group-directory').value = '';
|
|
document.getElementById('delete-group-btn').style.display = 'none';
|
|
}
|
|
|
|
async saveGroup() {
|
|
const formData = {
|
|
id: document.getElementById('group-id').value,
|
|
name: document.getElementById('group-name').value,
|
|
description: document.getElementById('group-description').value,
|
|
category: document.getElementById('group-category').value,
|
|
version: document.getElementById('group-version').value,
|
|
python_env: document.getElementById('group-python-env').value,
|
|
directory: document.getElementById('group-directory').value
|
|
};
|
|
|
|
try {
|
|
let response;
|
|
if (this.currentEditingGroup) {
|
|
// Actualizar grupo existente
|
|
response = await fetch(`/api/launcher-groups/${this.currentEditingGroup.id}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
} else {
|
|
// Crear nuevo grupo
|
|
response = await fetch('/api/launcher-groups', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
}
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
await this.loadGroups();
|
|
this.closeGroupEditor();
|
|
this.renderInterface();
|
|
} else {
|
|
alert(`Error: ${result.message}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving group:', error);
|
|
alert('Error al guardar el grupo');
|
|
}
|
|
}
|
|
|
|
renderExistingGroups() {
|
|
const container = document.getElementById('existing-groups-list');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = '';
|
|
this.groups.forEach(group => {
|
|
const envInfo = this.pythonEnvs.find(env => env.name === group.python_env);
|
|
const envDisplay = envInfo ? envInfo.display_name : group.python_env;
|
|
|
|
const item = document.createElement('div');
|
|
item.className = 'group-list-item';
|
|
item.innerHTML = `
|
|
<div class="group-icon-small default">
|
|
${this.getDefaultIconForCategory(group.category)}
|
|
</div>
|
|
<div class="group-info">
|
|
<div class="group-name">${group.name}</div>
|
|
<div class="group-category">${group.category} • ${envDisplay}</div>
|
|
</div>
|
|
<button class="text-blue-500 hover:underline text-sm" onclick="launcherManager.editGroup('${group.id}')">
|
|
Editar
|
|
</button>
|
|
`;
|
|
container.appendChild(item);
|
|
});
|
|
}
|
|
|
|
renderHistory() {
|
|
const historyList = document.getElementById('history-list');
|
|
if (!historyList) return;
|
|
|
|
if (this.history.length === 0) {
|
|
historyList.innerHTML = `
|
|
<div class="text-center text-gray-500 py-4">
|
|
<p>No hay ejecuciones recientes</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
historyList.innerHTML = '';
|
|
this.history.slice(0, 10).forEach(entry => {
|
|
const group = this.groups.find(g => g.id === entry.group_id);
|
|
const groupName = group ? group.name : 'Grupo desconocido';
|
|
|
|
const timeAgo = this.getTimeAgo(entry.executed_date);
|
|
const statusClass = entry.status === 'success' ? 'success' :
|
|
entry.status === 'error' ? 'error' : 'running';
|
|
const statusIcon = entry.status === 'success' ? '✅' :
|
|
entry.status === 'error' ? '❌' : '🔄';
|
|
|
|
// Información del entorno Python
|
|
const envInfo = entry.python_env ? ` • ${entry.python_env}` : '';
|
|
|
|
const item = document.createElement('div');
|
|
item.className = `history-item ${statusClass}`;
|
|
item.innerHTML = `
|
|
<div class="flex justify-between items-start">
|
|
<div>
|
|
<span class="font-medium">${entry.script_name.replace('.py', '')}</span>
|
|
<span class="text-sm text-gray-500 ml-2">${groupName}${envInfo}</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">${timeAgo}</span>
|
|
</div>
|
|
<div class="text-sm text-gray-600 mt-1">
|
|
${statusIcon} ${entry.status.charAt(0).toUpperCase() + entry.status.slice(1)}
|
|
${entry.execution_time ? ` - ${entry.execution_time}s` : ''}
|
|
${entry.arguments && entry.arguments.length > 0 ? ` - Con argumentos` : ''}
|
|
</div>
|
|
`;
|
|
historyList.appendChild(item);
|
|
});
|
|
}
|
|
|
|
// ... métodos existentes sin cambios ...
|
|
|
|
// El resto de métodos permanecen igual
|
|
filterByCategory(category) {
|
|
this.currentFilter = category;
|
|
|
|
// Actualizar botones activos
|
|
document.querySelectorAll('.category-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
document.querySelector(`[data-category="${category}"]`).classList.add('active');
|
|
|
|
// Filtrar grupos en el selector
|
|
const selector = document.getElementById('launcher-group-select');
|
|
Array.from(selector.options).forEach(option => {
|
|
if (option.value === '') return;
|
|
option.style.display = (category === 'all' || option.dataset.category === category) ? '' : 'none';
|
|
});
|
|
|
|
// Re-renderizar scripts si hay grupo seleccionado
|
|
if (this.currentGroup) {
|
|
this.renderScripts();
|
|
}
|
|
}
|
|
|
|
async toggleFavorite(groupId, scriptName) {
|
|
try {
|
|
const response = await fetch('/api/launcher-favorites', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
group_id: groupId,
|
|
script_name: scriptName
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
const favoriteId = `${groupId}_${scriptName}`;
|
|
if (result.action === 'added') {
|
|
this.favorites.add(favoriteId);
|
|
} else {
|
|
this.favorites.delete(favoriteId);
|
|
}
|
|
|
|
// Recargar datos y re-renderizar
|
|
await this.loadFavorites();
|
|
this.renderScripts();
|
|
this.updateFavoritesCount();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error toggling favorite:', error);
|
|
}
|
|
}
|
|
|
|
async executeScript(scriptName, args = []) {
|
|
if (!this.currentGroup) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/execute-gui-script', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
group_id: this.currentGroup.id,
|
|
script_name: scriptName,
|
|
args: args
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
// Recargar historial
|
|
await this.loadHistory();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error executing script:', error);
|
|
}
|
|
}
|
|
|
|
showArgsModal(scriptName, displayName) {
|
|
const modal = document.getElementById('script-args-modal');
|
|
const scriptDisplayElement = document.getElementById('script-display-name');
|
|
const argsInput = document.getElementById('script-args-input');
|
|
|
|
if (modal && scriptDisplayElement && argsInput) {
|
|
scriptDisplayElement.textContent = displayName;
|
|
argsInput.value = '';
|
|
modal.classList.remove('hidden');
|
|
|
|
// Guardar datos para uso posterior
|
|
modal.dataset.scriptName = scriptName;
|
|
modal.dataset.groupId = this.currentGroup.id;
|
|
}
|
|
}
|
|
|
|
renderFavorites(favorites) {
|
|
const favoritesList = document.getElementById('favorites-list');
|
|
const favoritesPanel = document.getElementById('favorites-panel');
|
|
|
|
if (!favoritesList || !favoritesPanel) return;
|
|
|
|
if (favorites.length === 0) {
|
|
favoritesPanel.classList.add('empty');
|
|
return;
|
|
}
|
|
|
|
favoritesPanel.classList.remove('empty');
|
|
favoritesList.innerHTML = '';
|
|
|
|
favorites.slice(0, 5).forEach(fav => {
|
|
const group = this.groups.find(g => g.id === fav.group_id);
|
|
if (!group) return;
|
|
|
|
const item = document.createElement('div');
|
|
item.className = 'flex items-center justify-between p-2 bg-white rounded border';
|
|
item.innerHTML = `
|
|
<div class="flex items-center">
|
|
<div class="group-icon-small default mr-2">
|
|
${this.getDefaultIconForCategory(group.category)}
|
|
</div>
|
|
<div>
|
|
<div class="font-medium text-sm">${fav.script_name.replace('.py', '')}</div>
|
|
<div class="text-xs text-gray-500">${group.name}</div>
|
|
</div>
|
|
</div>
|
|
<button class="text-blue-500 hover:underline text-sm"
|
|
onclick="launcherManager.executeFavoriteScript('${fav.group_id}', '${fav.script_name}')">
|
|
Ejecutar
|
|
</button>
|
|
`;
|
|
favoritesList.appendChild(item);
|
|
});
|
|
}
|
|
|
|
async executeFavoriteScript(groupId, scriptName) {
|
|
// Cambiar al grupo correcto si no está seleccionado
|
|
if (!this.currentGroup || this.currentGroup.id !== groupId) {
|
|
document.getElementById('launcher-group-select').value = groupId;
|
|
await this.loadLauncherScripts();
|
|
}
|
|
|
|
this.executeScript(scriptName);
|
|
}
|
|
|
|
getTimeAgo(dateString) {
|
|
const date = new Date(dateString);
|
|
const now = new Date();
|
|
const diffMs = now - date;
|
|
const diffMinutes = Math.floor(diffMs / 60000);
|
|
|
|
if (diffMinutes < 1) return 'ahora';
|
|
if (diffMinutes < 60) return `hace ${diffMinutes}m`;
|
|
if (diffMinutes < 1440) return `hace ${Math.floor(diffMinutes / 60)}h`;
|
|
return `hace ${Math.floor(diffMinutes / 1440)}d`;
|
|
}
|
|
|
|
updateFavoritesCount() {
|
|
const countElement = document.getElementById('favorites-count');
|
|
if (countElement) {
|
|
countElement.textContent = `${this.favorites.size} favoritos`;
|
|
}
|
|
}
|
|
|
|
async clearLauncherHistory() {
|
|
if (!confirm('¿Estás seguro de que quieres limpiar el historial?')) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/launcher-history', {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
this.history = [];
|
|
this.renderHistory();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error clearing history:', error);
|
|
}
|
|
}
|
|
|
|
// === GESTIÓN DE GRUPOS ===
|
|
|
|
openGroupEditor() {
|
|
const modal = document.getElementById('group-editor-modal');
|
|
if (modal) {
|
|
this.currentEditingGroup = null;
|
|
this.clearGroupForm();
|
|
this.renderExistingGroups();
|
|
modal.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
closeGroupEditor() {
|
|
const modal = document.getElementById('group-editor-modal');
|
|
if (modal) {
|
|
modal.classList.add('hidden');
|
|
this.currentEditingGroup = null;
|
|
}
|
|
}
|
|
|
|
editGroup(groupId) {
|
|
const group = this.groups.find(g => g.id === groupId);
|
|
if (!group) return;
|
|
|
|
this.currentEditingGroup = group;
|
|
this.populateGroupForm(group);
|
|
document.getElementById('delete-group-btn').style.display = 'block';
|
|
}
|
|
|
|
async deleteGroup() {
|
|
if (!this.currentEditingGroup) return;
|
|
|
|
if (!confirm(`¿Estás seguro de que quieres eliminar el grupo "${this.currentEditingGroup.name}"?`)) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/launcher-groups/${this.currentEditingGroup.id}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.status === 'success') {
|
|
await this.loadGroups();
|
|
this.closeGroupEditor();
|
|
this.renderInterface();
|
|
|
|
// Limpiar selección si era el grupo actual
|
|
if (this.currentGroup && this.currentGroup.id === this.currentEditingGroup.id) {
|
|
document.getElementById('launcher-group-select').value = '';
|
|
this.currentGroup = null;
|
|
this.scripts = [];
|
|
this.renderScripts();
|
|
this.updateManageScriptsButton(false);
|
|
}
|
|
} else {
|
|
alert(`Error: ${result.message}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error deleting group:', error);
|
|
alert('Error al eliminar el grupo');
|
|
}
|
|
}
|
|
|
|
browseGroupDirectory() {
|
|
// Similar a la función existente pero para el formulario de grupos
|
|
fetch('/api/browse-directories')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status === 'success') {
|
|
document.getElementById('group-directory').value = data.path;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error browsing directory:', error);
|
|
});
|
|
}
|
|
}
|
|
|
|
// === FUNCIONES GLOBALES ===
|
|
|
|
// Función para cambiar entre tabs
|
|
function switchTab(tabName) {
|
|
// Cambiar tabs activos
|
|
document.querySelectorAll('.tab-button').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
document.getElementById(`${tabName}-tab`).classList.add('active');
|
|
|
|
// Cambiar contenido
|
|
document.querySelectorAll('.tab-content').forEach(content => {
|
|
content.classList.add('hidden');
|
|
});
|
|
document.getElementById(`${tabName}-content`).classList.remove('hidden');
|
|
|
|
// Inicializar launcher si es la primera vez
|
|
if (tabName === 'launcher' && !window.launcherManager) {
|
|
window.launcherManager = new LauncherManager();
|
|
window.launcherManager.init();
|
|
}
|
|
}
|
|
|
|
// Funciones para modales
|
|
function openGroupEditor() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.openGroupEditor();
|
|
}
|
|
}
|
|
|
|
function closeGroupEditor() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.closeGroupEditor();
|
|
}
|
|
}
|
|
|
|
function deleteGroup() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.deleteGroup();
|
|
}
|
|
}
|
|
|
|
function browseGroupDirectory() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.browseGroupDirectory();
|
|
}
|
|
}
|
|
|
|
function filterByCategory(category) {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.filterByCategory(category);
|
|
}
|
|
}
|
|
|
|
function loadLauncherScripts() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.loadLauncherScripts();
|
|
}
|
|
}
|
|
|
|
function clearLauncherHistory() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.clearLauncherHistory();
|
|
}
|
|
}
|
|
|
|
// Funciones para gestión de scripts
|
|
function openScriptManager() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.openScriptManager();
|
|
}
|
|
}
|
|
|
|
function closeScriptManager() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.closeScriptManager();
|
|
}
|
|
}
|
|
|
|
function closeScriptMetadataEditor() {
|
|
if (window.launcherManager) {
|
|
window.launcherManager.closeScriptMetadataEditor();
|
|
}
|
|
}
|
|
|
|
// Funciones para modal de argumentos
|
|
function closeArgsModal() {
|
|
const modal = document.getElementById('script-args-modal');
|
|
if (modal) {
|
|
modal.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
function executeWithArgs() {
|
|
const modal = document.getElementById('script-args-modal');
|
|
const argsInput = document.getElementById('script-args-input');
|
|
|
|
if (modal && argsInput && window.launcherManager) {
|
|
const scriptName = modal.dataset.scriptName;
|
|
const args = argsInput.value.trim().split(/\s+/).filter(arg => arg.length > 0);
|
|
|
|
window.launcherManager.executeScript(scriptName, args);
|
|
closeArgsModal();
|
|
}
|
|
}
|
|
|
|
// Inicialización cuando se carga la página
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
console.log('Launcher JS loaded');
|
|
});
|