configs: save pending template changes

This commit is contained in:
Mikhail Chusavitin
2026-02-06 16:43:04 +03:00
parent 2f0ac2f6d2
commit 29035ddc5a

View File

@@ -63,10 +63,16 @@
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Проект</label>
<select id="create-project-select"
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">Без проекта</option>
</select>
<input id="create-project-input"
list="create-project-options"
placeholder="Начните вводить название проекта"
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<datalist id="create-project-options"></datalist>
<div class="mt-2 flex justify-between items-center gap-3">
<button type="button" onclick="clearCreateProjectInput()" class="text-sm text-gray-600 hover:text-gray-800">
Без проекта
</button>
</div>
</div>
</div>
@@ -171,10 +177,10 @@
<div id="create-project-on-move-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4 p-6">
<h2 class="text-xl font-semibold mb-3">Проект не найден</h2>
<p class="text-sm text-gray-600 mb-4">Проект "<span id="create-project-on-move-name" class="font-medium text-gray-900"></span>" не найден. Создать и привязать квоту?</p>
<p class="text-sm text-gray-600 mb-4">Проект "<span id="create-project-on-move-name" class="font-medium text-gray-900"></span>" не найден. <span id="create-project-on-move-description">Создать и привязать квоту?</span></p>
<div class="flex justify-end space-x-3">
<button onclick="closeCreateProjectOnMoveModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
<button onclick="confirmCreateProjectOnMove()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Создать и привязать</button>
<button id="create-project-on-move-confirm-btn" onclick="confirmCreateProjectOnMove()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Создать и привязать</button>
</div>
</div>
</div>
@@ -190,6 +196,8 @@ let projectsCache = [];
let projectNameByUUID = {};
let pendingMoveConfigUUID = '';
let pendingMoveProjectName = '';
let pendingCreateConfigName = '';
let pendingCreateProjectName = '';
function renderConfigs(configs) {
const emptyText = configStatusMode === 'archived'
@@ -407,6 +415,7 @@ async function cloneConfig() {
function openCreateModal() {
document.getElementById('opportunity-number').value = '';
document.getElementById('create-project-input').value = '';
document.getElementById('create-modal').classList.remove('hidden');
document.getElementById('create-modal').classList.add('flex');
document.getElementById('opportunity-number').focus();
@@ -425,8 +434,25 @@ async function createConfig() {
return;
}
const projectUUID = document.getElementById('create-project-select').value;
const projectName = document.getElementById('create-project-input').value.trim();
let projectUUID = '';
if (projectName) {
const existingProject = projectsCache.find(p => p.is_active && p.name.toLowerCase() === projectName.toLowerCase());
if (existingProject) {
projectUUID = existingProject.uuid;
} else {
pendingCreateConfigName = name;
pendingCreateProjectName = projectName;
openCreateProjectOnCreateModal(projectName);
return;
}
}
await createConfigWithProject(name, projectUUID);
}
async function createConfigWithProject(name, projectUUID) {
try {
const resp = await fetch('/api/configs', {
method: 'POST',
@@ -442,16 +468,17 @@ async function createConfig() {
})
});
const config = await resp.json();
if (!resp.ok) {
const err = await resp.json();
alert('Ошибка: ' + (err.error || 'Не удалось создать'));
return;
alert('Ошибка: ' + (config.error || 'Не удалось создать'));
return false;
}
const config = await resp.json();
window.location.href = '/configurator?uuid=' + config.uuid;
return true;
} catch(e) {
alert('Ошибка создания конфигурации');
return false;
}
}
@@ -510,8 +537,22 @@ function clearMoveProjectInput() {
document.getElementById('move-project-input').value = '';
}
function clearCreateProjectInput() {
document.getElementById('create-project-input').value = '';
}
function openCreateProjectOnMoveModal(projectName) {
document.getElementById('create-project-on-move-name').textContent = projectName;
document.getElementById('create-project-on-move-description').textContent = 'Создать и привязать квоту?';
document.getElementById('create-project-on-move-confirm-btn').textContent = 'Создать и привязать';
document.getElementById('create-project-on-move-modal').classList.remove('hidden');
document.getElementById('create-project-on-move-modal').classList.add('flex');
}
function openCreateProjectOnCreateModal(projectName) {
document.getElementById('create-project-on-move-name').textContent = projectName;
document.getElementById('create-project-on-move-description').textContent = 'Создать и использовать для новой конфигурации?';
document.getElementById('create-project-on-move-confirm-btn').textContent = 'Создать и использовать';
document.getElementById('create-project-on-move-modal').classList.remove('hidden');
document.getElementById('create-project-on-move-modal').classList.add('flex');
}
@@ -521,9 +562,43 @@ function closeCreateProjectOnMoveModal() {
document.getElementById('create-project-on-move-modal').classList.remove('flex');
pendingMoveConfigUUID = '';
pendingMoveProjectName = '';
pendingCreateConfigName = '';
pendingCreateProjectName = '';
}
async function confirmCreateProjectOnMove() {
if (pendingCreateConfigName && pendingCreateProjectName) {
const configName = pendingCreateConfigName;
const projectName = pendingCreateProjectName;
try {
const createResp = await fetch('/api/projects', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ name: projectName })
});
if (!createResp.ok) {
const err = await createResp.json();
alert('Не удалось создать проект: ' + (err.error || 'ошибка'));
return;
}
const newProject = await createResp.json();
pendingCreateConfigName = '';
pendingCreateProjectName = '';
await loadProjectsForConfigUI();
const created = await createConfigWithProject(configName, newProject.uuid);
if (created) {
closeCreateProjectOnMoveModal();
} else {
closeCreateProjectOnMoveModal();
document.getElementById('create-project-input').value = projectName;
}
} catch (e) {
alert('Ошибка создания проекта');
}
return;
}
const configUUID = pendingMoveConfigUUID;
const projectName = pendingMoveProjectName;
if (!configUUID || !projectName) {
@@ -544,10 +619,15 @@ async function confirmCreateProjectOnMove() {
}
const newProject = await createResp.json();
pendingMoveConfigUUID = '';
pendingMoveProjectName = '';
await loadProjectsForConfigUI();
document.getElementById('move-project-input').value = projectName;
const moved = await moveConfigToProject(configUUID, newProject.uuid);
if (moved) {
closeCreateProjectOnMoveModal();
closeMoveProjectModal();
} else {
closeCreateProjectOnMoveModal();
}
} catch (e) {
alert('Ошибка создания проекта');
@@ -760,16 +840,18 @@ async function loadProjectsForConfigUI() {
const data = await resp.json();
projectsCache = (data.projects || []);
const select = document.getElementById('create-project-select');
if (select) {
select.innerHTML = '<option value="">Без проекта</option>';
projectsCache.forEach(project => {
projectNameByUUID[project.uuid] = project.name;
});
const createOptions = document.getElementById('create-project-options');
if (createOptions) {
createOptions.innerHTML = '';
projectsCache.forEach(project => {
projectNameByUUID[project.uuid] = project.name;
if (!project.is_active) return;
const option = document.createElement('option');
option.value = project.uuid;
option.textContent = project.name;
select.appendChild(option);
option.value = project.name;
createOptions.appendChild(option);
});
}
} catch (e) {