feat(templates): add service language template management

Add normalized service and template catalogs, scoped administration, migration, validation, and regression coverage.

Ref: IT-1601
This commit is contained in:
2026-10-17 22:02:43 +03:00
parent 36810dc5f1
commit 81654c0d33
73 changed files with 4061 additions and 820 deletions
@@ -0,0 +1,36 @@
(() => {
const form = document.getElementById('serviceForm');
const rows = document.getElementById('serviceLanguages');
const alert = document.getElementById('serviceLanguageAlert');
let sequence = rows.children.length;
let dirty = false;
function reindex() {
Array.from(rows.children).forEach((row, index) => row.querySelectorAll('[name]').forEach(input => {
input.name = input.name.replace(/Languages\[\d+\]/, `Languages[${index}]`);
}));
}
document.getElementById('addServiceLanguage').addEventListener('click', () => {
const fragment = document.createElement('template');
fragment.innerHTML = document.getElementById('serviceLanguageRow').innerHTML.replaceAll('__index__', String(sequence++));
rows.append(fragment.content);
reindex();
rows.lastElementChild.querySelector('input:not([type="hidden"])').focus();
dirty = true;
});
rows.addEventListener('click', event => {
const button = event.target.closest('.remove-service-language');
if (!button) return;
if (Number(button.dataset.count) > 0) {
alert.textContent = `Cannot remove this language: ${button.dataset.count} version(s) use it. Save other changes, then use the separate delete language and versions confirmation.`;
return;
}
button.closest('tr').remove();
reindex();
dirty = true;
});
form.addEventListener('input', () => { dirty = true; });
form.addEventListener('submit', () => { dirty = false; });
window.addEventListener('beforeunload', event => {
if (dirty) { event.preventDefault(); event.returnValue = ''; }
});
})();