configs: save pending template changes
This commit is contained in:
@@ -63,10 +63,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Проект</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Проект</label>
|
||||||
<select id="create-project-select"
|
<input id="create-project-input"
|
||||||
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
list="create-project-options"
|
||||||
<option value="">Без проекта</option>
|
placeholder="Начните вводить название проекта"
|
||||||
</select>
|
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>
|
||||||
</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 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">
|
<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>
|
<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">
|
<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="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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,6 +196,8 @@ let projectsCache = [];
|
|||||||
let projectNameByUUID = {};
|
let projectNameByUUID = {};
|
||||||
let pendingMoveConfigUUID = '';
|
let pendingMoveConfigUUID = '';
|
||||||
let pendingMoveProjectName = '';
|
let pendingMoveProjectName = '';
|
||||||
|
let pendingCreateConfigName = '';
|
||||||
|
let pendingCreateProjectName = '';
|
||||||
|
|
||||||
function renderConfigs(configs) {
|
function renderConfigs(configs) {
|
||||||
const emptyText = configStatusMode === 'archived'
|
const emptyText = configStatusMode === 'archived'
|
||||||
@@ -407,6 +415,7 @@ async function cloneConfig() {
|
|||||||
|
|
||||||
function openCreateModal() {
|
function openCreateModal() {
|
||||||
document.getElementById('opportunity-number').value = '';
|
document.getElementById('opportunity-number').value = '';
|
||||||
|
document.getElementById('create-project-input').value = '';
|
||||||
document.getElementById('create-modal').classList.remove('hidden');
|
document.getElementById('create-modal').classList.remove('hidden');
|
||||||
document.getElementById('create-modal').classList.add('flex');
|
document.getElementById('create-modal').classList.add('flex');
|
||||||
document.getElementById('opportunity-number').focus();
|
document.getElementById('opportunity-number').focus();
|
||||||
@@ -425,8 +434,25 @@ async function createConfig() {
|
|||||||
return;
|
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 {
|
try {
|
||||||
const resp = await fetch('/api/configs', {
|
const resp = await fetch('/api/configs', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -442,16 +468,17 @@ async function createConfig() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const config = await resp.json();
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const err = await resp.json();
|
alert('Ошибка: ' + (config.error || 'Не удалось создать'));
|
||||||
alert('Ошибка: ' + (err.error || 'Не удалось создать'));
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = await resp.json();
|
|
||||||
window.location.href = '/configurator?uuid=' + config.uuid;
|
window.location.href = '/configurator?uuid=' + config.uuid;
|
||||||
|
return true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
alert('Ошибка создания конфигурации');
|
alert('Ошибка создания конфигурации');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,8 +537,22 @@ function clearMoveProjectInput() {
|
|||||||
document.getElementById('move-project-input').value = '';
|
document.getElementById('move-project-input').value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearCreateProjectInput() {
|
||||||
|
document.getElementById('create-project-input').value = '';
|
||||||
|
}
|
||||||
|
|
||||||
function openCreateProjectOnMoveModal(projectName) {
|
function openCreateProjectOnMoveModal(projectName) {
|
||||||
document.getElementById('create-project-on-move-name').textContent = 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.remove('hidden');
|
||||||
document.getElementById('create-project-on-move-modal').classList.add('flex');
|
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');
|
document.getElementById('create-project-on-move-modal').classList.remove('flex');
|
||||||
pendingMoveConfigUUID = '';
|
pendingMoveConfigUUID = '';
|
||||||
pendingMoveProjectName = '';
|
pendingMoveProjectName = '';
|
||||||
|
pendingCreateConfigName = '';
|
||||||
|
pendingCreateProjectName = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmCreateProjectOnMove() {
|
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 configUUID = pendingMoveConfigUUID;
|
||||||
const projectName = pendingMoveProjectName;
|
const projectName = pendingMoveProjectName;
|
||||||
if (!configUUID || !projectName) {
|
if (!configUUID || !projectName) {
|
||||||
@@ -544,10 +619,15 @@ async function confirmCreateProjectOnMove() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newProject = await createResp.json();
|
const newProject = await createResp.json();
|
||||||
|
pendingMoveConfigUUID = '';
|
||||||
|
pendingMoveProjectName = '';
|
||||||
|
await loadProjectsForConfigUI();
|
||||||
|
document.getElementById('move-project-input').value = projectName;
|
||||||
const moved = await moveConfigToProject(configUUID, newProject.uuid);
|
const moved = await moveConfigToProject(configUUID, newProject.uuid);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
closeCreateProjectOnMoveModal();
|
closeCreateProjectOnMoveModal();
|
||||||
closeMoveProjectModal();
|
} else {
|
||||||
|
closeCreateProjectOnMoveModal();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert('Ошибка создания проекта');
|
alert('Ошибка создания проекта');
|
||||||
@@ -760,16 +840,18 @@ async function loadProjectsForConfigUI() {
|
|||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
projectsCache = (data.projects || []);
|
projectsCache = (data.projects || []);
|
||||||
|
|
||||||
const select = document.getElementById('create-project-select');
|
projectsCache.forEach(project => {
|
||||||
if (select) {
|
projectNameByUUID[project.uuid] = project.name;
|
||||||
select.innerHTML = '<option value="">Без проекта</option>';
|
});
|
||||||
|
|
||||||
|
const createOptions = document.getElementById('create-project-options');
|
||||||
|
if (createOptions) {
|
||||||
|
createOptions.innerHTML = '';
|
||||||
projectsCache.forEach(project => {
|
projectsCache.forEach(project => {
|
||||||
projectNameByUUID[project.uuid] = project.name;
|
|
||||||
if (!project.is_active) return;
|
if (!project.is_active) return;
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.value = project.uuid;
|
option.value = project.name;
|
||||||
option.textContent = project.name;
|
createOptions.appendChild(option);
|
||||||
select.appendChild(option);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user