467 lines
17 KiB
JavaScript
467 lines
17 KiB
JavaScript
// static/js/csharp_launcher.js - Gestor para Launcher C#
|
|
|
|
class CSharpLauncherManager {
|
|
constructor() {
|
|
this.currentProject = null;
|
|
this.projects = [];
|
|
this.executables = [];
|
|
this.favorites = new Set();
|
|
this.runningProcesses = [];
|
|
this.categories = [
|
|
'Aplicaciones', 'Herramientas', 'Análisis',
|
|
'Desarrollo', 'APIs', 'Otros'
|
|
];
|
|
this.currentCategory = 'all';
|
|
}
|
|
|
|
async init() {
|
|
console.log('Initializing C# Launcher Manager...');
|
|
await this.loadProjects();
|
|
await this.loadFavorites();
|
|
this.setupEventListeners();
|
|
this.renderInterface();
|
|
await this.refreshProcesses();
|
|
|
|
// Actualizar procesos cada 10 segundos
|
|
setInterval(() => this.refreshProcesses(), 10000);
|
|
}
|
|
|
|
async loadProjects() {
|
|
try {
|
|
const response = await fetch('/api/csharp-projects');
|
|
if (response.ok) {
|
|
this.projects = await response.json();
|
|
this.renderProjectSelector();
|
|
} else {
|
|
console.error('Error loading C# projects:', await response.text());
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading C# projects:', error);
|
|
}
|
|
}
|
|
|
|
async loadFavorites() {
|
|
try {
|
|
const response = await fetch('/api/csharp-favorites');
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
this.favorites = new Set(data.favorites.map(fav => `${fav.project_id}_${fav.exe_name}`));
|
|
this.renderFavoritesPanel();
|
|
} else {
|
|
console.error('Error loading C# favorites:', await response.text());
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading C# favorites:', error);
|
|
}
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Event listeners específicos del launcher C#
|
|
const projectSelect = document.getElementById('csharp-project-select');
|
|
if (projectSelect) {
|
|
projectSelect.addEventListener('change', (e) => this.onProjectChange(e));
|
|
}
|
|
}
|
|
|
|
renderInterface() {
|
|
this.renderProjectSelector();
|
|
this.renderCategoryFilter();
|
|
this.renderFavoritesPanel();
|
|
}
|
|
|
|
renderProjectSelector() {
|
|
const select = document.getElementById('csharp-project-select');
|
|
if (!select) return;
|
|
|
|
select.innerHTML = '<option value="">-- Seleccionar Proyecto --</option>';
|
|
|
|
this.projects.forEach(project => {
|
|
const option = document.createElement('option');
|
|
option.value = project.id;
|
|
option.textContent = project.name;
|
|
option.setAttribute('data-description', project.description || '');
|
|
option.setAttribute('data-category', project.category || 'Otros');
|
|
select.appendChild(option);
|
|
});
|
|
}
|
|
|
|
async onProjectChange(e) {
|
|
const projectId = e.target.value;
|
|
|
|
if (!projectId) {
|
|
this.currentProject = null;
|
|
this.hideCSharpProjectButtons();
|
|
this.clearExecutables();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
this.currentProject = this.projects.find(p => p.id === projectId);
|
|
this.showCSharpProjectButtons();
|
|
await this.loadProjectExecutables(projectId);
|
|
} catch (error) {
|
|
console.error('Error changing project:', error);
|
|
}
|
|
}
|
|
|
|
showCSharpProjectButtons() {
|
|
const buttons = ['cursor-csharp-btn', 'vs2022-csharp-btn', 'folder-csharp-btn', 'copy-path-csharp-btn'];
|
|
buttons.forEach(id => {
|
|
const btn = document.getElementById(id);
|
|
if (btn) btn.style.display = 'block';
|
|
});
|
|
}
|
|
|
|
hideCSharpProjectButtons() {
|
|
const buttons = ['cursor-csharp-btn', 'vs2022-csharp-btn', 'folder-csharp-btn', 'copy-path-csharp-btn'];
|
|
buttons.forEach(id => {
|
|
const btn = document.getElementById(id);
|
|
if (btn) btn.style.display = 'none';
|
|
});
|
|
}
|
|
|
|
async loadProjectExecutables(projectId) {
|
|
try {
|
|
const response = await fetch(`/api/csharp-executables/${projectId}`);
|
|
if (response.ok) {
|
|
this.executables = await response.json();
|
|
this.renderExecutables();
|
|
} else {
|
|
console.error('Error loading executables:', await response.text());
|
|
this.executables = [];
|
|
this.renderExecutables();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading executables:', error);
|
|
this.executables = [];
|
|
this.renderExecutables();
|
|
}
|
|
}
|
|
|
|
renderExecutables() {
|
|
const grid = document.getElementById('csharp-executables-grid');
|
|
if (!grid) return;
|
|
|
|
// Filtrar por categoría si no es 'all'
|
|
let filteredExecutables = this.executables;
|
|
if (this.currentCategory !== 'all' && this.currentProject) {
|
|
filteredExecutables = this.executables.filter(exe =>
|
|
this.currentProject.category === this.currentCategory
|
|
);
|
|
}
|
|
|
|
if (filteredExecutables.length === 0) {
|
|
grid.innerHTML = `
|
|
<div class="col-span-full text-center py-8 text-gray-500">
|
|
<div class="text-4xl mb-2">🔍</div>
|
|
<div>No se encontraron ejecutables en este proyecto</div>
|
|
<div class="text-sm mt-1">Busque en: bin/Release y bin/Debug</div>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
grid.innerHTML = filteredExecutables.map(exe => this.createExecutableCard(exe)).join('');
|
|
}
|
|
|
|
createExecutableCard(exe) {
|
|
const favoriteKey = `${this.currentProject.id}_${exe.filename}`;
|
|
const isFavorite = this.favorites.has(favoriteKey);
|
|
const buildTypeBadge = exe.build_type === 'Release' ?
|
|
'<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">Release</span>' :
|
|
'<span class="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded">Debug</span>';
|
|
|
|
return `
|
|
<div class="executable-card bg-white border rounded-lg p-4 hover:shadow-md transition-shadow">
|
|
<div class="flex justify-between items-start mb-2">
|
|
<h4 class="font-medium text-sm">${exe.display_name}</h4>
|
|
<button class="favorite-star text-gray-300 hover:text-yellow-500 ${isFavorite ? 'text-yellow-500' : ''}"
|
|
onclick="csharpLauncherManager.toggleFavorite('${this.currentProject.id}', '${exe.filename}')">⭐</button>
|
|
</div>
|
|
<p class="text-xs text-gray-600 mb-2">${exe.short_description}</p>
|
|
<div class="flex justify-between items-center mb-3">
|
|
${buildTypeBadge}
|
|
<span class="text-xs text-gray-500">${exe.filename}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center">
|
|
<div class="space-x-1">
|
|
<button class="text-blue-500 hover:underline text-xs"
|
|
onclick="showCSharpExecutableArgs('${this.currentProject.id}', '${exe.filename}', '${exe.display_name}')">
|
|
Con Argumentos
|
|
</button>
|
|
</div>
|
|
<button class="bg-blue-500 text-white px-3 py-1 rounded text-xs hover:bg-blue-600"
|
|
onclick="csharpLauncherManager.executeExecutable('${this.currentProject.id}', '${exe.filename}')">
|
|
Ejecutar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async executeExecutable(projectId, exeName, args = [], workingDir = null) {
|
|
try {
|
|
const response = await fetch('/api/execute-csharp-executable', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
project_id: projectId,
|
|
exe_name: exeName,
|
|
args: args,
|
|
working_dir: workingDir
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.status === 'success') {
|
|
// Actualizar procesos después de un breve delay
|
|
setTimeout(() => this.refreshProcesses(), 1000);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error('Error executing executable:', error);
|
|
return { status: 'error', message: error.message };
|
|
}
|
|
}
|
|
|
|
async toggleFavorite(projectId, exeName) {
|
|
try {
|
|
const response = await fetch('/api/csharp-favorites', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
project_id: projectId,
|
|
exe_name: exeName
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
const favoriteKey = `${projectId}_${exeName}`;
|
|
|
|
if (result.is_favorite) {
|
|
this.favorites.add(favoriteKey);
|
|
} else {
|
|
this.favorites.delete(favoriteKey);
|
|
}
|
|
|
|
this.renderExecutables();
|
|
this.renderFavoritesPanel();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error toggling favorite:', error);
|
|
}
|
|
}
|
|
|
|
renderFavoritesPanel() {
|
|
const panel = document.getElementById('csharp-favorites-list');
|
|
const counter = document.getElementById('csharp-favorites-count');
|
|
|
|
if (!panel || !counter) return;
|
|
|
|
counter.textContent = `${this.favorites.size} favoritos`;
|
|
|
|
if (this.favorites.size === 0) {
|
|
panel.innerHTML = '<div class="text-center text-gray-500 py-2">No hay favoritos guardados</div>';
|
|
return;
|
|
}
|
|
|
|
// Crear lista de favoritos (simplificada - solo mostrar nombres)
|
|
const favoriteItems = Array.from(this.favorites).map(key => {
|
|
const [projectId, exeName] = key.split('_', 2);
|
|
const project = this.projects.find(p => p.id === projectId);
|
|
const projectName = project ? project.name : 'Proyecto desconocido';
|
|
|
|
return `
|
|
<div class="flex justify-between items-center bg-white p-2 rounded border">
|
|
<div>
|
|
<span class="font-medium text-sm">${exeName}</span>
|
|
<span class="text-xs text-gray-500 ml-2">${projectName}</span>
|
|
</div>
|
|
<button class="text-blue-500 hover:text-blue-700 text-xs"
|
|
onclick="csharpLauncherManager.executeFavorite('${projectId}', '${exeName}')">
|
|
Ejecutar
|
|
</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
panel.innerHTML = favoriteItems;
|
|
}
|
|
|
|
async executeFavorite(projectId, exeName) {
|
|
// Cambiar al proyecto si no está seleccionado
|
|
if (!this.currentProject || this.currentProject.id !== projectId) {
|
|
const select = document.getElementById('csharp-project-select');
|
|
if (select) {
|
|
select.value = projectId;
|
|
await this.onProjectChange({ target: { value: projectId } });
|
|
}
|
|
}
|
|
|
|
// Ejecutar el ejecutable
|
|
await this.executeExecutable(projectId, exeName);
|
|
}
|
|
|
|
renderCategoryFilter() {
|
|
// Las categorías ya están en el HTML, solo necesitamos la funcionalidad
|
|
console.log('Category filter rendered');
|
|
}
|
|
|
|
filterByCategory(category) {
|
|
this.currentCategory = category;
|
|
|
|
// Actualizar botones activos
|
|
document.querySelectorAll('.csharp-category-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
if (btn.getAttribute('data-category') === category) {
|
|
btn.classList.add('active');
|
|
}
|
|
});
|
|
|
|
this.renderExecutables();
|
|
}
|
|
|
|
async refreshProcesses() {
|
|
try {
|
|
const response = await fetch('/api/csharp-running-processes');
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
this.runningProcesses = data.processes || [];
|
|
this.renderRunningProcesses();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error refreshing processes:', error);
|
|
}
|
|
}
|
|
|
|
renderRunningProcesses() {
|
|
const container = document.getElementById('csharp-running-processes');
|
|
if (!container) return;
|
|
|
|
if (this.runningProcesses.length === 0) {
|
|
container.innerHTML = '<div class="text-center text-gray-500 py-2">No hay procesos C# en ejecución</div>';
|
|
return;
|
|
}
|
|
|
|
const processItems = this.runningProcesses.map(process => {
|
|
const startTime = new Date(process.start_time).toLocaleTimeString();
|
|
return `
|
|
<div class="flex justify-between items-center bg-gray-50 p-3 rounded border">
|
|
<div>
|
|
<span class="font-medium">${process.display_name}</span>
|
|
<span class="text-sm text-gray-500 block">PID: ${process.pid} | Iniciado: ${startTime}</span>
|
|
</div>
|
|
<button class="text-red-500 hover:text-red-700 text-sm"
|
|
onclick="csharpLauncherManager.terminateProcess(${process.pid})">
|
|
Cerrar
|
|
</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
container.innerHTML = processItems;
|
|
}
|
|
|
|
async terminateProcess(pid) {
|
|
try {
|
|
const response = await fetch(`/api/csharp-process-terminate/${pid}`, {
|
|
method: 'POST'
|
|
});
|
|
|
|
if (response.ok) {
|
|
await this.refreshProcesses();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error terminating process:', error);
|
|
}
|
|
}
|
|
|
|
clearExecutables() {
|
|
const grid = document.getElementById('csharp-executables-grid');
|
|
if (grid) {
|
|
grid.innerHTML = '<div class="col-span-full text-center py-8 text-gray-500">Selecciona un proyecto para ver los ejecutables</div>';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Funciones globales para el HTML
|
|
function loadCSharpExecutables() {
|
|
const select = document.getElementById('csharp-project-select');
|
|
if (select && window.csharpLauncherManager) {
|
|
window.csharpLauncherManager.onProjectChange({ target: select });
|
|
}
|
|
}
|
|
|
|
function filterCSharpByCategory(category) {
|
|
if (window.csharpLauncherManager) {
|
|
window.csharpLauncherManager.filterByCategory(category);
|
|
}
|
|
}
|
|
|
|
function refreshCSharpProcesses() {
|
|
if (window.csharpLauncherManager) {
|
|
window.csharpLauncherManager.refreshProcesses();
|
|
}
|
|
}
|
|
|
|
function openCSharpProjectEditor() {
|
|
// TODO: Implementar editor de proyectos C#
|
|
alert('Editor de proyectos C# - Por implementar');
|
|
}
|
|
|
|
function openCSharpProjectInEditor(editor) {
|
|
if (!window.csharpLauncherManager?.currentProject) {
|
|
alert('Selecciona un proyecto primero');
|
|
return;
|
|
}
|
|
|
|
const projectId = window.csharpLauncherManager.currentProject.id;
|
|
|
|
if (editor === 'cursor') {
|
|
// Implementar apertura en Cursor
|
|
alert(`Abriendo proyecto ${projectId} en Cursor - Por implementar`);
|
|
} else if (editor === 'vs2022') {
|
|
// Implementar apertura en Visual Studio 2022
|
|
alert(`Abriendo proyecto ${projectId} en Visual Studio 2022 - Por implementar`);
|
|
}
|
|
}
|
|
|
|
function openCSharpProjectFolder() {
|
|
if (!window.csharpLauncherManager?.currentProject) {
|
|
alert('Selecciona un proyecto primero');
|
|
return;
|
|
}
|
|
|
|
// Implementar apertura de carpeta
|
|
alert('Abriendo carpeta del proyecto - Por implementar');
|
|
}
|
|
|
|
function copyCSharpProjectPath() {
|
|
if (!window.csharpLauncherManager?.currentProject) {
|
|
alert('Selecciona un proyecto primero');
|
|
return;
|
|
}
|
|
|
|
// Implementar copia de path
|
|
navigator.clipboard.writeText(window.csharpLauncherManager.currentProject.directory);
|
|
}
|
|
|
|
function openCSharpExecutableManager() {
|
|
// TODO: Implementar gestor de ejecutables
|
|
alert('Gestor de ejecutables C# - Por implementar');
|
|
}
|
|
|
|
function showCSharpExecutableArgs(projectId, exeName, displayName) {
|
|
// TODO: Implementar modal de argumentos para C#
|
|
const args = prompt(`Argumentos para ${displayName}:`, '');
|
|
if (args !== null) {
|
|
const argArray = args.trim() ? args.split(' ') : [];
|
|
window.csharpLauncherManager.executeExecutable(projectId, exeName, argArray);
|
|
}
|
|
}
|
|
|
|
// Inicialización global
|
|
window.csharpLauncherManager = new CSharpLauncherManager();
|