From 3c6bc097e1643d2675957d8cd1b49e845ee759c3 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Thu, 4 Jun 2026 03:39:52 +0800 Subject: [PATCH] fix: show manual sync conflicts in gui --- frontend/src/App.svelte | 28 +++++++++++++++++++++++++--- frontend/src/lib/SyncStatus.svelte | 15 +++++++++++++++ frontend/src/lib/i18n/locales/en.js | 3 +++ frontend/src/lib/i18n/locales/ru.js | 2 ++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 04b5dc6..a3f17aa 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -148,6 +148,8 @@ // ===== Sync state ===== let syncStatus = null let syncLoading = false + let syncMessage = '' + let syncMessageKind = '' const tabs = [ { id: 'overview', label: t('tab.overview') }, @@ -1431,15 +1433,35 @@ showSettings = false } + function syncResultMessage(result) { + const conflicts = Array.isArray(result?.conflicts) ? result.conflicts : [] + const applyErrors = Array.isArray(result?.applyErrors) ? result.applyErrors : [] + const parts = [] + if (conflicts.length > 0) { + parts.push(t('sync.conflictsCount', { count: conflicts.length })) + } + if (applyErrors.length > 0) { + parts.push(t('sync.applyErrorsCount', { count: applyErrors.length })) + } + return parts.join(' · ') + } + async function runSyncNow() { syncLoading = true + syncMessage = '' + syncMessageKind = '' try { - await wailsCall('SyncNow') + const result = await wailsCall('SyncNow') await loadSyncStatus() + syncMessage = syncResultMessage(result) + syncMessageKind = syncMessage ? 'warning' : '' } catch (e) { console.error('sync error:', e) + syncMessage = `${t('sync.status.error')}: ${e?.message || e}` + syncMessageKind = 'warning' + } finally { + syncLoading = false } - syncLoading = false } // First run / recovery handlers @@ -1521,7 +1543,7 @@ + {#if syncMessage} +
+ {syncMessage} +
+ {/if} {:else}
@@ -88,6 +95,14 @@ gap: 0.3rem; margin-left: auto; } + .sync-message { + margin-top: 0.25rem; + color: var(--text-dim, #888); + line-height: 1.25; + } + .sync-message-warning { + color: #f59e0b; + } .btn-xs { padding: 0.2rem 0.5rem; font-size: 0.75rem; diff --git a/frontend/src/lib/i18n/locales/en.js b/frontend/src/lib/i18n/locales/en.js index 1f7c2a6..5a0cab1 100644 --- a/frontend/src/lib/i18n/locales/en.js +++ b/frontend/src/lib/i18n/locales/en.js @@ -87,6 +87,9 @@ export default { 'sync.connected': 'Connected', 'sync.notConnected': 'Not connected', 'sync.disabled': 'Disabled', + 'sync.status.error': 'Sync error', + 'sync.conflictsCount': 'Conflicts: {count}', + 'sync.applyErrorsCount': 'Apply errors: {count}', 'kind.project': 'Project', 'kind.client': 'Client', diff --git a/frontend/src/lib/i18n/locales/ru.js b/frontend/src/lib/i18n/locales/ru.js index 73d9586..d6cb2ba 100644 --- a/frontend/src/lib/i18n/locales/ru.js +++ b/frontend/src/lib/i18n/locales/ru.js @@ -431,6 +431,8 @@ export default { 'sync.retry': 'Повторить', 'sync.run': 'Синхронизировать', 'sync.running': 'Синхронизация...', + 'sync.conflictsCount': 'Конфликты: {count}', + 'sync.applyErrorsCount': 'Ошибки применения: {count}', 'error.generic': 'Произошла ошибка', 'error.invalidCredentials': 'Неверный логин или пароль',