LocalScriptsWeb/frontend/static/js/scripts.js

439 lines
16 KiB
JavaScript
Raw Normal View History

2025-02-07 19:08:39 -03:00
// frontend/static/js/scripts.js
async function loadScriptGroups() {
try {
const groups = await apiRequest('/script-groups');
const select = document.getElementById('groupSelect');
const lastGroupId = localStorage.getItem('lastGroupId');
// Remover event listener anterior si existe
const oldHandler = select.onchange;
if (oldHandler) {
select.removeEventListener('change', oldHandler);
}
// Actualizar opciones
select.innerHTML = `
<option value="">Select group...</option>
${groups.map(group => `
<option value="${group.id}" ${group.id === lastGroupId ? 'selected' : ''}>
${group.name}
</option>
`).join('')}
`;
// Agregar nuevo event listener
select.addEventListener('change', handleGroupChange);
// Si hay un grupo guardado, cargarlo
if (lastGroupId && groups.some(g => g.id === lastGroupId)) {
await selectGroup(lastGroupId);
}
2025-02-07 19:08:39 -03:00
} catch (error) {
console.error('Error loading script groups:', error);
showError('Error loading script groups');
2025-02-07 19:08:39 -03:00
}
}
async function handleGroupChange(event) {
const groupId = event.target.value;
if (groupId) {
localStorage.setItem('lastGroupId', groupId);
await selectGroup(groupId);
} else {
localStorage.removeItem('lastGroupId');
updateGroupDisplay(null);
}
}
async function selectGroup(groupId) {
try {
// Cargar configuración del grupo
const config = await apiRequest(`/script-groups/${groupId}/config`);
currentGroup = { id: groupId, ...config };
// Actualizar displays
updateGroupDisplay(currentGroup);
// Cargar scripts si hay un directorio de trabajo configurado
if (currentGroup.work_dir) {
await loadGroupScripts(groupId);
// Cargar configuración del directorio de trabajo
const workDirConfig = await apiRequest(`/workdir-config/${groupId}`);
updateWorkDirConfig(workDirConfig);
} else {
document.getElementById('scriptList').innerHTML = `
<div class="bg-yellow-50 border-l-4 border-yellow-400 p-4">
<div class="flex">
<div class="ml-3">
<p class="text-sm text-yellow-700">
Please configure a work directory for this group first
</p>
</div>
</div>
</div>
`;
}
} catch (error) {
console.error('Error selecting group:', error);
showError('Error loading group configuration');
}
}
async function loadGroupScripts(groupId) {
if (!currentGroup?.work_dir) {
return;
}
try {
// Cargar scripts y esquema
const [scripts, schema] = await Promise.all([
apiRequest(`/script-groups/${groupId}/scripts`),
apiRequest(`/script-groups/${groupId}/schema`)
]);
const scriptList = document.getElementById('scriptList');
scriptList.innerHTML = `
<div class="space-y-4">
${scripts.map(script => `
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="flex justify-between items-start">
<div>
<h3 class="text-lg leading-6 font-medium text-gray-900">
${script.name}
</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
${script.description || 'No description available'}
</p>
</div>
<button onclick="runScript('${script.id}')"
class="ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Run
</button>
</div>
</div>
</div>
`).join('')}
</div>
`;
} catch (error) {
console.error('Error loading group scripts:', error);
showError('Error loading scripts');
}
}
async function runScript(scriptId) {
if (!currentGroup?.work_dir) {
showError('No work directory configured');
2025-02-07 19:08:39 -03:00
return;
}
try {
const result = await apiRequest(`/script-groups/${currentGroup.id}/scripts/${scriptId}/run`, {
2025-02-07 19:08:39 -03:00
method: 'POST',
body: JSON.stringify({
work_dir: currentGroup.work_dir,
2025-02-07 19:08:39 -03:00
profile: currentProfile
})
});
if (result.error) {
2025-02-07 19:08:39 -03:00
showError(result.error);
} else {
showSuccess('Script executed successfully');
2025-02-07 19:08:39 -03:00
if (result.output) {
const outputArea = document.getElementById('outputArea');
const timestamp = new Date().toLocaleTimeString();
outputArea.innerHTML += `\n[${timestamp}] ${result.output}`;
outputArea.scrollTop = outputArea.scrollHeight;
2025-02-07 19:08:39 -03:00
}
}
} catch (error) {
showError('Error executing script');
2025-02-07 19:08:39 -03:00
}
}
async function editGroupConfig() {
if (!currentGroup) return;
2025-02-07 19:08:39 -03:00
try {
const schema = await apiRequest(`/script-groups/${currentGroup.id}/schema`);
const content = `
<form id="groupConfigForm" class="space-y-4">
${Object.entries(schema.config_schema).map(([key, field]) => `
<div>
<label class="block text-sm font-medium text-gray-700">
${field.description || key}
</label>
${generateFormField(key, field, currentGroup[key])}
</div>
`).join('')}
2025-02-07 19:08:39 -03:00
</form>
`;
2025-02-07 19:08:39 -03:00
const modal = createModal('Edit Group Configuration', content, true);
modal.querySelector('[onclick="saveModal(this)"]').onclick = () => saveGroupConfig(modal);
} catch (error) {
showError('Error loading group configuration');
}
}
async function saveGroupConfig(modal) {
if (!currentGroup) return;
const form = modal.querySelector('#groupConfigForm');
const formData = new FormData(form);
const config = {};
formData.forEach((value, key) => {
if (value === 'true') value = true;
else if (value === 'false') value = false;
else if (!isNaN(value) && value !== '') value = Number(value);
config[key] = value;
});
try {
await apiRequest(`/script-groups/${currentGroup.id}/config`, {
method: 'PUT',
body: JSON.stringify(config)
});
closeModal(modal);
showSuccess('Group configuration updated');
await selectGroup(currentGroup.id);
} catch (error) {
showError('Error saving group configuration');
}
}
async function editGroupSchema() {
if (!currentGroup) return;
try {
const schema = await apiRequest(`/script-groups/${currentGroup.id}/schema`);
const content = `
<div class="space-y-4">
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Group Name</label>
<input type="text" name="group_name" value="${schema.group_name || ''}"
2025-02-08 13:20:05 -03:00
class="${STYLES.editableInput}">
</div>
<div>
<div class="flex justify-end">
<button type="button" onclick="addSchemaField()"
class="mt-6 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500">
Add Field
</button>
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Description</label>
<input type="text" name="description" value="${schema.description || ''}"
class="${STYLES.editableInput}">
</div>
<div id="schemaFields" class="space-y-4">
${Object.entries(schema.config_schema || {}).map(([key, field]) =>
generateSchemaField(key, field)).join('')}
</div>
</div>
`;
const modal = createModal('Edit Group Schema', content, true);
modal.querySelector('[onclick="saveModal(this)"]').onclick = () => saveGroupSchema(modal);
} catch (error) {
showError('Error loading group schema');
}
}
async function saveGroupSchema(modal) {
const schema = {
group_name: modal.querySelector('[name="group_name"]').value,
description: modal.querySelector('[name="description"]').value,
config_schema: {}
};
// Recopilar definiciones de campos
modal.querySelectorAll('.schema-field').forEach(field => {
const key = field.querySelector('[name="field_name"]').value;
const type = field.querySelector('[name="field_type"]').value;
if (!key) return; // Ignorar campos sin nombre
const fieldSchema = {
type,
description: field.querySelector('[name="field_description"]').value,
required: field.querySelector('[name="field_required"]').value === 'true'
};
// Procesar valor por defecto según el tipo
const defaultValue = field.querySelector('[name="field_default"]').value;
if (defaultValue) {
if (type === 'number') {
fieldSchema.default = Number(defaultValue);
} else if (type === 'boolean') {
fieldSchema.default = defaultValue === 'true';
} else {
fieldSchema.default = defaultValue;
}
}
// Procesar opciones para campos tipo select
if (type === 'select') {
const optionsStr = field.querySelector('[name="field_options"]').value;
fieldSchema.options = optionsStr.split(',').map(opt => opt.trim()).filter(Boolean);
}
schema.config_schema[key] = fieldSchema;
});
try {
await apiRequest(`/script-groups/${currentGroup.id}/schema`, {
method: 'PUT',
body: JSON.stringify(schema)
});
2025-02-07 19:08:39 -03:00
closeModal(modal);
showSuccess('Group schema updated');
// Recargar configuración del grupo
await editGroupConfig();
2025-02-07 19:08:39 -03:00
} catch (error) {
showError('Error saving group schema');
}
}
function updateScriptList(scripts) {
const scriptList = document.getElementById('scriptList');
if (!scriptList) return;
if (!scripts || !scripts.length) {
scriptList.innerHTML = `
<div class="text-center text-gray-500 p-4">
No scripts available
</div>
`;
return;
}
scriptList.innerHTML = `
<div class="space-y-4">
${scripts.map(script => `
<div class="bg-white shadow sm:rounded-lg">
<div class="px-4 py-5 sm:p-6">
<div class="flex justify-between items-start">
<div>
<h3 class="text-lg leading-6 font-medium text-gray-900">
${script.name}
</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
${script.description || 'No description available'}
</p>
</div>
<button onclick="runScript('${script.id}')"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Run
</button>
</div>
</div>
</div>
`).join('')}
</div>
`;
}
async function restoreScriptGroup() {
const lastGroupId = localStorage.getItem('lastGroupId');
if (lastGroupId) {
const select = document.getElementById('groupSelect');
if (select) {
select.value = lastGroupId;
if (select.value === lastGroupId) { // Verifica que el grupo aún existe
await selectGroup(lastGroupId);
} else {
localStorage.removeItem('lastGroupId');
}
}
2025-02-07 19:08:39 -03:00
}
2025-02-08 13:20:05 -03:00
}
function updateGroupDisplay(group) {
const configContainer = document.getElementById('groupConfig');
if (!configContainer) return;
if (!group) {
configContainer.innerHTML = '';
return;
}
configContainer.innerHTML = `
<div class="space-y-4">
<div class="flex justify-between items-center">
<div>
<h3 class="text-lg font-medium">${group.name || 'Unnamed Group'}</h3>
<p class="text-sm text-gray-500">${group.description || 'No description'}</p>
2025-02-08 13:20:05 -03:00
</div>
<div class="flex space-x-2">
<button onclick="editGroupConfig()"
class="px-3 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
Edit Config
</button>
</div>
</div>
<div class="bg-gray-50 p-4 rounded-md">
<div class="flex justify-between items-center">
<div class="flex-grow">
<label class="block text-sm font-medium text-gray-700">Working Directory</label>
<div class="mt-1 flex items-center space-x-2">
<span class="text-gray-600">${group.work_dir || 'Not configured'}</span>
</div>
</div>
<button onclick="selectGroupWorkDir()"
class="px-3 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
${group.work_dir ? 'Change' : 'Select'} Directory
</button>
2025-02-08 13:20:05 -03:00
</div>
</div>
</div>
`;
}
async function selectGroupWorkDir() {
if (!currentGroup) {
showError('No group selected');
return;
}
try {
const response = await apiRequest('/select-directory');
if (response.path) {
const updatedConfig = {
...currentGroup,
work_dir: response.path
};
await apiRequest(`/script-groups/${currentGroup.id}/config`, {
method: 'PUT',
body: JSON.stringify(updatedConfig)
});
currentGroup = updatedConfig;
updateGroupDisplay(currentGroup);
showSuccess('Work directory updated successfully');
// Recargar scripts si hay
await loadGroupScripts(currentGroup.id);
}
} catch (error) {
showError('Failed to update work directory');
}
}
// Inicializar cuando la página carga
document.addEventListener('DOMContentLoaded', async () => {
await loadScriptGroups();
await restoreScriptGroup();
});