Deduplicate configuration revisions and update revisions UI
This commit is contained in:
@@ -114,38 +114,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rename-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
||||
<div id="config-action-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-4">Переименовать квоту</h2>
|
||||
<h2 class="text-xl font-semibold mb-4">Действия с квотой</h2>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Новое название</label>
|
||||
<input type="text" id="rename-input"
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Название</label>
|
||||
<input type="text" id="config-action-name"
|
||||
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<input type="hidden" id="rename-uuid">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-3 mt-6">
|
||||
<button onclick="closeRenameModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
|
||||
<button onclick="renameConfig()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="clone-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-4">Копировать квоту</h2>
|
||||
<div class="space-y-4">
|
||||
<label class="flex items-center gap-2 text-sm text-gray-700">
|
||||
<input type="checkbox" id="config-action-copy" class="rounded border-gray-300">
|
||||
Создать копию
|
||||
</label>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Название копии</label>
|
||||
<input type="text" id="clone-input"
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Проект</label>
|
||||
<input id="config-action-project-input"
|
||||
list="config-action-project-options"
|
||||
placeholder="Начните вводить проект"
|
||||
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<input type="hidden" id="clone-uuid">
|
||||
<datalist id="config-action-project-options"></datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Вариант</label>
|
||||
<input id="config-action-variant-input"
|
||||
list="config-action-variant-options"
|
||||
placeholder="Выберите вариант"
|
||||
class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<datalist id="config-action-variant-options"></datalist>
|
||||
</div>
|
||||
<input type="hidden" id="config-action-uuid">
|
||||
<input type="hidden" id="config-action-current-name">
|
||||
<input type="hidden" id="config-action-current-project">
|
||||
</div>
|
||||
<div class="flex justify-end space-x-3 mt-6">
|
||||
<button onclick="closeCloneModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
|
||||
<button onclick="cloneConfig()" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">Копировать</button>
|
||||
<button onclick="closeConfigActionModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
|
||||
<button onclick="saveConfigAction()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -202,30 +206,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="transfer-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-4">Перенести квоту в другой вариант</h2>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">Целевой вариант</label>
|
||||
<select id="transfer-variant-select" class="w-full px-3 py-2 border rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
</select>
|
||||
<input type="hidden" id="transfer-config-uuid">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-3 mt-6">
|
||||
<button onclick="closeTransferModal()" class="px-4 py-2 text-gray-600 hover:text-gray-800">Отмена</button>
|
||||
<button onclick="transferConfig()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Перенести</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const projectUUID = '{{.ProjectUUID}}';
|
||||
let configStatusMode = 'active';
|
||||
let project = null;
|
||||
let allConfigs = [];
|
||||
let projectVariants = [];
|
||||
let projectsCatalog = [];
|
||||
let variantMenuInitialized = false;
|
||||
|
||||
function escapeHtml(text) {
|
||||
@@ -258,12 +245,16 @@ function normalizeVariantLabel(variant) {
|
||||
}
|
||||
|
||||
async function loadVariantsForCode(code) {
|
||||
if (!code) return;
|
||||
try {
|
||||
const resp = await fetch('/api/projects/all');
|
||||
if (!resp.ok) return;
|
||||
const data = await resp.json();
|
||||
const allProjects = Array.isArray(data) ? data : (data.projects || []);
|
||||
projectsCatalog = allProjects.filter(p => p && p.uuid && p.is_active !== false);
|
||||
if (!code) {
|
||||
projectVariants = [];
|
||||
return;
|
||||
}
|
||||
projectVariants = allProjects
|
||||
.filter(p => (p.code || '').trim() === code && p.is_active !== false)
|
||||
.map(p => ({uuid: p.uuid, variant: (p.variant || '').trim()}));
|
||||
@@ -401,12 +392,8 @@ function renderConfigs(configs) {
|
||||
} else {
|
||||
html += '<a href="/configs/' + c.uuid + '/revisions" class="text-purple-600 hover:text-purple-800 inline-block" title="Ревизии">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg></a>';
|
||||
html += '<button onclick="openTransferModal(\'' + c.uuid + '\')" class="text-indigo-600 hover:text-indigo-800" title="Перенести в другой вариант">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4"></path></svg></button>';
|
||||
html += '<button onclick="openCloneModal(\'' + c.uuid + '\', \'' + escapeHtml(c.name).replace(/'/g, "\\'") + '\')" class="text-green-600 hover:text-green-800" title="Копировать">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg></button>';
|
||||
html += '<button onclick="openRenameModal(\'' + c.uuid + '\', \'' + escapeHtml(c.name).replace(/'/g, "\\'") + '\')" class="text-blue-600 hover:text-blue-800" title="Переименовать">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg></button>';
|
||||
html += '<button onclick="openConfigActionModal(\'' + c.uuid + '\', \'' + escapeHtml(c.name).replace(/'/g, "\\'") + '\', \'' + (c.project_uuid || projectUUID) + '\')" class="text-indigo-600 hover:text-indigo-800" title="Переименовать / копировать / переместить">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7h16M4 12h16M4 17h16"></path></svg></button>';
|
||||
html += '<button onclick="deleteConfig(\'' + c.uuid + '\')" class="text-red-600 hover:text-red-800" title="В архив">';
|
||||
html += '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg></button>';
|
||||
}
|
||||
@@ -576,68 +563,227 @@ async function reactivateConfig(uuid) {
|
||||
loadConfigs();
|
||||
}
|
||||
|
||||
function openRenameModal(uuid, currentName) {
|
||||
document.getElementById('rename-uuid').value = uuid;
|
||||
document.getElementById('rename-input').value = currentName;
|
||||
document.getElementById('rename-modal').classList.remove('hidden');
|
||||
document.getElementById('rename-modal').classList.add('flex');
|
||||
}
|
||||
|
||||
function closeRenameModal() {
|
||||
document.getElementById('rename-modal').classList.add('hidden');
|
||||
document.getElementById('rename-modal').classList.remove('flex');
|
||||
}
|
||||
|
||||
async function renameConfig() {
|
||||
const uuid = document.getElementById('rename-uuid').value;
|
||||
const name = document.getElementById('rename-input').value.trim();
|
||||
if (!name) {
|
||||
alert('Введите название');
|
||||
return;
|
||||
}
|
||||
const resp = await fetch('/api/configs/' + uuid + '/rename', {
|
||||
method: 'PATCH',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name: name})
|
||||
function projectCodeEntries() {
|
||||
const byCode = new Map();
|
||||
projectsCatalog.forEach(p => {
|
||||
const code = (p.code || '').trim();
|
||||
if (!code || byCode.has(code)) return;
|
||||
byCode.set(code, {
|
||||
code: code,
|
||||
name: (p.name || '').trim()
|
||||
});
|
||||
});
|
||||
if (!resp.ok) {
|
||||
alert('Не удалось переименовать');
|
||||
return;
|
||||
return Array.from(byCode.values()).sort((a, b) => a.code.localeCompare(b.code, 'ru'));
|
||||
}
|
||||
|
||||
function formatProjectAutocompleteValue(entry) {
|
||||
if (!entry) return '';
|
||||
return entry.name ? (entry.code + ' - ' + entry.name) : entry.code;
|
||||
}
|
||||
|
||||
function resolveProjectCodeFromInput(rawInput) {
|
||||
const input = (rawInput || '').trim();
|
||||
if (!input) return '';
|
||||
const entries = projectCodeEntries();
|
||||
|
||||
const exactCode = entries.find(e => e.code.toLowerCase() === input.toLowerCase());
|
||||
if (exactCode) return exactCode.code;
|
||||
|
||||
const exactDisplayMatches = entries.filter(e => formatProjectAutocompleteValue(e).toLowerCase() === input.toLowerCase());
|
||||
if (exactDisplayMatches.length === 1) return exactDisplayMatches[0].code;
|
||||
|
||||
const byUniqueName = entries.filter(e => (e.name || '').toLowerCase() === input.toLowerCase());
|
||||
if (byUniqueName.length === 1) return byUniqueName[0].code;
|
||||
|
||||
if (input.includes(' - ')) {
|
||||
const codeCandidate = input.split(' - ')[0].trim();
|
||||
const byCandidate = entries.find(e => e.code.toLowerCase() === codeCandidate.toLowerCase());
|
||||
if (byCandidate) return byCandidate.code;
|
||||
}
|
||||
closeRenameModal();
|
||||
loadConfigs();
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function openCloneModal(uuid, currentName) {
|
||||
document.getElementById('clone-uuid').value = uuid;
|
||||
document.getElementById('clone-input').value = currentName + ' (копия)';
|
||||
document.getElementById('clone-modal').classList.remove('hidden');
|
||||
document.getElementById('clone-modal').classList.add('flex');
|
||||
}
|
||||
|
||||
function closeCloneModal() {
|
||||
document.getElementById('clone-modal').classList.add('hidden');
|
||||
document.getElementById('clone-modal').classList.remove('flex');
|
||||
}
|
||||
|
||||
async function cloneConfig() {
|
||||
const uuid = document.getElementById('clone-uuid').value;
|
||||
const name = document.getElementById('clone-input').value.trim();
|
||||
if (!name) {
|
||||
alert('Введите название');
|
||||
return;
|
||||
}
|
||||
const resp = await fetch('/api/projects/' + projectUUID + '/configs/' + uuid + '/clone', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name: name})
|
||||
function populateProjectAutocomplete() {
|
||||
const options = document.getElementById('config-action-project-options');
|
||||
options.innerHTML = '';
|
||||
projectCodeEntries().forEach(entry => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = formatProjectAutocompleteValue(entry);
|
||||
opt.label = entry.code;
|
||||
options.appendChild(opt);
|
||||
});
|
||||
if (!resp.ok) {
|
||||
alert('Не удалось скопировать');
|
||||
}
|
||||
|
||||
function variantsForProjectCode(projectCode) {
|
||||
const code = (projectCode || '').trim();
|
||||
if (!code) return [];
|
||||
return projectsCatalog
|
||||
.filter(p => (p.code || '').trim() === code)
|
||||
.map(p => ({uuid: p.uuid, variant: normalizeVariantLabel(p.variant || '')}))
|
||||
.sort((a, b) => a.variant.localeCompare(b.variant, 'ru'));
|
||||
}
|
||||
|
||||
function populateVariantAutocomplete(projectCode, selectedVariantLabel) {
|
||||
const options = document.getElementById('config-action-variant-options');
|
||||
const input = document.getElementById('config-action-variant-input');
|
||||
const variants = variantsForProjectCode(projectCode);
|
||||
options.innerHTML = '';
|
||||
variants.forEach(v => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = v.variant;
|
||||
options.appendChild(opt);
|
||||
});
|
||||
if (selectedVariantLabel) {
|
||||
input.value = selectedVariantLabel;
|
||||
} else if (variants.length === 1) {
|
||||
input.value = variants[0].variant;
|
||||
} else {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function resolveTargetProjectUUIDFromInputs() {
|
||||
const projectCode = resolveProjectCodeFromInput(document.getElementById('config-action-project-input').value);
|
||||
if (!projectCode) {
|
||||
return {error: 'Выберите проект из подсказок'};
|
||||
}
|
||||
const variantLabel = normalizeVariantLabel(document.getElementById('config-action-variant-input').value || 'main');
|
||||
const target = projectsCatalog.find(p =>
|
||||
(p.code || '').trim() === projectCode &&
|
||||
normalizeVariantLabel(p.variant || '') === variantLabel
|
||||
);
|
||||
if (!target) {
|
||||
return {error: 'Выберите вариант из подсказок'};
|
||||
}
|
||||
return {uuid: target.uuid};
|
||||
}
|
||||
|
||||
function syncActionModalMode() {
|
||||
const copyCheckbox = document.getElementById('config-action-copy');
|
||||
if (copyCheckbox.checked) {
|
||||
// no-op: copy always uses latest revision
|
||||
} else {
|
||||
// no-op: copy always uses latest revision
|
||||
}
|
||||
}
|
||||
|
||||
async function openConfigActionModal(uuid, currentName, currentProjectUUID) {
|
||||
document.getElementById('config-action-uuid').value = uuid;
|
||||
document.getElementById('config-action-current-name').value = currentName;
|
||||
document.getElementById('config-action-current-project').value = currentProjectUUID || projectUUID;
|
||||
document.getElementById('config-action-name').value = currentName;
|
||||
document.getElementById('config-action-copy').checked = false;
|
||||
populateProjectAutocomplete();
|
||||
const currentProject = projectsCatalog.find(p => p.uuid === (currentProjectUUID || projectUUID));
|
||||
if (currentProject) {
|
||||
const entry = {
|
||||
code: (currentProject.code || '').trim(),
|
||||
name: (currentProject.name || '').trim()
|
||||
};
|
||||
document.getElementById('config-action-project-input').value = formatProjectAutocompleteValue(entry);
|
||||
populateVariantAutocomplete(entry.code, normalizeVariantLabel(currentProject.variant || ''));
|
||||
} else {
|
||||
document.getElementById('config-action-project-input').value = '';
|
||||
populateVariantAutocomplete('', '');
|
||||
}
|
||||
syncActionModalMode();
|
||||
document.getElementById('config-action-modal').classList.remove('hidden');
|
||||
document.getElementById('config-action-modal').classList.add('flex');
|
||||
const nameInput = document.getElementById('config-action-name');
|
||||
nameInput.focus();
|
||||
nameInput.select();
|
||||
}
|
||||
|
||||
function closeConfigActionModal() {
|
||||
document.getElementById('config-action-modal').classList.add('hidden');
|
||||
document.getElementById('config-action-modal').classList.remove('flex');
|
||||
}
|
||||
|
||||
async function saveConfigAction() {
|
||||
const notify = (message, type) => {
|
||||
if (typeof showToast === 'function') {
|
||||
showToast(message, type || 'success');
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
};
|
||||
|
||||
const uuid = document.getElementById('config-action-uuid').value;
|
||||
const currentName = document.getElementById('config-action-current-name').value;
|
||||
const currentProjectUUID = document.getElementById('config-action-current-project').value || projectUUID;
|
||||
const name = document.getElementById('config-action-name').value.trim();
|
||||
const copy = document.getElementById('config-action-copy').checked;
|
||||
const targetProject = resolveTargetProjectUUIDFromInputs();
|
||||
if (targetProject.error) {
|
||||
notify(targetProject.error, 'error');
|
||||
return;
|
||||
}
|
||||
closeCloneModal();
|
||||
loadConfigs();
|
||||
const targetProjectUUID = targetProject.uuid || currentProjectUUID;
|
||||
|
||||
if (!name) {
|
||||
notify('Введите название', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (copy) {
|
||||
const cloneResp = await fetch('/api/projects/' + targetProjectUUID + '/configs/' + uuid + '/clone', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name: name})
|
||||
});
|
||||
if (!cloneResp.ok) {
|
||||
notify('Не удалось скопировать квоту', 'error');
|
||||
return;
|
||||
}
|
||||
closeConfigActionModal();
|
||||
await loadConfigs();
|
||||
notify('Копия создана', 'success');
|
||||
if (targetProjectUUID && targetProjectUUID !== projectUUID) {
|
||||
window.location.href = '/projects/' + targetProjectUUID;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let changed = false;
|
||||
if (name !== currentName) {
|
||||
const renameResp = await fetch('/api/configs/' + uuid + '/rename', {
|
||||
method: 'PATCH',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({name: name})
|
||||
});
|
||||
if (!renameResp.ok) {
|
||||
notify('Не удалось переименовать квоту', 'error');
|
||||
return;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (targetProjectUUID !== currentProjectUUID) {
|
||||
const moveResp = await fetch('/api/configs/' + uuid + '/project', {
|
||||
method: 'PATCH',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({project_uuid: targetProjectUUID})
|
||||
});
|
||||
if (!moveResp.ok) {
|
||||
notify('Не удалось перенести квоту', 'error');
|
||||
return;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
closeConfigActionModal();
|
||||
return;
|
||||
}
|
||||
|
||||
closeConfigActionModal();
|
||||
await loadConfigs();
|
||||
notify('Изменения сохранены', 'success');
|
||||
if (targetProjectUUID && targetProjectUUID !== projectUUID) {
|
||||
window.location.href = '/projects/' + targetProjectUUID;
|
||||
}
|
||||
}
|
||||
|
||||
function openImportModal() {
|
||||
@@ -822,62 +968,29 @@ function updateDeleteVariantButton() {
|
||||
}
|
||||
}
|
||||
|
||||
function openTransferModal(configUUID) {
|
||||
const select = document.getElementById('transfer-variant-select');
|
||||
select.innerHTML = '';
|
||||
const otherVariants = projectVariants.filter(v => v.uuid !== projectUUID);
|
||||
if (otherVariants.length === 0) {
|
||||
alert('Нет других вариантов для переноса');
|
||||
return;
|
||||
}
|
||||
otherVariants.forEach(v => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = v.uuid;
|
||||
opt.textContent = normalizeVariantLabel(v.variant);
|
||||
select.appendChild(opt);
|
||||
});
|
||||
document.getElementById('transfer-config-uuid').value = configUUID;
|
||||
document.getElementById('transfer-modal').classList.remove('hidden');
|
||||
document.getElementById('transfer-modal').classList.add('flex');
|
||||
}
|
||||
|
||||
function closeTransferModal() {
|
||||
document.getElementById('transfer-modal').classList.add('hidden');
|
||||
document.getElementById('transfer-modal').classList.remove('flex');
|
||||
}
|
||||
|
||||
async function transferConfig() {
|
||||
const configUUID = document.getElementById('transfer-config-uuid').value;
|
||||
const targetProjectUUID = document.getElementById('transfer-variant-select').value;
|
||||
if (!configUUID || !targetProjectUUID) return;
|
||||
const resp = await fetch('/api/configs/' + configUUID + '/project', {
|
||||
method: 'PATCH',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({project_uuid: targetProjectUUID})
|
||||
});
|
||||
if (!resp.ok) {
|
||||
alert('Не удалось перенести квоту');
|
||||
return;
|
||||
}
|
||||
closeTransferModal();
|
||||
loadConfigs();
|
||||
}
|
||||
|
||||
document.getElementById('create-modal').addEventListener('click', function(e) { if (e.target === this) closeCreateModal(); });
|
||||
document.getElementById('rename-modal').addEventListener('click', function(e) { if (e.target === this) closeRenameModal(); });
|
||||
document.getElementById('new-variant-modal').addEventListener('click', function(e) { if (e.target === this) closeNewVariantModal(); });
|
||||
document.getElementById('clone-modal').addEventListener('click', function(e) { if (e.target === this) closeCloneModal(); });
|
||||
document.getElementById('config-action-modal').addEventListener('click', function(e) { if (e.target === this) closeConfigActionModal(); });
|
||||
document.getElementById('import-modal').addEventListener('click', function(e) { if (e.target === this) closeImportModal(); });
|
||||
document.getElementById('project-settings-modal').addEventListener('click', function(e) { if (e.target === this) closeProjectSettingsModal(); });
|
||||
document.getElementById('transfer-modal').addEventListener('click', function(e) { if (e.target === this) closeTransferModal(); });
|
||||
document.getElementById('config-action-project-input').addEventListener('input', function(e) {
|
||||
const code = resolveProjectCodeFromInput(e.target.value);
|
||||
populateVariantAutocomplete(code, '');
|
||||
});
|
||||
document.getElementById('config-action-copy').addEventListener('change', function(e) {
|
||||
const currentName = document.getElementById('config-action-current-name').value;
|
||||
const nameInput = document.getElementById('config-action-name');
|
||||
if (e.target.checked && nameInput.value.trim() === currentName.trim()) {
|
||||
nameInput.value = currentName + ' (копия)';
|
||||
}
|
||||
syncActionModalMode();
|
||||
});
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
closeCreateModal();
|
||||
closeRenameModal();
|
||||
closeCloneModal();
|
||||
closeConfigActionModal();
|
||||
closeImportModal();
|
||||
closeProjectSettingsModal();
|
||||
closeTransferModal();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user