feat: unify sync functionality with event-driven UI updates
- Refactored navbar sync button to dispatch 'sync-completed' event - Configs page: removed duplicate 'Импорт с сервера' button, added auto-refresh on sync - Projects page: wrapped initialization in DOMContentLoaded, added auto-refresh on sync - Pricelists page: added auto-refresh on sync completion - Consistent UX: all lists update automatically after 'Синхронизация' button click - Removed code duplication: importConfigsFromServer() function no longer needed - Event-driven architecture enables easy extension to other pages Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -285,6 +285,14 @@
|
|||||||
showToast(successMessage, 'success');
|
showToast(successMessage, 'success');
|
||||||
// Update last sync time - removed since dropdown is gone
|
// Update last sync time - removed since dropdown is gone
|
||||||
// loadLastSyncTime();
|
// loadLastSyncTime();
|
||||||
|
|
||||||
|
// Dispatch custom event for pages to react to sync completion
|
||||||
|
window.dispatchEvent(new CustomEvent('sync-completed', {
|
||||||
|
detail: {
|
||||||
|
endpoint: endpoint,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
}));
|
||||||
} else if (resp.status === 423) {
|
} else if (resp.status === 423) {
|
||||||
const reason = data.reason_text || data.error || 'Синхронизация заблокирована.';
|
const reason = data.reason_text || data.error || 'Синхронизация заблокирована.';
|
||||||
showToast(reason, 'error');
|
showToast(reason, 'error');
|
||||||
|
|||||||
@@ -4,13 +4,10 @@
|
|||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<h1 class="text-2xl font-bold">Мои конфигурации</h1>
|
<h1 class="text-2xl font-bold">Мои конфигурации</h1>
|
||||||
|
|
||||||
<div id="action-buttons" class="mt-4 grid grid-cols-1 sm:grid-cols-2 gap-3">
|
<div id="action-buttons" class="mt-4">
|
||||||
<button onclick="openCreateModal()" class="py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium">
|
<button onclick="openCreateModal()" class="w-full sm:w-auto py-3 px-6 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium">
|
||||||
+ Создать новую конфигурацию
|
+ Создать новую конфигурацию
|
||||||
</button>
|
</button>
|
||||||
<button id="import-configs-btn" onclick="importConfigsFromServer()" class="py-3 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 font-medium">
|
|
||||||
Импорт с сервера
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 inline-flex rounded-lg border border-gray-200 overflow-hidden">
|
<div class="mt-4 inline-flex rounded-lg border border-gray-200 overflow-hidden">
|
||||||
@@ -785,44 +782,19 @@ async function loadConfigs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importConfigsFromServer() {
|
|
||||||
const button = document.getElementById('import-configs-btn');
|
|
||||||
const originalText = button.textContent;
|
|
||||||
button.disabled = true;
|
|
||||||
button.textContent = 'Импорт...';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const resp = await fetch('/api/configs/import', { method: 'POST' });
|
|
||||||
const data = await resp.json();
|
|
||||||
|
|
||||||
if (!resp.ok) {
|
|
||||||
alert('Ошибка импорта: ' + (data.error || 'неизвестная ошибка'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
alert(
|
|
||||||
'Импорт завершен:\n' +
|
|
||||||
'- Новых: ' + (data.imported || 0) + '\n' +
|
|
||||||
'- Обновлено: ' + (data.updated || 0) + '\n' +
|
|
||||||
'- Пропущено (локальные изменения): ' + (data.skipped || 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
currentPage = 1;
|
|
||||||
await loadConfigs();
|
|
||||||
} catch (e) {
|
|
||||||
alert('Ошибка импорта с сервера');
|
|
||||||
} finally {
|
|
||||||
button.disabled = false;
|
|
||||||
button.textContent = originalText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
applyStatusModeUI();
|
applyStatusModeUI();
|
||||||
loadProjectsForConfigUI().then(loadConfigs);
|
loadProjectsForConfigUI().then(loadConfigs);
|
||||||
|
|
||||||
// Load latest pricelist version for badge
|
// Load latest pricelist version for badge
|
||||||
loadLatestPricelistVersion();
|
loadLatestPricelistVersion();
|
||||||
|
|
||||||
|
// Listen for sync completion events from navbar
|
||||||
|
window.addEventListener('sync-completed', function(e) {
|
||||||
|
// Reset pagination and reload configurations list
|
||||||
|
currentPage = 1;
|
||||||
|
loadConfigs();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('configs-search').addEventListener('input', function(e) {
|
document.getElementById('configs-search').addEventListener('input', function(e) {
|
||||||
|
|||||||
@@ -235,6 +235,12 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
checkPricelistWritePermission();
|
checkPricelistWritePermission();
|
||||||
loadPricelists(1);
|
loadPricelists(1);
|
||||||
|
|
||||||
|
// Listen for sync completion events from navbar
|
||||||
|
window.addEventListener('sync-completed', function(e) {
|
||||||
|
// Reload pricelists on sync completion
|
||||||
|
loadPricelists(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -385,6 +385,7 @@ async function copyProject(projectUUID, projectName) {
|
|||||||
loadProjects();
|
loadProjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
loadProjects();
|
loadProjects();
|
||||||
|
|
||||||
document.getElementById('projects-search').addEventListener('input', function(e) {
|
document.getElementById('projects-search').addEventListener('input', function(e) {
|
||||||
@@ -420,6 +421,13 @@ document.getElementById('create-project-modal').addEventListener('click', functi
|
|||||||
closeCreateProjectModal();
|
closeCreateProjectModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for sync completion events from navbar
|
||||||
|
window.addEventListener('sync-completed', function(e) {
|
||||||
|
// Reset pagination and reload projects list
|
||||||
|
loadProjects();
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user