Add offline RefreshPrices, fix sync bugs, implement auto-restart
- Implement RefreshPrices for local-first mode - Update prices from local_components.current_price cache - Graceful degradation when component not found - Add PriceUpdatedAt timestamp to LocalConfiguration model - Support both authenticated and no-auth price refresh - Fix sync duplicate entry bug - pushConfigurationUpdate now ensures server_id exists before update - Fetch from LocalConfiguration.ServerID or search on server if missing - Update local config with server_id after finding - Add application auto-restart after settings save - Implement restartProcess() using syscall.Exec - Setup handler signals restart via channel - Setup page polls /health endpoint and redirects when ready - Add "Back" button on setup page when settings exist - Fix setup handler password handling - Use PasswordEncrypted field consistently - Support empty password by using saved value - Improve sync status handling - Add fallback for is_offline check in SyncStatusPartial - Enhance background sync logging with prefixes - Update CLAUDE.md documentation - Mark Phase 2.5 tasks as complete - Add UI Improvements section with future tasks - Update SQLite tables documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,10 +28,10 @@
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- Sync Status Indicator (htmx-powered) -->
|
||||
<div id="sync-status"
|
||||
class="flex items-center gap-3 text-sm"
|
||||
hx-get="/partials/sync-status"
|
||||
hx-trigger="load, refresh from:body, every 30s"
|
||||
hx-swap="innerHTML">
|
||||
<span class="animate-pulse text-gray-400 text-xs">Загрузка...</span>
|
||||
</div>
|
||||
<span id="db-user" class="text-sm text-gray-600"></span>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
<div id="status" class="hidden p-3 rounded-md text-sm"></div>
|
||||
|
||||
<div class="flex space-x-3 pt-4">
|
||||
{{if .Settings}}
|
||||
<a href="/"
|
||||
class="flex-1 px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 transition text-center">
|
||||
Назад
|
||||
</a>
|
||||
{{end}}
|
||||
<button type="button" onclick="testConnection()"
|
||||
class="flex-1 px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 transition">
|
||||
Проверить
|
||||
@@ -122,6 +128,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function checkServerReady() {
|
||||
let attempts = 0;
|
||||
const maxAttempts = 30; // 30 seconds max
|
||||
|
||||
const checkInterval = setInterval(async () => {
|
||||
attempts++;
|
||||
try {
|
||||
const resp = await fetch('/health', { method: 'GET' });
|
||||
const data = await resp.json();
|
||||
|
||||
// Check if we're out of setup mode
|
||||
if (data.status === 'ok') {
|
||||
clearInterval(checkInterval);
|
||||
showStatus('✓ Приложение запущено! Перенаправление...', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/';
|
||||
}, 1000);
|
||||
}
|
||||
} catch (e) {
|
||||
// Server still restarting, continue polling
|
||||
if (attempts >= maxAttempts) {
|
||||
clearInterval(checkInterval);
|
||||
showStatus('Сервер не отвечает. Обновите страницу вручную.', 'error');
|
||||
}
|
||||
}
|
||||
}, 1000); // Check every second
|
||||
}
|
||||
|
||||
document.getElementById('setup-form').addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
showStatus('Сохранение настроек...', 'info');
|
||||
@@ -136,9 +170,12 @@
|
||||
const data = await resp.json();
|
||||
|
||||
if (data.success) {
|
||||
showStatus(data.message + ' Перенаправление...', 'success');
|
||||
showStatus('✓ ' + data.message, 'success');
|
||||
// Wait for restart and redirect to home
|
||||
setTimeout(() => {
|
||||
window.location.href = '/';
|
||||
showStatus('✓ Настройки сохранены. Проверка подключения...', 'success');
|
||||
// Poll until server is back
|
||||
checkServerReady();
|
||||
}, 2000);
|
||||
} else {
|
||||
showStatus(data.error, 'error');
|
||||
|
||||
Reference in New Issue
Block a user