LocalScriptsWeb/frontend/static/js/profile.js

323 lines
14 KiB
JavaScript
Raw Normal View History

let selectedProfileId = localStorage.getItem('selectedProfileId') || 'default';
2025-02-08 13:20:05 -03:00
let editingProfile = null;
2025-02-07 19:08:39 -03:00
// Profile functions
async function loadProfiles() {
try {
2025-02-08 13:20:05 -03:00
const response = await apiRequest('/profiles');
const profiles = Object.values(response);
// Actualizar el selector manteniendo el valor seleccionado
const select = document.getElementById('profileSelect');
select.innerHTML = profiles.map(profile => `
<option value="${profile.id}">
${profile.name}
</option>
`).join('');
2025-02-07 19:08:39 -03:00
2025-02-08 13:20:05 -03:00
// Establecer el valor seleccionado después de actualizar las opciones
if (response[selectedProfileId]) {
select.value = selectedProfileId;
await selectProfile(selectedProfileId);
} else {
selectedProfileId = 'default';
2025-02-08 13:20:05 -03:00
select.value = 'default';
await selectProfile('default');
2025-02-07 19:08:39 -03:00
}
2025-02-08 13:20:05 -03:00
// Asegurarse de que el evento change no sobrescriba la selección
select.addEventListener('change', onProfileChange, { once: true });
2025-02-07 19:08:39 -03:00
} catch (error) {
2025-02-08 13:20:05 -03:00
showError('Error al cargar los perfiles');
2025-02-07 19:08:39 -03:00
}
}
async function selectProfile(profileId) {
try {
currentProfile = await apiRequest(`/profiles/${profileId}`);
updateWorkDirDisplay();
} catch (error) {
showError('Failed to load profile');
}
}
async function changeProfile() {
const select = document.getElementById('profileSelect');
await selectProfile(select.value);
}
async function selectWorkDir() {
try {
const response = await apiRequest('/select-directory');
if (response.path) {
await apiRequest(`/profiles/${currentProfile.id}`, {
method: 'PUT',
body: JSON.stringify({
...currentProfile,
work_dir: response.path
})
});
await selectProfile(currentProfile.id);
showSuccess('Work directory updated successfully');
}
} catch (error) {
showError('Failed to update work directory');
}
}
2025-02-07 07:35:18 -03:00
// Profile editor modal
function showProfileEditor(profile = null) {
editingProfile = profile;
const modal = document.createElement('div');
modal.className = 'modal active';
2025-02-08 13:20:05 -03:00
const editableInputClass = "mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500";
const readonlyInputClass = "mt-1 block w-full rounded-md border-2 border-gray-200 bg-gray-100 px-3 py-2 shadow-sm";
2025-02-07 07:35:18 -03:00
modal.innerHTML = `
<div class="modal-content">
2025-02-08 13:20:05 -03:00
<h2 class="text-xl font-bold mb-4">${profile ? 'Editar Perfil' : 'Nuevo Perfil'}</h2>
2025-02-07 07:35:18 -03:00
<form id="profileForm" onsubmit="saveProfile(event)">
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="profileId" class="block text-sm font-medium text-gray-700">ID del Perfil</label>
2025-02-07 07:35:18 -03:00
<input type="text" id="profileId" name="id"
2025-02-08 13:20:05 -03:00
class="${profile ? readonlyInputClass : editableInputClass}"
2025-02-07 07:35:18 -03:00
value="${profile?.id || ''}"
2025-02-08 13:20:05 -03:00
${profile ? 'readonly' : ''}
2025-02-07 07:35:18 -03:00
required pattern="[a-zA-Z0-9_-]+"
2025-02-08 13:20:05 -03:00
title="Solo se permiten letras, números, guión bajo y guión">
2025-02-07 07:35:18 -03:00
</div>
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="profileName" class="block text-sm font-medium text-gray-700">Nombre</label>
<input type="text" id="profileName" name="name"
class="${editableInputClass}"
2025-02-07 07:35:18 -03:00
value="${profile?.name || ''}" required>
</div>
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="workDir" class="block text-sm font-medium text-gray-700">Directorio de Trabajo</label>
<input type="text" id="workDir" name="work_dir"
class="${readonlyInputClass}"
2025-02-07 19:08:39 -03:00
value="${profile?.work_dir || ''}" readonly>
2025-02-07 07:35:18 -03:00
</div>
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="llmModel" class="block text-sm font-medium text-gray-700">LLM Model</label>
<select id="llmModel" name="llm_model"
class="${editableInputClass}">
2025-02-07 07:35:18 -03:00
<option value="gpt-4" ${profile?.llm_settings?.model === 'gpt-4' ? 'selected' : ''}>GPT-4</option>
<option value="gpt-3.5-turbo" ${profile?.llm_settings?.model === 'gpt-3.5-turbo' ? 'selected' : ''}>GPT-3.5 Turbo</option>
</select>
</div>
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="apiKey" class="block text-sm font-medium text-gray-700">API Key</label>
<input type="password" id="apiKey" name="api_key"
class="${editableInputClass}"
2025-02-07 07:35:18 -03:00
value="${profile?.llm_settings?.api_key || ''}">
</div>
<div class="form-group">
2025-02-08 13:20:05 -03:00
<label for="temperature" class="block text-sm font-medium text-gray-700">Temperature</label>
<input type="number" id="temperature" name="temperature"
class="${editableInputClass}"
2025-02-07 07:35:18 -03:00
value="${profile?.llm_settings?.temperature || 0.7}"
min="0" max="2" step="0.1">
</div>
2025-02-08 13:20:05 -03:00
<div class="mt-4 flex justify-end space-x-3">
<button type="button" onclick="closeModal(this)"
class="px-4 py-2 bg-gray-200 text-gray-800 rounded-md hover:bg-gray-300">Cancelar</button>
<button type="submit"
class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">Guardar</button>
2025-02-07 07:35:18 -03:00
</div>
</form>
</div>
`;
document.body.appendChild(modal);
}
async function saveProfile(event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
const profileData = {
id: formData.get('id'),
name: formData.get('name'),
work_dir: formData.get('work_dir'),
llm_settings: {
model: formData.get('llm_model'),
api_key: formData.get('api_key'),
temperature: parseFloat(formData.get('temperature'))
}
};
try {
if (editingProfile) {
await apiRequest(`/profiles/${editingProfile.id}`, {
method: 'PUT',
body: JSON.stringify(profileData)
});
} else {
await apiRequest('/profiles', {
method: 'POST',
body: JSON.stringify(profileData)
});
}
await loadProfiles();
2025-02-07 19:08:39 -03:00
closeModal(event.target);
2025-02-08 13:20:05 -03:00
showSuccess(`Perfil ${editingProfile ? 'actualizado' : 'creado'} correctamente`);
2025-02-07 07:35:18 -03:00
} catch (error) {
2025-02-08 13:20:05 -03:00
showError(`Error al ${editingProfile ? 'actualizar' : 'crear'} el perfil`);
2025-02-07 07:35:18 -03:00
}
}
// static/js/profile.js
async function editProfile() {
2025-02-07 07:35:18 -03:00
if (!currentProfile) {
showError('No profile selected');
return;
}
const content = `
<form id="profileForm" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Profile ID</label>
<input type="text" name="id" value="${currentProfile.id}"
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
${currentProfile.id === 'default' ? 'readonly' : ''}>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<input type="text" name="name" value="${currentProfile.name}"
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Work Directory</label>
<input type="text" name="work_dir" value="${currentProfile.work_dir}" readonly
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">LLM Model</label>
<select name="llm_model"
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
<option value="gpt-4" ${currentProfile.llm_settings?.model === 'gpt-4' ? 'selected' : ''}>GPT-4</option>
<option value="gpt-3.5-turbo" ${currentProfile.llm_settings?.model === 'gpt-3.5-turbo' ? 'selected' : ''}>GPT-3.5 Turbo</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">API Key</label>
<input type="password" name="api_key" value="${currentProfile.llm_settings?.api_key || ''}"
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Temperature</label>
<input type="number" name="temperature" value="${currentProfile.llm_settings?.temperature || 0.7}"
min="0" max="2" step="0.1"
2025-02-08 13:20:05 -03:00
class="mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
</div>
</form>
`;
const modal = createModal('Edit Profile', content, true);
modal.querySelector('[onclick="saveModal(this)"]').onclick = async () => {
await saveProfile(modal);
};
}
async function saveProfile(modal) {
const form = modal.querySelector('#profileForm');
const formData = new FormData(form);
const profileData = {
id: formData.get('id'),
name: formData.get('name'),
work_dir: formData.get('work_dir'),
llm_settings: {
model: formData.get('llm_model'),
api_key: formData.get('api_key'),
temperature: parseFloat(formData.get('temperature'))
}
};
try {
2025-02-08 13:20:05 -03:00
if (editingProfile) {
await apiRequest(`/profiles/${editingProfile.id}`, {
method: 'PUT',
body: JSON.stringify(profileData)
});
} else {
await apiRequest('/profiles', {
method: 'POST',
body: JSON.stringify(profileData)
});
}
await loadProfiles();
2025-02-08 13:20:05 -03:00
closeModal(modal);
showSuccess(`Perfil ${editingProfile ? 'actualizado' : 'creado'} correctamente`);
} catch (error) {
2025-02-08 13:20:05 -03:00
showError(`Error al ${editingProfile ? 'actualizar' : 'crear'} el perfil`);
}
2025-02-07 07:35:18 -03:00
}
function newProfile() {
2025-02-08 13:20:05 -03:00
const editableInputClass = "mt-1 block w-full rounded-md border-2 border-gray-300 bg-green-50 px-3 py-2 shadow-sm focus:border-indigo-500 focus:ring-indigo-500";
const readonlyInputClass = "mt-1 block w-full rounded-md border-2 border-gray-200 bg-gray-100 px-3 py-2 shadow-sm";
const content = `
<form id="profileForm" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Profile ID</label>
<input type="text" name="id" required pattern="[a-zA-Z0-9_-]+"
class="${editableInputClass}"
title="Only letters, numbers, underscore and dash allowed">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<input type="text" name="name" required
class="${editableInputClass}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Work Directory</label>
<input type="text" name="work_dir" readonly
class="${readonlyInputClass}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">LLM Model</label>
<select name="llm_model"
class="${editableInputClass}">
<option value="gpt-4">GPT-4</option>
<option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">API Key</label>
<input type="password" name="api_key"
class="${editableInputClass}">
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Temperature</label>
<input type="number" name="temperature" value="0.7"
min="0" max="2" step="0.1"
class="${editableInputClass}">
</div>
</form>
`;
const modal = createModal('New Profile', content, true);
editingProfile = null;
modal.querySelector('[onclick="saveModal(this)"]').onclick = async () => {
await saveProfile(modal);
};
}
async function onProfileChange(event) {
2025-02-08 13:20:05 -03:00
const newProfileId = event.target.value;
if (newProfileId !== selectedProfileId) {
selectedProfileId = newProfileId;
localStorage.setItem('selectedProfileId', selectedProfileId);
await selectProfile(selectedProfileId);
}
2025-02-07 07:35:18 -03:00
}