diff --git a/plugins/sync/frontend/src/SyncSettings.svelte b/plugins/sync/frontend/src/SyncSettings.svelte index 8b9c9e0..46f2f50 100644 --- a/plugins/sync/frontend/src/SyncSettings.svelte +++ b/plugins/sync/frontend/src/SyncSettings.svelte @@ -6,67 +6,102 @@ let errorMsg = '' let resultMsg = '' let resultKind = '' + let connectionResult = '' + let connectionOk = null let serverUrl = '' let username = '' let password = '' - let syncInterval = 0 + let syncInterval = 5 let autoSync = false - let showDisconnectConfirm = false - let showResetKeyConfirm = false - let connectionOk = null + + const INPUT_STYLE = 'width:100%;background:#0f3460;border:1px solid #1a3a5c;color:#e0e0f0;padding:8px 10px;border-radius:4px;font-size:0.85rem;box-sizing:border-box;height:36px;' + const INPUT_FOCUS_STYLE = INPUT_STYLE + 'outline:none;border-color:#4ecca3;' function sanitizeError(msg) { if (!msg) return 'Unknown error' - let s = String(msg) - s = s.replace(/<[^>]+>/g, '') + let s = String(msg).replace(/<[^>]+>/g, '') if (s.length > 200) s = s.substring(0, 200) + '...' return s } async function backendCall(method, ...args) { - if (api && api.backend && typeof api.backend.call === 'function') { + if (api?.backend && typeof api.backend.call === 'function') { return await api.backend.call(method, ...args) } throw new Error('Plugin API backend.call not available') } async function load() { + try { + if (api?.settings?.read) { + const saved = await api.settings.read() + if (saved) { + serverUrl = saved.serverUrl || '' + username = saved.username || '' + autoSync = !!saved.autoSync + syncInterval = saved.syncInterval || 5 + } + } + } catch (_) {} try { settings = await backendCall('SyncStatus') if (settings) { - serverUrl = settings.serverUrl || '' - syncInterval = settings.syncInterval || 0 - autoSync = settings.syncInterval > 0 + if (settings.serverUrl) serverUrl = settings.serverUrl + if (settings.syncInterval != null) syncInterval = settings.syncInterval + if (settings.syncInterval > 0) autoSync = true } - } catch (e) { settings = null } + } catch (_) { settings = null } } load() - async function testConnection() { + async function saveSettings() { + if (syncInterval < 1 || syncInterval > 1440) { + errorMsg = 'Sync interval must be between 1 and 1440 minutes.' + return + } loading = true errorMsg = '' - resultKind = '' + resultMsg = '' + try { + if (api?.settings?.write) { + await api.settings.write({ serverUrl, username, autoSync, syncInterval }) + } + resultMsg = 'Settings saved.' + resultKind = '' + } catch (e) { + errorMsg = sanitizeError(e.message || e) + } + loading = false + } + + async function testConnection() { + if (!serverUrl) { errorMsg = 'Server URL is required.'; return } + loading = true + connectionResult = '' connectionOk = null + errorMsg = '' try { await backendCall('SyncTestConnection', serverUrl, username, password) connectionOk = true - resultMsg = 'connection ok' + connectionResult = 'Connection successful.' } catch (e) { connectionOk = false - resultMsg = 'connection failed: ' + sanitizeError(e.message || e) + connectionResult = 'Connection failed: ' + sanitizeError(e.message || e) } loading = false } async function configureSync() { + if (!serverUrl) { errorMsg = 'Server URL is required.'; return } loading = true errorMsg = '' - resultKind = '' + connectionResult = '' try { await backendCall('SyncConfigure', serverUrl, username, password) - resultMsg = 'configured' + connectionResult = 'Connected successfully.' + connectionOk = true username = '' password = '' await load() @@ -80,22 +115,18 @@ const conflicts = Array.isArray(result?.conflicts) ? result.conflicts : [] const applyErrors = Array.isArray(result?.applyErrors) ? result.applyErrors : [] const parts = [] - if (conflicts.length > 0) { - parts.push(conflicts.length + ' conflict(s)') - } - if (applyErrors.length > 0) { - parts.push(applyErrors.length + ' error(s)') - } + if (conflicts.length > 0) parts.push(conflicts.length + ' conflict(s)') + if (applyErrors.length > 0) parts.push(applyErrors.length + ' error(s)') return parts.join(' · ') } async function runSyncNow() { loading = true errorMsg = '' - resultKind = '' + resultMsg = '' try { const r = await backendCall('SyncNow') - const summary = 'pushed ' + (r?.pushed || 0) + ', pulled ' + (r?.pulled || 0) + const summary = 'Pushed ' + (r?.pushed || 0) + ', pulled ' + (r?.pulled || 0) const warning = syncResultWarning(r) resultMsg = warning ? summary + ' · ' + warning : summary resultKind = warning ? 'warning' : '' @@ -106,420 +137,105 @@ loading = false } - async function saveInterval() { - loading = true - errorMsg = '' - resultKind = '' - try { - await backendCall('SyncSetInterval', syncInterval) - resultMsg = 'settings saved' - resultKind = '' - } catch (e) { - errorMsg = sanitizeError(e.message || e) - } - loading = false + function toggleAutoSync() { + autoSync = !autoSync + if (autoSync && syncInterval < 1) syncInterval = 5 + saveSettings() } - async function setAutoSync() { - const minutes = autoSync ? 5 : 0 - syncInterval = minutes - loading = true - errorMsg = '' - resultKind = '' - try { - await backendCall('SyncSetInterval', minutes) - resultMsg = autoSync ? 'auto-sync enabled' : 'auto-sync disabled' - resultKind = '' - } catch (e) { - errorMsg = sanitizeError(e.message || e) + function saveInterval() { + if (syncInterval < 1 || syncInterval > 1440) { + errorMsg = 'Sync interval must be between 1 and 1440 minutes.' + return } - loading = false - } - - function confirmDisconnect() { - showDisconnectConfirm = true + autoSync = syncInterval > 0 + saveSettings() } async function doDisconnect() { - showDisconnectConfirm = false loading = true - resultKind = '' + errorMsg = '' + resultMsg = '' try { await backendCall('SyncDisconnect') - resultMsg = 'disconnected' + resultMsg = 'Disconnected from server.' + resultKind = '' + settings = null await load() - } catch (e) { errorMsg = sanitizeError(e.message || e) } - loading = false - } - - function confirmResetKey() { - showResetKeyConfirm = true - } - - async function doResetKey() { - showResetKeyConfirm = false - loading = true - resultKind = '' - try { - await backendCall('ResetSyncKey') - resultMsg = 'key reset' - await load() - } catch (e) { errorMsg = sanitizeError(e.message || e) } - loading = false - } - - function statusLabel(s) { - if (!s) return 'not configured' - const labels = { - 'connected': 'connected', - 'disconnected': 'disconnected', - 'disabled': 'not configured', - 'error': 'error', - 'revoked': 'revoked', + } catch (e) { + errorMsg = sanitizeError(e.message || e) } - return labels[s] || s + loading = false } -
Synchronize your vault across devices.
+Synchronize your vault across devices.
{#if errorMsg} -This will remove the stored device token. You will need to re-pair this device with the server.
-